BIND 10 trac684, updated. d11b5e89203a5340d4e5ca51c4c02db17c33dc1f Merge branch 'master' into trac684
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue May 17 08:50:16 UTC 2011
The branch, trac684 has been updated
via d11b5e89203a5340d4e5ca51c4c02db17c33dc1f (commit)
via de0694d2f4c7dba909eb922e3fa1a1269d3cbc78 (commit)
via 7c390c1149baab7bd33e741afcdefb827275d5cd (commit)
via d1b5154a7c17058ff49aa67f389f52496228e4b6 (commit)
via 7c576f2e3d986b0f58883776822323ff57535a3c (commit)
via 201bae76d11706e9fe9c09491ed216c225a02e9d (commit)
via be4334aa0b66fd01f9b3f859c309545459dfab00 (commit)
via 1440e71559ad3565dff46e9cac31f31e6748d8f2 (commit)
via a407cb3d58c78b93afe294be13e7b360b11fd542 (commit)
via 1cccbc6845d795f8d8e2b0c7ba637fb28e179e71 (commit)
via 0c81e90348e53e673a05e92e150cec0f598a2d4e (commit)
via 882cc4d6b2b9f391e72fdc0bf8eb82bdb846ca61 (commit)
via 081891b38f05f9a186814ab7d1cd5c572b8f777f (commit)
via 4472e3c7cbfb5fd33ce575bd2666036d363b2ce2 (commit)
via 04c0fbf9fa780b4a281c5982ec33e5632852cfa1 (commit)
via dc19181b46dec42bc5db83861731656a5b45b899 (commit)
via 224c7b9aeb3000e11790a2c667f0ee45c9481f17 (commit)
via fd08a0dc40846f58aaa8a7df7726ac83e5e4c038 (commit)
via 98f5e0e604e60fead409c28645b064510b8fc8de (commit)
via 46629b17783d3ddf624002893af955d525f453a8 (commit)
via a1a58a7382e82256f3f6785b7bebfa4643cced67 (commit)
via 928a439496c6040392cc03615c38aa3de45bfe87 (commit)
via 8e28187a582820857ef2dae9b13637a3881f13ba (commit)
via 4b3e621a4497ac99978d40b316b11581cf80d088 (commit)
via 1ce058332d84de9bc2f37344d0b49c24d3c30551 (commit)
via 4e0adcf35398ec9f5c3a7a4b14e9a1aedcf9f66a (commit)
via 87d5f96fe04dab6de30c733230669703a2429701 (commit)
via 324cf344f3e0cd9e35e50076911fe7801a7d4690 (commit)
via d3da4f1f4f00d13962e6f23ff1272269569be5d4 (commit)
via 3336f575aee4072d1d88b05f7db79712384ef2d8 (commit)
via f6e9a1186d00e023021f5853e5a7a1d7c3f838cf (commit)
via f15bdf8420351828159c0d7847d4f653388bf53c (commit)
via a234b20dc6617392deb8a1e00eb0eed0ff353c0a (commit)
via 97a0938cfafb96358649b9a538b00fbb3ee42ea0 (commit)
via 023527c23812b2f999c938ff1ee5b30434209297 (commit)
via 86632c12308c3ed099d75eb828f740c526dd7ec0 (commit)
via dafe7a6038499cc0432f4dd6f968b7fb1ffb119b (commit)
via e93cfe3f6812d8a1fef103e34d9d1a6ee88dd8d7 (commit)
via d1fdfd86c9b8e0120e557e2c7baaab542f9c2719 (commit)
via 744fe91ac965c576cbe916ca39a0bef54afdcd3f (commit)
via ff36bea0314636d978f61923cc7292364c1808fa (commit)
via d686e00a5dd1efae29891e8056af324ea983d187 (commit)
via da57d4a08a2e14e5e6589138692674894f667f54 (commit)
via 5aaa6c0f628ed7c2093ecdbac93a2c8cf6c94349 (commit)
via 345b5986ff26015475b5e17506b3ca6cafaea8bd (commit)
via 7b25152b5bbbaff6840f88ad7ff2684f8b8062a6 (commit)
via 76a81d33b95b12341515cc6ca5718d72a242ab59 (commit)
via 8339141a4a64043e82685f0e6793b592b7ac820a (commit)
via 25c5c37094f9845be826f91bf5901068415891f6 (commit)
via 9df5e254832c5c65ddf4a0895c09256e8386820f (commit)
via 36af50328be059026859a09d402ff2d591789dfd (commit)
via f8c763ef2c9eb8343ead481093e2d0024e3f1cd2 (commit)
via f5278f2ac4becb33b93dc4c2fa7e6558a7daad8f (commit)
via c47f23e502e998d7885d4d3d679c1eacb1dab790 (commit)
via f80cdaf115a8ad80184240b283b243ac07bb9739 (commit)
via c2693bb84ea22e3b44617d729d8d2e8dbd99c51c (commit)
via 2b521f9674a0d9aea7fb06d71b008e64c40922aa (commit)
via 2f25f64f9f7a1021b67b9c37cfca41e86f5ae032 (commit)
via 14f8767d89d62e0d573a1e6b31fbeea9272e7011 (commit)
via 32872f1e745f45d1c0e84943cf57ad985a925f3e (commit)
via a82432e09cc7f3b22920d9baecba1f8e89332f37 (commit)
via 9eddc07cd32918f3b8e9ebd114d9c8f8f39a359b (commit)
via 143b2c6769c64eb55d2f34305ad8e2b7ce681aa6 (commit)
via 4569c1b87f5d04f663e1c8e2813d090a78dd9e40 (commit)
via ee53746391bcfdaa75bba0db87add3dc7becb84d (commit)
via 92c0c95057cd98a5b8cf8099367a122684cf329b (commit)
via 296ec6be00c208aa9ab8cbaa20376749e8b6ab49 (commit)
via 7deb4955ef8816885376e558e7f0eaf65e22b4d4 (commit)
via b916d130e0799f457634cfba2b06fc1250db54a0 (commit)
via 1ea71dc16928433c1243375bd9210d5fceb28fe6 (commit)
via e7a49bee8af14cf5d4e16e14cb5bdd3ba83385b9 (commit)
via ed62a7f4dde0264cd60e4b739c41be9c98bbe3e4 (commit)
via 38932d7e76c4e35aca7382640e9e86360a389545 (commit)
via 55b3152ebb03fbe946986a52732f79a68d926163 (commit)
via 29d36377ec206cbe52274ee9a5a6e88ef27921d5 (commit)
via 25b33e62902b5bb181405e2177d2fe935cfe6c75 (commit)
via a892818fb13a1839c82104523cb6cb359c970e88 (commit)
via df1ab797a9d1a2a188060c70071bb8fa7d6f1a01 (commit)
via 6fc6ecda47f8556fc0a4daabc042b0b1a2d7d592 (commit)
via b653f950b906ecf4194d2a2cd07fa92ae47dd546 (commit)
via ceef68cd1223ae14d8412adbe18af2812ade8c2d (commit)
via 879d981650dff5ee577712aa45aa9b363b039a04 (commit)
via e595402348d7766d7e3f7fd8d9f32bd8b144f747 (commit)
via 33cd7d9232078f70aa380309a3615a1a9d743988 (commit)
via fb26d933e7af0cc07fe686ef88ef95b28cd10d2b (commit)
via 48d2369e3a7c0e55f5c94973ab0191ddfbaa02c1 (commit)
via afd75a89d7aeba622b53c5b37e3f76572ef68c3a (commit)
via 8d9debda3a88cb20d19d23dbdfe106b3132a4ead (commit)
via 6eba2b45ef54d671c674d7d840dc99208eb5d00c (commit)
via 4787c281a351b04b9570b8bb2d863db706a9d9c9 (commit)
via 9bd9fa819f30aff560da9412ffa14d87e557ab69 (commit)
via d53bbaf239de6059dd0d8872f84d1a0db6ccb90c (commit)
via 7b0d9b1dc03d9343f3ccfed2fb5876d7d9f048d5 (commit)
via d65686925bbd04cbbfa3ca2705f54696b76beb45 (commit)
via 4f6b51bc00d3f37b8938951217cd1f3564bedcd8 (commit)
via b395258c708b49a5da8d0cffcb48d83294354ba3 (commit)
via 569b2b6e5d84277316bce84c0e118ffd116ffe5e (commit)
via e5687a75c06966ab68ad453093fb6c7b9d8fe761 (commit)
via 119678f768f09b13d6ecb715ad731d1dca8f05b0 (commit)
via 4903410e45670b30d7283f5d69dc28c2069237d6 (commit)
via 27a4c936d87d31952f6a8377e04cae1fb90edffd (commit)
via 9eb7b41d5253c44e59987170a74e345b651c96bc (commit)
via 7f642b767c8274a6f3344e4a5e1141e9e7f38924 (commit)
via 7efc144e0eacc123544507d635630b7949052993 (commit)
via 43db6eac145a6a9a59f6d892a9b9fd2384a12d51 (commit)
via ad6d052794693ec22f430109de624b8fd7ea212d (commit)
via a4f08f816c968fd9dc614f171b8925b5b7998da7 (commit)
via a7a3c9f8cc85f04267a5606f4413afcde7af1864 (commit)
via ea37ca8caa7c56fea957fc7aac066d5708675f28 (commit)
via 4ff5a9f61d9ad1c96468556771562f1dbad7ec98 (commit)
via e93f054a2d0cf1c21d00112ccaa93d5d2432a677 (commit)
via c16b3ab523860ccca5e8e9648b58801c3eefae29 (commit)
via b734c55b73941125af327595ba39252add032791 (commit)
via daab0dcd59baee4b1e56eab640e29c9e8e947e80 (commit)
via 00a15b4b06f9de757b30cd320fd56431980f8458 (commit)
via 8bfccfb1fead0448e959126e07dad1a800880575 (commit)
via a09ced080782388e389ee6c669b9d36da65f9dc5 (commit)
via b21c74c08fbdd350bcd01b083fc3cf29a98e5a3a (commit)
via cabd3b127cf5ab2b916c5717992338316496de8b (commit)
via 9a8870c515be763e8be63cdc28231883601867d4 (commit)
via fb1d629419b6c58b9c9f410e6c027c8769e0c9a3 (commit)
via 0709f8b56df68cfe0c79ed98bfe7e9dd25ce0e1e (commit)
via 40e06e655ce78197f0b52d8c5dc9c7516795362f (commit)
via 80c0a2c3eec3ac5d3ac862f9b4c5926f0eece6ed (commit)
via 11439c030741ce402c52ad9d3cd1a407d45a443e (commit)
via e564debcb683454296d3e3cf478748daa0b08cbc (commit)
via fba4ec1d7269284b48042b1a7ea084b531bf8d9c (commit)
via cccc20cac1d91951bd9b707c3dfb532e9ad8686b (commit)
via 68c9545bb7d57933e514ef55779abfd06c38145b (commit)
via 2cf390147f147dfab2c8c63c470177189799ed20 (commit)
via 287ee379ad62f9043699c936dc1204b6a906f52c (commit)
via b5646b50e23e6049f233f755d7e143a09d4fb19c (commit)
via d4d910b28b3226d1330b7da1df170c406771b939 (commit)
via 7bb5dc265a830d8993c9cb1da55194631e657587 (commit)
via 1e3c154cd21cede83a8bbd7a559c20752b58ce24 (commit)
via 434719dc9b7eeee0d0901fa6f5e1847bc40691c2 (commit)
via 0ecb807011196eac01f281d40bc7c9d44565b364 (commit)
via fa321eca22c746101dd9cf67c7bc9da6de30483a (commit)
via a64f778b468ff7bd95461d1228aec66565602d57 (commit)
via eef87432f746406d467c647dd7302fc4cac8d53f (commit)
via ee2664ecf4fda60a78e97d39c4f69b4f22d5aa24 (commit)
via fb283c1a0e6f8cdacc9c326f00caef141b058f1f (commit)
via 4c178871eba133fbbf56c2dac1dde1a28ad20477 (commit)
via ffa2f0672084c1f16e5784cdcdd55822f119feaa (commit)
via 7c40e60eeaad7f2c1ea79f92e866dee08eafd5ab (commit)
via fcc1b5e13946c5e58e2bd0bf287f551e161f0544 (commit)
via b6d140b6169c130b06896d2b40df58752991a47d (commit)
via eab5008d28b04fdd7c0f4c93051fd3b1c1a416f7 (commit)
via 313464eed2b54281b8b2357002cd7dfb9231ddf6 (commit)
via 121d3e844ad6d8ed8aa21dd48c53095e2f770117 (commit)
via c3dad479414b01979693ba71c832aedd681f5044 (commit)
via a23491a635d7f74132fc0b91eac832275f8f1f87 (commit)
via 9a2ca8e5de8a23018ebb0ac7fee819c065542ff1 (commit)
via 284c8b457d8a8940265da1e4d0c7b1050806afbb (commit)
via 7c54055c0e47c7a0e36fcfab4b47ff180c0ca8c8 (commit)
via 5c497dfce7d23487c2aefe9907f942c39c4c5846 (commit)
via 83717978e3941e4eb5d7dc90d26a88256efd3175 (commit)
via df0c3599c1f3ad957df20eb8cc04c33d1c958e4a (commit)
via 40870d717a8017379cdb68db9ed15ca71faddd5f (commit)
via d846851699d5c76937533adf9ff9d948dfd593ca (commit)
via 372a2f033edf044d3f515f3b5009d0c8fce3ce16 (commit)
via 89fcb0f002447e2cc3148e212f1ecd4f6d1bd821 (commit)
via a437d4e26b81bb07181ff35a625c540703eee845 (commit)
via 0338dd8c3ef74395235bc37533269fb252142263 (commit)
via 28c50de2e9ef07250b54a3d99850ee353f511ffe (commit)
via 297955d6928e3202c25d0f1fa17708c032c46a40 (commit)
via 2979d921553eaaf59cfbe6b78bd726e09006ca9e (commit)
via db0ca2fbc64b390f261b5e36938c736321b171f9 (commit)
via 7f0a7a5ff8d2452c4b48575a725f97e5981aff66 (commit)
via 2aca19e705f02400a6b213ef84fa81c86dff0375 (commit)
via cf46f370333b15487f6c02f85749d90c2e0bd710 (commit)
via 4fff42d6c9ae24effcae3f6eaa73a8a4eda5a38f (commit)
via 25bc145bb597683411ece6ad7cb72fc0fabedeae (commit)
via df8ef3fffa7a4186d7ade60b514bb78acbb9b33c (commit)
via 79b087eab39177799e38611661fd86125d9b8a67 (commit)
via efdf126e6e0fe75afa26d4d7cdcce663892a840c (commit)
via 35a7c63a23646994af69a1a6d325ad11b4bc8354 (commit)
via a91fc737dd4c982194392b467b68c6c8383cec55 (commit)
via 34c2d5bbe08e41b0802eb6ca58a8084595064803 (commit)
via 4a2c0e7a8852496e9b8f9a56f5058cb1f55d3f55 (commit)
via c83d4bea0e9abc94b84315eb42c8ed7a879c8899 (commit)
via 7e9ea719c8fda75f346eb87daae58cf06c8070e0 (commit)
via e4f2823d8b564c5b2c2f7029e5eb81be6b058d3c (commit)
via 25301e86fb8aa4cb8d98933a0c3b7dcf46f8c4be (commit)
via 1b967a5870088c3f4c7b5a3b8202e1b2e9572690 (commit)
via 50ebc839b1c8389eb1b7b70f02758a9034138552 (commit)
via bb568b0fbb855dcf79681de5024c09b91251ccda (commit)
via 04c515e17a08b41c9dbf241e3983148596353d2c (commit)
via 45417c48a7d32fb6e3f7fdccc70ec2faa8441135 (commit)
via f1dfe74d6b9b2b8c4dc85dd39a43084dc2b73aa9 (commit)
via 6daf339b7a83843a12d4938424063d1b96929924 (commit)
via 3ce5e0a2b96c84ae003ea372bb84ebb19ca355e8 (commit)
via 9e8b5ec4233217fba5c7e9b17afd6c01e4fc7b79 (commit)
via cca71e70d0667d066ba5ab63c65b21d83cbb896c (commit)
via 2d514a764119f29d3e2fbb04366d880df1866928 (commit)
via e22700fc2021180a0dab3f312df5fdabe9bc47e2 (commit)
via 98d147ea68fc1e62b6e7e3bc74c80e9457b5249f (commit)
via 96d1613a474602b833af953a364fb045fcfee776 (commit)
via 6f8490fe9ce1d6dbef326d75f9eab79c09e83462 (commit)
via ac7ff7f2226bdba60809b70caa82659b77c6e2e6 (commit)
via 677cebce1708ba85e46a0712d939176dc7ab7a94 (commit)
via f0fe344b15c3e1be2604201000e6c9fbe6a910bc (commit)
via 5a4d69114ef60bbb86c4fc2190b78761ac4ccc3f (commit)
via 776f5ebd79615b0c05f2009c09bf61c44c59343a (commit)
via 314e299226288d66efe5e65d8e00fc041b688f35 (commit)
via 0e3b55edc75e91ea11df51ecffae0ae4ff07fdac (commit)
via 0261bbec3a5cd8770aee567aaebab2a4f93c2303 (commit)
via e997ff18a6bf1eeb23391e0957db0defdecd0213 (commit)
via 9e183cb0529aeb9f0674b5727affa223d8fc9db5 (commit)
via 31a6f34026c83594bd9f205df18eb290114d9ea1 (commit)
via e34dd62b8eca7abfbfd4851140d663efc43041f1 (commit)
via 8320ec6eb230fe761ae4769367f10383e967655c (commit)
via 38cddfdc23f6d2aa31be24173f9d7c1df2e3c4bc (commit)
via d033a50a7e32664848c360b160e9170cdcd79886 (commit)
via e2e13d0bd0856496a3571ba6b7f35f41e6534859 (commit)
via c8b7abc5751b171621be9edd5156dd2691ff60d1 (commit)
via b8422db8e0120d3998b15581dddcbfe4efe91a68 (commit)
via da16cc776443e1414f779d7402996c6949934765 (commit)
via d6db622c5649e745fb3c64218e36c41545c47aed (commit)
via cce60befee1e0c25e20449b9242112cc0a777089 (commit)
via 89dd4548179485bdf76a84d289ab88ba65bd07bc (commit)
via 364be72653933235d362a57c9342bae1c6e17b3a (commit)
via 43f9ce0c56cd14c0349a8f3c3c9a5f4dc092f65a (commit)
via ebe0c4b1e66d359227bdd1bd47395fee7b957f14 (commit)
via d9b00f6ded6d0cfb41a0939cb613c1e7bd703a67 (commit)
via 2c60d79949a79fc8f093f3447c949e7c63f83137 (commit)
via 0ede9e8f8c0e1d89a01cdb1eccb5256363bda0cf (commit)
via 64cee1a7ad8341b83954e022487744060b59d04a (commit)
via 177b356c926307e94a95e6e2de7a3f0ee7124021 (commit)
via 1867180c5e2263baf319514b5b765b8eb4049c08 (commit)
via 6c554c8b4e37daeaa4182d05af69a40a0b78cea2 (commit)
via 6eb7a93e81027bcf67435188c1ff7788965253cb (commit)
via cacab413e886e8c90691428e1e3f78b77814945e (commit)
via ea1f2d6e96715f0821df5d096be46b2454e6073a (commit)
via 04f7331a44e0bfd48f52d06f6fd463c6652dd38f (commit)
via 5b4feea19e2cc1bdf18ce52cf0062828ad9067c7 (commit)
via ec1ad752576f7f3541b1b57f906256c6a5ae0dc6 (commit)
via 1ce2874170c85de79a896b1cc3077d9f3032d9e0 (commit)
via 1151e49bcec0ac69fe01d084e10f106481337dea (commit)
via b92cca798d702273d63d56d9197782edeb927c8c (commit)
via abdf624576745fa0a4f37319e3c7dbd76047e2d2 (commit)
via 28143beb0e57bbd4d62432b81edc8e179b95959f (commit)
via 76705c8fc54809ece24609deda2d156a844d2bf5 (commit)
via 47dc61713d6bcfc16410fdb657c41dbbef85fb2c (commit)
via a42b39784b65894e7dc164f1b7f2f887715f0c45 (commit)
via 9713a50748616587ca32f17e9931c752aa1e5d3d (commit)
via fe141c14e201993b5e0efe848c2a47e0a4b553bc (commit)
via 0310b8b77e6adb8671d1f9ebfe826e394e95f53f (commit)
via 29170e28d19f35a874d84b88f7c0873c51e28f89 (commit)
via 53d9f46923a22920c04d5bc4fc706ec202686b1b (commit)
via 2842dda9275c1a471d70d3a571d810c8d715bf3a (commit)
via 78bd2b77782510d02748254a8c79249e493b6024 (commit)
via daf48e860413d4c3229ce309253b29d1ad974c7a (commit)
via daa24430a497d145849a687f51252bfed16a2caf (commit)
via 6d03a35ac6dec0508d30cd778fed48257fc6c0e1 (commit)
via 87e4b9874ac16ccc5d236a2fcb8221942713e086 (commit)
via d9433ad4bd9aec1028b9b05aa55e9b083e35a4d4 (commit)
via 9df42279a47eb617f586144dce8cce680598558a (commit)
via 0640f80c7a62cf9c3e289f8290c5a3b44f4385f5 (commit)
via 05c6223cf7f145ec6e96cffed0561a03387b7367 (commit)
via cc788af2c45043fbb98365d5fb85c1d16307dda2 (commit)
via fd45c40964a9557c0a6534c6d0cbe5c377d05066 (commit)
via 475e26bae3b3c4c8823c4931638d0a7af0ac66cd (commit)
via f4ad75548592b2f3eeae22de5685cacbf5c82bae (commit)
via dabf205231ff9e720d8693800e311a89ace18488 (commit)
via ed5025a1322aec3c6aa2855ec807bdcb8e013f1d (commit)
via e4034daa010c24286b969cd9ad6d75c30895cd52 (commit)
via 4903de33e8f5d16ed99b6ad6b22fac023e653f71 (commit)
via 2bb4420b73b5485cbd05a221a414a40f9e7674b0 (commit)
via 0660b35c79dce9ff27361fee48da8c174bf05cd5 (commit)
via 3e37899f95fe561fee0a73fb5d85071065ef3c7d (commit)
via 088bb8cbca563a17b97166bcbb799fd50bbbca4f (commit)
via f099c11348b7947c64f7467677e9afa58ca7023c (commit)
via ad134794bd3fdbb058fe5d50d8e92c71d03d47cc (commit)
via 309bc10ee624106cf75165efd4251312deed3212 (commit)
via 5cd716bd9844e154e6ca58a981787614a3a6fe6c (commit)
via adfd1014c34da20e272f058c9cce43130c637071 (commit)
via 65874313065ddb02756d5ef06c8802c7540c17c7 (commit)
via 98eab34d80219120219d064f6b3b9f0afce3e59a (commit)
via 00e36b253bd643b007f89a8ccb3addac1a723eba (commit)
via 7be4a7e7f859881a3e5a3f4268dbdbc3468b7214 (commit)
via abdb0ff5e8cdd781d7c4960bb51d8538f4e3b44e (commit)
via d4ab440d337cb9ef3f1301c3b655ed0a913cf257 (commit)
via 33eb030ea0a6f980573c9a7ffff41c99535df98e (commit)
via 6c274fd95d3c2bcc99113108f5a68aa0364f924c (commit)
via 241c11e7b06b233585b52df53a9273ab8e0ad405 (commit)
via 3427f489904a83ed1adb8e740aaaf1f6ba80267e (commit)
via dfddb7ba4637530a542b833ee14083421eeba826 (commit)
via 1cbd51919237a6e65983be46e4f5a63d1877b1d3 (commit)
via 81b2d1ceaf680d740f66250b848eea1db05c4a3b (commit)
via d743478f2b76e0f37381f64d5f4e90417260d67c (commit)
via bc436f1f6715aabcc62c468fa6cfd7d3bf694f29 (commit)
via 0194e3a376aa9c1ec2c232b0f2fd9a6cf02e448d (commit)
via 74472396fc8f91daedcd6a286b34b5cae8a5ab57 (commit)
via e5cae846407b0f627ea67ba687132c141c4de57b (commit)
via 5542432e850b29dcd316842a61fcbc2903acbaab (commit)
via b963854734ff8ba78ccb14f2e5a481c9426881c6 (commit)
via ea46adf9f6bbdd78a06ae748d979986a75b9b8d2 (commit)
via ffbe8a099bece23efb94e3adbe8fdfff8cfb379e (commit)
via 3c194549a61e68ed38bbcd90e69f1f954ff286f4 (commit)
via 5a6f9f8c21674d8f70fe33de2b7d7e23c105e888 (commit)
via 5573b0bc953d1a9589d2e0f06b8da58dadb64bc3 (commit)
via b1cb4c4a1421bb512d093690c95d27425b33e1e5 (commit)
via 521c140da800fdb7a7c87e53e01270e02ae4bce2 (commit)
via 583203a8ca082541bc2982752b20294bb972bdcc (commit)
via c32718be9f5409b6f72d98ddcd0b1ccd4c5c2293 (commit)
via 2ec061bcb5fbdd5893377a233219af11a6309cf4 (commit)
via 1096417815a2e2241aa059a24fada61108b2ca90 (commit)
via 2463b96680bb3e9a76e50c38a4d7f1d38d810643 (commit)
via 912b79387bbbe16f5a97513dce140d31917e091e (commit)
via a1703e5ae5fc9458c066fb4aab7666bf4e5fdb8a (commit)
via 823fa0556364ad5bdcd26cb7a42999d502f3af02 (commit)
via e37bfa349bd0b7866a57519bf7f86dbb18c3a104 (commit)
via 145a6173191e6cd39be3d495a6e5d0511dfe867a (commit)
via fb7877b06ba873d4fb222409dd92b4701ae11ffb (commit)
via 21385dbdb72fe02275c859a88674a9d2166a0ed0 (commit)
via 158af09a0032d47503a9e52102bc495b8d5bba46 (commit)
via e9f3843c953ce9a3e05c3dcc4b8df2a67a9d9e6d (commit)
via 9f729b786ad2d12fde55cbaad5de72918fbe209e (commit)
via 20336851f494ff1d9c8937400a99ed4d0203a340 (commit)
via 246e56b3bb7792789b3aa891e21e580976d9e7be (commit)
via 168bed01625dd25fc2c40bd6b402763849e840ec (commit)
via e831ffa2129fc5e013a0217f004896f6f40f258e (commit)
via 4eda7bbc802b24730eb8ef9e5716fc47f19d5a00 (commit)
via fb4a0a36ba0d90409684e8042916341ce35c5f21 (commit)
via 7b1677584cd0cc94825741792f9ed66f16029938 (commit)
via fafa0c06f358f9cc32860535bef1c56d25f20775 (commit)
via bf1cf162e37ff391874569c82c6bef7e8b7e4f18 (commit)
via 122d477847f80c7d77bec087a849b9e6743c17d3 (commit)
via e74f6d5e8f9abb081bde606bc46319488c7e546b (commit)
via f137e0fa3a387fcc13898ea6da6b61dcd80dc8ef (commit)
via 572ac2cf62e18f7eb69d670b890e2a3443bfd6e7 (commit)
via cf456aa1546145ac403e75535e555d773b39ff20 (commit)
via 006b2ea9dabd869bc05682b73b083ea815d520db (commit)
via c34d8eb763ceb840f65de77a22eb67c8b1ab6392 (commit)
via 2aa47d167c58b6718706f8e037927b824ff0cf00 (commit)
via 7ed21ab7e857037f18944e63fa5deac02ecf017a (commit)
via 81c81d70342c7aacfb2689d86aa239e231c310cd (commit)
via 9b16d3b4c04d35914b9eeba56a168d5039d7342b (commit)
via e16c86b6229017d8b79f8bbe342976ca2b938c3c (commit)
via 604e90d1e0c928cc8d94146beea6e24fe2252eec (commit)
via dcf58b7836e854107438368905576de7d29e0e3b (commit)
via f4f11a9b1c09adb07e2d6b99a0bd342d5a75ea3f (commit)
via 74e6966d7f8f8216dad871f1648cab977fb9fea2 (commit)
via 0334c1798ea43061494a530d8bc274283f1f1fc7 (commit)
via dcd582cc0a7d02d69c3c7c28916980f71034f9b2 (commit)
via c6947d22cd80d5934ad53c91b74c640c8a64e57c (commit)
via 40f4efbbd9f5685147cd1abf19d12c336bc1b8d9 (commit)
via a57662d6db020dd0b334472b5bb7ea88aefb6a7d (commit)
via 122d9611bd552c3113eca8aa5e91d2b8a3018210 (commit)
via 36b32903369f9a3afda93e2537d369d2402a3bfc (commit)
via bb5efb65cb0114b5bf985fd1588e8b645d4c45aa (commit)
via 7ae7577211c77f31a9f30be122d245add72d893d (commit)
via 0eea320309f86b8f1f95bed053078bdcf4c82071 (commit)
via 8eb1d7a04312f7fa70ee3c986e66b6444a1dfde4 (commit)
via 99c44efcd64b8262614354faaef2b5abb6fb644e (commit)
via af9f4f7fdaf88b906022bb808f44c6e586e702fc (commit)
via 1ea4834d960f3d5f14ff8cee312448baab72e075 (commit)
via f1ac03b8147047bee020fbc019d4969f16c75064 (commit)
via 231b29911894b0f5ddbd0d1444d9dfdf9cb5abb3 (commit)
via 4e8ed21d6a2e80e81393e64d808bb07655f42cbf (commit)
via 5012fabe00f1ebcbd2d67564df325fc69a529b5c (commit)
via 160b06212023cfce40c1ff6f13c5307c4d4f6e50 (commit)
via 8541053e6fffaf84127fddd2c0a25d0dcd5c635b (commit)
via 5e89e6afd429bf91d66f2f70435342fa1de388a4 (commit)
via a37c25cdb88ceb49b518d27a324ad7523f936fb2 (commit)
via b1610a09098d7019c6701daf77c2b8b98eb03b75 (commit)
via 04330565df2cc183a92f196772e03b05482046eb (commit)
via 44f4b82933783502be198c0ab0a81020fb3fe510 (commit)
via 3437b4fa8efb83ce5395ec159e85b38951e23504 (commit)
via 4b65b6bdb511b88979d0b1c6f44161c223e1dc9d (commit)
via 3f6620c5ba918a2a411aca9430fd8ac347e1aeca (commit)
via 2018011dab54aaff10385ae4905c1a5706997062 (commit)
via b751b7e0cc08dca691029169909a54a0bd1e6b45 (commit)
via d7cf894e555a8aa8508f695fabac2061822d454d (commit)
via 41361697fe474af2b511e922c18dc0b211f1344c (commit)
via 0dc2e2582d63c42847400701a7c3c6b0fb2d6d9b (commit)
via 4d55533790df1992aee5c088d4f91593d055c080 (commit)
via c374a5c5a329a307346be02d5b884ab57e1cb8c1 (commit)
via cd3ce64ac0ac3e82ba905f3eea77f1040b7e69b8 (commit)
via 660d7d782c81bc55b8cc009836c35d9ca3948063 (commit)
via a9f80cc455747b38115c5279bafde024e78b5f30 (commit)
via 24aa99548a4164d2c57adcf3829cc50f1fd34de5 (commit)
via f8a702716291db0b289aa211e5adac6fb2790cb7 (commit)
via 390af5c81d043a9f4cc8e908365e7f0734bddb8f (commit)
via 2df69541deceaa8a3bbbcc04d2087e94aa063d11 (commit)
via ed3c8e2f7a386b05b696d3ff79fa285ae7a050e9 (commit)
via 1f16df990ddee676893ae701b8553fd42d6992a7 (commit)
via aa0ddfbb4f0aa61cfee383f5459c2183b353674b (commit)
via 4f1d8d0f2ce99880306f7926a23b28f1aa8e4fd9 (commit)
via a7c4e0bc10a5430008d12081f4cb30d1d0d26723 (commit)
via 3987357f56e0fc2feca75001b963a11f1b7120ff (commit)
via 6cece2fc1d8a086b65421a583cf35b40f6ee1751 (commit)
via 400d3b61a32c0fc47c5f41a93ea649fbde6a5445 (commit)
via fac1bf01a628b3b922af67cdd94f05257b6eef9a (commit)
via 34ba5055b70c9de09d406b3e51ad2e02b98f6439 (commit)
via 238dca82160452df0eb732ce014166777380767e (commit)
via 253d063204f1e0656c89650999c76f942b4840f6 (commit)
via 817462f1ea1f1e9b4e05b2da90b8d311a7b59843 (commit)
via 30ab4cfbd7f0744653248efc5635c68930359eea (commit)
via 97feb3a88bae42f4051cd67384a4dc7dcd018c9a (commit)
via b78eefc13bc53a301327674a10d88cb917d6f28d (commit)
via 34d2f102aedbdb6b818f8eb8deb1e00fe431dae4 (commit)
via 6eab8b3fc5922c7b9c6403f4510b929544eafe30 (commit)
via e29c4f167f9d466eb9310989e836a0be428e5ace (commit)
via 992f3702aad9c83836af20d32e96313ff22cde3b (commit)
via 051d8bf74c500b8e1f1d2eabb9bb384d01104d10 (commit)
via 150914707089969bde30fbc6276abc00f3211ba3 (commit)
via 342926bcc0d317101321ff9afe6cf61967472a6a (commit)
via 7a7299fb09d2a02023041d3fe7a92e22d17ab549 (commit)
from 9c3195a542df8d7e747e28d49d7abdc707781632 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 134 +-
Makefile.am | 450 ++--
configure.ac | 107 +-
doc/Doxyfile | 14 +-
ext/asio/README | 9 +-
ext/asio/asio.hpp | 2 +-
ext/asio/asio/basic_datagram_socket.hpp | 13 +-
ext/asio/asio/basic_deadline_timer.hpp | 13 +-
ext/asio/asio/basic_io_object.hpp | 9 +-
ext/asio/asio/basic_raw_socket.hpp | 15 +-
ext/asio/asio/basic_serial_port.hpp | 20 +-
ext/asio/asio/basic_socket.hpp | 13 +-
ext/asio/asio/basic_socket_acceptor.hpp | 9 +-
ext/asio/asio/basic_socket_iostream.hpp | 17 +-
ext/asio/asio/basic_socket_streambuf.hpp | 19 +-
ext/asio/asio/basic_stream_socket.hpp | 13 +-
ext/asio/asio/basic_streambuf.hpp | 38 +-
ext/asio/asio/basic_streambuf_fwd.hpp | 33 +
ext/asio/asio/buffer.hpp | 22 +-
ext/asio/asio/buffered_read_stream.hpp | 15 +-
ext/asio/asio/buffered_read_stream_fwd.hpp | 6 +-
ext/asio/asio/buffered_stream.hpp | 13 +-
ext/asio/asio/buffered_stream_fwd.hpp | 6 +-
ext/asio/asio/buffered_write_stream.hpp | 17 +-
ext/asio/asio/buffered_write_stream_fwd.hpp | 6 +-
ext/asio/asio/buffers_iterator.hpp | 20 +-
ext/asio/asio/completion_condition.hpp | 8 +-
ext/asio/asio/datagram_socket_service.hpp | 12 +-
ext/asio/asio/deadline_timer.hpp | 10 +-
ext/asio/asio/deadline_timer_service.hpp | 14 +-
ext/asio/asio/detail/array_fwd.hpp | 25 +
ext/asio/asio/detail/base_from_completion_cond.hpp | 17 +-
ext/asio/asio/detail/bind_handler.hpp | 31 +-
ext/asio/asio/detail/buffer_resize_guard.hpp | 12 +-
ext/asio/asio/detail/buffer_sequence_adapter.hpp | 20 +-
ext/asio/asio/detail/buffered_stream_storage.hpp | 14 +-
ext/asio/asio/detail/call_stack.hpp | 11 +-
ext/asio/asio/detail/completion_handler.hpp | 34 +-
ext/asio/asio/detail/config.hpp | 205 ++
ext/asio/asio/detail/consuming_buffers.hpp | 20 +-
ext/asio/asio/detail/deadline_timer_service.hpp | 76 +-
ext/asio/asio/detail/descriptor_ops.hpp | 171 +-
ext/asio/asio/detail/descriptor_read_op.hpp | 114 +
ext/asio/asio/detail/descriptor_write_op.hpp | 114 +
ext/asio/asio/detail/dev_poll_reactor.hpp | 366 +---
ext/asio/asio/detail/dev_poll_reactor_fwd.hpp | 19 +-
ext/asio/asio/detail/epoll_reactor.hpp | 426 +---
ext/asio/asio/detail/epoll_reactor_fwd.hpp | 26 +-
ext/asio/asio/detail/event.hpp | 14 +-
.../asio/detail/eventfd_select_interrupter.hpp | 120 +-
ext/asio/asio/detail/fd_set_adapter.hpp | 15 +-
ext/asio/asio/detail/fenced_block.hpp | 34 +-
ext/asio/asio/detail/gcc_arm_fenced_block.hpp | 76 +
ext/asio/asio/detail/gcc_hppa_fenced_block.hpp | 58 +
ext/asio/asio/detail/gcc_sync_fenced_block.hpp | 61 +
ext/asio/asio/detail/gcc_x86_fenced_block.hpp | 18 +-
ext/asio/asio/detail/handler_alloc_helpers.hpp | 238 +--
ext/asio/asio/detail/handler_invoke_helpers.hpp | 14 +-
ext/asio/asio/detail/hash_map.hpp | 35 +-
ext/asio/asio/detail/impl/descriptor_ops.ipp | 382 +++
ext/asio/asio/detail/impl/dev_poll_reactor.hpp | 77 +
ext/asio/asio/detail/impl/dev_poll_reactor.ipp | 338 +++
ext/asio/asio/detail/impl/epoll_reactor.hpp | 75 +
ext/asio/asio/detail/impl/epoll_reactor.ipp | 390 +++
.../detail/impl/eventfd_select_interrupter.ipp | 125 +
ext/asio/asio/detail/impl/kqueue_reactor.hpp | 79 +
ext/asio/asio/detail/impl/kqueue_reactor.ipp | 385 +++
.../asio/detail/impl/pipe_select_interrupter.ipp | 96 +
ext/asio/asio/detail/impl/posix_event.ipp | 46 +
ext/asio/asio/detail/impl/posix_mutex.ipp | 46 +
ext/asio/asio/detail/impl/posix_thread.ipp | 74 +
ext/asio/asio/detail/impl/posix_tss_ptr.ipp | 46 +
.../detail/impl/reactive_descriptor_service.ipp | 136 +
.../detail/impl/reactive_serial_port_service.ipp | 151 +
.../detail/impl/reactive_socket_service_base.ipp | 212 ++
.../asio/detail/impl/resolver_service_base.ipp | 106 +
ext/asio/asio/detail/impl/select_reactor.hpp | 84 +
ext/asio/asio/detail/impl/select_reactor.ipp | 273 ++
ext/asio/asio/detail/impl/service_registry.hpp | 70 +
ext/asio/asio/detail/impl/service_registry.ipp | 164 ++
ext/asio/asio/detail/impl/socket_ops.ipp | 2917 ++++++++++++++++++++
.../asio/detail/impl/socket_select_interrupter.ipp | 151 +
ext/asio/asio/detail/impl/strand_service.hpp | 140 +
ext/asio/asio/detail/impl/strand_service.ipp | 106 +
ext/asio/asio/detail/impl/task_io_service.hpp | 60 +
ext/asio/asio/detail/impl/task_io_service.ipp | 354 +++
ext/asio/asio/detail/impl/throw_error.ipp | 47 +
ext/asio/asio/detail/impl/timer_queue.ipp | 85 +
ext/asio/asio/detail/impl/timer_queue_set.ipp | 101 +
ext/asio/asio/detail/impl/win_event.ipp | 50 +
.../asio/detail/impl/win_iocp_handle_service.ipp | 452 +++
ext/asio/asio/detail/impl/win_iocp_io_service.hpp | 115 +
ext/asio/asio/detail/impl/win_iocp_io_service.ipp | 496 ++++
.../detail/impl/win_iocp_serial_port_service.ipp | 180 ++
.../detail/impl/win_iocp_socket_service_base.ipp | 575 ++++
ext/asio/asio/detail/impl/win_mutex.ipp | 78 +
ext/asio/asio/detail/impl/win_thread.ipp | 138 +
ext/asio/asio/detail/impl/win_tss_ptr.ipp | 57 +
ext/asio/asio/detail/impl/winsock_init.ipp | 69 +
ext/asio/asio/detail/io_control.hpp | 14 +-
ext/asio/asio/detail/kqueue_reactor.hpp | 406 +---
ext/asio/asio/detail/kqueue_reactor_fwd.hpp | 23 +-
ext/asio/asio/detail/local_free_on_block_exit.hpp | 18 +-
ext/asio/asio/detail/macos_fenced_block.hpp | 20 +-
ext/asio/asio/detail/mutex.hpp | 14 +-
ext/asio/asio/detail/noncopyable.hpp | 14 +-
ext/asio/asio/detail/null_event.hpp | 18 +-
ext/asio/asio/detail/null_fenced_block.hpp | 6 +-
ext/asio/asio/detail/null_mutex.hpp | 18 +-
ext/asio/asio/detail/null_signal_blocker.hpp | 28 +-
ext/asio/asio/detail/null_thread.hpp | 31 +-
ext/asio/asio/detail/null_tss_ptr.hpp | 18 +-
ext/asio/asio/detail/object_pool.hpp | 146 +
ext/asio/asio/detail/old_win_sdk_compat.hpp | 18 +-
ext/asio/asio/detail/op_queue.hpp | 10 +-
ext/asio/asio/detail/operation.hpp | 15 +-
ext/asio/asio/detail/pipe_select_interrupter.hpp | 84 +-
ext/asio/asio/detail/pop_options.hpp | 16 +-
ext/asio/asio/detail/posix_event.hpp | 44 +-
ext/asio/asio/detail/posix_fd_set_adapter.hpp | 19 +-
ext/asio/asio/detail/posix_mutex.hpp | 43 +-
ext/asio/asio/detail/posix_signal_blocker.hpp | 23 +-
ext/asio/asio/detail/posix_thread.hpp | 80 +-
ext/asio/asio/detail/posix_tss_ptr.hpp | 44 +-
ext/asio/asio/detail/push_options.hpp | 18 +-
.../asio/detail/reactive_descriptor_service.hpp | 549 +----
ext/asio/asio/detail/reactive_null_buffers_op.hpp | 83 +
.../asio/detail/reactive_serial_port_service.hpp | 186 +-
ext/asio/asio/detail/reactive_socket_accept_op.hpp | 131 +
.../asio/detail/reactive_socket_connect_op.hpp | 101 +
ext/asio/asio/detail/reactive_socket_recv_op.hpp | 118 +
.../asio/detail/reactive_socket_recvfrom_op.hpp | 128 +
ext/asio/asio/detail/reactive_socket_send_op.hpp | 115 +
ext/asio/asio/detail/reactive_socket_sendto_op.hpp | 118 +
ext/asio/asio/detail/reactive_socket_service.hpp | 1576 +----------
.../asio/detail/reactive_socket_service_base.hpp | 298 ++
ext/asio/asio/detail/reactor.hpp | 10 +-
ext/asio/asio/detail/reactor_fwd.hpp | 30 +-
ext/asio/asio/detail/reactor_op.hpp | 11 +-
ext/asio/asio/detail/reactor_op_queue.hpp | 13 +-
ext/asio/asio/detail/regex_fwd.hpp | 31 +
ext/asio/asio/detail/resolve_endpoint_op.hpp | 116 +
ext/asio/asio/detail/resolve_op.hpp | 126 +
ext/asio/asio/detail/resolver_service.hpp | 401 +---
ext/asio/asio/detail/resolver_service_base.hpp | 123 +
ext/asio/asio/detail/scoped_lock.hpp | 10 +-
ext/asio/asio/detail/select_interrupter.hpp | 21 +-
ext/asio/asio/detail/select_reactor.hpp | 308 +--
ext/asio/asio/detail/select_reactor_fwd.hpp | 11 +-
ext/asio/asio/detail/service_registry.hpp | 197 +--
ext/asio/asio/detail/service_registry_fwd.hpp | 10 +-
ext/asio/asio/detail/shared_ptr.hpp | 38 +
ext/asio/asio/detail/signal_blocker.hpp | 24 +-
ext/asio/asio/detail/signal_init.hpp | 20 +-
ext/asio/asio/detail/socket_holder.hpp | 17 +-
ext/asio/asio/detail/socket_ops.hpp | 2051 ++------------
ext/asio/asio/detail/socket_option.hpp | 14 +-
ext/asio/asio/detail/socket_select_interrupter.hpp | 156 +-
ext/asio/asio/detail/socket_types.hpp | 76 +-
ext/asio/asio/detail/solaris_fenced_block.hpp | 20 +-
ext/asio/asio/detail/strand_service.hpp | 204 +--
ext/asio/asio/detail/task_io_service.hpp | 381 +---
ext/asio/asio/detail/task_io_service_fwd.hpp | 11 +-
ext/asio/asio/detail/task_io_service_operation.hpp | 18 +-
ext/asio/asio/detail/thread.hpp | 14 +-
ext/asio/asio/detail/throw_error.hpp | 35 +-
ext/asio/asio/detail/timer_op.hpp | 11 +-
ext/asio/asio/detail/timer_queue.hpp | 289 ++-
ext/asio/asio/detail/timer_queue_base.hpp | 11 +-
ext/asio/asio/detail/timer_queue_fwd.hpp | 10 +-
ext/asio/asio/detail/timer_queue_set.hpp | 85 +-
ext/asio/asio/detail/timer_scheduler.hpp | 11 +-
ext/asio/asio/detail/timer_scheduler_fwd.hpp | 28 +-
ext/asio/asio/detail/tss_ptr.hpp | 14 +-
ext/asio/asio/detail/wait_handler.hpp | 76 +
ext/asio/asio/detail/weak_ptr.hpp | 39 +
ext/asio/asio/detail/win_event.hpp | 40 +-
ext/asio/asio/detail/win_fd_set_adapter.hpp | 16 +-
ext/asio/asio/detail/win_fenced_block.hpp | 36 +-
ext/asio/asio/detail/win_iocp_handle_read_op.hpp | 101 +
ext/asio/asio/detail/win_iocp_handle_service.hpp | 573 +----
ext/asio/asio/detail/win_iocp_handle_write_op.hpp | 97 +
ext/asio/asio/detail/win_iocp_io_service.hpp | 599 +----
ext/asio/asio/detail/win_iocp_io_service_fwd.hpp | 30 +-
ext/asio/asio/detail/win_iocp_null_buffers_op.hpp | 112 +
ext/asio/asio/detail/win_iocp_operation.hpp | 19 +-
ext/asio/asio/detail/win_iocp_overlapped_op.hpp | 84 +
ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp | 72 +-
.../asio/detail/win_iocp_serial_port_service.hpp | 214 +-
ext/asio/asio/detail/win_iocp_socket_accept_op.hpp | 158 ++
ext/asio/asio/detail/win_iocp_socket_recv_op.hpp | 108 +
.../asio/detail/win_iocp_socket_recvfrom_op.hpp | 116 +
ext/asio/asio/detail/win_iocp_socket_send_op.hpp | 102 +
ext/asio/asio/detail/win_iocp_socket_service.hpp | 1806 +-----------
.../asio/detail/win_iocp_socket_service_base.hpp | 385 +++
ext/asio/asio/detail/win_mutex.hpp | 69 +-
ext/asio/asio/detail/win_thread.hpp | 153 +-
ext/asio/asio/detail/win_tss_ptr.hpp | 44 +-
ext/asio/asio/detail/wince_thread.hpp | 32 +-
ext/asio/asio/detail/winsock_init.hpp | 120 +-
ext/asio/asio/detail/wrapped_handler.hpp | 18 +-
ext/asio/asio/error.hpp | 44 +-
ext/asio/asio/error_code.hpp | 28 +-
ext/asio/asio/handler_alloc_hook.hpp | 8 +-
ext/asio/asio/handler_invoke_hook.hpp | 4 +-
ext/asio/asio/impl/error.ipp | 33 +
ext/asio/asio/impl/error_code.ipp | 97 +-
ext/asio/asio/impl/io_service.hpp | 132 +
ext/asio/asio/impl/io_service.ipp | 143 +-
ext/asio/asio/impl/read.hpp | 386 +++
ext/asio/asio/impl/read_at.hpp | 410 +++
ext/asio/asio/impl/read_until.hpp | 902 ++++++
ext/asio/asio/impl/serial_port_base.hpp | 59 +
ext/asio/asio/impl/serial_port_base.ipp | 106 +-
ext/asio/asio/impl/src.cpp | 25 +
ext/asio/asio/impl/src.hpp | 65 +
ext/asio/asio/impl/write.hpp | 396 +++
ext/asio/asio/impl/write_at.hpp | 417 +++
ext/asio/asio/io_service.hpp | 105 +-
ext/asio/asio/ip/address.hpp | 207 +--
ext/asio/asio/ip/address_v4.hpp | 175 +-
ext/asio/asio/ip/address_v6.hpp | 305 +--
ext/asio/asio/ip/basic_endpoint.hpp | 235 +--
ext/asio/asio/ip/basic_resolver.hpp | 13 +-
ext/asio/asio/ip/basic_resolver_entry.hpp | 11 +-
ext/asio/asio/ip/basic_resolver_iterator.hpp | 18 +-
ext/asio/asio/ip/basic_resolver_query.hpp | 15 +-
ext/asio/asio/ip/detail/endpoint.hpp | 140 +
ext/asio/asio/ip/detail/impl/endpoint.ipp | 202 ++
ext/asio/asio/ip/detail/socket_option.hpp | 17 +-
ext/asio/asio/ip/host_name.hpp | 44 +-
ext/asio/asio/ip/icmp.hpp | 13 +-
ext/asio/asio/ip/impl/address.hpp | 53 +
ext/asio/asio/ip/impl/address.ipp | 203 ++
ext/asio/asio/ip/impl/address_v4.hpp | 53 +
ext/asio/asio/ip/impl/address_v4.ipp | 178 ++
ext/asio/asio/ip/impl/address_v6.hpp | 53 +
ext/asio/asio/ip/impl/address_v6.ipp | 313 +++
ext/asio/asio/ip/impl/basic_endpoint.hpp | 55 +
ext/asio/asio/ip/impl/host_name.ipp | 56 +
ext/asio/asio/ip/multicast.hpp | 15 +-
ext/asio/asio/ip/resolver_query_base.hpp | 15 +-
ext/asio/asio/ip/resolver_service.hpp | 23 +-
ext/asio/asio/ip/tcp.hpp | 15 +-
ext/asio/asio/ip/udp.hpp | 13 +-
ext/asio/asio/ip/unicast.hpp | 15 +-
ext/asio/asio/ip/v6_only.hpp | 11 +-
ext/asio/asio/is_read_buffered.hpp | 11 +-
ext/asio/asio/is_write_buffered.hpp | 11 +-
ext/asio/asio/local/basic_endpoint.hpp | 137 +-
ext/asio/asio/local/connect_pair.hpp | 30 +-
ext/asio/asio/local/datagram_protocol.hpp | 20 +-
ext/asio/asio/local/detail/endpoint.hpp | 133 +
ext/asio/asio/local/detail/impl/endpoint.ipp | 138 +
ext/asio/asio/local/stream_protocol.hpp | 20 +-
ext/asio/asio/placeholders.hpp | 9 +-
ext/asio/asio/posix/basic_descriptor.hpp | 20 +-
ext/asio/asio/posix/basic_stream_descriptor.hpp | 24 +-
ext/asio/asio/posix/descriptor_base.hpp | 19 +-
ext/asio/asio/posix/stream_descriptor.hpp | 14 +-
ext/asio/asio/posix/stream_descriptor_service.hpp | 32 +-
ext/asio/asio/raw_socket_service.hpp | 12 +-
ext/asio/asio/read.hpp | 17 +-
ext/asio/asio/read_at.hpp | 17 +-
ext/asio/asio/read_until.hpp | 21 +-
ext/asio/asio/serial_port.hpp | 10 +-
ext/asio/asio/serial_port_base.hpp | 71 +-
ext/asio/asio/serial_port_service.hpp | 23 +-
ext/asio/asio/socket_acceptor_service.hpp | 8 +-
ext/asio/asio/socket_base.hpp | 11 +-
ext/asio/asio/ssl.hpp | 2 +-
ext/asio/asio/ssl/basic_context.hpp | 16 +-
ext/asio/asio/ssl/context.hpp | 11 +-
ext/asio/asio/ssl/context_base.hpp | 15 +-
ext/asio/asio/ssl/context_service.hpp | 15 +-
.../asio/ssl/detail/openssl_context_service.hpp | 15 +-
ext/asio/asio/ssl/detail/openssl_init.hpp | 15 +-
ext/asio/asio/ssl/detail/openssl_operation.hpp | 22 +-
.../asio/ssl/detail/openssl_stream_service.hpp | 26 +-
ext/asio/asio/ssl/detail/openssl_types.hpp | 16 +-
ext/asio/asio/ssl/stream.hpp | 17 +-
ext/asio/asio/ssl/stream_base.hpp | 11 +-
ext/asio/asio/ssl/stream_service.hpp | 18 +-
ext/asio/asio/strand.hpp | 9 +-
ext/asio/asio/stream_socket_service.hpp | 12 +-
ext/asio/asio/streambuf.hpp | 10 +-
ext/asio/asio/system_error.hpp | 11 +-
ext/asio/asio/thread.hpp | 7 +-
ext/asio/asio/time_traits.hpp | 6 +-
ext/asio/asio/version.hpp | 4 +-
ext/asio/asio/windows/basic_handle.hpp | 22 +-
.../asio/windows/basic_random_access_handle.hpp | 24 +-
ext/asio/asio/windows/basic_stream_handle.hpp | 22 +-
ext/asio/asio/windows/overlapped_ptr.hpp | 26 +-
ext/asio/asio/windows/random_access_handle.hpp | 14 +-
.../asio/windows/random_access_handle_service.hpp | 30 +-
ext/asio/asio/windows/stream_handle.hpp | 14 +-
ext/asio/asio/windows/stream_handle_service.hpp | 31 +-
ext/asio/asio/write.hpp | 17 +-
ext/asio/asio/write_at.hpp | 17 +-
src/bin/auth/main.cc | 10 +-
src/bin/auth/statistics.cc | 4 -
src/bin/auth/tests/Makefile.am | 2 -
src/bin/bind10/bind10.py.in | 5 +
src/bin/bind10/run_bind10.sh.in | 4 +-
src/bin/bind10/tests/bind10_test.py.in | 21 +-
src/bin/cfgmgr/b10-cfgmgr.py.in | 23 +-
src/bin/cfgmgr/plugins/Makefile.am | 6 +-
src/bin/cfgmgr/plugins/tests/Makefile.am | 27 +
src/bin/cfgmgr/plugins/tests/tsig_keys_test.py | 103 +
src/bin/cfgmgr/plugins/tsig_keys.py | 50 +
src/bin/cfgmgr/plugins/tsig_keys.spec | 21 +
src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in | 3 +
src/bin/host/Makefile.am | 31 +-
src/bin/host/README | 16 +-
src/bin/host/b10-host.1 | 122 +
src/bin/host/b10-host.xml | 201 ++
src/bin/host/host.cc | 73 +-
src/bin/msgq/tests/msgq_test.py | 2 +-
src/bin/resolver/resolver.cc | 16 +-
src/bin/resolver/response_scrubber.cc | 24 +-
src/bin/stats/Makefile.am | 30 +-
src/bin/stats/b10-stats-httpd.8 | 136 +
src/bin/stats/b10-stats-httpd.xml | 221 ++
src/bin/stats/b10-stats.8 | 8 +-
src/bin/stats/b10-stats.xml | 16 +-
src/bin/stats/run_b10-stats.sh.in | 33 -
src/bin/stats/run_b10-stats_stub.sh.in | 33 -
src/bin/stats/stats-httpd-xml.tpl.in | 24 +
src/bin/stats/stats-httpd-xsd.tpl.in | 38 +
src/bin/stats/stats-httpd-xsl.tpl.in | 56 +
src/bin/stats/stats-httpd.spec.in | 54 +
src/bin/stats/stats-schema.spec.in | 87 +
src/bin/stats/stats.py.in | 24 +-
src/bin/stats/stats.spec.in | 61 +
src/bin/stats/stats.spec.pre.in | 140 -
src/bin/stats/stats_httpd.py.in | 485 ++++
src/bin/stats/stats_stub.py.in | 154 -
src/bin/stats/tests/Makefile.am | 10 +-
src/bin/stats/tests/b10-stats-httpd_test.py | 444 +++
src/bin/stats/tests/b10-stats_stub_test.py | 115 -
src/bin/stats/tests/b10-stats_test.py | 27 +-
src/bin/stats/tests/fake_select.py | 43 +
src/bin/stats/tests/fake_socket.py | 70 +
src/bin/stats/tests/http/Makefile.am | 2 +
.../stats/tests/{isc/utils => http}/__init__.py | 0
src/bin/stats/tests/http/server.py | 96 +
src/bin/stats/tests/isc/cc/session.py | 46 +-
src/bin/stats/tests/isc/config/ccsession.py | 59 +-
src/bin/stats/tests/isc/util/process.py | 5 +-
src/bin/stats/tests/isc/utils/Makefile.am | 2 -
src/bin/stats/tests/isc/utils/process.py | 18 -
src/bin/stats/tests/stats_test.in | 31 -
src/bin/xfrin/tests/Makefile.am | 2 +-
src/bin/xfrin/tests/xfrin_test.py | 51 +
src/bin/xfrin/xfrin.py.in | 94 +-
src/bin/xfrin/xfrin.spec | 5 +
src/bin/xfrout/tests/Makefile.am | 2 +-
src/bin/zonemgr/tests/zonemgr_test.py | 96 +-
src/cppcheck-suppress.lst | 2 +-
src/lib/Makefile.am | 5 +-
src/lib/asiodns/Makefile.am | 13 +-
src/lib/asiodns/asiodef.cc | 39 -
src/lib/asiodns/asiodef.h | 23 -
src/lib/asiodns/asiodef.mes | 56 +
src/lib/asiodns/asiodef.msg | 56 -
src/lib/asiodns/io_fetch.cc | 127 +-
src/lib/asiodns/io_fetch.h | 24 +
src/lib/asiolink/Makefile.am | 1 -
src/lib/asiolink/interval_timer.h | 2 +-
src/lib/asiolink/io_service.h | 2 +-
src/lib/asiolink/tests/Makefile.am | 10 +-
src/lib/asiolink/tests/interval_timer_unittest.cc | 26 +-
src/lib/asiolink/tests/run_unittests.cc | 1 -
src/lib/cc/Makefile.am | 1 +
src/lib/cc/tests/Makefile.am | 1 -
src/lib/config/Makefile.am | 20 +-
src/lib/config/ccsession.cc | 31 +-
src/lib/config/ccsession.h | 14 +
src/lib/config/config_log.cc | 26 +
src/lib/config/config_log.h | 38 +
src/lib/config/configdef.mes | 50 +
src/lib/config/tests/Makefile.am | 1 +
src/lib/config/tests/ccsession_unittests.cc | 25 +-
src/lib/config/tests/fake_session.cc | 8 +-
src/lib/config/tests/run_unittests.cc | 7 +
src/lib/cryptolink/Makefile.am | 14 +
src/lib/cryptolink/crypto_hmac.cc | 246 ++
src/lib/cryptolink/crypto_hmac.h | 209 ++
src/lib/cryptolink/cryptolink.cc | 69 +
src/lib/cryptolink/cryptolink.h | 204 ++
src/lib/cryptolink/tests/Makefile.am | 26 +
src/lib/cryptolink/tests/crypto_unittests.cc | 519 ++++
src/lib/cryptolink/tests/run_unittests.cc | 22 +
src/lib/datasrc/Makefile.am | 15 +-
src/lib/datasrc/cache.cc | 23 +-
src/lib/datasrc/data_source.cc | 97 +-
src/lib/datasrc/logger.cc | 23 +
src/lib/datasrc/logger.h | 46 +
src/lib/datasrc/memory_datasrc.cc | 60 +
src/lib/datasrc/messagedef.mes | 498 ++++
src/lib/datasrc/sqlite3_datasrc.cc | 37 +-
src/lib/datasrc/static_datasrc.cc | 5 +
src/lib/datasrc/tests/Makefile.am | 6 +-
src/lib/datasrc/tests/datasrc_unittest.cc | 16 +
src/lib/datasrc/tests/logger_unittest.cc | 31 +
src/lib/dns/Makefile.am | 64 +-
src/lib/dns/edns.cc | 29 +-
src/lib/dns/edns.h | 12 +-
src/lib/dns/message.cc | 419 ++--
src/lib/dns/message.h | 56 +-
src/lib/dns/messagerenderer.cc | 5 +-
src/lib/dns/python/Makefile.am | 4 +
src/lib/dns/python/message_python.cc | 131 +-
src/lib/dns/python/pydnspp.cc | 36 +-
src/lib/dns/python/pydnspp_common.cc | 18 +-
src/lib/dns/python/pydnspp_common.h | 29 +-
src/lib/dns/python/rcode_python.cc | 157 +-
src/lib/dns/python/rcode_python.h | 57 +
src/lib/dns/python/tests/Makefile.am | 4 +-
src/lib/dns/python/tests/message_python_test.py | 37 +-
src/lib/dns/python/tests/tsig_python_test.py | 29 +
src/lib/dns/python/tests/tsigerror_python_test.py | 97 +
src/lib/dns/python/tests/tsigkey_python_test.py | 53 +-
src/lib/dns/python/tsig_python.cc | 156 ++
src/lib/dns/python/tsigerror_python.cc | 362 +++
src/lib/dns/python/tsigerror_python.h | 44 +
src/lib/dns/python/tsigerror_python_inc.cc | 83 +
src/lib/dns/python/tsigkey_python.cc | 46 +-
src/lib/dns/question.cc | 2 +-
src/lib/dns/question.h | 6 +-
src/lib/dns/rdata/any_255/tsig_250.cc | 12 +-
src/lib/dns/rrclass-placeholder.h | 4 +-
src/lib/dns/rrclass.cc | 2 +-
src/lib/dns/rrset.cc | 6 +-
src/lib/dns/rrset.h | 6 +-
src/lib/dns/rrttl.cc | 2 +-
src/lib/dns/rrttl.h | 4 +-
src/lib/dns/tests/Makefile.am | 6 +
src/lib/dns/tests/message_unittest.cc | 192 ++-
src/lib/dns/tests/run_unittests.cc | 3 +
src/lib/dns/tests/testdata/Makefile.am | 29 +-
src/lib/dns/tests/testdata/gen-wiredata.py.in | 105 +-
src/lib/dns/tests/testdata/message_fromWire12.spec | 21 +
src/lib/dns/tests/testdata/message_fromWire13.spec | 20 +
src/lib/dns/tests/testdata/message_fromWire14.spec | 21 +
src/lib/dns/tests/testdata/message_fromWire15.spec | 22 +
src/lib/dns/tests/testdata/message_fromWire16.spec | 21 +
src/lib/dns/tests/testdata/message_toText1.spec | 24 +
src/lib/dns/tests/testdata/message_toText1.txt | 14 +
src/lib/dns/tests/testdata/message_toText2.spec | 14 +
src/lib/dns/tests/testdata/message_toText2.txt | 8 +
src/lib/dns/tests/testdata/message_toText3.spec | 31 +
src/lib/dns/tests/testdata/message_toText3.txt | 17 +
src/lib/dns/tests/testdata/message_toWire2.spec | 21 +
src/lib/dns/tests/testdata/message_toWire3.spec | 22 +
src/lib/dns/tests/testdata/tsig_verify1.spec | 19 +
src/lib/dns/tests/testdata/tsig_verify10.spec | 22 +
src/lib/dns/tests/testdata/tsig_verify2.spec | 32 +
src/lib/dns/tests/testdata/tsig_verify3.spec | 26 +
src/lib/dns/tests/testdata/tsig_verify4.spec | 27 +
src/lib/dns/tests/testdata/tsig_verify5.spec | 26 +
src/lib/dns/tests/testdata/tsig_verify6.spec | 21 +
src/lib/dns/tests/testdata/tsig_verify7.spec | 21 +
src/lib/dns/tests/testdata/tsig_verify8.spec | 23 +
src/lib/dns/tests/testdata/tsig_verify9.spec | 21 +
src/lib/dns/tests/testdata/tsigrecord_toWire1.spec | 16 +
src/lib/dns/tests/testdata/tsigrecord_toWire2.spec | 19 +
src/lib/dns/tests/tsig_unittest.cc | 907 ++++++
src/lib/dns/tests/tsigerror_unittest.cc | 116 +
src/lib/dns/tests/tsigkey_unittest.cc | 129 +-
src/lib/dns/tests/tsigrecord_unittest.cc | 159 ++
src/lib/dns/tsig.cc | 453 +++
src/lib/dns/tsig.h | 394 +++
src/lib/dns/tsigerror.cc | 68 +
src/lib/dns/tsigerror.h | 338 +++
src/lib/dns/tsigkey.cc | 115 +-
src/lib/dns/tsigkey.h | 76 +-
src/lib/dns/tsigrecord.cc | 147 +
src/lib/dns/tsigrecord.h | 308 +++
src/lib/log/Makefile.am | 4 +-
src/lib/log/README | 119 +-
src/lib/log/compiler/message.cc | 47 +-
src/lib/log/log_formatter.cc | 42 +
src/lib/log/log_formatter.h | 150 +
src/lib/log/logger.cc | 63 +-
src/lib/log/logger.h | 25 +-
src/lib/log/logger_impl.cc | 20 +-
src/lib/log/logger_impl.h | 62 +-
src/lib/log/logger_support.cc | 89 +-
src/lib/log/logger_support.h | 31 +
src/lib/log/macros.h | 50 +
src/lib/log/message_exception.cc | 26 -
src/lib/log/message_exception.h | 37 +-
src/lib/log/message_reader.cc | 182 +-
src/lib/log/message_reader.h | 19 +-
src/lib/log/messagedef.cc | 70 +-
src/lib/log/messagedef.h | 14 +-
src/lib/log/messagedef.mes | 202 +-
src/lib/log/tests/Makefile.am | 1 +
src/lib/log/tests/log_formatter_unittest.cc | 125 +
src/lib/log/tests/logger_support_test.cc | 18 +-
src/lib/log/tests/message_dictionary_unittest.cc | 4 +-
src/lib/log/tests/message_reader_unittest.cc | 47 +-
src/lib/log/tests/run_time_init_test.sh.in | 41 +-
src/lib/nsas/Makefile.am | 31 +-
src/lib/nsas/nameserver_address_store.cc | 7 +
src/lib/nsas/nameserver_address_store.h | 1 -
src/lib/nsas/nameserver_entry.cc | 24 +-
src/lib/nsas/nsas_log.cc | 26 +
src/lib/nsas/nsas_log.h | 53 +
src/lib/nsas/nsasdef.mes | 61 +
src/lib/nsas/tests/Makefile.am | 1 +
src/lib/nsas/tests/nameserver_address_unittest.cc | 3 +-
src/lib/nsas/tests/nameserver_entry_unittest.cc | 3 +-
src/lib/nsas/tests/nsas_test.h | 148 +-
src/lib/nsas/tests/run_unittests.cc | 9 +
src/lib/python/bind10_config.py.in | 38 +-
src/lib/python/isc/notify/notify_out.py | 2 +-
src/lib/python/isc/notify/tests/Makefile.am | 2 +-
src/lib/python/isc/util/Makefile.am | 2 +-
src/lib/python/isc/util/file.py | 29 +
src/lib/python/isc/util/tests/Makefile.am | 2 +-
src/lib/python/isc/util/tests/file_test.py | 32 +
src/lib/resolve/recursive_query.cc | 318 ++-
src/lib/resolve/recursive_query.h | 14 +
src/lib/resolve/tests/recursive_query_unittest.cc | 245 ++-
src/lib/server_common/portconfig.cc | 19 +-
src/lib/server_common/tests/portconfig_unittest.cc | 2 +-
src/lib/util/Makefile.am | 2 +
src/lib/util/encode/base_n.cc | 2 +-
src/lib/util/python/mkpywrapper.py.in | 100 +
src/lib/util/python/pycppwrapper_util.h | 308 +++
src/lib/util/python/wrapper_template.cc | 293 ++
src/lib/util/python/wrapper_template.h | 44 +
src/lib/util/time_utilities.cc | 7 +-
src/lib/util/time_utilities.h | 28 +
src/lib/util/unittests/Makefile.am | 5 +-
src/lib/util/unittests/newhook.cc | 51 +
src/lib/util/unittests/newhook.h | 82 +
src/lib/util/unittests/resolver.h | 193 ++
src/lib/util/unittests/testdata.cc | 61 +
src/lib/util/unittests/testdata.h | 54 +
src/lib/util/unittests/textdata.h | 103 +
tests/tools/badpacket/scan.cc | 4 -
tests/tools/badpacket/tests/Makefile.am | 1 +
546 files changed, 35650 insertions(+), 15513 deletions(-)
create mode 100644 ext/asio/asio/basic_streambuf_fwd.hpp
create mode 100644 ext/asio/asio/detail/array_fwd.hpp
create mode 100644 ext/asio/asio/detail/config.hpp
create mode 100644 ext/asio/asio/detail/descriptor_read_op.hpp
create mode 100644 ext/asio/asio/detail/descriptor_write_op.hpp
create mode 100644 ext/asio/asio/detail/gcc_arm_fenced_block.hpp
create mode 100644 ext/asio/asio/detail/gcc_hppa_fenced_block.hpp
create mode 100644 ext/asio/asio/detail/gcc_sync_fenced_block.hpp
create mode 100644 ext/asio/asio/detail/impl/descriptor_ops.ipp
create mode 100644 ext/asio/asio/detail/impl/dev_poll_reactor.hpp
create mode 100644 ext/asio/asio/detail/impl/dev_poll_reactor.ipp
create mode 100644 ext/asio/asio/detail/impl/epoll_reactor.hpp
create mode 100644 ext/asio/asio/detail/impl/epoll_reactor.ipp
create mode 100644 ext/asio/asio/detail/impl/eventfd_select_interrupter.ipp
create mode 100644 ext/asio/asio/detail/impl/kqueue_reactor.hpp
create mode 100644 ext/asio/asio/detail/impl/kqueue_reactor.ipp
create mode 100644 ext/asio/asio/detail/impl/pipe_select_interrupter.ipp
create mode 100644 ext/asio/asio/detail/impl/posix_event.ipp
create mode 100644 ext/asio/asio/detail/impl/posix_mutex.ipp
create mode 100644 ext/asio/asio/detail/impl/posix_thread.ipp
create mode 100644 ext/asio/asio/detail/impl/posix_tss_ptr.ipp
create mode 100644 ext/asio/asio/detail/impl/reactive_descriptor_service.ipp
create mode 100644 ext/asio/asio/detail/impl/reactive_serial_port_service.ipp
create mode 100644 ext/asio/asio/detail/impl/reactive_socket_service_base.ipp
create mode 100644 ext/asio/asio/detail/impl/resolver_service_base.ipp
create mode 100644 ext/asio/asio/detail/impl/select_reactor.hpp
create mode 100644 ext/asio/asio/detail/impl/select_reactor.ipp
create mode 100644 ext/asio/asio/detail/impl/service_registry.hpp
create mode 100644 ext/asio/asio/detail/impl/service_registry.ipp
create mode 100644 ext/asio/asio/detail/impl/socket_ops.ipp
create mode 100644 ext/asio/asio/detail/impl/socket_select_interrupter.ipp
create mode 100644 ext/asio/asio/detail/impl/strand_service.hpp
create mode 100644 ext/asio/asio/detail/impl/strand_service.ipp
create mode 100644 ext/asio/asio/detail/impl/task_io_service.hpp
create mode 100644 ext/asio/asio/detail/impl/task_io_service.ipp
create mode 100644 ext/asio/asio/detail/impl/throw_error.ipp
create mode 100644 ext/asio/asio/detail/impl/timer_queue.ipp
create mode 100644 ext/asio/asio/detail/impl/timer_queue_set.ipp
create mode 100644 ext/asio/asio/detail/impl/win_event.ipp
create mode 100644 ext/asio/asio/detail/impl/win_iocp_handle_service.ipp
create mode 100644 ext/asio/asio/detail/impl/win_iocp_io_service.hpp
create mode 100644 ext/asio/asio/detail/impl/win_iocp_io_service.ipp
create mode 100644 ext/asio/asio/detail/impl/win_iocp_serial_port_service.ipp
create mode 100644 ext/asio/asio/detail/impl/win_iocp_socket_service_base.ipp
create mode 100644 ext/asio/asio/detail/impl/win_mutex.ipp
create mode 100644 ext/asio/asio/detail/impl/win_thread.ipp
create mode 100644 ext/asio/asio/detail/impl/win_tss_ptr.ipp
create mode 100644 ext/asio/asio/detail/impl/winsock_init.ipp
create mode 100644 ext/asio/asio/detail/object_pool.hpp
create mode 100644 ext/asio/asio/detail/reactive_null_buffers_op.hpp
create mode 100644 ext/asio/asio/detail/reactive_socket_accept_op.hpp
create mode 100644 ext/asio/asio/detail/reactive_socket_connect_op.hpp
create mode 100644 ext/asio/asio/detail/reactive_socket_recv_op.hpp
create mode 100644 ext/asio/asio/detail/reactive_socket_recvfrom_op.hpp
create mode 100644 ext/asio/asio/detail/reactive_socket_send_op.hpp
create mode 100644 ext/asio/asio/detail/reactive_socket_sendto_op.hpp
create mode 100644 ext/asio/asio/detail/reactive_socket_service_base.hpp
create mode 100644 ext/asio/asio/detail/regex_fwd.hpp
create mode 100644 ext/asio/asio/detail/resolve_endpoint_op.hpp
create mode 100644 ext/asio/asio/detail/resolve_op.hpp
create mode 100644 ext/asio/asio/detail/resolver_service_base.hpp
create mode 100644 ext/asio/asio/detail/shared_ptr.hpp
create mode 100644 ext/asio/asio/detail/wait_handler.hpp
create mode 100644 ext/asio/asio/detail/weak_ptr.hpp
create mode 100644 ext/asio/asio/detail/win_iocp_handle_read_op.hpp
create mode 100644 ext/asio/asio/detail/win_iocp_handle_write_op.hpp
create mode 100644 ext/asio/asio/detail/win_iocp_null_buffers_op.hpp
create mode 100644 ext/asio/asio/detail/win_iocp_overlapped_op.hpp
create mode 100644 ext/asio/asio/detail/win_iocp_socket_accept_op.hpp
create mode 100644 ext/asio/asio/detail/win_iocp_socket_recv_op.hpp
create mode 100644 ext/asio/asio/detail/win_iocp_socket_recvfrom_op.hpp
create mode 100644 ext/asio/asio/detail/win_iocp_socket_send_op.hpp
create mode 100644 ext/asio/asio/detail/win_iocp_socket_service_base.hpp
create mode 100644 ext/asio/asio/impl/error.ipp
create mode 100644 ext/asio/asio/impl/io_service.hpp
create mode 100644 ext/asio/asio/impl/read.hpp
create mode 100644 ext/asio/asio/impl/read_at.hpp
create mode 100644 ext/asio/asio/impl/read_until.hpp
create mode 100644 ext/asio/asio/impl/serial_port_base.hpp
create mode 100644 ext/asio/asio/impl/src.cpp
create mode 100644 ext/asio/asio/impl/src.hpp
create mode 100644 ext/asio/asio/impl/write.hpp
create mode 100644 ext/asio/asio/impl/write_at.hpp
create mode 100644 ext/asio/asio/ip/detail/endpoint.hpp
create mode 100644 ext/asio/asio/ip/detail/impl/endpoint.ipp
create mode 100644 ext/asio/asio/ip/impl/address.hpp
create mode 100644 ext/asio/asio/ip/impl/address.ipp
create mode 100644 ext/asio/asio/ip/impl/address_v4.hpp
create mode 100644 ext/asio/asio/ip/impl/address_v4.ipp
create mode 100644 ext/asio/asio/ip/impl/address_v6.hpp
create mode 100644 ext/asio/asio/ip/impl/address_v6.ipp
create mode 100644 ext/asio/asio/ip/impl/basic_endpoint.hpp
create mode 100644 ext/asio/asio/ip/impl/host_name.ipp
create mode 100644 ext/asio/asio/local/detail/endpoint.hpp
create mode 100644 ext/asio/asio/local/detail/impl/endpoint.ipp
mode change 100644 => 100755 src/bin/bind10/run_bind10.sh.in
create mode 100644 src/bin/cfgmgr/plugins/tests/Makefile.am
create mode 100644 src/bin/cfgmgr/plugins/tests/tsig_keys_test.py
create mode 100644 src/bin/cfgmgr/plugins/tsig_keys.py
create mode 100644 src/bin/cfgmgr/plugins/tsig_keys.spec
create mode 100644 src/bin/host/b10-host.1
create mode 100644 src/bin/host/b10-host.xml
create mode 100644 src/bin/stats/b10-stats-httpd.8
create mode 100644 src/bin/stats/b10-stats-httpd.xml
delete mode 100644 src/bin/stats/run_b10-stats.sh.in
delete mode 100644 src/bin/stats/run_b10-stats_stub.sh.in
create mode 100644 src/bin/stats/stats-httpd-xml.tpl.in
create mode 100644 src/bin/stats/stats-httpd-xsd.tpl.in
create mode 100644 src/bin/stats/stats-httpd-xsl.tpl.in
create mode 100644 src/bin/stats/stats-httpd.spec.in
create mode 100644 src/bin/stats/stats-schema.spec.in
mode change 100755 => 100644 src/bin/stats/stats.py.in
create mode 100644 src/bin/stats/stats.spec.in
delete mode 100644 src/bin/stats/stats.spec.pre.in
create mode 100644 src/bin/stats/stats_httpd.py.in
delete mode 100755 src/bin/stats/stats_stub.py.in
create mode 100644 src/bin/stats/tests/b10-stats-httpd_test.py
delete mode 100644 src/bin/stats/tests/b10-stats_stub_test.py
create mode 100644 src/bin/stats/tests/fake_select.py
create mode 100644 src/bin/stats/tests/fake_socket.py
create mode 100644 src/bin/stats/tests/http/Makefile.am
rename src/bin/stats/tests/{isc/utils => http}/__init__.py (100%)
create mode 100644 src/bin/stats/tests/http/server.py
delete mode 100644 src/bin/stats/tests/isc/utils/Makefile.am
delete mode 100644 src/bin/stats/tests/isc/utils/process.py
delete mode 100644 src/bin/stats/tests/stats_test.in
delete mode 100644 src/lib/asiodns/asiodef.cc
delete mode 100644 src/lib/asiodns/asiodef.h
create mode 100644 src/lib/asiodns/asiodef.mes
delete mode 100644 src/lib/asiodns/asiodef.msg
create mode 100644 src/lib/config/config_log.cc
create mode 100644 src/lib/config/config_log.h
create mode 100644 src/lib/config/configdef.mes
create mode 100644 src/lib/cryptolink/Makefile.am
create mode 100644 src/lib/cryptolink/crypto_hmac.cc
create mode 100644 src/lib/cryptolink/crypto_hmac.h
create mode 100644 src/lib/cryptolink/cryptolink.cc
create mode 100644 src/lib/cryptolink/cryptolink.h
create mode 100644 src/lib/cryptolink/tests/Makefile.am
create mode 100644 src/lib/cryptolink/tests/crypto_unittests.cc
create mode 100644 src/lib/cryptolink/tests/run_unittests.cc
create mode 100644 src/lib/datasrc/logger.cc
create mode 100644 src/lib/datasrc/logger.h
create mode 100644 src/lib/datasrc/messagedef.mes
create mode 100644 src/lib/datasrc/tests/logger_unittest.cc
create mode 100644 src/lib/dns/python/rcode_python.h
create mode 100644 src/lib/dns/python/tests/tsig_python_test.py
create mode 100644 src/lib/dns/python/tests/tsigerror_python_test.py
create mode 100644 src/lib/dns/python/tsig_python.cc
create mode 100644 src/lib/dns/python/tsigerror_python.cc
create mode 100644 src/lib/dns/python/tsigerror_python.h
create mode 100644 src/lib/dns/python/tsigerror_python_inc.cc
create mode 100644 src/lib/dns/tests/testdata/message_fromWire12.spec
create mode 100644 src/lib/dns/tests/testdata/message_fromWire13.spec
create mode 100644 src/lib/dns/tests/testdata/message_fromWire14.spec
create mode 100644 src/lib/dns/tests/testdata/message_fromWire15.spec
create mode 100644 src/lib/dns/tests/testdata/message_fromWire16.spec
create mode 100644 src/lib/dns/tests/testdata/message_toText1.spec
create mode 100644 src/lib/dns/tests/testdata/message_toText1.txt
create mode 100644 src/lib/dns/tests/testdata/message_toText2.spec
create mode 100644 src/lib/dns/tests/testdata/message_toText2.txt
create mode 100644 src/lib/dns/tests/testdata/message_toText3.spec
create mode 100644 src/lib/dns/tests/testdata/message_toText3.txt
create mode 100644 src/lib/dns/tests/testdata/message_toWire2.spec
create mode 100644 src/lib/dns/tests/testdata/message_toWire3.spec
create mode 100644 src/lib/dns/tests/testdata/tsig_verify1.spec
create mode 100644 src/lib/dns/tests/testdata/tsig_verify10.spec
create mode 100644 src/lib/dns/tests/testdata/tsig_verify2.spec
create mode 100644 src/lib/dns/tests/testdata/tsig_verify3.spec
create mode 100644 src/lib/dns/tests/testdata/tsig_verify4.spec
create mode 100644 src/lib/dns/tests/testdata/tsig_verify5.spec
create mode 100644 src/lib/dns/tests/testdata/tsig_verify6.spec
create mode 100644 src/lib/dns/tests/testdata/tsig_verify7.spec
create mode 100644 src/lib/dns/tests/testdata/tsig_verify8.spec
create mode 100644 src/lib/dns/tests/testdata/tsig_verify9.spec
create mode 100644 src/lib/dns/tests/testdata/tsigrecord_toWire1.spec
create mode 100644 src/lib/dns/tests/testdata/tsigrecord_toWire2.spec
create mode 100644 src/lib/dns/tests/tsig_unittest.cc
create mode 100644 src/lib/dns/tests/tsigerror_unittest.cc
create mode 100644 src/lib/dns/tests/tsigrecord_unittest.cc
create mode 100644 src/lib/dns/tsig.cc
create mode 100644 src/lib/dns/tsig.h
create mode 100644 src/lib/dns/tsigerror.cc
create mode 100644 src/lib/dns/tsigerror.h
create mode 100644 src/lib/dns/tsigrecord.cc
create mode 100644 src/lib/dns/tsigrecord.h
create mode 100644 src/lib/log/log_formatter.cc
create mode 100644 src/lib/log/log_formatter.h
create mode 100644 src/lib/log/macros.h
delete mode 100644 src/lib/log/message_exception.cc
create mode 100644 src/lib/log/tests/log_formatter_unittest.cc
create mode 100644 src/lib/nsas/nsas_log.cc
create mode 100644 src/lib/nsas/nsas_log.h
create mode 100644 src/lib/nsas/nsasdef.mes
create mode 100644 src/lib/python/isc/util/file.py
create mode 100644 src/lib/python/isc/util/tests/file_test.py
create mode 100755 src/lib/util/python/mkpywrapper.py.in
create mode 100644 src/lib/util/python/pycppwrapper_util.h
create mode 100644 src/lib/util/python/wrapper_template.cc
create mode 100644 src/lib/util/python/wrapper_template.h
create mode 100644 src/lib/util/unittests/newhook.cc
create mode 100644 src/lib/util/unittests/newhook.h
create mode 100644 src/lib/util/unittests/resolver.h
create mode 100644 src/lib/util/unittests/testdata.cc
create mode 100644 src/lib/util/unittests/testdata.h
create mode 100644 src/lib/util/unittests/textdata.h
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 4975002..679542c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,126 @@
-222. [bug] jerry
+238. [func] zhang likun
+ Implement the simplest forwarder, which pass everything throught
+ except QID, port number. The response will not be cached.
+ (Trac #598_new, git 8e28187a582820857ef2dae9b13637a3881f13ba)
+
+237. [bug] naokikambe
+ Resolved that the stats module wasn't configurable in bindctl in
+ spite of its having configuration items. The configuration part
+ was removed from the original spec file "stats.spec" and was
+ placed in a new spec file "stats-schema.spec". Because it means
+ definitions of statistics items. The command part is still
+ there. Thus stats module currently has no its own configuration,
+ and the items in "stats-schema.spec" are neither visible nor
+ configurable through bindctl. "stats-schema.spec" is shared with
+ stats module and stats-httpd module, and maybe with other
+ statistical modules in future. "stats.spec" has own configuration
+ and commands of stats module, if it requires.
+ (Trac#719, git a234b20dc6617392deb8a1e00eb0eed0ff353c0a)
+
+236. [func] jelte
+ C++ client side of configuration now uses BIND10 logging system.
+ It also has improved error handling when communicating with the
+ rest of the system.
+ (Trac #743, git 86632c12308c3ed099d75eb828f740c526dd7ec0)
+
+235. [func] jinmei
+ libdns++: added support for TSIG signing and verification. It can
+ be done using a newly introduced TSIGContext class.
+ Note: we temporarily disabled support for truncated signature
+ and modified some part of the code introduced in #226 accordingly.
+ We plan to fix this pretty soon.
+ (Trac #812, git ebe0c4b1e66d359227bdd1bd47395fee7b957f14)
+ (Trac #871, git 7c54055c0e47c7a0e36fcfab4b47ff180c0ca8c8)
+ (Trac #813, git ffa2f0672084c1f16e5784cdcdd55822f119feaa)
+ (Trac #893, git 5aaa6c0f628ed7c2093ecdbac93a2c8cf6c94349)
+
+234. [func] jerry
+ src/bin/xfrin: update xfrin to use TSIG. Currently it only supports
+ sending a signed TSIG request or SOA request.
+ (Trac #815, git a892818fb13a1839c82104523cb6cb359c970e88)
+
+233. [func] stephen
+ Added new-style logging statements to the NSAS code.
+ (Trac #745, git ceef68cd1223ae14d8412adbe18af2812ade8c2d)
+
+232. [func] stephen
+ To facilitate the writing of extended descriptions in
+ message files, altered the message file format. The message
+ is now flagged with a "%" as the first non-blank character
+ in the line and the lines in the extended description are
+ no longer preceded by a "+".
+ (Trac #900, git b395258c708b49a5da8d0cffcb48d83294354ba3)
+
+231. [func]* vorner
+ The logging interface changed slightly. We use
+ logger.foo(MESSAGE_ID).arg(bar); instead of logger.foo(MESSAGE_ID,
+ bar); internally. The message definitions use '%1,%2,...'
+ instead of '%s,%d', which allows us to cope better with
+ mismatched placeholders and allows reordering of them in
+ case of translation.
+ (Trac901, git 4903410e45670b30d7283f5d69dc28c2069237d6)
+
+230. [bug] naokikambe
+ Removed too repeated verbose messages in two cases of:
+ - when auth sends statistics data to stats
+ - when stats receives statistics data from other modules
+ (Trac#620, git 0ecb807011196eac01f281d40bc7c9d44565b364)
+
+229. [doc] jreed
+ Add manual page for b10-host.
+ (git a437d4e26b81bb07181ff35a625c540703eee845)
+
+228. [func]* jreed
+ The host tool is renamed to b10-host. While the utility is
+ a work in progress, it is expected to now be shipped with
+ tarballs. Its initial goal was to be a host(1) clone,
+ rewritten in C++ from scratch and using BIND 10's libdns++.
+ It now supports the -a (any), -c class, -d (verbose) switches
+ and has improved output.
+ (Trac #872, git d846851699d5c76937533adf9ff9d948dfd593ca)
+
+227. [build] jreed
+ Add missing libdns++ rdata files for the distribution (this
+ fixes distcheck error). Change three generated libdns++
+ headers to "nodist" so they aren't included in the distribution
+ (they were mistakenly included in last tarball).
+
+226. [func]* jelte
+ Introduced an API for cryptographic operations. Currently it only
+ supports HMAC, intended for use with TSIG. The current
+ implementation uses Botan as the backend library.
+ This introduces a new dependency, on Botan. Currently only Botan
+ 1.8.x works; older or newer versions don't.
+ (Trac #781, git 9df42279a47eb617f586144dce8cce680598558a)
+
+225. [func] naokikambe
+ Added the HTTP/XML interface(b10-stats-httpd) to the
+ statistics feature in BIND 10. b10-stats-httpd is a standalone
+ HTTP server and it requests statistics data to the stats
+ daemon(b10-stats) and sends it to HTTP clients in XML
+ format. Items of the data collected via b10-stats-httpd
+ are almost equivalent to ones which are collected via
+ bindctl. Since it also can send XSL(Extensible Stylessheet
+ Language) document and XSD(XML Schema definition) document,
+ XML document is human-friendly to view through web browsers
+ and its data types are strictly defined.
+ (Trac #547, git 1cbd51919237a6e65983be46e4f5a63d1877b1d3)
+
+224. [bug] jinmei
+ b10-auth, src/lib/datasrc: inconsistency between the hot spot
+ cache and actual data source could cause a crash while query
+ processing. The crash could happen, e.g., when an sqlite3 DB file
+ is being updated after a zone transfer while b10-auth handles a
+ query using the corresponding sqlite3 data source.
+ (Trac #851, git 2463b96680bb3e9a76e50c38a4d7f1d38d810643)
+
+223. [bug] feng
+ If ip address or port isn't usable for name server, name
+ server process won't exist and give end user chance to
+ reconfigure them.
+ (Trac #775, git 572ac2cf62e18f7eb69d670b890e2a3443bfd6e7)
+
+222. [bug] jerry
src/lib/zonemgr: Fix a bug that xfrin not checking for new copy of
zone on startup. Imposes some random jitters to avoid many zones
need to do refresh at the same time.
@@ -13,7 +135,7 @@
(potentially) bad packets to a nameserver and prints the responses.
(Trac #703, git 1b666838b6c0fe265522b30971e878d9f0d21fde)
-219. [func] ocean
+219. [func] ocean
src/lib: move some dns related code out of asiolink library to
asiodns library
(Trac #751, git 262ac6c6fc61224d54705ed4c700dadb606fcb1c)
@@ -23,9 +145,9 @@
(Trac #806, git 4e47d5f6b692c63c907af6681a75024450884a88)
217. [bug] jerry
- src/lib/dns/python: Use a signed version of larger size of integer and
- perform more strict range checks with PyArg_ParseTuple() in case of
- overflows.
+ src/lib/dns/python: Use a signed version of larger size of
+ integer and perform more strict range checks with
+ PyArg_ParseTuple() in case of overflows.
(Trac #363, git ce281e646be9f0f273229d94ccd75bf7e08d17cf)
216. [func] vorner
@@ -1047,7 +1169,7 @@ bind10-devel-20100701 released on July 1, 2010
55. [bug] shane
bin/xfrout: xfrout exception on Ctrl-C now no longer generates
exception for 'Interrupted system call'
- (Track #136, svn r2147)
+ (Trac #136, svn r2147)
54. [bug] zhanglikun
bin/xfrout: Enable b10-xfrout can be launched in source
diff --git a/Makefile.am b/Makefile.am
index e31a1a5..bab6679 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -84,214 +84,310 @@ systest:
#### include external sources in the distributed tarball:
EXTRA_DIST = ext/asio/README
-EXTRA_DIST += ext/asio/asio/local/stream_protocol.hpp
-EXTRA_DIST += ext/asio/asio/local/basic_endpoint.hpp
-EXTRA_DIST += ext/asio/asio/local/datagram_protocol.hpp
-EXTRA_DIST += ext/asio/asio/local/connect_pair.hpp
-EXTRA_DIST += ext/asio/asio/windows/basic_handle.hpp
-EXTRA_DIST += ext/asio/asio/windows/random_access_handle.hpp
-EXTRA_DIST += ext/asio/asio/windows/random_access_handle_service.hpp
-EXTRA_DIST += ext/asio/asio/windows/basic_random_access_handle.hpp
-EXTRA_DIST += ext/asio/asio/windows/overlapped_ptr.hpp
-EXTRA_DIST += ext/asio/asio/windows/stream_handle.hpp
-EXTRA_DIST += ext/asio/asio/windows/stream_handle_service.hpp
-EXTRA_DIST += ext/asio/asio/windows/basic_stream_handle.hpp
-EXTRA_DIST += ext/asio/asio/impl/write.ipp
-EXTRA_DIST += ext/asio/asio/impl/read.ipp
-EXTRA_DIST += ext/asio/asio/impl/serial_port_base.ipp
-EXTRA_DIST += ext/asio/asio/impl/write_at.ipp
-EXTRA_DIST += ext/asio/asio/impl/read_at.ipp
-EXTRA_DIST += ext/asio/asio/impl/error_code.ipp
-EXTRA_DIST += ext/asio/asio/impl/read_until.ipp
-EXTRA_DIST += ext/asio/asio/impl/io_service.ipp
-EXTRA_DIST += ext/asio/asio/detail/win_iocp_serial_port_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/reactive_socket_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/wince_thread.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_event.hpp
-EXTRA_DIST += ext/asio/asio/detail/descriptor_ops.hpp
-EXTRA_DIST += ext/asio/asio/detail/pipe_select_interrupter.hpp
-EXTRA_DIST += ext/asio/asio/detail/task_io_service_fwd.hpp
-EXTRA_DIST += ext/asio/asio/detail/handler_alloc_helpers.hpp
-EXTRA_DIST += ext/asio/asio/detail/pop_options.hpp
-EXTRA_DIST += ext/asio/asio/detail/strand_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/buffer_resize_guard.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_iocp_io_service_fwd.hpp
-EXTRA_DIST += ext/asio/asio/detail/timer_scheduler.hpp
-EXTRA_DIST += ext/asio/asio/detail/kqueue_reactor_fwd.hpp
-EXTRA_DIST += ext/asio/asio/detail/hash_map.hpp
-EXTRA_DIST += ext/asio/asio/detail/event.hpp
-EXTRA_DIST += ext/asio/asio/detail/buffered_stream_storage.hpp
-EXTRA_DIST += ext/asio/asio/detail/posix_mutex.hpp
-EXTRA_DIST += ext/asio/asio/detail/timer_queue_fwd.hpp
-EXTRA_DIST += ext/asio/asio/detail/deadline_timer_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/posix_fd_set_adapter.hpp
-EXTRA_DIST += ext/asio/asio/detail/service_registry.hpp
+EXTRA_DIST += ext/asio/README
+EXTRA_DIST += ext/asio/asio.hpp
+EXTRA_DIST += ext/asio/asio/basic_socket.hpp
+EXTRA_DIST += ext/asio/asio/streambuf.hpp
+EXTRA_DIST += ext/asio/asio/thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/wait_handler.hpp
+EXTRA_DIST += ext/asio/asio/detail/resolve_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/gcc_hppa_fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/null_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/noncopyable.hpp
+EXTRA_DIST += ext/asio/asio/detail/eventfd_select_interrupter.hpp
EXTRA_DIST += ext/asio/asio/detail/task_io_service_operation.hpp
-EXTRA_DIST += ext/asio/asio/detail/epoll_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/service_base.hpp
+EXTRA_DIST += ext/asio/asio/detail/task_io_service_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_buffers_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_handle_write_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/select_reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/event.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_descriptor_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_overlapped_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_recv_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/macos_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/dev_poll_reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_tss_ptr.hpp
EXTRA_DIST += ext/asio/asio/detail/local_free_on_block_exit.hpp
-EXTRA_DIST += ext/asio/asio/detail/socket_select_interrupter.hpp
-EXTRA_DIST += ext/asio/asio/detail/null_mutex.hpp
-EXTRA_DIST += ext/asio/asio/detail/reactor_op.hpp
-EXTRA_DIST += ext/asio/asio/detail/fenced_block.hpp
-EXTRA_DIST += ext/asio/asio/detail/tss_ptr.hpp
-EXTRA_DIST += ext/asio/asio/detail/timer_queue_set.hpp
-EXTRA_DIST += ext/asio/asio/detail/winsock_init.hpp
-EXTRA_DIST += ext/asio/asio/detail/signal_init.hpp
-EXTRA_DIST += ext/asio/asio/detail/call_stack.hpp
-EXTRA_DIST += ext/asio/asio/detail/operation.hpp
-EXTRA_DIST += ext/asio/asio/detail/posix_signal_blocker.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_iocp_handle_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/fd_set_adapter.hpp
-EXTRA_DIST += ext/asio/asio/detail/io_control.hpp
-EXTRA_DIST += ext/asio/asio/detail/null_signal_blocker.hpp
-EXTRA_DIST += ext/asio/asio/detail/socket_ops.hpp
-EXTRA_DIST += ext/asio/asio/detail/bind_handler.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp
-EXTRA_DIST += ext/asio/asio/detail/timer_scheduler_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_scheduler.hpp
EXTRA_DIST += ext/asio/asio/detail/signal_blocker.hpp
-EXTRA_DIST += ext/asio/asio/detail/consuming_buffers.hpp
-EXTRA_DIST += ext/asio/asio/detail/socket_option.hpp
-EXTRA_DIST += ext/asio/asio/detail/reactor.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_fd_set_adapter.hpp
-EXTRA_DIST += ext/asio/asio/detail/select_interrupter.hpp
-EXTRA_DIST += ext/asio/asio/detail/null_buffers_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/resolver_service_base.hpp
EXTRA_DIST += ext/asio/asio/detail/socket_holder.hpp
-EXTRA_DIST += ext/asio/asio/detail/scoped_lock.hpp
-EXTRA_DIST += ext/asio/asio/detail/service_registry_fwd.hpp
-EXTRA_DIST += ext/asio/asio/detail/base_from_completion_cond.hpp
-EXTRA_DIST += ext/asio/asio/detail/posix_thread.hpp
-EXTRA_DIST += ext/asio/asio/detail/solaris_fenced_block.hpp
-EXTRA_DIST += ext/asio/asio/detail/epoll_reactor_fwd.hpp
-EXTRA_DIST += ext/asio/asio/detail/push_options.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_signal_blocker.hpp
-EXTRA_DIST += ext/asio/asio/detail/eventfd_select_interrupter.hpp
+EXTRA_DIST += ext/asio/asio/detail/dev_poll_reactor.hpp
EXTRA_DIST += ext/asio/asio/detail/select_reactor.hpp
-EXTRA_DIST += ext/asio/asio/detail/old_win_sdk_compat.hpp
+EXTRA_DIST += ext/asio/asio/detail/gcc_arm_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/consuming_buffers.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactor_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/base_from_completion_cond.hpp
+EXTRA_DIST += ext/asio/asio/detail/epoll_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/bind_handler.hpp
+EXTRA_DIST += ext/asio/asio/detail/strand_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/op_queue.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_mutex.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_operation.hpp
+EXTRA_DIST += ext/asio/asio/detail/pipe_select_interrupter.hpp
+EXTRA_DIST += ext/asio/asio/detail/wince_thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/buffered_stream_storage.hpp
+EXTRA_DIST += ext/asio/asio/detail/mutex.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_mutex.hpp
EXTRA_DIST += ext/asio/asio/detail/reactor_op_queue.hpp
-EXTRA_DIST += ext/asio/asio/detail/null_thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_event.hpp
+EXTRA_DIST += ext/asio/asio/detail/select_interrupter.hpp
+EXTRA_DIST += ext/asio/asio/detail/io_control.hpp
EXTRA_DIST += ext/asio/asio/detail/buffer_sequence_adapter.hpp
-EXTRA_DIST += ext/asio/asio/detail/posix_event.hpp
-EXTRA_DIST += ext/asio/asio/detail/thread.hpp
-EXTRA_DIST += ext/asio/asio/detail/handler_invoke_helpers.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_io_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_handle_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_send_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/epoll_reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/operation.hpp
+EXTRA_DIST += ext/asio/asio/detail/descriptor_ops.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/shared_ptr.hpp
+EXTRA_DIST += ext/asio/asio/detail/winsock_init.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_queue_set.hpp
+EXTRA_DIST += ext/asio/asio/detail/completion_handler.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_serial_port_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/null_event.hpp
+EXTRA_DIST += ext/asio/asio/detail/hash_map.hpp
+EXTRA_DIST += ext/asio/asio/detail/gcc_sync_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_tss_ptr.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_fd_set_adapter.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_null_buffers_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_queue_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/old_win_sdk_compat.hpp
+EXTRA_DIST += ext/asio/asio/detail/call_stack.hpp
+EXTRA_DIST += ext/asio/asio/detail/weak_ptr.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_accept_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/gcc_x86_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/gcc_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_mutex.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_recvfrom_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_event.hpp
EXTRA_DIST += ext/asio/asio/detail/service_id.hpp
-EXTRA_DIST += ext/asio/asio/detail/socket_types.hpp
+EXTRA_DIST += ext/asio/asio/detail/kqueue_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/regex_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_sendto_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/push_options.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/socket_select_interrupter.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_service_base.hpp
EXTRA_DIST += ext/asio/asio/detail/throw_error.hpp
-EXTRA_DIST += ext/asio/asio/detail/timer_op.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_mutex.hpp
-EXTRA_DIST += ext/asio/asio/detail/reactive_descriptor_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/resolver_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/op_queue.hpp
-EXTRA_DIST += ext/asio/asio/detail/dev_poll_reactor.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_thread.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_iocp_operation.hpp
-EXTRA_DIST += ext/asio/asio/detail/service_base.hpp
-EXTRA_DIST += ext/asio/asio/detail/select_reactor_fwd.hpp
-EXTRA_DIST += ext/asio/asio/detail/reactor_fwd.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_signal_blocker.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_accept_op.hpp
EXTRA_DIST += ext/asio/asio/detail/wrapped_handler.hpp
-EXTRA_DIST += ext/asio/asio/detail/mutex.hpp
-EXTRA_DIST += ext/asio/asio/detail/completion_handler.hpp
-EXTRA_DIST += ext/asio/asio/detail/noncopyable.hpp
-EXTRA_DIST += ext/asio/asio/detail/task_io_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/gcc_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/object_pool.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_scheduler_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/resolve_endpoint_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/array_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/config.hpp
+EXTRA_DIST += ext/asio/asio/detail/socket_option.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp
EXTRA_DIST += ext/asio/asio/detail/win_fenced_block.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_tss_ptr.hpp
-EXTRA_DIST += ext/asio/asio/detail/kqueue_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/socket_types.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_tss_ptr.hpp
+EXTRA_DIST += ext/asio/asio/detail/handler_invoke_helpers.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_send_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_null_buffers_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/pop_options.hpp
+EXTRA_DIST += ext/asio/asio/detail/resolver_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_service_base.hpp
+EXTRA_DIST += ext/asio/asio/detail/descriptor_read_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_connect_op.hpp
EXTRA_DIST += ext/asio/asio/detail/timer_queue_base.hpp
-EXTRA_DIST += ext/asio/asio/detail/win_iocp_io_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/gcc_x86_fenced_block.hpp
-EXTRA_DIST += ext/asio/asio/detail/posix_tss_ptr.hpp
-EXTRA_DIST += ext/asio/asio/detail/macos_fenced_block.hpp
-EXTRA_DIST += ext/asio/asio/detail/dev_poll_reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_recvfrom_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_serial_port_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/tss_ptr.hpp
+EXTRA_DIST += ext/asio/asio/detail/buffer_resize_guard.hpp
+EXTRA_DIST += ext/asio/asio/detail/kqueue_reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/deadline_timer_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_recv_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/signal_init.hpp
+EXTRA_DIST += ext/asio/asio/detail/descriptor_write_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_signal_blocker.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/reactive_socket_service_base.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_mutex.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/posix_event.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_iocp_io_service.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/select_reactor.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/posix_tss_ptr.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/task_io_service.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/dev_poll_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/select_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/eventfd_select_interrupter.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/epoll_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/strand_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/winsock_init.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/pipe_select_interrupter.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_iocp_serial_port_service.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/dev_poll_reactor.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_iocp_io_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/strand_service.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_iocp_socket_service_base.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/timer_queue.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/posix_mutex.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/reactive_serial_port_service.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/socket_ops.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/socket_select_interrupter.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/posix_thread.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/reactive_descriptor_service.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/kqueue_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/kqueue_reactor.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_event.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/timer_queue_set.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_tss_ptr.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_iocp_handle_service.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/resolver_service_base.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/win_thread.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/task_io_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/throw_error.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/epoll_reactor.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/service_registry.hpp
+EXTRA_DIST += ext/asio/asio/detail/impl/descriptor_ops.ipp
+EXTRA_DIST += ext/asio/asio/detail/impl/service_registry.ipp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_io_service_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/fd_set_adapter.hpp
+EXTRA_DIST += ext/asio/asio/detail/task_io_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/solaris_fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/timer_queue.hpp
-EXTRA_DIST += ext/asio/asio/detail/reactive_serial_port_service.hpp
-EXTRA_DIST += ext/asio/asio/detail/null_tss_ptr.hpp
-EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_stream_service.hpp
-EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_operation.hpp
-EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_init.hpp
-EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_context_service.hpp
-EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_types.hpp
-EXTRA_DIST += ext/asio/asio/ssl/stream.hpp
-EXTRA_DIST += ext/asio/asio/ssl/stream_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/handler_alloc_helpers.hpp
+EXTRA_DIST += ext/asio/asio/detail/scoped_lock.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_handle_read_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/service_registry_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/service_registry.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_fd_set_adapter.hpp
+EXTRA_DIST += ext/asio/asio/detail/socket_ops.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_signal_blocker.hpp
+EXTRA_DIST += ext/asio/asio/serial_port_base.hpp
EXTRA_DIST += ext/asio/asio/ssl/context_base.hpp
EXTRA_DIST += ext/asio/asio/ssl/context.hpp
EXTRA_DIST += ext/asio/asio/ssl/context_service.hpp
+EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_types.hpp
+EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_context_service.hpp
+EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_stream_service.hpp
+EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_operation.hpp
+EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_init.hpp
EXTRA_DIST += ext/asio/asio/ssl/basic_context.hpp
+EXTRA_DIST += ext/asio/asio/ssl/stream_service.hpp
+EXTRA_DIST += ext/asio/asio/ssl/stream.hpp
EXTRA_DIST += ext/asio/asio/ssl/stream_base.hpp
-EXTRA_DIST += ext/asio/asio/posix/stream_descriptor.hpp
-EXTRA_DIST += ext/asio/asio/posix/stream_descriptor_service.hpp
+EXTRA_DIST += ext/asio/asio/basic_streambuf.hpp
+EXTRA_DIST += ext/asio/asio/serial_port_service.hpp
+EXTRA_DIST += ext/asio/asio/error.hpp
+EXTRA_DIST += ext/asio/asio/handler_alloc_hook.hpp
+EXTRA_DIST += ext/asio/asio/buffers_iterator.hpp
+EXTRA_DIST += ext/asio/asio/is_read_buffered.hpp
+EXTRA_DIST += ext/asio/asio/buffered_stream_fwd.hpp
+EXTRA_DIST += ext/asio/asio/placeholders.hpp
+EXTRA_DIST += ext/asio/asio/local/stream_protocol.hpp
+EXTRA_DIST += ext/asio/asio/local/detail/impl/endpoint.ipp
+EXTRA_DIST += ext/asio/asio/local/detail/endpoint.hpp
+EXTRA_DIST += ext/asio/asio/local/datagram_protocol.hpp
+EXTRA_DIST += ext/asio/asio/local/connect_pair.hpp
+EXTRA_DIST += ext/asio/asio/local/basic_endpoint.hpp
+EXTRA_DIST += ext/asio/asio/buffered_stream.hpp
+EXTRA_DIST += ext/asio/asio/basic_serial_port.hpp
+EXTRA_DIST += ext/asio/asio/datagram_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/socket_base.hpp
+EXTRA_DIST += ext/asio/asio/io_service.hpp
+EXTRA_DIST += ext/asio/asio/ssl.hpp
+EXTRA_DIST += ext/asio/asio/basic_socket_iostream.hpp
+EXTRA_DIST += ext/asio/asio/basic_io_object.hpp
+EXTRA_DIST += ext/asio/asio/basic_socket_streambuf.hpp
+EXTRA_DIST += ext/asio/asio/error_code.hpp
+EXTRA_DIST += ext/asio/asio/basic_stream_socket.hpp
+EXTRA_DIST += ext/asio/asio/read_until.hpp
+EXTRA_DIST += ext/asio/asio/basic_streambuf_fwd.hpp
+EXTRA_DIST += ext/asio/asio/is_write_buffered.hpp
+EXTRA_DIST += ext/asio/asio/basic_datagram_socket.hpp
+EXTRA_DIST += ext/asio/asio/buffered_write_stream_fwd.hpp
+EXTRA_DIST += ext/asio/asio/basic_deadline_timer.hpp
+EXTRA_DIST += ext/asio/asio/socket_acceptor_service.hpp
+EXTRA_DIST += ext/asio/asio/raw_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/buffered_read_stream.hpp
+EXTRA_DIST += ext/asio/asio/time_traits.hpp
+EXTRA_DIST += ext/asio/asio/completion_condition.hpp
EXTRA_DIST += ext/asio/asio/posix/basic_stream_descriptor.hpp
EXTRA_DIST += ext/asio/asio/posix/basic_descriptor.hpp
EXTRA_DIST += ext/asio/asio/posix/descriptor_base.hpp
+EXTRA_DIST += ext/asio/asio/posix/stream_descriptor_service.hpp
+EXTRA_DIST += ext/asio/asio/posix/stream_descriptor.hpp
+EXTRA_DIST += ext/asio/asio/write.hpp
+EXTRA_DIST += ext/asio/asio/write_at.hpp
+EXTRA_DIST += ext/asio/asio/basic_raw_socket.hpp
+EXTRA_DIST += ext/asio/asio/serial_port.hpp
+EXTRA_DIST += ext/asio/asio/windows/basic_stream_handle.hpp
+EXTRA_DIST += ext/asio/asio/windows/basic_handle.hpp
+EXTRA_DIST += ext/asio/asio/windows/random_access_handle.hpp
+EXTRA_DIST += ext/asio/asio/windows/overlapped_ptr.hpp
+EXTRA_DIST += ext/asio/asio/windows/stream_handle.hpp
+EXTRA_DIST += ext/asio/asio/windows/random_access_handle_service.hpp
+EXTRA_DIST += ext/asio/asio/windows/stream_handle_service.hpp
+EXTRA_DIST += ext/asio/asio/windows/basic_random_access_handle.hpp
+EXTRA_DIST += ext/asio/asio/read.hpp
+EXTRA_DIST += ext/asio/asio/deadline_timer_service.hpp
+EXTRA_DIST += ext/asio/asio/buffered_write_stream.hpp
+EXTRA_DIST += ext/asio/asio/buffer.hpp
+EXTRA_DIST += ext/asio/asio/impl/read_until.ipp
+EXTRA_DIST += ext/asio/asio/impl/serial_port_base.hpp
+EXTRA_DIST += ext/asio/asio/impl/read_at.ipp
+EXTRA_DIST += ext/asio/asio/impl/read.ipp
+EXTRA_DIST += ext/asio/asio/impl/error.ipp
+EXTRA_DIST += ext/asio/asio/impl/io_service.ipp
+EXTRA_DIST += ext/asio/asio/impl/io_service.hpp
+EXTRA_DIST += ext/asio/asio/impl/src.hpp
+EXTRA_DIST += ext/asio/asio/impl/src.cpp
+EXTRA_DIST += ext/asio/asio/impl/read_until.hpp
+EXTRA_DIST += ext/asio/asio/impl/serial_port_base.ipp
+EXTRA_DIST += ext/asio/asio/impl/write.hpp
+EXTRA_DIST += ext/asio/asio/impl/write_at.hpp
+EXTRA_DIST += ext/asio/asio/impl/write.ipp
+EXTRA_DIST += ext/asio/asio/impl/read.hpp
+EXTRA_DIST += ext/asio/asio/impl/write_at.ipp
+EXTRA_DIST += ext/asio/asio/impl/error_code.ipp
+EXTRA_DIST += ext/asio/asio/impl/read_at.hpp
+EXTRA_DIST += ext/asio/asio/strand.hpp
+EXTRA_DIST += ext/asio/asio/version.hpp
+EXTRA_DIST += ext/asio/asio/basic_socket_acceptor.hpp
+EXTRA_DIST += ext/asio/asio/ip/basic_resolver_query.hpp
+EXTRA_DIST += ext/asio/asio/ip/address.hpp
+EXTRA_DIST += ext/asio/asio/ip/host_name.hpp
EXTRA_DIST += ext/asio/asio/ip/detail/socket_option.hpp
+EXTRA_DIST += ext/asio/asio/ip/detail/impl/endpoint.ipp
+EXTRA_DIST += ext/asio/asio/ip/detail/endpoint.hpp
+EXTRA_DIST += ext/asio/asio/ip/udp.hpp
+EXTRA_DIST += ext/asio/asio/ip/basic_resolver_iterator.hpp
EXTRA_DIST += ext/asio/asio/ip/v6_only.hpp
EXTRA_DIST += ext/asio/asio/ip/address_v4.hpp
-EXTRA_DIST += ext/asio/asio/ip/address_v6.hpp
-EXTRA_DIST += ext/asio/asio/ip/basic_resolver.hpp
+EXTRA_DIST += ext/asio/asio/ip/resolver_query_base.hpp
EXTRA_DIST += ext/asio/asio/ip/multicast.hpp
+EXTRA_DIST += ext/asio/asio/ip/address_v6.hpp
+EXTRA_DIST += ext/asio/asio/ip/tcp.hpp
+EXTRA_DIST += ext/asio/asio/ip/basic_resolver_entry.hpp
EXTRA_DIST += ext/asio/asio/ip/unicast.hpp
-EXTRA_DIST += ext/asio/asio/ip/basic_resolver_iterator.hpp
-EXTRA_DIST += ext/asio/asio/ip/host_name.hpp
-EXTRA_DIST += ext/asio/asio/ip/resolver_query_base.hpp
-EXTRA_DIST += ext/asio/asio/ip/basic_endpoint.hpp
EXTRA_DIST += ext/asio/asio/ip/resolver_service.hpp
-EXTRA_DIST += ext/asio/asio/ip/basic_resolver_entry.hpp
-EXTRA_DIST += ext/asio/asio/ip/address.hpp
-EXTRA_DIST += ext/asio/asio/ip/tcp.hpp
-EXTRA_DIST += ext/asio/asio/ip/basic_resolver_query.hpp
-EXTRA_DIST += ext/asio/asio/ip/udp.hpp
EXTRA_DIST += ext/asio/asio/ip/icmp.hpp
-EXTRA_DIST += ext/asio/asio/error.hpp
-EXTRA_DIST += ext/asio/asio/basic_socket.hpp
-EXTRA_DIST += ext/asio/asio/buffered_stream.hpp
-EXTRA_DIST += ext/asio/asio/system_error.hpp
-EXTRA_DIST += ext/asio/asio/basic_io_object.hpp
-EXTRA_DIST += ext/asio/asio/read_at.hpp
-EXTRA_DIST += ext/asio/asio/basic_raw_socket.hpp
-EXTRA_DIST += ext/asio/asio/serial_port_service.hpp
-EXTRA_DIST += ext/asio/asio/basic_stream_socket.hpp
-EXTRA_DIST += ext/asio/asio/placeholders.hpp
-EXTRA_DIST += ext/asio/asio/basic_deadline_timer.hpp
-EXTRA_DIST += ext/asio/asio/thread.hpp
-EXTRA_DIST += ext/asio/asio/buffered_write_stream_fwd.hpp
-EXTRA_DIST += ext/asio/asio/datagram_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/ip/basic_endpoint.hpp
+EXTRA_DIST += ext/asio/asio/ip/basic_resolver.hpp
+EXTRA_DIST += ext/asio/asio/ip/impl/address.hpp
+EXTRA_DIST += ext/asio/asio/ip/impl/address_v4.hpp
+EXTRA_DIST += ext/asio/asio/ip/impl/address_v4.ipp
+EXTRA_DIST += ext/asio/asio/ip/impl/address_v6.hpp
+EXTRA_DIST += ext/asio/asio/ip/impl/address.ipp
+EXTRA_DIST += ext/asio/asio/ip/impl/host_name.ipp
+EXTRA_DIST += ext/asio/asio/ip/impl/basic_endpoint.hpp
+EXTRA_DIST += ext/asio/asio/ip/impl/address_v6.ipp
EXTRA_DIST += ext/asio/asio/handler_invoke_hook.hpp
-EXTRA_DIST += ext/asio/asio/is_read_buffered.hpp
-EXTRA_DIST += ext/asio/asio/buffer.hpp
-EXTRA_DIST += ext/asio/asio/basic_socket_acceptor.hpp
-EXTRA_DIST += ext/asio/asio/write_at.hpp
-EXTRA_DIST += ext/asio/asio/completion_condition.hpp
-EXTRA_DIST += ext/asio/asio/raw_socket_service.hpp
-EXTRA_DIST += ext/asio/asio/socket_base.hpp
-EXTRA_DIST += ext/asio/asio/serial_port.hpp
-EXTRA_DIST += ext/asio/asio/error_code.hpp
-EXTRA_DIST += ext/asio/asio/basic_serial_port.hpp
-EXTRA_DIST += ext/asio/asio/version.hpp
-EXTRA_DIST += ext/asio/asio/deadline_timer_service.hpp
-EXTRA_DIST += ext/asio/asio/io_service.hpp
-EXTRA_DIST += ext/asio/asio/buffered_read_stream.hpp
-EXTRA_DIST += ext/asio/asio/streambuf.hpp
-EXTRA_DIST += ext/asio/asio/basic_datagram_socket.hpp
-EXTRA_DIST += ext/asio/asio/basic_streambuf.hpp
-EXTRA_DIST += ext/asio/asio/write.hpp
-EXTRA_DIST += ext/asio/asio/strand.hpp
-EXTRA_DIST += ext/asio/asio/basic_socket_iostream.hpp
-EXTRA_DIST += ext/asio/asio/buffered_stream_fwd.hpp
-EXTRA_DIST += ext/asio/asio/basic_socket_streambuf.hpp
-EXTRA_DIST += ext/asio/asio/ssl.hpp
+EXTRA_DIST += ext/asio/asio/read_at.hpp
+EXTRA_DIST += ext/asio/asio/buffered_read_stream_fwd.hpp
+EXTRA_DIST += ext/asio/asio/system_error.hpp
EXTRA_DIST += ext/asio/asio/deadline_timer.hpp
-EXTRA_DIST += ext/asio/asio/buffers_iterator.hpp
-EXTRA_DIST += ext/asio/asio/handler_alloc_hook.hpp
-EXTRA_DIST += ext/asio/asio/buffered_write_stream.hpp
-EXTRA_DIST += ext/asio/asio/read.hpp
-EXTRA_DIST += ext/asio/asio/serial_port_base.hpp
EXTRA_DIST += ext/asio/asio/stream_socket_service.hpp
-EXTRA_DIST += ext/asio/asio/time_traits.hpp
-EXTRA_DIST += ext/asio/asio/read_until.hpp
-EXTRA_DIST += ext/asio/asio/is_write_buffered.hpp
-EXTRA_DIST += ext/asio/asio/buffered_read_stream_fwd.hpp
-EXTRA_DIST += ext/asio/asio/socket_acceptor_service.hpp
-EXTRA_DIST += ext/asio/asio.hpp
EXTRA_DIST += ext/coroutine/coroutine.h
diff --git a/configure.ac b/configure.ac
index 81df476..c95396a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -374,6 +374,79 @@ if test "$lcov" != "no"; then
fi
AC_SUBST(USE_LCOV)
+# Check for Botan
+botan_path="yes"
+AC_ARG_WITH([botan],
+ AC_HELP_STRING([--with-botan=PATH],
+ [specify exact directory of Botan library]),
+ [botan_path="$withval"])
+if test "${botan_path}" == "no" ; then
+ AC_MSG_ERROR([Need botan for libcryptolink])
+fi
+if test "${botan_path}" != "yes" ; then
+ if test -x "${botan_path}/bin/botan-config" ; then
+ BOTAN_CONFIG="${botan_path}/bin/botan-config"
+ else
+ AC_MSG_ERROR([${botan_path}/bin/botan-config not found])
+ fi
+else
+ AC_PATH_PROG([BOTAN_CONFIG], [botan-config])
+fi
+
+if test -x "${BOTAN_CONFIG}" ; then
+ BOTAN_LDFLAGS=`${BOTAN_CONFIG} --libs`
+ # We expect botan-config --libs to contain -L<path_to_libbotan>, but
+ # this is not always the case. As a heuristics workaround we add
+ # -L`botan-config --prefix/lib` in this case. Same for BOTAN_INCLUDES
+ # (but using include instead of lib) below.
+ echo ${BOTAN_LDFLAGS} | grep -- -L > /dev/null || \
+ BOTAN_LDFLAGS="-L`${BOTAN_CONFIG} --prefix`/lib ${BOTAN_LDFLAGS}"
+ BOTAN_INCLUDES=`${BOTAN_CONFIG} --cflags`
+ echo ${BOTAN_INCLUDES} | grep -- -I > /dev/null || \
+ BOTAN_INCLUDES="-I`${BOTAN_CONFIG} --prefix`/include ${BOTAN_INCLUDES}"
+ # See python_rpath for some info on why we do this
+ if test $rpath_available = yes; then
+ BOTAN_RPATH=
+ for flag in ${BOTAN_LDFLAGS}; do
+ BOTAN_RPATH="${BOTAN_RPATH} `echo $flag | sed -ne 's/^\(\-L\)/-R/p'`"
+ done
+ AC_SUBST(BOTAN_RPATH)
+
+ # According to the libtool manual, it should be sufficient if we
+ # specify the "-R libdir" in our wrapper library of botan (no other
+ # programs will need libbotan directly); "libdir" should be added to
+ # the program's binary image. But we've seen in our build environments
+ # that (some versions of?) libtool doesn't propagate -R as documented,
+ # and it caused a linker error at run time. To work around this, we
+ # also add the rpath to the global LDFLAGS.
+ LDFLAGS="$BOTAN_RPATH $LDFLAGS"
+ fi
+
+ AC_SUBST(BOTAN_LDFLAGS)
+ AC_SUBST(BOTAN_INCLUDES)
+fi
+
+CPPFLAGS_SAVED=$CPPFLAGS
+CPPFLAGS="$BOTAN_INCLUDES $CPPFLAGS"
+LDFLAGS_SAVED="$LDFLAGS"
+LDFLAGS="$BOTAN_LDFLAGS $LDFLAGS"
+
+AC_CHECK_HEADERS([botan/botan.h],,AC_MSG_ERROR([Missing required header files.]))
+AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([#include <botan/botan.h>
+ #include <botan/hash.h>
+ ],
+ [using namespace Botan;
+ LibraryInitializer::initialize();
+ HashFunction *h = get_hash("MD5");
+ ])],
+ [AC_MSG_RESULT([checking for Botan library... yes])],
+ [AC_MSG_RESULT([checking for Botan library... no])
+ AC_MSG_ERROR([Needs Botan library 1.8 or higher])]
+)
+CPPFLAGS=$CPPFLAGS_SAVED
+LDFLAGS=$LDFLAGS_SAVED
+
#
# Configure Boost header path
#
@@ -613,6 +686,7 @@ AC_CONFIG_FILES([Makefile
src/bin/bindctl/tests/Makefile
src/bin/cfgmgr/Makefile
src/bin/cfgmgr/plugins/Makefile
+ src/bin/cfgmgr/plugins/tests/Makefile
src/bin/cfgmgr/tests/Makefile
src/bin/host/Makefile
src/bin/loadzone/Makefile
@@ -640,6 +714,7 @@ AC_CONFIG_FILES([Makefile
src/bin/stats/tests/isc/config/Makefile
src/bin/stats/tests/isc/util/Makefile
src/bin/stats/tests/testdata/Makefile
+ src/bin/stats/tests/http/Makefile
src/bin/usermgr/Makefile
src/bin/tests/Makefile
src/lib/Makefile
@@ -672,11 +747,8 @@ AC_CONFIG_FILES([Makefile
src/lib/config/Makefile
src/lib/config/tests/Makefile
src/lib/config/tests/testdata/Makefile
- src/lib/util/Makefile
- src/lib/util/io/Makefile
- src/lib/util/io/tests/Makefile
- src/lib/util/unittests/Makefile
- src/lib/util/tests/Makefile
+ src/lib/cryptolink/Makefile
+ src/lib/cryptolink/tests/Makefile
src/lib/dns/Makefile
src/lib/dns/tests/Makefile
src/lib/dns/tests/testdata/Makefile
@@ -701,6 +773,11 @@ AC_CONFIG_FILES([Makefile
src/lib/cache/tests/Makefile
src/lib/server_common/Makefile
src/lib/server_common/tests/Makefile
+ src/lib/util/Makefile
+ src/lib/util/io/Makefile
+ src/lib/util/io/tests/Makefile
+ src/lib/util/unittests/Makefile
+ src/lib/util/tests/Makefile
tests/Makefile
tests/system/Makefile
tests/tools/Makefile
@@ -729,11 +806,13 @@ AC_OUTPUT([doc/version.ent
src/bin/zonemgr/tests/zonemgr_test
src/bin/zonemgr/run_b10-zonemgr.sh
src/bin/stats/stats.py
- src/bin/stats/stats_stub.py
- src/bin/stats/stats.spec.pre
- src/bin/stats/run_b10-stats.sh
- src/bin/stats/run_b10-stats_stub.sh
- src/bin/stats/tests/stats_test
+ src/bin/stats/stats_httpd.py
+ src/bin/stats/stats.spec
+ src/bin/stats/stats-schema.spec
+ src/bin/stats/stats-httpd.spec
+ src/bin/stats/stats-httpd-xml.tpl
+ src/bin/stats/stats-httpd-xsd.tpl
+ src/bin/stats/stats-httpd-xsl.tpl
src/bin/bind10/bind10.py
src/bin/bind10/run_bind10.sh
src/bin/bind10/tests/bind10_test.py
@@ -763,6 +842,7 @@ AC_OUTPUT([doc/version.ent
src/lib/cc/session_config.h.pre
src/lib/cc/tests/session_unittests_config.h
src/lib/log/tests/run_time_init_test.sh
+ src/lib/util/python/mkpywrapper.py
tests/system/conf.sh
tests/system/glue/setup.sh
tests/system/glue/nsx1/b10-config.db
@@ -772,9 +852,6 @@ AC_OUTPUT([doc/version.ent
chmod +x src/bin/xfrin/run_b10-xfrin.sh
chmod +x src/bin/xfrout/run_b10-xfrout.sh
chmod +x src/bin/zonemgr/run_b10-zonemgr.sh
- chmod +x src/bin/stats/tests/stats_test
- chmod +x src/bin/stats/run_b10-stats.sh
- chmod +x src/bin/stats/run_b10-stats_stub.sh
chmod +x src/bin/bind10/run_bind10.sh
chmod +x src/bin/cmdctl/tests/cmdctl_test
chmod +x src/bin/xfrin/tests/xfrin_test
@@ -791,6 +868,7 @@ AC_OUTPUT([doc/version.ent
chmod +x src/lib/dns/gen-rdatacode.py
chmod +x src/lib/dns/tests/testdata/gen-wiredata.py
chmod +x src/lib/log/tests/run_time_init_test.sh
+ chmod +x src/lib/util/python/mkpywrapper.py
chmod +x tests/system/conf.sh
])
AC_OUTPUT
@@ -813,12 +891,15 @@ Flags:
DEFS: $DEFS
CPPFLAGS: $CPPFLAGS
CXXFLAGS: $CXXFLAGS
+ LDFLAGS: $LDFLAGS
B10_CXXFLAGS: $B10_CXXFLAGS
dnl includes too
Python: ${PYTHON_INCLUDES}
${PYTHON_LDFLAGS}
${PYTHON_LIB}
Boost: ${BOOST_INCLUDES}
+ Botan: ${BOTAN_INCLUDES}
+ ${BOTAN_LDFLAGS}
SQLite: $SQLITE_CFLAGS
$SQLITE_LIBS
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 83e85b8..05b6ef3 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -568,11 +568,13 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = ../src/lib/cc ../src/lib/config ../src/lib/dns \
- ../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth \
- ../src/bin/resolver ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ \
- ../src/lib/nsas ../src/lib/testutils ../src/lib/cache \
- ../src/lib/server_common/ ../src/bin/sockcreator/ ../src/lib/util/
+INPUT = ../src/lib/cc ../src/lib/config \
+ ../src/lib/cryptolink ../src/lib/dns ../src/lib/datasrc \
+ ../src/bin/auth ../src/bin/resolver ../src/lib/bench \
+ ../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas \
+ ../src/lib/testutils ../src/lib/cache ../src/lib/server_common/ \
+ ../src/bin/sockcreator/ ../src/lib/util/
+ ../src/lib/resolve
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@@ -1163,7 +1165,7 @@ XML_DTD =
# and cross-referencing information) to the XML output. Note that
# enabling this will significantly increase the size of the XML output.
-XML_PROGRAMLISTING = YES
+XML_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
diff --git a/ext/asio/README b/ext/asio/README
index c581e8e..da12a9d 100644
--- a/ext/asio/README
+++ b/ext/asio/README
@@ -1,5 +1,10 @@
ASIO library header files
-Version 1.4.5 (2010-05-12)
+Version 1.4.8 (2011-04-19)
Downloaded from http://sourceforge.net/projects/asio/files
Project page: http://think-async.com/Asio
-No local modifications.
+
+Local modifications:
+Added ASIO_DECL to a number of function definitions
+git commit c32718be9f5409b6f72d98ddcd0b1ccd4c5c2293
+See also the bug report at:
+http://sourceforge.net/tracker/?func=detail&aid=3291113&group_id=122478&atid=694037
diff --git a/ext/asio/asio.hpp b/ext/asio/asio.hpp
index d8acd58..b0ebc96 100644
--- a/ext/asio/asio.hpp
+++ b/ext/asio/asio.hpp
@@ -2,7 +2,7 @@
// asio.hpp
// ~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
diff --git a/ext/asio/asio/basic_datagram_socket.hpp b/ext/asio/asio/basic_datagram_socket.hpp
index cb149f9..2cbb354 100644
--- a/ext/asio/asio/basic_datagram_socket.hpp
+++ b/ext/asio/asio/basic_datagram_socket.hpp
@@ -2,7 +2,7 @@
// basic_datagram_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/basic_socket.hpp"
#include "asio/datagram_socket_service.hpp"
-#include "asio/error.hpp"
#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
diff --git a/ext/asio/asio/basic_deadline_timer.hpp b/ext/asio/asio/basic_deadline_timer.hpp
index 0d183f7..27781e7 100644
--- a/ext/asio/asio/basic_deadline_timer.hpp
+++ b/ext/asio/asio/basic_deadline_timer.hpp
@@ -2,7 +2,7 @@
// basic_deadline_timer.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/basic_io_object.hpp"
#include "asio/deadline_timer_service.hpp"
-#include "asio/error.hpp"
#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
diff --git a/ext/asio/asio/basic_io_object.hpp b/ext/asio/asio/basic_io_object.hpp
index 092170d..da35462 100644
--- a/ext/asio/asio/basic_io_object.hpp
+++ b/ext/asio/asio/basic_io_object.hpp
@@ -2,7 +2,7 @@
// basic_io_object.hpp
// ~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,10 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/io_service.hpp"
+#include "asio/detail/config.hpp"
#include "asio/detail/noncopyable.hpp"
+#include "asio/io_service.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
diff --git a/ext/asio/asio/basic_raw_socket.hpp b/ext/asio/asio/basic_raw_socket.hpp
index 9d93b97..7a55c4a 100644
--- a/ext/asio/asio/basic_raw_socket.hpp
+++ b/ext/asio/asio/basic_raw_socket.hpp
@@ -2,7 +2,7 @@
// basic_raw_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/basic_socket.hpp"
-#include "asio/raw_socket_service.hpp"
-#include "asio/error.hpp"
#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/raw_socket_service.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
diff --git a/ext/asio/asio/basic_serial_port.hpp b/ext/asio/asio/basic_serial_port.hpp
index edb7bb0..38fe5e9 100644
--- a/ext/asio/asio/basic_serial_port.hpp
+++ b/ext/asio/asio/basic_serial_port.hpp
@@ -2,7 +2,7 @@
// basic_serial_port.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,21 +16,19 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
-#include <string>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HAS_SERIAL_PORT) \
+ || defined(GENERATING_DOCUMENTATION)
+#include <string>
#include "asio/basic_io_object.hpp"
+#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/serial_port_base.hpp"
#include "asio/serial_port_service.hpp"
-#include "asio/detail/throw_error.hpp"
-#if defined(ASIO_HAS_SERIAL_PORT) \
- || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
namespace asio {
@@ -614,9 +612,9 @@ public:
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#endif // defined(ASIO_HAS_SERIAL_PORT)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_BASIC_SERIAL_PORT_HPP
diff --git a/ext/asio/asio/basic_socket.hpp b/ext/asio/asio/basic_socket.hpp
index 8b3f1d7..5c66b4a 100644
--- a/ext/asio/asio/basic_socket.hpp
+++ b/ext/asio/asio/basic_socket.hpp
@@ -2,7 +2,7 @@
// basic_socket.hpp
// ~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/basic_io_object.hpp"
+#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/socket_base.hpp"
-#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
diff --git a/ext/asio/asio/basic_socket_acceptor.hpp b/ext/asio/asio/basic_socket_acceptor.hpp
index 97fa56b..15f9220 100644
--- a/ext/asio/asio/basic_socket_acceptor.hpp
+++ b/ext/asio/asio/basic_socket_acceptor.hpp
@@ -2,7 +2,7 @@
// basic_socket_acceptor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/basic_socket.hpp"
+#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/socket_acceptor_service.hpp"
#include "asio/socket_base.hpp"
-#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
diff --git a/ext/asio/asio/basic_socket_iostream.hpp b/ext/asio/asio/basic_socket_iostream.hpp
index 361ecb8..efcd51e 100644
--- a/ext/asio/asio/basic_socket_iostream.hpp
+++ b/ext/asio/asio/basic_socket_iostream.hpp
@@ -2,7 +2,7 @@
// basic_socket_iostream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,22 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if !defined(BOOST_NO_IOSTREAM)
-#include "asio/detail/push_options.hpp"
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/utility/base_from_member.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/basic_socket_streambuf.hpp"
#include "asio/stream_socket_service.hpp"
@@ -79,6 +72,8 @@
} \
/**/
+#include "asio/detail/push_options.hpp"
+
namespace asio {
/// Iostream interface for a socket.
@@ -146,11 +141,11 @@ public:
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#undef ASIO_PRIVATE_CTR_DEF
#undef ASIO_PRIVATE_CONNECT_DEF
#endif // defined(BOOST_NO_IOSTREAM)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_BASIC_SOCKET_IOSTREAM_HPP
diff --git a/ext/asio/asio/basic_socket_streambuf.hpp b/ext/asio/asio/basic_socket_streambuf.hpp
index ae0264e..05fc865 100644
--- a/ext/asio/asio/basic_socket_streambuf.hpp
+++ b/ext/asio/asio/basic_socket_streambuf.hpp
@@ -2,7 +2,7 @@
// basic_socket_streambuf.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if !defined(BOOST_NO_IOSTREAM)
-#include "asio/detail/push_options.hpp"
#include <streambuf>
#include <boost/array.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
@@ -31,12 +26,10 @@
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/utility/base_from_member.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/basic_socket.hpp"
+#include "asio/detail/throw_error.hpp"
#include "asio/io_service.hpp"
#include "asio/stream_socket_service.hpp"
-#include "asio/detail/throw_error.hpp"
#if !defined(ASIO_SOCKET_STREAMBUF_MAX_ARITY)
#define ASIO_SOCKET_STREAMBUF_MAX_ARITY 5
@@ -74,6 +67,8 @@
} \
/**/
+#include "asio/detail/push_options.hpp"
+
namespace asio {
/// Iostream streambuf for a socket.
@@ -286,10 +281,10 @@ private:
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#undef ASIO_PRIVATE_CONNECT_DEF
#endif // !defined(BOOST_NO_IOSTREAM)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP
diff --git a/ext/asio/asio/basic_stream_socket.hpp b/ext/asio/asio/basic_stream_socket.hpp
index b7b4f06..41543fc 100644
--- a/ext/asio/asio/basic_stream_socket.hpp
+++ b/ext/asio/asio/basic_stream_socket.hpp
@@ -2,7 +2,7 @@
// basic_stream_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/basic_socket.hpp"
+#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/stream_socket_service.hpp"
-#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
diff --git a/ext/asio/asio/basic_streambuf.hpp b/ext/asio/asio/basic_streambuf.hpp
index b34b3fe..17157da 100644
--- a/ext/asio/asio/basic_streambuf.hpp
+++ b/ext/asio/asio/basic_streambuf.hpp
@@ -2,7 +2,7 @@
// basic_streambuf.hpp
// ~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,28 +15,23 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if !defined(BOOST_NO_IOSTREAM)
-#include "asio/detail/push_options.hpp"
#include <algorithm>
#include <cstring>
-#include <memory>
#include <stdexcept>
#include <streambuf>
#include <vector>
#include <boost/limits.hpp>
#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/basic_streambuf_fwd.hpp"
#include "asio/buffer.hpp"
#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
/// Automatically resizable buffer class based on std::streambuf.
@@ -107,7 +102,11 @@ namespace asio {
* is >> s;
* @endcode
*/
+#if defined(GENERATING_DOCUMENTATION)
template <typename Allocator = std::allocator<char> >
+#else
+template <typename Allocator>
+#endif
class basic_streambuf
: public std::streambuf,
private noncopyable
@@ -337,8 +336,27 @@ protected:
private:
std::size_t max_size_;
std::vector<char_type, Allocator> buffer_;
+
+ // Helper function to get the preferred size for reading data.
+ friend std::size_t read_size_helper(
+ basic_streambuf& sb, std::size_t max_size)
+ {
+ return std::min<std::size_t>(
+ std::max<std::size_t>(512, sb.buffer_.capacity() - sb.size()),
+ std::min<std::size_t>(max_size, sb.max_size() - sb.size()));
+ }
};
+// Helper function to get the preferred size for reading data. Used for any
+// user-provided specialisations of basic_streambuf.
+template <typename Allocator>
+inline std::size_t read_size_helper(
+ basic_streambuf<Allocator>& sb, std::size_t max_size)
+{
+ return std::min<std::size_t>(512,
+ std::min<std::size_t>(max_size, sb.max_size() - sb.size()));
+}
+
} // namespace asio
#include "asio/detail/pop_options.hpp"
diff --git a/ext/asio/asio/basic_streambuf_fwd.hpp b/ext/asio/asio/basic_streambuf_fwd.hpp
new file mode 100644
index 0000000..e1d81ac
--- /dev/null
+++ b/ext/asio/asio/basic_streambuf_fwd.hpp
@@ -0,0 +1,33 @@
+//
+// basic_streambuf_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BASIC_STREAMBUF_FWD_HPP
+#define ASIO_BASIC_STREAMBUF_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+#include <memory>
+
+namespace asio {
+
+template <typename Allocator = std::allocator<char> >
+class basic_streambuf;
+
+} // namespace asio
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+#endif // ASIO_BASIC_STREAMBUF_FWD_HPP
diff --git a/ext/asio/asio/buffer.hpp b/ext/asio/asio/buffer.hpp
index 43b475c..6810fca 100644
--- a/ext/asio/asio/buffer.hpp
+++ b/ext/asio/asio/buffer.hpp
@@ -2,7 +2,7 @@
// buffer.hpp
// ~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
-#include <boost/array.hpp>
-#include <boost/type_traits/is_const.hpp>
#include <string>
#include <vector>
-#include "asio/detail/pop_options.hpp"
+#include <boost/detail/workaround.hpp>
+#include "asio/detail/array_fwd.hpp"
#if defined(BOOST_MSVC)
# if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0)
@@ -43,11 +39,17 @@
#endif // defined(__GNUC__)
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-# include "asio/detail/push_options.hpp"
# include <boost/function.hpp>
-# include "asio/detail/pop_options.hpp"
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \
+ || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
+# include <boost/type_traits/is_const.hpp>
+#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
+ // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
+
+#include "asio/detail/push_options.hpp"
+
namespace asio {
class mutable_buffer;
diff --git a/ext/asio/asio/buffered_read_stream.hpp b/ext/asio/asio/buffered_read_stream.hpp
index afd22ce..d9dc311 100644
--- a/ext/asio/asio/buffered_read_stream.hpp
+++ b/ext/asio/asio/buffered_read_stream.hpp
@@ -2,7 +2,7 @@
// buffered_read_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,23 +15,20 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
#include <cstring>
-#include <boost/config.hpp>
#include <boost/type_traits/remove_reference.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/buffered_read_stream_fwd.hpp"
#include "asio/buffer.hpp"
-#include "asio/error.hpp"
-#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffer_resize_guard.hpp"
#include "asio/detail/buffered_stream_storage.hpp"
#include "asio/detail/noncopyable.hpp"
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
diff --git a/ext/asio/asio/buffered_read_stream_fwd.hpp b/ext/asio/asio/buffered_read_stream_fwd.hpp
index 5078775..0e8495a 100644
--- a/ext/asio/asio/buffered_read_stream_fwd.hpp
+++ b/ext/asio/asio/buffered_read_stream_fwd.hpp
@@ -2,7 +2,7 @@
// buffered_read_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,8 +15,6 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
namespace asio {
template <typename Stream>
@@ -24,6 +22,4 @@ class buffered_read_stream;
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_BUFFERED_READ_STREAM_FWD_HPP
diff --git a/ext/asio/asio/buffered_stream.hpp b/ext/asio/asio/buffered_stream.hpp
index 23dc9c3..11b99f6 100644
--- a/ext/asio/asio/buffered_stream.hpp
+++ b/ext/asio/asio/buffered_stream.hpp
@@ -2,7 +2,7 @@
// buffered_stream.hpp
// ~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,19 +15,16 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/buffered_read_stream.hpp"
#include "asio/buffered_write_stream.hpp"
#include "asio/buffered_stream_fwd.hpp"
+#include "asio/detail/noncopyable.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
-#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
diff --git a/ext/asio/asio/buffered_stream_fwd.hpp b/ext/asio/asio/buffered_stream_fwd.hpp
index f26cd43..a8e958e 100644
--- a/ext/asio/asio/buffered_stream_fwd.hpp
+++ b/ext/asio/asio/buffered_stream_fwd.hpp
@@ -2,7 +2,7 @@
// buffered_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,8 +15,6 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
namespace asio {
template <typename Stream>
@@ -24,6 +22,4 @@ class buffered_stream;
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_BUFFERED_STREAM_FWD_HPP
diff --git a/ext/asio/asio/buffered_write_stream.hpp b/ext/asio/asio/buffered_write_stream.hpp
index 30a92ce..ee0ec77 100644
--- a/ext/asio/asio/buffered_write_stream.hpp
+++ b/ext/asio/asio/buffered_write_stream.hpp
@@ -2,7 +2,7 @@
// buffered_write_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,24 +15,21 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
#include <cstring>
-#include <boost/config.hpp>
#include <boost/type_traits/remove_reference.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/buffered_write_stream_fwd.hpp"
#include "asio/buffer.hpp"
#include "asio/completion_condition.hpp"
-#include "asio/error.hpp"
-#include "asio/io_service.hpp"
-#include "asio/write.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffered_stream_storage.hpp"
#include "asio/detail/noncopyable.hpp"
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/write.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
diff --git a/ext/asio/asio/buffered_write_stream_fwd.hpp b/ext/asio/asio/buffered_write_stream_fwd.hpp
index dc0e014..cb09fe8 100644
--- a/ext/asio/asio/buffered_write_stream_fwd.hpp
+++ b/ext/asio/asio/buffered_write_stream_fwd.hpp
@@ -2,7 +2,7 @@
// buffered_write_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,8 +15,6 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
namespace asio {
template <typename Stream>
@@ -24,6 +22,4 @@ class buffered_write_stream;
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
diff --git a/ext/asio/asio/buffers_iterator.hpp b/ext/asio/asio/buffers_iterator.hpp
index 7da55f2..dcca2d3 100644
--- a/ext/asio/asio/buffers_iterator.hpp
+++ b/ext/asio/asio/buffers_iterator.hpp
@@ -2,7 +2,7 @@
// buffers_iterator.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,20 +15,17 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
#include <boost/assert.hpp>
-#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/iterator.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/add_const.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/buffer.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail
@@ -210,6 +207,15 @@ public:
return tmp;
}
+ /// Addition operator.
+ friend buffers_iterator operator+(std::ptrdiff_t difference,
+ const buffers_iterator& iter)
+ {
+ buffers_iterator tmp(iter);
+ tmp.advance(difference);
+ return tmp;
+ }
+
/// Subtraction operator.
friend buffers_iterator operator-(const buffers_iterator& iter,
std::ptrdiff_t difference)
diff --git a/ext/asio/asio/completion_condition.hpp b/ext/asio/asio/completion_condition.hpp
index d4e631d..dd1fb27 100644
--- a/ext/asio/asio/completion_condition.hpp
+++ b/ext/asio/asio/completion_condition.hpp
@@ -2,7 +2,7 @@
// completion_condition.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include <cstddef>
#include "asio/detail/push_options.hpp"
-#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
namespace asio {
diff --git a/ext/asio/asio/datagram_socket_service.hpp b/ext/asio/asio/datagram_socket_service.hpp
index 7d135ee..87821c3 100644
--- a/ext/asio/asio/datagram_socket_service.hpp
+++ b/ext/asio/asio/datagram_socket_service.hpp
@@ -2,7 +2,7 @@
// datagram_socket_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/error.hpp"
#include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_socket_service.hpp"
@@ -32,6 +26,8 @@
# include "asio/detail/reactive_socket_service.hpp"
#endif
+#include "asio/detail/push_options.hpp"
+
namespace asio {
/// Default service implementation for a datagram socket.
diff --git a/ext/asio/asio/deadline_timer.hpp b/ext/asio/asio/deadline_timer.hpp
index e0905f2..fd0d5dc 100644
--- a/ext/asio/asio/deadline_timer.hpp
+++ b/ext/asio/asio/deadline_timer.hpp
@@ -2,7 +2,7 @@
// deadline_timer.hpp
// ~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/detail/socket_types.hpp" // Must come before posix_time.
+#include "asio/basic_deadline_timer.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "asio/detail/pop_options.hpp"
-#include "asio/basic_deadline_timer.hpp"
-
namespace asio {
/// Typedef for the typical usage of timer. Uses a UTC clock.
@@ -32,6 +30,4 @@ typedef basic_deadline_timer<boost::posix_time::ptime> deadline_timer;
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DEADLINE_TIMER_HPP
diff --git a/ext/asio/asio/deadline_timer_service.hpp b/ext/asio/asio/deadline_timer_service.hpp
index 284a690..60d898b 100644
--- a/ext/asio/asio/deadline_timer_service.hpp
+++ b/ext/asio/asio/deadline_timer_service.hpp
@@ -2,7 +2,7 @@
// deadline_timer_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/deadline_timer_service.hpp"
#include "asio/io_service.hpp"
#include "asio/time_traits.hpp"
-#include "asio/detail/deadline_timer_service.hpp"
-#include "asio/detail/service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
diff --git a/ext/asio/asio/detail/array_fwd.hpp b/ext/asio/asio/detail/array_fwd.hpp
new file mode 100644
index 0000000..12c295c
--- /dev/null
+++ b/ext/asio/asio/detail/array_fwd.hpp
@@ -0,0 +1,25 @@
+//
+// detail/array_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_ARRAY_FWD_HPP
+#define ASIO_DETAIL_ARRAY_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+namespace boost {
+
+template<class T, std::size_t N>
+class array;
+
+} // namespace boost
+
+#endif // ASIO_DETAIL_ARRAY_FWD_HPP
diff --git a/ext/asio/asio/detail/base_from_completion_cond.hpp b/ext/asio/asio/detail/base_from_completion_cond.hpp
index 90a11f9..93cc8c4 100644
--- a/ext/asio/asio/detail/base_from_completion_cond.hpp
+++ b/ext/asio/asio/detail/base_from_completion_cond.hpp
@@ -1,8 +1,8 @@
//
-// base_from_completion_cond.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/base_from_completion_cond.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,10 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/completion_condition.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -31,7 +32,8 @@ protected:
{
}
- std::size_t check(const asio::error_code& ec,
+ std::size_t check_for_completion(
+ const asio::error_code& ec,
std::size_t total_transferred)
{
return detail::adapt_completion_condition_result(
@@ -50,7 +52,8 @@ protected:
{
}
- static std::size_t check(const asio::error_code& ec,
+ static std::size_t check_for_completion(
+ const asio::error_code& ec,
std::size_t total_transferred)
{
return transfer_all_t()(ec, total_transferred);
diff --git a/ext/asio/asio/detail/bind_handler.hpp b/ext/asio/asio/detail/bind_handler.hpp
index 5d9eb00..f663a5b 100644
--- a/ext/asio/asio/detail/bind_handler.hpp
+++ b/ext/asio/asio/detail/bind_handler.hpp
@@ -1,8 +1,8 @@
//
-// bind_handler.hpp
-// ~~~~~~~~~~~~~~~~
+// detail/bind_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -35,7 +36,7 @@ public:
void operator()()
{
- handler_(arg1_);
+ handler_(static_cast<const Arg1&>(arg1_));
}
void operator()() const
@@ -92,7 +93,8 @@ public:
void operator()()
{
- handler_(arg1_, arg2_);
+ handler_(static_cast<const Arg1&>(arg1_),
+ static_cast<const Arg2&>(arg2_));
}
void operator()() const
@@ -152,7 +154,9 @@ public:
void operator()()
{
- handler_(arg1_, arg2_, arg3_);
+ handler_(static_cast<const Arg1&>(arg1_),
+ static_cast<const Arg2&>(arg2_),
+ static_cast<const Arg3&>(arg3_));
}
void operator()() const
@@ -216,7 +220,10 @@ public:
void operator()()
{
- handler_(arg1_, arg2_, arg3_, arg4_);
+ handler_(static_cast<const Arg1&>(arg1_),
+ static_cast<const Arg2&>(arg2_),
+ static_cast<const Arg3&>(arg3_),
+ static_cast<const Arg4&>(arg4_));
}
void operator()() const
@@ -287,7 +294,11 @@ public:
void operator()()
{
- handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
+ handler_(static_cast<const Arg1&>(arg1_),
+ static_cast<const Arg2&>(arg2_),
+ static_cast<const Arg3&>(arg3_),
+ static_cast<const Arg4&>(arg4_),
+ static_cast<const Arg5&>(arg5_));
}
void operator()() const
diff --git a/ext/asio/asio/detail/buffer_resize_guard.hpp b/ext/asio/asio/detail/buffer_resize_guard.hpp
index 368de32..4bf6a8e 100644
--- a/ext/asio/asio/detail/buffer_resize_guard.hpp
+++ b/ext/asio/asio/detail/buffer_resize_guard.hpp
@@ -1,8 +1,8 @@
//
-// buffer_resize_guard.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~
+// detail/buffer_resize_guard.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include <boost/limits.hpp>
#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include <boost/limits.hpp>
-#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
diff --git a/ext/asio/asio/detail/buffer_sequence_adapter.hpp b/ext/asio/asio/detail/buffer_sequence_adapter.hpp
index 6269d6a..17044b7 100644
--- a/ext/asio/asio/detail/buffer_sequence_adapter.hpp
+++ b/ext/asio/asio/detail/buffer_sequence_adapter.hpp
@@ -1,8 +1,8 @@
//
-// buffer_sequence_adapter.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/buffer_sequence_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,9 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/buffer.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -32,14 +34,14 @@ protected:
const asio::mutable_buffer& buffer)
{
buf.buf = asio::buffer_cast<char*>(buffer);
- buf.len = asio::buffer_size(buffer);
+ buf.len = static_cast<ULONG>(asio::buffer_size(buffer));
}
static void init_native_buffer(WSABUF& buf,
const asio::const_buffer& buffer)
{
buf.buf = const_cast<char*>(asio::buffer_cast<const char*>(buffer));
- buf.len = asio::buffer_size(buffer);
+ buf.len = static_cast<ULONG>(asio::buffer_size(buffer));
}
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
typedef iovec native_buffer_type;
@@ -158,7 +160,7 @@ public:
explicit buffer_sequence_adapter(
const asio::mutable_buffers_1& buffers)
{
- init_native_buffer(buffer_, buffers);
+ init_native_buffer(buffer_, Buffer(buffers));
total_buffer_size_ = asio::buffer_size(buffers);
}
@@ -205,7 +207,7 @@ public:
explicit buffer_sequence_adapter(
const asio::const_buffers_1& buffers)
{
- init_native_buffer(buffer_, buffers);
+ init_native_buffer(buffer_, Buffer(buffers));
total_buffer_size_ = asio::buffer_size(buffers);
}
diff --git a/ext/asio/asio/detail/buffered_stream_storage.hpp b/ext/asio/asio/detail/buffered_stream_storage.hpp
index 51f6556..7e1b746 100644
--- a/ext/asio/asio/detail/buffered_stream_storage.hpp
+++ b/ext/asio/asio/detail/buffered_stream_storage.hpp
@@ -1,8 +1,8 @@
//
-// buffered_stream_storage.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/buffered_stream_storage.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
+#include "asio/detail/config.hpp"
#include <cassert>
#include <cstddef>
#include <cstring>
#include <vector>
-#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
diff --git a/ext/asio/asio/detail/call_stack.hpp b/ext/asio/asio/detail/call_stack.hpp
index 0e9ddaf..7ad5dc5 100644
--- a/ext/asio/asio/detail/call_stack.hpp
+++ b/ext/asio/asio/detail/call_stack.hpp
@@ -1,8 +1,8 @@
//
-// call_stack.hpp
-// ~~~~~~~~~~~~~~
+// detail/call_stack.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/tss_ptr.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
diff --git a/ext/asio/asio/detail/completion_handler.hpp b/ext/asio/asio/detail/completion_handler.hpp
index 16167df..0224d7e 100644
--- a/ext/asio/asio/detail/completion_handler.hpp
+++ b/ext/asio/asio/detail/completion_handler.hpp
@@ -1,8 +1,8 @@
//
-// completion_handler.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~
+// detail/completion_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,13 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/detail/fenced_block.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/operation.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -29,6 +30,8 @@ template <typename Handler>
class completion_handler : public operation
{
public:
+ ASIO_DEFINE_HANDLER_PTR(completion_handler);
+
completion_handler(Handler h)
: operation(&completion_handler::do_complete),
handler_(h)
@@ -40,20 +43,21 @@ public:
{
// Take ownership of the handler object.
completion_handler* h(static_cast<completion_handler*>(base));
- typedef handler_alloc_traits<Handler, completion_handler> alloc_traits;
- handler_ptr<alloc_traits> ptr(h->handler_, h);
+ ptr p = { boost::addressof(h->handler_), h, h };
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ Handler handler(h->handler_);
+ p.h = boost::addressof(handler);
+ p.reset();
// Make the upcall if required.
if (owner)
{
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- Handler handler(h->handler_);
- ptr.reset();
asio::detail::fenced_block b;
asio_handler_invoke_helpers::invoke(handler, handler);
}
diff --git a/ext/asio/asio/detail/config.hpp b/ext/asio/asio/detail/config.hpp
new file mode 100644
index 0000000..8328d76
--- /dev/null
+++ b/ext/asio/asio/detail/config.hpp
@@ -0,0 +1,205 @@
+//
+// detail/config.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_CONFIG_HPP
+#define ASIO_DETAIL_CONFIG_HPP
+
+#include <boost/config.hpp>
+
+// Default to a header-only implementation. The user must specifically request
+// separate compilation by defining either ASIO_SEPARATE_COMPILATION or
+// ASIO_DYN_LINK (as a DLL/shared library implies separate compilation).
+#if !defined(ASIO_HEADER_ONLY)
+# if !defined(ASIO_SEPARATE_COMPILATION)
+# if !defined(ASIO_DYN_LINK)
+# define ASIO_HEADER_ONLY
+# endif // !defined(ASIO_DYN_LINK)
+# endif // !defined(ASIO_SEPARATE_COMPILATION)
+#endif // !defined(ASIO_HEADER_ONLY)
+
+#if defined(ASIO_HEADER_ONLY)
+# define ASIO_DECL inline
+#else // defined(ASIO_HEADER_ONLY)
+# if defined(BOOST_HAS_DECLSPEC)
+// We need to import/export our code only if the user has specifically asked
+// for it by defining ASIO_DYN_LINK.
+# if defined(ASIO_DYN_LINK)
+// Export if this is our own source, otherwise import.
+# if defined(ASIO_SOURCE)
+# define ASIO_DECL __declspec(dllexport)
+# else // defined(ASIO_SOURCE)
+# define ASIO_DECL __declspec(dllimport)
+# endif // defined(ASIO_SOURCE)
+# endif // defined(ASIO_DYN_LINK)
+# endif // defined(BOOST_HAS_DECLSPEC)
+#endif // defined(ASIO_HEADER_ONLY)
+
+// If ASIO_DECL isn't defined yet define it now.
+#if !defined(ASIO_DECL)
+# define ASIO_DECL
+#endif // !defined(ASIO_DECL)
+
+// Windows: target OS version.
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
+# if defined(_MSC_VER) || defined(__BORLANDC__)
+# pragma message( \
+ "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\
+ "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\
+ "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\
+ "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).")
+# else // defined(_MSC_VER) || defined(__BORLANDC__)
+# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately.
+# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line.
+# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).
+# endif // defined(_MSC_VER) || defined(__BORLANDC__)
+# define _WIN32_WINNT 0x0501
+# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
+# if defined(_MSC_VER)
+# if defined(_WIN32) && !defined(WIN32)
+# if !defined(_WINSOCK2API_)
+# define WIN32 // Needed for correct types in winsock2.h
+# else // !defined(_WINSOCK2API_)
+# error Please define the macro WIN32 in your compiler options
+# endif // !defined(_WINSOCK2API_)
+# endif // defined(_WIN32) && !defined(WIN32)
+# endif // defined(_MSC_VER)
+# if defined(__BORLANDC__)
+# if defined(__WIN32__) && !defined(WIN32)
+# if !defined(_WINSOCK2API_)
+# define WIN32 // Needed for correct types in winsock2.h
+# else // !defined(_WINSOCK2API_)
+# error Please define the macro WIN32 in your compiler options
+# endif // !defined(_WINSOCK2API_)
+# endif // defined(__WIN32__) && !defined(WIN32)
+# endif // defined(__BORLANDC__)
+# if defined(__CYGWIN__)
+# if !defined(__USE_W32_SOCKETS)
+# error You must add -D__USE_W32_SOCKETS to your compiler options.
+# endif // !defined(__USE_W32_SOCKETS)
+# endif // defined(__CYGWIN__)
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+// Windows: minimise header inclusion.
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
+# if !defined(WIN32_LEAN_AND_MEAN)
+# define WIN32_LEAN_AND_MEAN
+# endif // !defined(WIN32_LEAN_AND_MEAN)
+# endif // !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+// Windows: suppress definition of "min" and "max" macros.
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if !defined(ASIO_NO_NOMINMAX)
+# if !defined(NOMINMAX)
+# define NOMINMAX 1
+# endif // !defined(NOMINMAX)
+# endif // !defined(ASIO_NO_NOMINMAX)
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+// Windows: IO Completion Ports.
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
+# if !defined(UNDER_CE)
+# if !defined(ASIO_DISABLE_IOCP)
+# define ASIO_HAS_IOCP 1
+# endif // !defined(ASIO_DISABLE_IOCP)
+# endif // !defined(UNDER_CE)
+# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+// Linux: epoll, eventfd and timerfd.
+#if defined(__linux__)
+# include <linux/version.h>
+# if !defined(ASIO_DISABLE_EPOLL)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)
+# define ASIO_HAS_EPOLL 1
+# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)
+# endif // !defined(ASIO_DISABLE_EVENTFD)
+# if !defined(ASIO_DISABLE_EVENTFD)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+# define ASIO_HAS_EVENTFD 1
+# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+# endif // !defined(ASIO_DISABLE_EVENTFD)
+# if defined(ASIO_HAS_EPOLL)
+# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
+# define ASIO_HAS_TIMERFD 1
+# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
+# endif // defined(ASIO_HAS_EPOLL)
+#endif // defined(__linux__)
+
+// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue.
+#if (defined(__MACH__) && defined(__APPLE__)) \
+ || defined(__FreeBSD__) \
+ || defined(__NetBSD__) \
+ || defined(__OpenBSD__)
+# if !defined(ASIO_DISABLE_KQUEUE)
+# define ASIO_HAS_KQUEUE 1
+# endif // !defined(ASIO_DISABLE_KQUEUE)
+#endif // (defined(__MACH__) && defined(__APPLE__))
+ // || defined(__FreeBSD__)
+ // || defined(__NetBSD__)
+ // || defined(__OpenBSD__)
+
+// Solaris: /dev/poll.
+#if defined(__sun)
+# if !defined(ASIO_DISABLE_DEV_POLL)
+# define ASIO_HAS_DEV_POLL 1
+# endif // !defined(ASIO_DISABLE_DEV_POLL)
+#endif // defined(__sun)
+
+// Serial ports.
+#if defined(ASIO_HAS_IOCP) \
+ || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+# if !defined(__SYMBIAN32__)
+# if !defined(ASIO_DISABLE_SERIAL_PORT)
+# define ASIO_HAS_SERIAL_PORT 1
+# endif // !defined(ASIO_DISABLE_SERIAL_PORT)
+# endif // !defined(__SYMBIAN32__)
+#endif // defined(ASIO_HAS_IOCP)
+ // || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+// Windows: stream handles.
+#if !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)
+# if defined(ASIO_HAS_IOCP)
+# define ASIO_HAS_WINDOWS_STREAM_HANDLE 1
+# endif // defined(ASIO_HAS_IOCP)
+#endif // !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)
+
+// Windows: random access handles.
+#if !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)
+# if defined(ASIO_HAS_IOCP)
+# define ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1
+# endif // defined(ASIO_HAS_IOCP)
+#endif // !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)
+
+// Windows: OVERLAPPED wrapper.
+#if !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR)
+# if defined(ASIO_HAS_IOCP)
+# define ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1
+# endif // defined(ASIO_HAS_IOCP)
+#endif // !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR)
+
+// POSIX: stream-oriented file descriptors.
+#if !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
+# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+# define ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1
+# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#endif // !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
+
+// UNIX domain sockets.
+#if !defined(ASIO_DISABLE_LOCAL_SOCKETS)
+# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+# define ASIO_HAS_LOCAL_SOCKETS 1
+# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#endif // !defined(ASIO_DISABLE_LOCAL_SOCKETS)
+
+#endif // ASIO_DETAIL_CONFIG_HPP
diff --git a/ext/asio/asio/detail/consuming_buffers.hpp b/ext/asio/asio/detail/consuming_buffers.hpp
index 80b6a8e..8969ae4 100644
--- a/ext/asio/asio/detail/consuming_buffers.hpp
+++ b/ext/asio/asio/detail/consuming_buffers.hpp
@@ -1,8 +1,8 @@
//
-// consuming_buffers.hpp
-// ~~~~~~~~~~~~~~~~~~~~~
+// detail/consuming_buffers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,18 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <algorithm>
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
#include <boost/iterator.hpp>
#include <boost/limits.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/buffer.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -156,12 +152,14 @@ public:
consuming_buffers(const Buffers& buffers)
: buffers_(buffers),
at_end_(buffers_.begin() == buffers_.end()),
- first_(*buffers_.begin()),
begin_remainder_(buffers_.begin()),
max_size_((std::numeric_limits<std::size_t>::max)())
{
if (!at_end_)
+ {
+ first_ = *buffers_.begin();
++begin_remainder_;
+ }
}
// Copy constructor.
diff --git a/ext/asio/asio/detail/deadline_timer_service.hpp b/ext/asio/asio/detail/deadline_timer_service.hpp
index 6daf7ac..782f5c3 100644
--- a/ext/asio/asio/detail/deadline_timer_service.hpp
+++ b/ext/asio/asio/detail/deadline_timer_service.hpp
@@ -1,8 +1,8 @@
//
-// deadline_timer_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/deadline_timer_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,8 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
@@ -33,6 +27,13 @@
#include "asio/detail/timer_op.hpp"
#include "asio/detail/timer_queue.hpp"
#include "asio/detail/timer_scheduler.hpp"
+#include "asio/detail/wait_handler.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -54,6 +55,7 @@ public:
{
time_type expiry;
bool might_have_pending_waits;
+ typename timer_queue<Time_Traits>::per_timer_data timer_data;
};
// Constructor.
@@ -97,7 +99,7 @@ public:
ec = asio::error_code();
return 0;
}
- std::size_t count = scheduler_.cancel_timer(timer_queue_, &impl);
+ std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data);
impl.might_have_pending_waits = false;
ec = asio::error_code();
return count;
@@ -151,59 +153,21 @@ public:
ec = asio::error_code();
}
- template <typename Handler>
- class wait_handler : public timer_op
- {
- public:
- wait_handler(Handler handler)
- : timer_op(&wait_handler::do_complete),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
- {
- // Take ownership of the handler object.
- wait_handler* h(static_cast<wait_handler*>(base));
- typedef handler_alloc_traits<Handler, wait_handler> alloc_traits;
- handler_ptr<alloc_traits> ptr(h->handler_, h);
-
- // Make the upcall if required.
- if (owner)
- {
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder1<Handler, asio::error_code>
- handler(h->handler_, h->ec_);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- Handler handler_;
- };
-
// Start an asynchronous wait on the timer.
template <typename Handler>
void async_wait(implementation_type& impl, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef wait_handler<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+ typedef wait_handler<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
impl.might_have_pending_waits = true;
- scheduler_.schedule_timer(timer_queue_, impl.expiry, ptr.get(), &impl);
- ptr.release();
+ scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p);
+ p.v = p.p = 0;
}
private:
diff --git a/ext/asio/asio/detail/descriptor_ops.hpp b/ext/asio/asio/detail/descriptor_ops.hpp
index ea3731e..5cac91d 100644
--- a/ext/asio/asio/detail/descriptor_ops.hpp
+++ b/ext/asio/asio/detail/descriptor_ops.hpp
@@ -1,8 +1,8 @@
//
-// descriptor_ops.hpp
-// ~~~~~~~~~~~~~~~~~~
+// detail/descriptor_ops.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,27 +15,34 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include <cerrno>
-#include "asio/detail/pop_options.hpp"
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-#include "asio/error.hpp"
+#include <cstddef>
+#include "asio/error_code.hpp"
#include "asio/detail/socket_types.hpp"
-#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
namespace descriptor_ops {
-inline void clear_error(asio::error_code& ec)
+// Descriptor state bits.
+enum
{
- errno = 0;
- ec = asio::error_code();
-}
+ // The user wants a non-blocking descriptor.
+ user_set_non_blocking = 1,
+
+ // The descriptor has been set non-blocking.
+ internal_non_blocking = 2,
+
+ // Helper "state" used to determine whether the descriptor is non-blocking.
+ non_blocking = user_set_non_blocking | internal_non_blocking
+};
+
+typedef unsigned char state_type;
template <typename ReturnType>
inline ReturnType error_wrapper(ReturnType return_value,
@@ -46,131 +53,53 @@ inline ReturnType error_wrapper(ReturnType return_value,
return return_value;
}
-inline int open(const char* path, int flags, asio::error_code& ec)
-{
- clear_error(ec);
- int result = error_wrapper(::open(path, flags), ec);
- if (result >= 0)
- clear_error(ec);
- return result;
-}
+ASIO_DECL int open(const char* path, int flags,
+ asio::error_code& ec);
-inline int close(int d, asio::error_code& ec)
-{
- clear_error(ec);
- int result = error_wrapper(::close(d), ec);
- if (result == 0)
- clear_error(ec);
- return result;
-}
+ASIO_DECL int close(int d, state_type& state,
+ asio::error_code& ec);
-inline void init_buf_iov_base(void*& base, void* addr)
-{
- base = addr;
-}
-
-template <typename T>
-inline void init_buf_iov_base(T& base, void* addr)
-{
- base = static_cast<T>(addr);
-}
+ASIO_DECL bool set_internal_non_blocking(int d,
+ state_type& state, asio::error_code& ec);
typedef iovec buf;
-inline void init_buf(buf& b, void* data, size_t size)
-{
- init_buf_iov_base(b.iov_base, data);
- b.iov_len = size;
-}
+ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs,
+ std::size_t count, bool all_empty, asio::error_code& ec);
-inline void init_buf(buf& b, const void* data, size_t size)
-{
- init_buf_iov_base(b.iov_base, const_cast<void*>(data));
- b.iov_len = size;
-}
+ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count,
+ asio::error_code& ec, std::size_t& bytes_transferred);
-inline int scatter_read(int d, buf* bufs, size_t count,
- asio::error_code& ec)
-{
- clear_error(ec);
- int result = error_wrapper(::readv(d, bufs, static_cast<int>(count)), ec);
- if (result >= 0)
- clear_error(ec);
- return result;
-}
+ASIO_DECL std::size_t sync_write(int d, state_type state,
+ const buf* bufs, std::size_t count, bool all_empty,
+ asio::error_code& ec);
-inline int gather_write(int d, const buf* bufs, size_t count,
- asio::error_code& ec)
-{
- clear_error(ec);
- int result = error_wrapper(::writev(d, bufs, static_cast<int>(count)), ec);
- if (result >= 0)
- clear_error(ec);
- return result;
-}
+ASIO_DECL bool non_blocking_write(int d,
+ const buf* bufs, std::size_t count,
+ asio::error_code& ec, std::size_t& bytes_transferred);
-inline int ioctl(int d, long cmd, ioctl_arg_type* arg,
- asio::error_code& ec)
-{
- clear_error(ec);
- int result = error_wrapper(::ioctl(d, cmd, arg), ec);
- if (result >= 0)
- clear_error(ec);
- return result;
-}
+ASIO_DECL int ioctl(int d, state_type& state, long cmd,
+ ioctl_arg_type* arg, asio::error_code& ec);
-inline int fcntl(int d, long cmd, asio::error_code& ec)
-{
- clear_error(ec);
- int result = error_wrapper(::fcntl(d, cmd), ec);
- if (result != -1)
- clear_error(ec);
- return result;
-}
+ASIO_DECL int fcntl(int d, long cmd, asio::error_code& ec);
-inline int fcntl(int d, long cmd, long arg, asio::error_code& ec)
-{
- clear_error(ec);
- int result = error_wrapper(::fcntl(d, cmd, arg), ec);
- if (result != -1)
- clear_error(ec);
- return result;
-}
+ASIO_DECL int fcntl(int d, long cmd,
+ long arg, asio::error_code& ec);
-inline int poll_read(int d, asio::error_code& ec)
-{
- clear_error(ec);
- pollfd fds;
- fds.fd = d;
- fds.events = POLLIN;
- fds.revents = 0;
- clear_error(ec);
- int result = error_wrapper(::poll(&fds, 1, -1), ec);
- if (result >= 0)
- clear_error(ec);
- return result;
-}
+ASIO_DECL int poll_read(int d, asio::error_code& ec);
-inline int poll_write(int d, asio::error_code& ec)
-{
- clear_error(ec);
- pollfd fds;
- fds.fd = d;
- fds.events = POLLOUT;
- fds.revents = 0;
- clear_error(ec);
- int result = error_wrapper(::poll(&fds, 1, -1), ec);
- if (result >= 0)
- clear_error(ec);
- return result;
-}
+ASIO_DECL int poll_write(int d, asio::error_code& ec);
} // namespace descriptor_ops
} // namespace detail
} // namespace asio
-#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/descriptor_ops.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
#endif // ASIO_DETAIL_DESCRIPTOR_OPS_HPP
diff --git a/ext/asio/asio/detail/descriptor_read_op.hpp b/ext/asio/asio/detail/descriptor_read_op.hpp
new file mode 100644
index 0000000..0d45167
--- /dev/null
+++ b/ext/asio/asio/detail/descriptor_read_op.hpp
@@ -0,0 +1,114 @@
+//
+// detail/descriptor_read_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP
+#define ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/descriptor_ops.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/reactor_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class descriptor_read_op_base : public reactor_op
+{
+public:
+ descriptor_read_op_base(int descriptor,
+ const MutableBufferSequence& buffers, func_type complete_func)
+ : reactor_op(&descriptor_read_op_base::do_perform, complete_func),
+ descriptor_(descriptor),
+ buffers_(buffers)
+ {
+ }
+
+ static bool do_perform(reactor_op* base)
+ {
+ descriptor_read_op_base* o(static_cast<descriptor_read_op_base*>(base));
+
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
+
+ return descriptor_ops::non_blocking_read(o->descriptor_,
+ bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_);
+ }
+
+private:
+ int descriptor_;
+ MutableBufferSequence buffers_;
+};
+
+template <typename MutableBufferSequence, typename Handler>
+class descriptor_read_op
+ : public descriptor_read_op_base<MutableBufferSequence>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(descriptor_read_op);
+
+ descriptor_read_op(int descriptor,
+ const MutableBufferSequence& buffers, Handler handler)
+ : descriptor_read_op_base<MutableBufferSequence>(
+ descriptor, buffers, &descriptor_read_op::do_complete),
+ handler_(handler)
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ descriptor_read_op* o(static_cast<descriptor_read_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP
diff --git a/ext/asio/asio/detail/descriptor_write_op.hpp b/ext/asio/asio/detail/descriptor_write_op.hpp
new file mode 100644
index 0000000..9caa283
--- /dev/null
+++ b/ext/asio/asio/detail/descriptor_write_op.hpp
@@ -0,0 +1,114 @@
+//
+// detail/descriptor_write_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP
+#define ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/descriptor_ops.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/reactor_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence>
+class descriptor_write_op_base : public reactor_op
+{
+public:
+ descriptor_write_op_base(int descriptor,
+ const ConstBufferSequence& buffers, func_type complete_func)
+ : reactor_op(&descriptor_write_op_base::do_perform, complete_func),
+ descriptor_(descriptor),
+ buffers_(buffers)
+ {
+ }
+
+ static bool do_perform(reactor_op* base)
+ {
+ descriptor_write_op_base* o(static_cast<descriptor_write_op_base*>(base));
+
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence> bufs(o->buffers_);
+
+ return descriptor_ops::non_blocking_write(o->descriptor_,
+ bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_);
+ }
+
+private:
+ int descriptor_;
+ ConstBufferSequence buffers_;
+};
+
+template <typename ConstBufferSequence, typename Handler>
+class descriptor_write_op
+ : public descriptor_write_op_base<ConstBufferSequence>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(descriptor_write_op);
+
+ descriptor_write_op(int descriptor,
+ const ConstBufferSequence& buffers, Handler handler)
+ : descriptor_write_op_base<ConstBufferSequence>(
+ descriptor, buffers, &descriptor_write_op::do_complete),
+ handler_(handler)
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ descriptor_write_op* o(static_cast<descriptor_write_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP
diff --git a/ext/asio/asio/detail/dev_poll_reactor.hpp b/ext/asio/asio/detail/dev_poll_reactor.hpp
index 1367b71..6bbf1b2 100644
--- a/ext/asio/asio/detail/dev_poll_reactor.hpp
+++ b/ext/asio/asio/detail/dev_poll_reactor.hpp
@@ -1,8 +1,8 @@
//
-// dev_poll_reactor.hpp
-// ~~~~~~~~~~~~~~~~~~~~
+// detail/dev_poll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,36 +15,28 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/dev_poll_reactor_fwd.hpp"
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_DEV_POLL)
-#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <vector>
-#include <boost/config.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include <boost/throw_exception.hpp>
#include <sys/devpoll.h>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/io_service.hpp"
-#include "asio/system_error.hpp"
+#include "asio/detail/dev_poll_reactor_fwd.hpp"
#include "asio/detail/hash_map.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/op_queue.hpp"
#include "asio/detail/reactor_op.hpp"
#include "asio/detail/reactor_op_queue.hpp"
#include "asio/detail/select_interrupter.hpp"
-#include "asio/detail/service_base.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_op.hpp"
#include "asio/detail/timer_queue_base.hpp"
#include "asio/detail/timer_queue_fwd.hpp"
#include "asio/detail/timer_queue_set.hpp"
+#include "asio/io_service.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -62,358 +54,93 @@ public:
};
// Constructor.
- dev_poll_reactor(asio::io_service& io_service)
- : asio::detail::service_base<dev_poll_reactor>(io_service),
- io_service_(use_service<io_service_impl>(io_service)),
- mutex_(),
- dev_poll_fd_(do_dev_poll_create()),
- interrupter_(),
- shutdown_(false)
- {
- // Add the interrupter's descriptor to /dev/poll.
- ::pollfd ev = { 0 };
- ev.fd = interrupter_.read_descriptor();
- ev.events = POLLIN | POLLERR;
- ev.revents = 0;
- ::write(dev_poll_fd_, &ev, sizeof(ev));
- }
+ ASIO_DECL dev_poll_reactor(asio::io_service& io_service);
// Destructor.
- ~dev_poll_reactor()
- {
- shutdown_service();
- ::close(dev_poll_fd_);
- }
+ ASIO_DECL ~dev_poll_reactor();
// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- shutdown_ = true;
- lock.unlock();
-
- op_queue<operation> ops;
-
- for (int i = 0; i < max_ops; ++i)
- op_queue_[i].get_all_operations(ops);
-
- timer_queues_.get_all_timers(ops);
- }
+ ASIO_DECL void shutdown_service();
// Initialise the task.
- void init_task()
- {
- io_service_.init_task();
- }
+ ASIO_DECL void init_task();
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
- int register_descriptor(socket_type, per_descriptor_data&)
+ ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&);
+
+ // Post a reactor operation for immediate completion.
+ void post_immediate_completion(reactor_op* op)
{
- return 0;
+ io_service_.post_immediate_completion(op);
}
// Start a new operation. The reactor operation will be performed when the
// given descriptor is flagged as ready, or an error has occurred.
- void start_op(int op_type, socket_type descriptor,
- per_descriptor_data&, reactor_op* op, bool allow_speculative)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
-
- if (shutdown_)
- return;
-
- if (allow_speculative)
- {
- if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor))
- {
- if (!op_queue_[op_type].has_operation(descriptor))
- {
- if (op->perform())
- {
- lock.unlock();
- io_service_.post_immediate_completion(op);
- return;
- }
- }
- }
- }
-
- bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
- io_service_.work_started();
- if (first)
- {
- ::pollfd& ev = add_pending_event_change(descriptor);
- ev.events = POLLERR | POLLHUP;
- if (op_type == read_op
- || op_queue_[read_op].has_operation(descriptor))
- ev.events |= POLLIN;
- if (op_type == write_op
- || op_queue_[write_op].has_operation(descriptor))
- ev.events |= POLLOUT;
- if (op_type == except_op
- || op_queue_[except_op].has_operation(descriptor))
- ev.events |= POLLPRI;
- interrupter_.interrupt();
- }
- }
+ ASIO_DECL void start_op(int op_type, socket_type descriptor,
+ per_descriptor_data&, reactor_op* op, bool allow_speculative);
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
- void cancel_ops(socket_type descriptor, per_descriptor_data&)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
- }
+ ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&);
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor.
- void close_descriptor(socket_type descriptor, per_descriptor_data&)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
-
- // Remove the descriptor from /dev/poll.
- ::pollfd& ev = add_pending_event_change(descriptor);
- ev.events = POLLREMOVE;
- interrupter_.interrupt();
-
- // Cancel any outstanding operations associated with the descriptor.
- cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
- }
+ ASIO_DECL void close_descriptor(
+ socket_type descriptor, per_descriptor_data&);
// Add a new timer queue to the reactor.
template <typename Time_Traits>
- void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- timer_queues_.insert(&timer_queue);
- }
+ void add_timer_queue(timer_queue<Time_Traits>& queue);
// Remove a timer queue from the reactor.
template <typename Time_Traits>
- void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- timer_queues_.erase(&timer_queue);
- }
+ void remove_timer_queue(timer_queue<Time_Traits>& queue);
// Schedule a new operation in the given timer queue to expire at the
// specified absolute time.
template <typename Time_Traits>
- void schedule_timer(timer_queue<Time_Traits>& timer_queue,
- const typename Time_Traits::time_type& time, timer_op* op, void* token)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- if (!shutdown_)
- {
- bool earliest = timer_queue.enqueue_timer(time, op, token);
- io_service_.work_started();
- if (earliest)
- interrupter_.interrupt();
- }
- }
+ void schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op);
// Cancel the timer operations associated with the given token. Returns the
// number of operations that have been posted or dispatched.
template <typename Time_Traits>
- std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- op_queue<operation> ops;
- std::size_t n = timer_queue.cancel_timer(token, ops);
- lock.unlock();
- io_service_.post_deferred_completions(ops);
- return n;
- }
+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer);
// Run /dev/poll once until interrupted or events are ready to be dispatched.
- void run(bool block, op_queue<operation>& ops)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
-
- // We can return immediately if there's no work to do and the reactor is
- // not supposed to block.
- if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty()
- && op_queue_[except_op].empty() && timer_queues_.all_empty())
- return;
-
- // Write the pending event registration changes to the /dev/poll descriptor.
- std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size();
- if (events_size > 0)
- {
- errno = 0;
- int result = ::write(dev_poll_fd_,
- &pending_event_changes_[0], events_size);
- if (result != static_cast<int>(events_size))
- {
- asio::error_code ec = asio::error_code(
- errno, asio::error::get_system_category());
- for (std::size_t i = 0; i < pending_event_changes_.size(); ++i)
- {
- int descriptor = pending_event_changes_[i].fd;
- for (int j = 0; j < max_ops; ++j)
- op_queue_[j].cancel_operations(descriptor, ops, ec);
- }
- }
- pending_event_changes_.clear();
- pending_event_change_index_.clear();
- }
-
- int timeout = block ? get_timeout() : 0;
- lock.unlock();
-
- // Block on the /dev/poll descriptor.
- ::pollfd events[128] = { { 0 } };
- ::dvpoll dp = { 0 };
- dp.dp_fds = events;
- dp.dp_nfds = 128;
- dp.dp_timeout = timeout;
- int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp);
-
- lock.lock();
-
- // Dispatch the waiting events.
- for (int i = 0; i < num_events; ++i)
- {
- int descriptor = events[i].fd;
- if (descriptor == interrupter_.read_descriptor())
- {
- interrupter_.reset();
- }
- else
- {
- bool more_reads = false;
- bool more_writes = false;
- bool more_except = false;
-
- // Exception operations must be processed first to ensure that any
- // out-of-band data is read before normal data.
- if (events[i].events & (POLLPRI | POLLERR | POLLHUP))
- more_except =
- op_queue_[except_op].perform_operations(descriptor, ops);
- else
- more_except = op_queue_[except_op].has_operation(descriptor);
-
- if (events[i].events & (POLLIN | POLLERR | POLLHUP))
- more_reads = op_queue_[read_op].perform_operations(descriptor, ops);
- else
- more_reads = op_queue_[read_op].has_operation(descriptor);
-
- if (events[i].events & (POLLOUT | POLLERR | POLLHUP))
- more_writes = op_queue_[write_op].perform_operations(descriptor, ops);
- else
- more_writes = op_queue_[write_op].has_operation(descriptor);
-
- if ((events[i].events & (POLLERR | POLLHUP)) != 0
- && !more_except && !more_reads && !more_writes)
- {
- // If we have an event and no operations associated with the
- // descriptor then we need to delete the descriptor from /dev/poll.
- // The poll operation can produce POLLHUP or POLLERR events when there
- // is no operation pending, so if we do not remove the descriptor we
- // can end up in a tight polling loop.
- ::pollfd ev = { 0 };
- ev.fd = descriptor;
- ev.events = POLLREMOVE;
- ev.revents = 0;
- ::write(dev_poll_fd_, &ev, sizeof(ev));
- }
- else
- {
- ::pollfd ev = { 0 };
- ev.fd = descriptor;
- ev.events = POLLERR | POLLHUP;
- if (more_reads)
- ev.events |= POLLIN;
- if (more_writes)
- ev.events |= POLLOUT;
- if (more_except)
- ev.events |= POLLPRI;
- ev.revents = 0;
- int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
- if (result != sizeof(ev))
- {
- asio::error_code ec(errno,
- asio::error::get_system_category());
- for (int j = 0; j < max_ops; ++j)
- op_queue_[j].cancel_operations(descriptor, ops, ec);
- }
- }
- }
- }
- timer_queues_.get_ready_timers(ops);
- }
+ ASIO_DECL void run(bool block, op_queue<operation>& ops);
// Interrupt the select loop.
- void interrupt()
- {
- interrupter_.interrupt();
- }
+ ASIO_DECL void interrupt();
private:
// Create the /dev/poll file descriptor. Throws an exception if the descriptor
// cannot be created.
- static int do_dev_poll_create()
- {
- int fd = ::open("/dev/poll", O_RDWR);
- if (fd == -1)
- {
- boost::throw_exception(
- asio::system_error(
- asio::error_code(errno,
- asio::error::get_system_category()),
- "/dev/poll"));
- }
- return fd;
- }
+ ASIO_DECL static int do_dev_poll_create();
+
+ // Helper function to add a new timer queue.
+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+ // Helper function to remove a timer queue.
+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
// Get the timeout value for the /dev/poll DP_POLL operation. The timeout
// value is returned as a number of milliseconds. A return value of -1
// indicates that the poll should block indefinitely.
- int get_timeout()
- {
- // By default we will wait no longer than 5 minutes. This will ensure that
- // any changes to the system clock are detected after no longer than this.
- return timer_queues_.wait_duration_msec(5 * 60 * 1000);
- }
+ ASIO_DECL int get_timeout();
// Cancel all operations associated with the given descriptor. The do_cancel
// function of the handler objects will be invoked. This function does not
// acquire the dev_poll_reactor's mutex.
- void cancel_ops_unlocked(socket_type descriptor,
- const asio::error_code& ec)
- {
- bool need_interrupt = false;
- op_queue<operation> ops;
- for (int i = 0; i < max_ops; ++i)
- need_interrupt = op_queue_[i].cancel_operations(
- descriptor, ops, ec) || need_interrupt;
- io_service_.post_deferred_completions(ops);
- if (need_interrupt)
- interrupter_.interrupt();
- }
+ ASIO_DECL void cancel_ops_unlocked(socket_type descriptor,
+ const asio::error_code& ec);
// Add a pending event entry for the given descriptor.
- ::pollfd& add_pending_event_change(int descriptor)
- {
- hash_map<int, std::size_t>::iterator iter
- = pending_event_change_index_.find(descriptor);
- if (iter == pending_event_change_index_.end())
- {
- std::size_t index = pending_event_changes_.size();
- pending_event_changes_.reserve(pending_event_changes_.size() + 1);
- pending_event_change_index_.insert(std::make_pair(descriptor, index));
- pending_event_changes_.push_back(::pollfd());
- pending_event_changes_[index].fd = descriptor;
- pending_event_changes_[index].revents = 0;
- return pending_event_changes_[index];
- }
- else
- {
- return pending_event_changes_[iter->second];
- }
- }
+ ASIO_DECL ::pollfd& add_pending_event_change(int descriptor);
// The io_service implementation used to post completions.
io_service_impl& io_service_;
@@ -446,8 +173,13 @@ private:
} // namespace detail
} // namespace asio
-#endif // defined(ASIO_HAS_DEV_POLL)
-
#include "asio/detail/pop_options.hpp"
+#include "asio/detail/impl/dev_poll_reactor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/dev_poll_reactor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_DEV_POLL)
+
#endif // ASIO_DETAIL_DEV_POLL_REACTOR_HPP
diff --git a/ext/asio/asio/detail/dev_poll_reactor_fwd.hpp b/ext/asio/asio/detail/dev_poll_reactor_fwd.hpp
index f7f1aeb..c54f5e1 100644
--- a/ext/asio/asio/detail/dev_poll_reactor_fwd.hpp
+++ b/ext/asio/asio/detail/dev_poll_reactor_fwd.hpp
@@ -1,8 +1,8 @@
//
-// dev_poll_reactor_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/dev_poll_reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,13 +15,9 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#if !defined(ASIO_DISABLE_DEV_POLL)
-#if defined(__sun) // This service is only supported on Solaris.
-
-// Define this to indicate that /dev/poll is supported on the target platform.
-#define ASIO_HAS_DEV_POLL 1
+#if defined(ASIO_HAS_DEV_POLL)
namespace asio {
namespace detail {
@@ -31,9 +27,6 @@ class dev_poll_reactor;
} // namespace detail
} // namespace asio
-#endif // defined(__sun)
-#endif // !defined(ASIO_DISABLE_DEV_POLL)
-
-#include "asio/detail/pop_options.hpp"
+#endif // defined(ASIO_HAS_DEV_POLL)
#endif // ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP
diff --git a/ext/asio/asio/detail/epoll_reactor.hpp b/ext/asio/asio/detail/epoll_reactor.hpp
index 0a1eac0..a085766 100644
--- a/ext/asio/asio/detail/epoll_reactor.hpp
+++ b/ext/asio/asio/detail/epoll_reactor.hpp
@@ -1,8 +1,8 @@
//
-// epoll_reactor.hpp
-// ~~~~~~~~~~~~~~~~~
+// detail/epoll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,43 +15,24 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/epoll_reactor_fwd.hpp"
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_EPOLL)
-#include "asio/detail/push_options.hpp"
-#include <cstddef>
-#include <sys/epoll.h>
-#include <boost/config.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
#include "asio/io_service.hpp"
-#include "asio/system_error.hpp"
-#include "asio/detail/hash_map.hpp"
+#include "asio/detail/epoll_reactor_fwd.hpp"
#include "asio/detail/mutex.hpp"
+#include "asio/detail/object_pool.hpp"
#include "asio/detail/op_queue.hpp"
#include "asio/detail/reactor_op.hpp"
#include "asio/detail/select_interrupter.hpp"
-#include "asio/detail/service_base.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_op.hpp"
#include "asio/detail/timer_queue_base.hpp"
#include "asio/detail/timer_queue_fwd.hpp"
#include "asio/detail/timer_queue_set.hpp"
-#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
-# define ASIO_HAS_TIMERFD 1
-#endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
-
-#if defined(ASIO_HAS_TIMERFD)
-# include "asio/detail/push_options.hpp"
-# include <sys/timerfd.h>
-# include "asio/detail/pop_options.hpp"
-#endif // defined(ASIO_HAS_TIMERFD)
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -64,357 +45,86 @@ public:
connect_op = 1, except_op = 2, max_ops = 3 };
// Per-descriptor queues.
- struct descriptor_state
+ class descriptor_state
{
- descriptor_state() {}
- descriptor_state(const descriptor_state&) {}
- void operator=(const descriptor_state&) {}
-
+ friend class epoll_reactor;
+ friend class object_pool_access;
mutex mutex_;
op_queue<reactor_op> op_queue_[max_ops];
bool shutdown_;
+ descriptor_state* next_;
+ descriptor_state* prev_;
};
// Per-descriptor data.
typedef descriptor_state* per_descriptor_data;
// Constructor.
- epoll_reactor(asio::io_service& io_service)
- : asio::detail::service_base<epoll_reactor>(io_service),
- io_service_(use_service<io_service_impl>(io_service)),
- mutex_(),
- epoll_fd_(do_epoll_create()),
-#if defined(ASIO_HAS_TIMERFD)
- timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)),
-#else // defined(ASIO_HAS_TIMERFD)
- timer_fd_(-1),
-#endif // defined(ASIO_HAS_TIMERFD)
- interrupter_(),
- shutdown_(false)
- {
- // Add the interrupter's descriptor to epoll.
- epoll_event ev = { 0, { 0 } };
- ev.events = EPOLLIN | EPOLLERR | EPOLLET;
- ev.data.ptr = &interrupter_;
- epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);
- interrupter_.interrupt();
-
- // Add the timer descriptor to epoll.
- if (timer_fd_ != -1)
- {
- ev.events = EPOLLIN | EPOLLERR;
- ev.data.ptr = &timer_fd_;
- epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev);
- }
- }
+ ASIO_DECL epoll_reactor(asio::io_service& io_service);
// Destructor.
- ~epoll_reactor()
- {
- close(epoll_fd_);
- if (timer_fd_ != -1)
- close(timer_fd_);
- }
+ ASIO_DECL ~epoll_reactor();
// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- mutex::scoped_lock lock(mutex_);
- shutdown_ = true;
- lock.unlock();
-
- op_queue<operation> ops;
-
- descriptor_map::iterator iter = registered_descriptors_.begin();
- descriptor_map::iterator end = registered_descriptors_.end();
- while (iter != end)
- {
- for (int i = 0; i < max_ops; ++i)
- ops.push(iter->second.op_queue_[i]);
- iter->second.shutdown_ = true;
- ++iter;
- }
-
- timer_queues_.get_all_timers(ops);
- }
+ ASIO_DECL void shutdown_service();
// Initialise the task.
- void init_task()
- {
- io_service_.init_task();
- }
+ ASIO_DECL void init_task();
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
- int register_descriptor(socket_type descriptor,
- per_descriptor_data& descriptor_data)
- {
- mutex::scoped_lock lock(registered_descriptors_mutex_);
-
- descriptor_map::iterator new_entry = registered_descriptors_.insert(
- std::make_pair(descriptor, descriptor_state())).first;
- descriptor_data = &new_entry->second;
-
- epoll_event ev = { 0, { 0 } };
- ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET;
- ev.data.ptr = descriptor_data;
- int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
- if (result != 0)
- return errno;
-
- descriptor_data->shutdown_ = false;
+ ASIO_DECL int register_descriptor(socket_type descriptor,
+ per_descriptor_data& descriptor_data);
- return 0;
+ // Post a reactor operation for immediate completion.
+ void post_immediate_completion(reactor_op* op)
+ {
+ io_service_.post_immediate_completion(op);
}
// Start a new operation. The reactor operation will be performed when the
// given descriptor is flagged as ready, or an error has occurred.
- void start_op(int op_type, socket_type descriptor,
+ ASIO_DECL void start_op(int op_type, socket_type descriptor,
per_descriptor_data& descriptor_data,
- reactor_op* op, bool allow_speculative)
- {
- mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
- if (descriptor_data->shutdown_)
- return;
-
- if (descriptor_data->op_queue_[op_type].empty())
- {
- if (allow_speculative
- && (op_type != read_op
- || descriptor_data->op_queue_[except_op].empty()))
- {
- if (op->perform())
- {
- descriptor_lock.unlock();
- io_service_.post_immediate_completion(op);
- return;
- }
- }
- else
- {
- epoll_event ev = { 0, { 0 } };
- ev.events = EPOLLIN | EPOLLERR | EPOLLHUP
- | EPOLLOUT | EPOLLPRI | EPOLLET;
- ev.data.ptr = descriptor_data;
- epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
- }
- }
-
- descriptor_data->op_queue_[op_type].push(op);
- io_service_.work_started();
- }
+ reactor_op* op, bool allow_speculative);
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
- void cancel_ops(socket_type, per_descriptor_data& descriptor_data)
- {
- mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
-
- op_queue<operation> ops;
- for (int i = 0; i < max_ops; ++i)
- {
- while (reactor_op* op = descriptor_data->op_queue_[i].front())
- {
- op->ec_ = asio::error::operation_aborted;
- descriptor_data->op_queue_[i].pop();
- ops.push(op);
- }
- }
-
- descriptor_lock.unlock();
-
- io_service_.post_deferred_completions(ops);
- }
+ ASIO_DECL void cancel_ops(socket_type descriptor,
+ per_descriptor_data& descriptor_data);
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor.
- void close_descriptor(socket_type descriptor,
- per_descriptor_data& descriptor_data)
- {
- mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
- mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
-
- // Remove the descriptor from the set of known descriptors. The descriptor
- // will be automatically removed from the epoll set when it is closed.
- descriptor_data->shutdown_ = true;
-
- op_queue<operation> ops;
- for (int i = 0; i < max_ops; ++i)
- {
- while (reactor_op* op = descriptor_data->op_queue_[i].front())
- {
- op->ec_ = asio::error::operation_aborted;
- descriptor_data->op_queue_[i].pop();
- ops.push(op);
- }
- }
-
- descriptor_lock.unlock();
-
- registered_descriptors_.erase(descriptor);
-
- descriptors_lock.unlock();
-
- io_service_.post_deferred_completions(ops);
- }
+ ASIO_DECL void close_descriptor(socket_type descriptor,
+ per_descriptor_data& descriptor_data);
// Add a new timer queue to the reactor.
template <typename Time_Traits>
- void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
- {
- mutex::scoped_lock lock(mutex_);
- timer_queues_.insert(&timer_queue);
- }
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue);
// Remove a timer queue from the reactor.
template <typename Time_Traits>
- void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
- {
- mutex::scoped_lock lock(mutex_);
- timer_queues_.erase(&timer_queue);
- }
+ void remove_timer_queue(timer_queue<Time_Traits>& timer_queue);
// Schedule a new operation in the given timer queue to expire at the
// specified absolute time.
template <typename Time_Traits>
- void schedule_timer(timer_queue<Time_Traits>& timer_queue,
- const typename Time_Traits::time_type& time, timer_op* op, void* token)
- {
- mutex::scoped_lock lock(mutex_);
- if (!shutdown_)
- {
- bool earliest = timer_queue.enqueue_timer(time, op, token);
- io_service_.work_started();
- if (earliest)
- {
-#if defined(ASIO_HAS_TIMERFD)
- if (timer_fd_ != -1)
- {
- itimerspec new_timeout;
- itimerspec old_timeout;
- int flags = get_timeout(new_timeout);
- timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
- return;
- }
-#endif // defined(ASIO_HAS_TIMERFD)
- interrupter_.interrupt();
- }
- }
- }
+ void schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op);
// Cancel the timer operations associated with the given token. Returns the
// number of operations that have been posted or dispatched.
template <typename Time_Traits>
- std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
- {
- mutex::scoped_lock lock(mutex_);
- op_queue<operation> ops;
- std::size_t n = timer_queue.cancel_timer(token, ops);
- lock.unlock();
- io_service_.post_deferred_completions(ops);
- return n;
- }
+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer);
// Run epoll once until interrupted or events are ready to be dispatched.
- void run(bool block, op_queue<operation>& ops)
- {
- // Calculate a timeout only if timerfd is not used.
- int timeout;
- if (timer_fd_ != -1)
- timeout = block ? -1 : 0;
- else
- {
- mutex::scoped_lock lock(mutex_);
- timeout = block ? get_timeout() : 0;
- }
-
- // Block on the epoll descriptor.
- epoll_event events[128];
- int num_events = epoll_wait(epoll_fd_, events, 128, timeout);
-
-#if defined(ASIO_HAS_TIMERFD)
- bool check_timers = (timer_fd_ == -1);
-#else // defined(ASIO_HAS_TIMERFD)
- bool check_timers = true;
-#endif // defined(ASIO_HAS_TIMERFD)
-
- // Dispatch the waiting events.
- for (int i = 0; i < num_events; ++i)
- {
- void* ptr = events[i].data.ptr;
- if (ptr == &interrupter_)
- {
- // No need to reset the interrupter since we're leaving the descriptor
- // in a ready-to-read state and relying on edge-triggered notifications
- // to make it so that we only get woken up when the descriptor's epoll
- // registration is updated.
-
-#if defined(ASIO_HAS_TIMERFD)
- if (timer_fd_ == -1)
- check_timers = true;
-#else // defined(ASIO_HAS_TIMERFD)
- check_timers = true;
-#endif // defined(ASIO_HAS_TIMERFD)
- }
-#if defined(ASIO_HAS_TIMERFD)
- else if (ptr == &timer_fd_)
- {
- check_timers = true;
- }
-#endif // defined(ASIO_HAS_TIMERFD)
- else
- {
- descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
- mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
-
- // Exception operations must be processed first to ensure that any
- // out-of-band data is read before normal data.
- static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI };
- for (int j = max_ops - 1; j >= 0; --j)
- {
- if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP))
- {
- while (reactor_op* op = descriptor_data->op_queue_[j].front())
- {
- if (op->perform())
- {
- descriptor_data->op_queue_[j].pop();
- ops.push(op);
- }
- else
- break;
- }
- }
- }
- }
- }
-
- if (check_timers)
- {
- mutex::scoped_lock common_lock(mutex_);
- timer_queues_.get_ready_timers(ops);
-
-#if defined(ASIO_HAS_TIMERFD)
- if (timer_fd_ != -1)
- {
- itimerspec new_timeout;
- itimerspec old_timeout;
- int flags = get_timeout(new_timeout);
- timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
- }
-#endif // defined(ASIO_HAS_TIMERFD)
- }
- }
+ ASIO_DECL void run(bool block, op_queue<operation>& ops);
// Interrupt the select loop.
- void interrupt()
- {
- epoll_event ev = { 0, { 0 } };
- ev.events = EPOLLIN | EPOLLERR | EPOLLET;
- ev.data.ptr = &interrupter_;
- epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev);
- }
+ ASIO_DECL void interrupt();
private:
// The hint to pass to epoll_create to size its data structures.
@@ -422,44 +132,26 @@ private:
// Create the epoll file descriptor. Throws an exception if the descriptor
// cannot be created.
- static int do_epoll_create()
- {
- int fd = epoll_create(epoll_size);
- if (fd == -1)
- {
- boost::throw_exception(
- asio::system_error(
- asio::error_code(errno,
- asio::error::get_system_category()),
- "epoll"));
- }
- return fd;
- }
+ ASIO_DECL static int do_epoll_create();
+
+ // Helper function to add a new timer queue.
+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+ // Helper function to remove a timer queue.
+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
+
+ // Called to recalculate and update the timeout.
+ ASIO_DECL void update_timeout();
// Get the timeout value for the epoll_wait call. The timeout value is
// returned as a number of milliseconds. A return value of -1 indicates
// that epoll_wait should block indefinitely.
- int get_timeout()
- {
- // By default we will wait no longer than 5 minutes. This will ensure that
- // any changes to the system clock are detected after no longer than this.
- return timer_queues_.wait_duration_msec(5 * 60 * 1000);
- }
+ ASIO_DECL int get_timeout();
#if defined(ASIO_HAS_TIMERFD)
// Get the timeout value for the timer descriptor. The return value is the
// flag argument to be used when calling timerfd_settime.
- int get_timeout(itimerspec& ts)
- {
- ts.it_interval.tv_sec = 0;
- ts.it_interval.tv_nsec = 0;
-
- long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
- ts.it_value.tv_sec = usec / 1000000;
- ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1;
-
- return usec ? 0 : TFD_TIMER_ABSTIME;
- }
+ ASIO_DECL int get_timeout(itimerspec& ts);
#endif // defined(ASIO_HAS_TIMERFD)
// The io_service implementation used to post completions.
@@ -486,22 +178,20 @@ private:
// Mutex to protect access to the registered descriptors.
mutex registered_descriptors_mutex_;
- // Keep track of all registered descriptors. This code relies on the fact that
- // the hash_map implementation pools deleted nodes, meaning that we can assume
- // our descriptor_state pointer remains valid even after the entry is removed.
- // Technically this is not true for C++98, as that standard says that spliced
- // elements in a list are invalidated. However, C++0x fixes this shortcoming
- // so we'll just assume that C++98 std::list implementations will do the right
- // thing anyway.
- typedef detail::hash_map<socket_type, descriptor_state> descriptor_map;
- descriptor_map registered_descriptors_;
+ // Keep track of all registered descriptors.
+ object_pool<descriptor_state> registered_descriptors_;
};
} // namespace detail
} // namespace asio
-#endif // defined(ASIO_HAS_EPOLL)
-
#include "asio/detail/pop_options.hpp"
+#include "asio/detail/impl/epoll_reactor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/epoll_reactor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_EPOLL)
+
#endif // ASIO_DETAIL_EPOLL_REACTOR_HPP
diff --git a/ext/asio/asio/detail/epoll_reactor_fwd.hpp b/ext/asio/asio/detail/epoll_reactor_fwd.hpp
index 266bccd..49df6ed 100644
--- a/ext/asio/asio/detail/epoll_reactor_fwd.hpp
+++ b/ext/asio/asio/detail/epoll_reactor_fwd.hpp
@@ -1,8 +1,8 @@
//
-// epoll_reactor_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~~~
+// detail/epoll_reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,19 +15,9 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#if !defined(ASIO_DISABLE_EPOLL)
-#if defined(__linux__) // This service is only supported on Linux.
-
-#include "asio/detail/push_options.hpp"
-#include <linux/version.h>
-#include "asio/detail/pop_options.hpp"
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45) // Only kernels >= 2.5.45.
-
-// Define this to indicate that epoll is supported on the target platform.
-#define ASIO_HAS_EPOLL 1
+#if defined(ASIO_HAS_EPOLL)
namespace asio {
namespace detail {
@@ -37,10 +27,6 @@ class epoll_reactor;
} // namespace detail
} // namespace asio
-#endif // LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45)
-#endif // defined(__linux__)
-#endif // !defined(ASIO_DISABLE_EPOLL)
-
-#include "asio/detail/pop_options.hpp"
+#endif // defined(ASIO_HAS_EPOLL)
#endif // ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP
diff --git a/ext/asio/asio/detail/event.hpp b/ext/asio/asio/detail/event.hpp
index 65aa4cb..46ee8a6 100644
--- a/ext/asio/asio/detail/event.hpp
+++ b/ext/asio/asio/detail/event.hpp
@@ -1,8 +1,8 @@
//
-// event.hpp
-// ~~~~~~~~~
+// detail/event.hpp
+// ~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,7 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
# include "asio/detail/null_event.hpp"
@@ -45,6 +41,4 @@ typedef posix_event event;
} // namespace detail
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_EVENT_HPP
diff --git a/ext/asio/asio/detail/eventfd_select_interrupter.hpp b/ext/asio/asio/detail/eventfd_select_interrupter.hpp
index 63b7ac4..0d3b958 100644
--- a/ext/asio/asio/detail/eventfd_select_interrupter.hpp
+++ b/ext/asio/asio/detail/eventfd_select_interrupter.hpp
@@ -1,8 +1,8 @@
//
-// eventfd_select_interrupter.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/eventfd_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,36 +16,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#if defined(__linux__)
-# if !defined(ASIO_DISABLE_EVENTFD)
-# include <linux/version.h>
-# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-# define ASIO_HAS_EVENTFD
-# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-# endif // !defined(ASIO_DISABLE_EVENTFD)
-#endif // defined(__linux__)
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_EVENTFD)
#include "asio/detail/push_options.hpp"
-#include <fcntl.h>
-#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
-# include <asm/unistd.h>
-#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
-# include <sys/eventfd.h>
-#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
-#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
@@ -54,87 +29,16 @@ class eventfd_select_interrupter
{
public:
// Constructor.
- eventfd_select_interrupter()
- {
-#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
- write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0);
-#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
- write_descriptor_ = read_descriptor_ = ::eventfd(0, 0);
-#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
- if (read_descriptor_ != -1)
- {
- ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
- }
- else
- {
- int pipe_fds[2];
- if (pipe(pipe_fds) == 0)
- {
- read_descriptor_ = pipe_fds[0];
- ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
- write_descriptor_ = pipe_fds[1];
- ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
- }
- else
- {
- asio::error_code ec(errno,
- asio::error::get_system_category());
- asio::system_error e(ec, "eventfd_select_interrupter");
- boost::throw_exception(e);
- }
- }
- }
+ ASIO_DECL eventfd_select_interrupter();
// Destructor.
- ~eventfd_select_interrupter()
- {
- if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_)
- ::close(write_descriptor_);
- if (read_descriptor_ != -1)
- ::close(read_descriptor_);
- }
+ ASIO_DECL ~eventfd_select_interrupter();
// Interrupt the select call.
- void interrupt()
- {
- uint64_t counter(1UL);
- int result = ::write(write_descriptor_, &counter, sizeof(uint64_t));
- (void)result;
- }
+ ASIO_DECL void interrupt();
// Reset the select interrupt. Returns true if the call was interrupted.
- bool reset()
- {
- if (write_descriptor_ == read_descriptor_)
- {
- for (;;)
- {
- // Only perform one read. The kernel maintains an atomic counter.
- uint64_t counter(0);
- errno = 0;
- int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t));
- if (bytes_read < 0 && errno == EINTR)
- continue;
- bool was_interrupted = (bytes_read > 0);
- return was_interrupted;
- }
- }
- else
- {
- for (;;)
- {
- // Clear all data from the pipe.
- char data[1024];
- int bytes_read = ::read(read_descriptor_, data, sizeof(data));
- if (bytes_read < 0 && errno == EINTR)
- continue;
- bool was_interrupted = (bytes_read > 0);
- while (bytes_read == sizeof(data))
- bytes_read = ::read(read_descriptor_, data, sizeof(data));
- return was_interrupted;
- }
- }
- }
+ ASIO_DECL bool reset();
// Get the read descriptor to be passed to select.
int read_descriptor() const
@@ -159,8 +63,12 @@ private:
} // namespace detail
} // namespace asio
-#endif // defined(ASIO_HAS_EVENTFD)
-
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/eventfd_select_interrupter.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_EVENTFD)
+
#endif // ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP
diff --git a/ext/asio/asio/detail/fd_set_adapter.hpp b/ext/asio/asio/detail/fd_set_adapter.hpp
index a575491..953cad1 100644
--- a/ext/asio/asio/detail/fd_set_adapter.hpp
+++ b/ext/asio/asio/detail/fd_set_adapter.hpp
@@ -1,8 +1,8 @@
//
-// fd_set_adapter.hpp
-// ~~~~~~~~~~~~~~~~~~
+// detail/fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,7 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/detail/posix_fd_set_adapter.hpp"
#include "asio/detail/win_fd_set_adapter.hpp"
@@ -36,6 +31,4 @@ typedef posix_fd_set_adapter fd_set_adapter;
} // namespace detail
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_FD_SET_ADAPTER_HPP
diff --git a/ext/asio/asio/detail/fenced_block.hpp b/ext/asio/asio/detail/fenced_block.hpp
index 60198bc..70c47e1 100644
--- a/ext/asio/asio/detail/fenced_block.hpp
+++ b/ext/asio/asio/detail/fenced_block.hpp
@@ -1,8 +1,8 @@
//
-// fenced_block.hpp
-// ~~~~~~~~~~~~~~~~
+// detail/fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,23 +15,25 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+#if !defined(BOOST_HAS_THREADS) \
+ || defined(ASIO_DISABLE_THREADS) \
+ || defined(ASIO_DISABLE_FENCED_BLOCK)
# include "asio/detail/null_fenced_block.hpp"
#elif defined(__MACH__) && defined(__APPLE__)
# include "asio/detail/macos_fenced_block.hpp"
#elif defined(__sun)
# include "asio/detail/solaris_fenced_block.hpp"
+#elif defined(__GNUC__) && defined(__arm__)
+# include "asio/detail/gcc_arm_fenced_block.hpp"
+#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+# include "asio/detail/gcc_hppa_fenced_block.hpp"
#elif defined(__GNUC__) \
&& ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
&& !defined(__INTEL_COMPILER) && !defined(__ICL) \
&& !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
-# include "asio/detail/gcc_fenced_block.hpp"
+# include "asio/detail/gcc_sync_fenced_block.hpp"
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
# include "asio/detail/gcc_x86_fenced_block.hpp"
#elif defined(BOOST_WINDOWS) && !defined(UNDER_CE)
@@ -43,17 +45,23 @@
namespace asio {
namespace detail {
-#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+#if !defined(BOOST_HAS_THREADS) \
+ || defined(ASIO_DISABLE_THREADS) \
+ || defined(ASIO_DISABLE_FENCED_BLOCK)
typedef null_fenced_block fenced_block;
#elif defined(__MACH__) && defined(__APPLE__)
typedef macos_fenced_block fenced_block;
#elif defined(__sun)
typedef solaris_fenced_block fenced_block;
+#elif defined(__GNUC__) && defined(__arm__)
+typedef gcc_arm_fenced_block fenced_block;
+#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+typedef gcc_hppa_fenced_block fenced_block;
#elif defined(__GNUC__) \
&& ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
&& !defined(__INTEL_COMPILER) && !defined(__ICL) \
&& !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
-typedef gcc_fenced_block fenced_block;
+typedef gcc_sync_fenced_block fenced_block;
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
typedef gcc_x86_fenced_block fenced_block;
#elif defined(BOOST_WINDOWS) && !defined(UNDER_CE)
@@ -65,6 +73,4 @@ typedef null_fenced_block fenced_block;
} // namespace detail
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_FENCED_BLOCK_HPP
diff --git a/ext/asio/asio/detail/gcc_arm_fenced_block.hpp b/ext/asio/asio/detail/gcc_arm_fenced_block.hpp
new file mode 100644
index 0000000..76c4d99
--- /dev/null
+++ b/ext/asio/asio/detail/gcc_arm_fenced_block.hpp
@@ -0,0 +1,76 @@
+//
+// detail/gcc_arm_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__GNUC__) && defined(__arm__)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class gcc_arm_fenced_block
+ : private noncopyable
+{
+public:
+ // Constructor.
+ gcc_arm_fenced_block()
+ {
+ barrier();
+ }
+
+ // Destructor.
+ ~gcc_arm_fenced_block()
+ {
+ barrier();
+ }
+
+private:
+ static void barrier()
+ {
+#if defined(__ARM_ARCH_4__) \
+ || defined(__ARM_ARCH_4T__) \
+ || defined(__ARM_ARCH_5__) \
+ || defined(__ARM_ARCH_5E__) \
+ || defined(__ARM_ARCH_5T__) \
+ || defined(__ARM_ARCH_5TE__) \
+ || defined(__ARM_ARCH_5TEJ__) \
+ || defined(__ARM_ARCH_6__) \
+ || defined(__ARM_ARCH_6J__) \
+ || defined(__ARM_ARCH_6K__) \
+ || defined(__ARM_ARCH_6Z__) \
+ || defined(__ARM_ARCH_6ZK__) \
+ || defined(__ARM_ARCH_6T2__)
+ int a = 0, b = 0;
+ __asm__ __volatile__ ("swp %0, %1, [%2]"
+ : "=&r"(a) : "r"(1), "r"(&b) : "memory", "cc");
+#else
+ // ARMv7 and later.
+ __asm__ __volatile__ ("dmb" : : : "memory");
+#endif
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__GNUC__) && defined(__arm__)
+
+#endif // ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP
diff --git a/ext/asio/asio/detail/gcc_hppa_fenced_block.hpp b/ext/asio/asio/detail/gcc_hppa_fenced_block.hpp
new file mode 100644
index 0000000..215086a
--- /dev/null
+++ b/ext/asio/asio/detail/gcc_hppa_fenced_block.hpp
@@ -0,0 +1,58 @@
+//
+// detail/gcc_hppa_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class gcc_hppa_fenced_block
+ : private noncopyable
+{
+public:
+ // Constructor.
+ gcc_hppa_fenced_block()
+ {
+ barrier();
+ }
+
+ // Destructor.
+ ~gcc_hppa_fenced_block()
+ {
+ barrier();
+ }
+
+private:
+ static void barrier()
+ {
+ // This is just a placeholder and almost certainly not sufficient.
+ __asm__ __volatile__ ("" : : : "memory");
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+
+#endif // ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP
diff --git a/ext/asio/asio/detail/gcc_sync_fenced_block.hpp b/ext/asio/asio/detail/gcc_sync_fenced_block.hpp
new file mode 100644
index 0000000..569b559
--- /dev/null
+++ b/ext/asio/asio/detail/gcc_sync_fenced_block.hpp
@@ -0,0 +1,61 @@
+//
+// detail/gcc_sync_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__GNUC__) \
+ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
+ && !defined(__INTEL_COMPILER) && !defined(__ICL) \
+ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class gcc_sync_fenced_block
+ : private noncopyable
+{
+public:
+ // Constructor.
+ gcc_sync_fenced_block()
+ : value_(0)
+ {
+ __sync_lock_test_and_set(&value_, 1);
+ }
+
+ // Destructor.
+ ~gcc_sync_fenced_block()
+ {
+ __sync_lock_release(&value_);
+ }
+
+private:
+ int value_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__GNUC__)
+ // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4))
+ // && !defined(__INTEL_COMPILER) && !defined(__ICL)
+ // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+
+#endif // ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP
diff --git a/ext/asio/asio/detail/gcc_x86_fenced_block.hpp b/ext/asio/asio/detail/gcc_x86_fenced_block.hpp
index 48119f4..3e2e5bc 100644
--- a/ext/asio/asio/detail/gcc_x86_fenced_block.hpp
+++ b/ext/asio/asio/detail/gcc_x86_fenced_block.hpp
@@ -1,8 +1,8 @@
//
-// gcc_x86_fenced_block.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/gcc_x86_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -54,8 +52,8 @@ private:
} // namespace detail
} // namespace asio
-#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
-
#include "asio/detail/pop_options.hpp"
+#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
#endif // ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP
diff --git a/ext/asio/asio/detail/handler_alloc_helpers.hpp b/ext/asio/asio/detail/handler_alloc_helpers.hpp
index 0ac42a7..9ae80de 100644
--- a/ext/asio/asio/detail/handler_alloc_helpers.hpp
+++ b/ext/asio/asio/detail/handler_alloc_helpers.hpp
@@ -1,8 +1,8 @@
//
-// handler_alloc_helpers.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/handler_alloc_helpers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <boost/detail/workaround.hpp>
#include <boost/utility/addressof.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/handler_alloc_hook.hpp"
#include "asio/detail/noncopyable.hpp"
+#include "asio/handler_alloc_hook.hpp"
+
+#include "asio/detail/push_options.hpp"
// Calls to asio_handler_allocate and asio_handler_deallocate must be made from
// a namespace that does not contain any overloads of these functions. The
@@ -56,203 +54,31 @@ inline void deallocate(void* p, std::size_t s, Handler& h)
} // namespace asio_handler_alloc_helpers
-namespace asio {
-namespace detail {
-
-// Traits for handler allocation.
-template <typename Handler, typename Object>
-struct handler_alloc_traits
-{
- typedef Handler handler_type;
- typedef Object value_type;
- typedef Object* pointer_type;
- BOOST_STATIC_CONSTANT(std::size_t, value_size = sizeof(Object));
-};
-
-template <typename Alloc_Traits>
-class handler_ptr;
-
-// Helper class to provide RAII on uninitialised handler memory.
-template <typename Alloc_Traits>
-class raw_handler_ptr
- : private noncopyable
-{
-public:
- typedef typename Alloc_Traits::handler_type handler_type;
- typedef typename Alloc_Traits::value_type value_type;
- typedef typename Alloc_Traits::pointer_type pointer_type;
- BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size);
-
- // Constructor allocates the memory.
- raw_handler_ptr(handler_type& handler)
- : handler_(handler),
- pointer_(static_cast<pointer_type>(
- asio_handler_alloc_helpers::allocate(value_size, handler_)))
- {
- }
-
- // Destructor automatically deallocates memory, unless it has been stolen by
- // a handler_ptr object.
- ~raw_handler_ptr()
- {
- if (pointer_)
- asio_handler_alloc_helpers::deallocate(
- pointer_, value_size, handler_);
- }
-
-private:
- friend class handler_ptr<Alloc_Traits>;
- handler_type& handler_;
- pointer_type pointer_;
-};
-
-// Helper class to provide RAII on uninitialised handler memory.
-template <typename Alloc_Traits>
-class handler_ptr
- : private noncopyable
-{
-public:
- typedef typename Alloc_Traits::handler_type handler_type;
- typedef typename Alloc_Traits::value_type value_type;
- typedef typename Alloc_Traits::pointer_type pointer_type;
- BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size);
- typedef raw_handler_ptr<Alloc_Traits> raw_ptr_type;
-
- // Take ownership of existing memory.
- handler_ptr(handler_type& handler, pointer_type pointer)
- : handler_(handler),
- pointer_(pointer)
- {
- }
-
- // Construct object in raw memory and take ownership if construction succeeds.
- handler_ptr(raw_ptr_type& raw_ptr)
- : handler_(raw_ptr.handler_),
- pointer_(new (raw_ptr.pointer_) value_type)
- {
- raw_ptr.pointer_ = 0;
- }
-
- // Construct object in raw memory and take ownership if construction succeeds.
- template <typename Arg1>
- handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1)
- : handler_(raw_ptr.handler_),
- pointer_(new (raw_ptr.pointer_) value_type(a1))
- {
- raw_ptr.pointer_ = 0;
- }
-
- // Construct object in raw memory and take ownership if construction succeeds.
- template <typename Arg1, typename Arg2>
- handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2)
- : handler_(raw_ptr.handler_),
- pointer_(new (raw_ptr.pointer_) value_type(a1, a2))
- {
- raw_ptr.pointer_ = 0;
- }
-
- // Construct object in raw memory and take ownership if construction succeeds.
- template <typename Arg1, typename Arg2, typename Arg3>
- handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3)
- : handler_(raw_ptr.handler_),
- pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3))
- {
- raw_ptr.pointer_ = 0;
- }
-
- // Construct object in raw memory and take ownership if construction succeeds.
- template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
- handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4)
- : handler_(raw_ptr.handler_),
- pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4))
- {
- raw_ptr.pointer_ = 0;
- }
-
- // Construct object in raw memory and take ownership if construction succeeds.
- template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
- typename Arg5>
- handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
- Arg5& a5)
- : handler_(raw_ptr.handler_),
- pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5))
- {
- raw_ptr.pointer_ = 0;
- }
-
- // Construct object in raw memory and take ownership if construction succeeds.
- template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
- typename Arg5, typename Arg6>
- handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
- Arg5& a5, Arg6& a6)
- : handler_(raw_ptr.handler_),
- pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6))
- {
- raw_ptr.pointer_ = 0;
- }
-
- // Construct object in raw memory and take ownership if construction succeeds.
- template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
- typename Arg5, typename Arg6, typename Arg7>
- handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
- Arg5& a5, Arg6& a6, Arg7& a7)
- : handler_(raw_ptr.handler_),
- pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6, a7))
- {
- raw_ptr.pointer_ = 0;
- }
-
- // Construct object in raw memory and take ownership if construction succeeds.
- template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
- typename Arg5, typename Arg6, typename Arg7, typename Arg8>
- handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
- Arg5& a5, Arg6& a6, Arg7& a7, Arg8& a8)
- : handler_(raw_ptr.handler_),
- pointer_(new (raw_ptr.pointer_) value_type(
- a1, a2, a3, a4, a5, a6, a7, a8))
- {
- raw_ptr.pointer_ = 0;
- }
-
- // Destructor automatically deallocates memory, unless it has been released.
- ~handler_ptr()
- {
- reset();
- }
-
- // Get the memory.
- pointer_type get() const
- {
- return pointer_;
- }
-
- // Release ownership of the memory.
- pointer_type release()
- {
- pointer_type tmp = pointer_;
- pointer_ = 0;
- return tmp;
- }
-
- // Explicitly destroy and deallocate the memory.
- void reset()
- {
- if (pointer_)
- {
- pointer_->value_type::~value_type();
- asio_handler_alloc_helpers::deallocate(
- pointer_, value_size, handler_);
- pointer_ = 0;
- }
- }
-
-private:
- handler_type& handler_;
- pointer_type pointer_;
-};
-
-} // namespace detail
-} // namespace asio
+#define ASIO_DEFINE_HANDLER_PTR(op) \
+ struct ptr \
+ { \
+ Handler* h; \
+ void* v; \
+ op* p; \
+ ~ptr() \
+ { \
+ reset(); \
+ } \
+ void reset() \
+ { \
+ if (p) \
+ { \
+ p->~op(); \
+ p = 0; \
+ } \
+ if (v) \
+ { \
+ asio_handler_alloc_helpers::deallocate(v, sizeof(op), *h); \
+ v = 0; \
+ } \
+ } \
+ } \
+ /**/
#include "asio/detail/pop_options.hpp"
diff --git a/ext/asio/asio/detail/handler_invoke_helpers.hpp b/ext/asio/asio/detail/handler_invoke_helpers.hpp
index 8332567..5b122d9 100644
--- a/ext/asio/asio/detail/handler_invoke_helpers.hpp
+++ b/ext/asio/asio/detail/handler_invoke_helpers.hpp
@@ -1,8 +1,8 @@
//
-// handler_invoke_helpers.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/handler_invoke_helpers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <boost/detail/workaround.hpp>
#include <boost/utility/addressof.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/handler_invoke_hook.hpp"
+#include "asio/detail/push_options.hpp"
+
// Calls to asio_handler_invoke must be made from a namespace that does not
// contain overloads of this function. The asio_handler_invoke_helpers
// namespace is defined here for that purpose.
diff --git a/ext/asio/asio/detail/hash_map.hpp b/ext/asio/asio/detail/hash_map.hpp
index b2a1517..a3957df 100644
--- a/ext/asio/asio/detail/hash_map.hpp
+++ b/ext/asio/asio/detail/hash_map.hpp
@@ -1,8 +1,8 @@
//
-// hash_map.hpp
-// ~~~~~~~~~~~~
+// detail/hash_map.hpp
+// ~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,33 +15,38 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cassert>
#include <list>
#include <utility>
-#include <boost/functional/hash.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/detail/noncopyable.hpp"
-#include "asio/detail/socket_types.hpp"
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# include "asio/detail/socket_types.hpp"
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
-template <typename T>
-inline std::size_t calculate_hash_value(const T& t)
+inline std::size_t calculate_hash_value(int i)
+{
+ return static_cast<std::size_t>(i);
+}
+
+inline std::size_t calculate_hash_value(void* p)
{
- return boost::hash_value(t);
+ return reinterpret_cast<std::size_t>(p)
+ + (reinterpret_cast<std::size_t>(p) >> 3);
}
-#if defined(_WIN64)
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
inline std::size_t calculate_hash_value(SOCKET s)
{
return static_cast<std::size_t>(s);
}
-#endif // defined(_WIN64)
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
// Note: assumes K and V are POD types.
template <typename K, typename V>
diff --git a/ext/asio/asio/detail/impl/descriptor_ops.ipp b/ext/asio/asio/detail/impl/descriptor_ops.ipp
new file mode 100644
index 0000000..8e0c27d
--- /dev/null
+++ b/ext/asio/asio/detail/impl/descriptor_ops.ipp
@@ -0,0 +1,382 @@
+//
+// detail/impl/descriptor_ops.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
+#define ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cerrno>
+#include "asio/detail/descriptor_ops.hpp"
+#include "asio/error.hpp"
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace descriptor_ops {
+
+ASIO_DECL
+int open(const char* path, int flags, asio::error_code& ec)
+{
+ errno = 0;
+ int result = error_wrapper(::open(path, flags), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+}
+
+ASIO_DECL
+int close(int d, state_type& state, asio::error_code& ec)
+{
+ int result = 0;
+ if (d != -1)
+ {
+ if (state & internal_non_blocking)
+ {
+#if defined(__SYMBIAN32__)
+ int flags = ::fcntl(d, F_GETFL, 0);
+ if (flags >= 0)
+ ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK);
+#else // defined(__SYMBIAN32__)
+ ioctl_arg_type arg = 0;
+ ::ioctl(d, FIONBIO, &arg);
+#endif // defined(__SYMBIAN32__)
+ state &= ~internal_non_blocking;
+ }
+
+ errno = 0;
+ result = error_wrapper(::close(d), ec);
+ }
+
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+}
+
+ASIO_DECL
+bool set_internal_non_blocking(int d,
+ state_type& state, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return false;
+ }
+
+ errno = 0;
+#if defined(__SYMBIAN32__)
+ int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec);
+ if (result >= 0)
+ {
+ errno = 0;
+ result = error_wrapper(::fcntl(d, F_SETFL, result | O_NONBLOCK), ec);
+ }
+#else // defined(__SYMBIAN32__)
+ ioctl_arg_type arg = 1;
+ int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec);
+#endif // defined(__SYMBIAN32__)
+
+ if (result >= 0)
+ {
+ ec = asio::error_code();
+ state |= internal_non_blocking;
+ return true;
+ }
+
+ return false;
+}
+
+ASIO_DECL
+std::size_t sync_read(int d, state_type state, buf* bufs,
+ std::size_t count, bool all_empty, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // A request to read 0 bytes on a stream is a no-op.
+ if (all_empty)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // Read some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ errno = 0;
+ int bytes = error_wrapper(::readv(d, bufs, static_cast<int>(count)), ec);
+
+ // Check if operation succeeded.
+ if (bytes > 0)
+ return bytes;
+
+ // Check for EOF.
+ if (bytes == 0)
+ {
+ ec = asio::error::eof;
+ return 0;
+ }
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != asio::error::try_again))
+ return 0;
+
+ // Wait for descriptor to become ready.
+ if (descriptor_ops::poll_read(d, ec) < 0)
+ return 0;
+ }
+}
+
+ASIO_DECL
+bool non_blocking_read(int d, buf* bufs, std::size_t count,
+ asio::error_code& ec, std::size_t& bytes_transferred)
+{
+ for (;;)
+ {
+ // Read some data.
+ errno = 0;
+ int bytes = error_wrapper(::readv(d, bufs, static_cast<int>(count)), ec);
+
+ // Check for end of stream.
+ if (bytes == 0)
+ {
+ ec = asio::error::eof;
+ return true;
+ }
+
+ // Retry operation if interrupted by signal.
+ if (ec == asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes > 0)
+ {
+ ec = asio::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+ASIO_DECL
+std::size_t sync_write(int d, state_type state, const buf* bufs,
+ std::size_t count, bool all_empty, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // A request to write 0 bytes on a stream is a no-op.
+ if (all_empty)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // Write some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ errno = 0;
+ int bytes = error_wrapper(::writev(d, bufs, static_cast<int>(count)), ec);
+
+ // Check if operation succeeded.
+ if (bytes > 0)
+ return bytes;
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != asio::error::try_again))
+ return 0;
+
+ // Wait for descriptor to become ready.
+ if (descriptor_ops::poll_write(d, ec) < 0)
+ return 0;
+ }
+}
+
+ASIO_DECL
+bool non_blocking_write(int d, const buf* bufs, std::size_t count,
+ asio::error_code& ec, std::size_t& bytes_transferred)
+{
+ for (;;)
+ {
+ // Write some data.
+ errno = 0;
+ int bytes = error_wrapper(::writev(d, bufs, static_cast<int>(count)), ec);
+
+ // Retry operation if interrupted by signal.
+ if (ec == asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes >= 0)
+ {
+ ec = asio::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+ASIO_DECL
+int ioctl(int d, state_type& state, long cmd,
+ ioctl_arg_type* arg, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return -1;
+ }
+
+ errno = 0;
+ int result = error_wrapper(::ioctl(d, cmd, arg), ec);
+
+ if (result >= 0)
+ {
+ ec = asio::error_code();
+
+ // When updating the non-blocking mode we always perform the ioctl syscall,
+ // even if the flags would otherwise indicate that the descriptor is
+ // already in the correct state. This ensures that the underlying
+ // descriptor is put into the state that has been requested by the user. If
+ // the ioctl syscall was successful then we need to update the flags to
+ // match.
+ if (cmd == static_cast<long>(FIONBIO))
+ {
+ if (*arg)
+ {
+ state |= user_set_non_blocking;
+ }
+ else
+ {
+ // Clearing the non-blocking mode always overrides any internally-set
+ // non-blocking flag. Any subsequent asynchronous operations will need
+ // to re-enable non-blocking I/O.
+ state &= ~(user_set_non_blocking | internal_non_blocking);
+ }
+ }
+ }
+
+ return result;
+}
+
+ASIO_DECL
+int fcntl(int d, long cmd, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return -1;
+ }
+
+ errno = 0;
+ int result = error_wrapper(::fcntl(d, cmd), ec);
+ if (result != -1)
+ ec = asio::error_code();
+ return result;
+}
+
+ASIO_DECL
+int fcntl(int d, long cmd, long arg, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return -1;
+ }
+
+ errno = 0;
+ int result = error_wrapper(::fcntl(d, cmd, arg), ec);
+ if (result != -1)
+ ec = asio::error_code();
+ return result;
+}
+
+ASIO_DECL
+int poll_read(int d, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return -1;
+ }
+
+ pollfd fds;
+ fds.fd = d;
+ fds.events = POLLIN;
+ fds.revents = 0;
+ errno = 0;
+ int result = error_wrapper(::poll(&fds, 1, -1), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+}
+
+ASIO_DECL
+int poll_write(int d, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return -1;
+ }
+
+ pollfd fds;
+ fds.fd = d;
+ fds.events = POLLOUT;
+ fds.revents = 0;
+ errno = 0;
+ int result = error_wrapper(::poll(&fds, 1, -1), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+}
+
+} // namespace descriptor_ops
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
diff --git a/ext/asio/asio/detail/impl/dev_poll_reactor.hpp b/ext/asio/asio/detail/impl/dev_poll_reactor.hpp
new file mode 100644
index 0000000..7fbef82
--- /dev/null
+++ b/ext/asio/asio/detail/impl/dev_poll_reactor.hpp
@@ -0,0 +1,77 @@
+//
+// detail/impl/dev_poll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP
+#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_DEV_POLL)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void dev_poll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_add_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void dev_poll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void dev_poll_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ {
+ io_service_.post_immediate_completion(op);
+ return;
+ }
+
+ bool earliest = queue.enqueue_timer(time, timer, op);
+ io_service_.work_started();
+ if (earliest)
+ interrupter_.interrupt();
+}
+
+template <typename Time_Traits>
+std::size_t dev_poll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ std::size_t n = queue.cancel_timer(timer, ops);
+ lock.unlock();
+ io_service_.post_deferred_completions(ops);
+ return n;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_DEV_POLL)
+
+#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP
diff --git a/ext/asio/asio/detail/impl/dev_poll_reactor.ipp b/ext/asio/asio/detail/impl/dev_poll_reactor.ipp
new file mode 100644
index 0000000..0d1456f
--- /dev/null
+++ b/ext/asio/asio/detail/impl/dev_poll_reactor.ipp
@@ -0,0 +1,338 @@
+//
+// detail/impl/dev_poll_reactor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP
+#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_DEV_POLL)
+
+#include "asio/detail/dev_poll_reactor.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+dev_poll_reactor::dev_poll_reactor(asio::io_service& io_service)
+ : asio::detail::service_base<dev_poll_reactor>(io_service),
+ io_service_(use_service<io_service_impl>(io_service)),
+ mutex_(),
+ dev_poll_fd_(do_dev_poll_create()),
+ interrupter_(),
+ shutdown_(false)
+{
+ // Add the interrupter's descriptor to /dev/poll.
+ ::pollfd ev = { 0 };
+ ev.fd = interrupter_.read_descriptor();
+ ev.events = POLLIN | POLLERR;
+ ev.revents = 0;
+ ::write(dev_poll_fd_, &ev, sizeof(ev));
+}
+
+dev_poll_reactor::~dev_poll_reactor()
+{
+ shutdown_service();
+ ::close(dev_poll_fd_);
+}
+
+void dev_poll_reactor::shutdown_service()
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ lock.unlock();
+
+ op_queue<operation> ops;
+
+ for (int i = 0; i < max_ops; ++i)
+ op_queue_[i].get_all_operations(ops);
+
+ timer_queues_.get_all_timers(ops);
+}
+
+void dev_poll_reactor::init_task()
+{
+ io_service_.init_task();
+}
+
+int dev_poll_reactor::register_descriptor(socket_type, per_descriptor_data&)
+{
+ return 0;
+}
+
+void dev_poll_reactor::start_op(int op_type, socket_type descriptor,
+ dev_poll_reactor::per_descriptor_data&,
+ reactor_op* op, bool allow_speculative)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ {
+ post_immediate_completion(op);
+ return;
+ }
+
+ if (allow_speculative)
+ {
+ if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor))
+ {
+ if (!op_queue_[op_type].has_operation(descriptor))
+ {
+ if (op->perform())
+ {
+ lock.unlock();
+ io_service_.post_immediate_completion(op);
+ return;
+ }
+ }
+ }
+ }
+
+ bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
+ io_service_.work_started();
+ if (first)
+ {
+ ::pollfd& ev = add_pending_event_change(descriptor);
+ ev.events = POLLERR | POLLHUP;
+ if (op_type == read_op
+ || op_queue_[read_op].has_operation(descriptor))
+ ev.events |= POLLIN;
+ if (op_type == write_op
+ || op_queue_[write_op].has_operation(descriptor))
+ ev.events |= POLLOUT;
+ if (op_type == except_op
+ || op_queue_[except_op].has_operation(descriptor))
+ ev.events |= POLLPRI;
+ interrupter_.interrupt();
+ }
+}
+
+void dev_poll_reactor::cancel_ops(socket_type descriptor,
+ dev_poll_reactor::per_descriptor_data&)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
+}
+
+void dev_poll_reactor::close_descriptor(socket_type descriptor,
+ dev_poll_reactor::per_descriptor_data&)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Remove the descriptor from /dev/poll.
+ ::pollfd& ev = add_pending_event_change(descriptor);
+ ev.events = POLLREMOVE;
+ interrupter_.interrupt();
+
+ // Cancel any outstanding operations associated with the descriptor.
+ cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
+}
+
+void dev_poll_reactor::run(bool block, op_queue<operation>& ops)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // We can return immediately if there's no work to do and the reactor is
+ // not supposed to block.
+ if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty()
+ && op_queue_[except_op].empty() && timer_queues_.all_empty())
+ return;
+
+ // Write the pending event registration changes to the /dev/poll descriptor.
+ std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size();
+ if (events_size > 0)
+ {
+ errno = 0;
+ int result = ::write(dev_poll_fd_,
+ &pending_event_changes_[0], events_size);
+ if (result != static_cast<int>(events_size))
+ {
+ asio::error_code ec = asio::error_code(
+ errno, asio::error::get_system_category());
+ for (std::size_t i = 0; i < pending_event_changes_.size(); ++i)
+ {
+ int descriptor = pending_event_changes_[i].fd;
+ for (int j = 0; j < max_ops; ++j)
+ op_queue_[j].cancel_operations(descriptor, ops, ec);
+ }
+ }
+ pending_event_changes_.clear();
+ pending_event_change_index_.clear();
+ }
+
+ int timeout = block ? get_timeout() : 0;
+ lock.unlock();
+
+ // Block on the /dev/poll descriptor.
+ ::pollfd events[128] = { { 0 } };
+ ::dvpoll dp = { 0 };
+ dp.dp_fds = events;
+ dp.dp_nfds = 128;
+ dp.dp_timeout = timeout;
+ int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp);
+
+ lock.lock();
+
+ // Dispatch the waiting events.
+ for (int i = 0; i < num_events; ++i)
+ {
+ int descriptor = events[i].fd;
+ if (descriptor == interrupter_.read_descriptor())
+ {
+ interrupter_.reset();
+ }
+ else
+ {
+ bool more_reads = false;
+ bool more_writes = false;
+ bool more_except = false;
+
+ // Exception operations must be processed first to ensure that any
+ // out-of-band data is read before normal data.
+ if (events[i].events & (POLLPRI | POLLERR | POLLHUP))
+ more_except =
+ op_queue_[except_op].perform_operations(descriptor, ops);
+ else
+ more_except = op_queue_[except_op].has_operation(descriptor);
+
+ if (events[i].events & (POLLIN | POLLERR | POLLHUP))
+ more_reads = op_queue_[read_op].perform_operations(descriptor, ops);
+ else
+ more_reads = op_queue_[read_op].has_operation(descriptor);
+
+ if (events[i].events & (POLLOUT | POLLERR | POLLHUP))
+ more_writes = op_queue_[write_op].perform_operations(descriptor, ops);
+ else
+ more_writes = op_queue_[write_op].has_operation(descriptor);
+
+ if ((events[i].events & (POLLERR | POLLHUP)) != 0
+ && !more_except && !more_reads && !more_writes)
+ {
+ // If we have an event and no operations associated with the
+ // descriptor then we need to delete the descriptor from /dev/poll.
+ // The poll operation can produce POLLHUP or POLLERR events when there
+ // is no operation pending, so if we do not remove the descriptor we
+ // can end up in a tight polling loop.
+ ::pollfd ev = { 0 };
+ ev.fd = descriptor;
+ ev.events = POLLREMOVE;
+ ev.revents = 0;
+ ::write(dev_poll_fd_, &ev, sizeof(ev));
+ }
+ else
+ {
+ ::pollfd ev = { 0 };
+ ev.fd = descriptor;
+ ev.events = POLLERR | POLLHUP;
+ if (more_reads)
+ ev.events |= POLLIN;
+ if (more_writes)
+ ev.events |= POLLOUT;
+ if (more_except)
+ ev.events |= POLLPRI;
+ ev.revents = 0;
+ int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
+ if (result != sizeof(ev))
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ for (int j = 0; j < max_ops; ++j)
+ op_queue_[j].cancel_operations(descriptor, ops, ec);
+ }
+ }
+ }
+ }
+ timer_queues_.get_ready_timers(ops);
+}
+
+void dev_poll_reactor::interrupt()
+{
+ interrupter_.interrupt();
+}
+
+int dev_poll_reactor::do_dev_poll_create()
+{
+ int fd = ::open("/dev/poll", O_RDWR);
+ if (fd == -1)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "/dev/poll");
+ }
+ return fd;
+}
+
+void dev_poll_reactor::do_add_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.insert(&queue);
+}
+
+void dev_poll_reactor::do_remove_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.erase(&queue);
+}
+
+int dev_poll_reactor::get_timeout()
+{
+ // By default we will wait no longer than 5 minutes. This will ensure that
+ // any changes to the system clock are detected after no longer than this.
+ return timer_queues_.wait_duration_msec(5 * 60 * 1000);
+}
+
+void dev_poll_reactor::cancel_ops_unlocked(socket_type descriptor,
+ const asio::error_code& ec)
+{
+ bool need_interrupt = false;
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ need_interrupt = op_queue_[i].cancel_operations(
+ descriptor, ops, ec) || need_interrupt;
+ io_service_.post_deferred_completions(ops);
+ if (need_interrupt)
+ interrupter_.interrupt();
+}
+
+::pollfd& dev_poll_reactor::add_pending_event_change(int descriptor)
+{
+ hash_map<int, std::size_t>::iterator iter
+ = pending_event_change_index_.find(descriptor);
+ if (iter == pending_event_change_index_.end())
+ {
+ std::size_t index = pending_event_changes_.size();
+ pending_event_changes_.reserve(pending_event_changes_.size() + 1);
+ pending_event_change_index_.insert(std::make_pair(descriptor, index));
+ pending_event_changes_.push_back(::pollfd());
+ pending_event_changes_[index].fd = descriptor;
+ pending_event_changes_[index].revents = 0;
+ return pending_event_changes_[index];
+ }
+ else
+ {
+ return pending_event_changes_[iter->second];
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_DEV_POLL)
+
+#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP
diff --git a/ext/asio/asio/detail/impl/epoll_reactor.hpp b/ext/asio/asio/detail/impl/epoll_reactor.hpp
new file mode 100644
index 0000000..9f50a23
--- /dev/null
+++ b/ext/asio/asio/detail/impl/epoll_reactor.hpp
@@ -0,0 +1,75 @@
+//
+// detail/impl/epoll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP
+#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if defined(ASIO_HAS_EPOLL)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void epoll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_add_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void epoll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void epoll_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op)
+{
+ mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ {
+ io_service_.post_immediate_completion(op);
+ return;
+ }
+
+ bool earliest = queue.enqueue_timer(time, timer, op);
+ io_service_.work_started();
+ if (earliest)
+ update_timeout();
+}
+
+template <typename Time_Traits>
+std::size_t epoll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer)
+{
+ mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ std::size_t n = queue.cancel_timer(timer, ops);
+ lock.unlock();
+ io_service_.post_deferred_completions(ops);
+ return n;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_EPOLL)
+
+#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP
diff --git a/ext/asio/asio/detail/impl/epoll_reactor.ipp b/ext/asio/asio/detail/impl/epoll_reactor.ipp
new file mode 100644
index 0000000..a95b8f2
--- /dev/null
+++ b/ext/asio/asio/detail/impl/epoll_reactor.ipp
@@ -0,0 +1,390 @@
+//
+// detail/impl/epoll_reactor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP
+#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_EPOLL)
+
+#include <cstddef>
+#include <sys/epoll.h>
+#include "asio/detail/epoll_reactor.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#if defined(ASIO_HAS_TIMERFD)
+# include <sys/timerfd.h>
+#endif // defined(ASIO_HAS_TIMERFD)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+epoll_reactor::epoll_reactor(asio::io_service& io_service)
+ : asio::detail::service_base<epoll_reactor>(io_service),
+ io_service_(use_service<io_service_impl>(io_service)),
+ mutex_(),
+ epoll_fd_(do_epoll_create()),
+#if defined(ASIO_HAS_TIMERFD)
+ timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)),
+#else // defined(ASIO_HAS_TIMERFD)
+ timer_fd_(-1),
+#endif // defined(ASIO_HAS_TIMERFD)
+ interrupter_(),
+ shutdown_(false)
+{
+ // Add the interrupter's descriptor to epoll.
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLIN | EPOLLERR | EPOLLET;
+ ev.data.ptr = &interrupter_;
+ epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);
+ interrupter_.interrupt();
+
+ // Add the timer descriptor to epoll.
+ if (timer_fd_ != -1)
+ {
+ ev.events = EPOLLIN | EPOLLERR;
+ ev.data.ptr = &timer_fd_;
+ epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev);
+ }
+}
+
+epoll_reactor::~epoll_reactor()
+{
+ close(epoll_fd_);
+ if (timer_fd_ != -1)
+ close(timer_fd_);
+}
+
+void epoll_reactor::shutdown_service()
+{
+ mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ lock.unlock();
+
+ op_queue<operation> ops;
+
+ while (descriptor_state* state = registered_descriptors_.first())
+ {
+ for (int i = 0; i < max_ops; ++i)
+ ops.push(state->op_queue_[i]);
+ state->shutdown_ = true;
+ registered_descriptors_.free(state);
+ }
+
+ timer_queues_.get_all_timers(ops);
+}
+
+void epoll_reactor::init_task()
+{
+ io_service_.init_task();
+}
+
+int epoll_reactor::register_descriptor(socket_type descriptor,
+ epoll_reactor::per_descriptor_data& descriptor_data)
+{
+ mutex::scoped_lock lock(registered_descriptors_mutex_);
+
+ descriptor_data = registered_descriptors_.alloc();
+ descriptor_data->shutdown_ = false;
+
+ lock.unlock();
+
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET;
+ ev.data.ptr = descriptor_data;
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+ if (result != 0)
+ return errno;
+
+ return 0;
+}
+
+void epoll_reactor::start_op(int op_type, socket_type descriptor,
+ epoll_reactor::per_descriptor_data& descriptor_data,
+ reactor_op* op, bool allow_speculative)
+{
+ if (!descriptor_data)
+ {
+ op->ec_ = asio::error::bad_descriptor;
+ post_immediate_completion(op);
+ return;
+ }
+
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ if (descriptor_data->shutdown_)
+ {
+ post_immediate_completion(op);
+ return;
+ }
+
+ if (descriptor_data->op_queue_[op_type].empty())
+ {
+ if (allow_speculative
+ && (op_type != read_op
+ || descriptor_data->op_queue_[except_op].empty()))
+ {
+ if (op->perform())
+ {
+ descriptor_lock.unlock();
+ io_service_.post_immediate_completion(op);
+ return;
+ }
+ }
+ else
+ {
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLIN | EPOLLERR | EPOLLHUP
+ | EPOLLOUT | EPOLLPRI | EPOLLET;
+ ev.data.ptr = descriptor_data;
+ epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
+ }
+ }
+
+ descriptor_data->op_queue_[op_type].push(op);
+ io_service_.work_started();
+}
+
+void epoll_reactor::cancel_ops(socket_type,
+ epoll_reactor::per_descriptor_data& descriptor_data)
+{
+ if (!descriptor_data)
+ return;
+
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ {
+ while (reactor_op* op = descriptor_data->op_queue_[i].front())
+ {
+ op->ec_ = asio::error::operation_aborted;
+ descriptor_data->op_queue_[i].pop();
+ ops.push(op);
+ }
+ }
+
+ descriptor_lock.unlock();
+
+ io_service_.post_deferred_completions(ops);
+}
+
+void epoll_reactor::close_descriptor(socket_type,
+ epoll_reactor::per_descriptor_data& descriptor_data)
+{
+ if (!descriptor_data)
+ return;
+
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+
+ if (!descriptor_data->shutdown_)
+ {
+ // Remove the descriptor from the set of known descriptors. The descriptor
+ // will be automatically removed from the epoll set when it is closed.
+
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ {
+ while (reactor_op* op = descriptor_data->op_queue_[i].front())
+ {
+ op->ec_ = asio::error::operation_aborted;
+ descriptor_data->op_queue_[i].pop();
+ ops.push(op);
+ }
+ }
+
+ descriptor_data->shutdown_ = true;
+
+ descriptor_lock.unlock();
+
+ registered_descriptors_.free(descriptor_data);
+ descriptor_data = 0;
+
+ descriptors_lock.unlock();
+
+ io_service_.post_deferred_completions(ops);
+ }
+}
+
+void epoll_reactor::run(bool block, op_queue<operation>& ops)
+{
+ // Calculate a timeout only if timerfd is not used.
+ int timeout;
+ if (timer_fd_ != -1)
+ timeout = block ? -1 : 0;
+ else
+ {
+ mutex::scoped_lock lock(mutex_);
+ timeout = block ? get_timeout() : 0;
+ }
+
+ // Block on the epoll descriptor.
+ epoll_event events[128];
+ int num_events = epoll_wait(epoll_fd_, events, 128, timeout);
+
+#if defined(ASIO_HAS_TIMERFD)
+ bool check_timers = (timer_fd_ == -1);
+#else // defined(ASIO_HAS_TIMERFD)
+ bool check_timers = true;
+#endif // defined(ASIO_HAS_TIMERFD)
+
+ // Dispatch the waiting events.
+ for (int i = 0; i < num_events; ++i)
+ {
+ void* ptr = events[i].data.ptr;
+ if (ptr == &interrupter_)
+ {
+ // No need to reset the interrupter since we're leaving the descriptor
+ // in a ready-to-read state and relying on edge-triggered notifications
+ // to make it so that we only get woken up when the descriptor's epoll
+ // registration is updated.
+
+#if defined(ASIO_HAS_TIMERFD)
+ if (timer_fd_ == -1)
+ check_timers = true;
+#else // defined(ASIO_HAS_TIMERFD)
+ check_timers = true;
+#endif // defined(ASIO_HAS_TIMERFD)
+ }
+#if defined(ASIO_HAS_TIMERFD)
+ else if (ptr == &timer_fd_)
+ {
+ check_timers = true;
+ }
+#endif // defined(ASIO_HAS_TIMERFD)
+ else
+ {
+ descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ // Exception operations must be processed first to ensure that any
+ // out-of-band data is read before normal data.
+ static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI };
+ for (int j = max_ops - 1; j >= 0; --j)
+ {
+ if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP))
+ {
+ while (reactor_op* op = descriptor_data->op_queue_[j].front())
+ {
+ if (op->perform())
+ {
+ descriptor_data->op_queue_[j].pop();
+ ops.push(op);
+ }
+ else
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (check_timers)
+ {
+ mutex::scoped_lock common_lock(mutex_);
+ timer_queues_.get_ready_timers(ops);
+
+#if defined(ASIO_HAS_TIMERFD)
+ if (timer_fd_ != -1)
+ {
+ itimerspec new_timeout;
+ itimerspec old_timeout;
+ int flags = get_timeout(new_timeout);
+ timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
+ }
+#endif // defined(ASIO_HAS_TIMERFD)
+ }
+}
+
+void epoll_reactor::interrupt()
+{
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLIN | EPOLLERR | EPOLLET;
+ ev.data.ptr = &interrupter_;
+ epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev);
+}
+
+int epoll_reactor::do_epoll_create()
+{
+ int fd = epoll_create(epoll_size);
+ if (fd == -1)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "epoll");
+ }
+ return fd;
+}
+
+void epoll_reactor::do_add_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.insert(&queue);
+}
+
+void epoll_reactor::do_remove_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.erase(&queue);
+}
+
+void epoll_reactor::update_timeout()
+{
+#if defined(ASIO_HAS_TIMERFD)
+ if (timer_fd_ != -1)
+ {
+ itimerspec new_timeout;
+ itimerspec old_timeout;
+ int flags = get_timeout(new_timeout);
+ timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
+ return;
+ }
+#endif // defined(ASIO_HAS_TIMERFD)
+ interrupt();
+}
+
+int epoll_reactor::get_timeout()
+{
+ // By default we will wait no longer than 5 minutes. This will ensure that
+ // any changes to the system clock are detected after no longer than this.
+ return timer_queues_.wait_duration_msec(5 * 60 * 1000);
+}
+
+#if defined(ASIO_HAS_TIMERFD)
+int epoll_reactor::get_timeout(itimerspec& ts)
+{
+ ts.it_interval.tv_sec = 0;
+ ts.it_interval.tv_nsec = 0;
+
+ long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
+ ts.it_value.tv_sec = usec / 1000000;
+ ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1;
+
+ return usec ? 0 : TFD_TIMER_ABSTIME;
+}
+#endif // defined(ASIO_HAS_TIMERFD)
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_EPOLL)
+
+#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP
diff --git a/ext/asio/asio/detail/impl/eventfd_select_interrupter.ipp b/ext/asio/asio/detail/impl/eventfd_select_interrupter.ipp
new file mode 100644
index 0000000..959d356
--- /dev/null
+++ b/ext/asio/asio/detail/impl/eventfd_select_interrupter.ipp
@@ -0,0 +1,125 @@
+//
+// detail/impl/eventfd_select_interrupter.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
+#define ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_EVENTFD)
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+# include <asm/unistd.h>
+#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+# include <sys/eventfd.h>
+#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+#include "asio/detail/eventfd_select_interrupter.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+eventfd_select_interrupter::eventfd_select_interrupter()
+{
+#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+ write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0);
+#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+ write_descriptor_ = read_descriptor_ = ::eventfd(0, 0);
+#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+ if (read_descriptor_ != -1)
+ {
+ ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
+ }
+ else
+ {
+ int pipe_fds[2];
+ if (pipe(pipe_fds) == 0)
+ {
+ read_descriptor_ = pipe_fds[0];
+ ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
+ write_descriptor_ = pipe_fds[1];
+ ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
+ }
+ else
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "eventfd_select_interrupter");
+ }
+ }
+}
+
+eventfd_select_interrupter::~eventfd_select_interrupter()
+{
+ if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_)
+ ::close(write_descriptor_);
+ if (read_descriptor_ != -1)
+ ::close(read_descriptor_);
+}
+
+void eventfd_select_interrupter::interrupt()
+{
+ uint64_t counter(1UL);
+ int result = ::write(write_descriptor_, &counter, sizeof(uint64_t));
+ (void)result;
+}
+
+bool eventfd_select_interrupter::reset()
+{
+ if (write_descriptor_ == read_descriptor_)
+ {
+ for (;;)
+ {
+ // Only perform one read. The kernel maintains an atomic counter.
+ uint64_t counter(0);
+ errno = 0;
+ int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t));
+ if (bytes_read < 0 && errno == EINTR)
+ continue;
+ bool was_interrupted = (bytes_read > 0);
+ return was_interrupted;
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ // Clear all data from the pipe.
+ char data[1024];
+ int bytes_read = ::read(read_descriptor_, data, sizeof(data));
+ if (bytes_read < 0 && errno == EINTR)
+ continue;
+ bool was_interrupted = (bytes_read > 0);
+ while (bytes_read == sizeof(data))
+ bytes_read = ::read(read_descriptor_, data, sizeof(data));
+ return was_interrupted;
+ }
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_EVENTFD)
+
+#endif // ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
diff --git a/ext/asio/asio/detail/impl/kqueue_reactor.hpp b/ext/asio/asio/detail/impl/kqueue_reactor.hpp
new file mode 100644
index 0000000..7950c3b
--- /dev/null
+++ b/ext/asio/asio/detail/impl/kqueue_reactor.hpp
@@ -0,0 +1,79 @@
+//
+// detail/impl/kqueue_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP
+#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_KQUEUE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void kqueue_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_add_timer_queue(queue);
+}
+
+// Remove a timer queue from the reactor.
+template <typename Time_Traits>
+void kqueue_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void kqueue_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ {
+ io_service_.post_immediate_completion(op);
+ return;
+ }
+
+ bool earliest = queue.enqueue_timer(time, timer, op);
+ io_service_.work_started();
+ if (earliest)
+ interrupt();
+}
+
+template <typename Time_Traits>
+std::size_t kqueue_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ std::size_t n = queue.cancel_timer(timer, ops);
+ lock.unlock();
+ io_service_.post_deferred_completions(ops);
+ return n;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_KQUEUE)
+
+#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP
diff --git a/ext/asio/asio/detail/impl/kqueue_reactor.ipp b/ext/asio/asio/detail/impl/kqueue_reactor.ipp
new file mode 100644
index 0000000..8db77cb
--- /dev/null
+++ b/ext/asio/asio/detail/impl/kqueue_reactor.ipp
@@ -0,0 +1,385 @@
+//
+// detail/impl/kqueue_reactor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP
+#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_KQUEUE)
+
+#include "asio/detail/kqueue_reactor.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(__NetBSD__)
+# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \
+ EV_SET(ev, ident, filt, flags, fflags, \
+ data, reinterpret_cast<intptr_t>(udata))
+#else
+# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \
+ EV_SET(ev, ident, filt, flags, fflags, data, udata)
+#endif
+
+namespace asio {
+namespace detail {
+
+kqueue_reactor::kqueue_reactor(asio::io_service& io_service)
+ : asio::detail::service_base<kqueue_reactor>(io_service),
+ io_service_(use_service<io_service_impl>(io_service)),
+ mutex_(),
+ kqueue_fd_(do_kqueue_create()),
+ interrupter_(),
+ shutdown_(false)
+{
+ // The interrupter is put into a permanently readable state. Whenever we
+ // want to interrupt the blocked kevent call we register a one-shot read
+ // operation against the descriptor.
+ interrupter_.interrupt();
+}
+
+kqueue_reactor::~kqueue_reactor()
+{
+ close(kqueue_fd_);
+}
+
+void kqueue_reactor::shutdown_service()
+{
+ mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ lock.unlock();
+
+ op_queue<operation> ops;
+
+ while (descriptor_state* state = registered_descriptors_.first())
+ {
+ for (int i = 0; i < max_ops; ++i)
+ ops.push(state->op_queue_[i]);
+ state->shutdown_ = true;
+ registered_descriptors_.free(state);
+ }
+
+ timer_queues_.get_all_timers(ops);
+}
+
+void kqueue_reactor::init_task()
+{
+ io_service_.init_task();
+}
+
+int kqueue_reactor::register_descriptor(socket_type,
+ kqueue_reactor::per_descriptor_data& descriptor_data)
+{
+ mutex::scoped_lock lock(registered_descriptors_mutex_);
+
+ descriptor_data = registered_descriptors_.alloc();
+ descriptor_data->shutdown_ = false;
+
+ return 0;
+}
+
+void kqueue_reactor::start_op(int op_type, socket_type descriptor,
+ kqueue_reactor::per_descriptor_data& descriptor_data,
+ reactor_op* op, bool allow_speculative)
+{
+ if (!descriptor_data)
+ {
+ op->ec_ = asio::error::bad_descriptor;
+ post_immediate_completion(op);
+ return;
+ }
+
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ if (descriptor_data->shutdown_)
+ {
+ post_immediate_completion(op);
+ return;
+ }
+
+ bool first = descriptor_data->op_queue_[op_type].empty();
+ if (first)
+ {
+ if (allow_speculative)
+ {
+ if (op_type != read_op || descriptor_data->op_queue_[except_op].empty())
+ {
+ if (op->perform())
+ {
+ descriptor_lock.unlock();
+ io_service_.post_immediate_completion(op);
+ return;
+ }
+ }
+ }
+ }
+
+ descriptor_data->op_queue_[op_type].push(op);
+ io_service_.work_started();
+
+ if (first)
+ {
+ struct kevent event;
+ switch (op_type)
+ {
+ case read_op:
+ ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
+ EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+ break;
+ case write_op:
+ ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_WRITE,
+ EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+ break;
+ case except_op:
+ if (!descriptor_data->op_queue_[read_op].empty())
+ return; // Already registered for read events.
+ ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
+ EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data);
+ break;
+ }
+
+ if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+ {
+ op->ec_ = asio::error_code(errno,
+ asio::error::get_system_category());
+ descriptor_data->op_queue_[op_type].pop();
+ io_service_.post_deferred_completion(op);
+ }
+ }
+}
+
+void kqueue_reactor::cancel_ops(socket_type,
+ kqueue_reactor::per_descriptor_data& descriptor_data)
+{
+ if (!descriptor_data)
+ return;
+
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ {
+ while (reactor_op* op = descriptor_data->op_queue_[i].front())
+ {
+ op->ec_ = asio::error::operation_aborted;
+ descriptor_data->op_queue_[i].pop();
+ ops.push(op);
+ }
+ }
+
+ descriptor_lock.unlock();
+
+ io_service_.post_deferred_completions(ops);
+}
+
+void kqueue_reactor::close_descriptor(socket_type,
+ kqueue_reactor::per_descriptor_data& descriptor_data)
+{
+ if (!descriptor_data)
+ return;
+
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+
+ if (!descriptor_data->shutdown_)
+ {
+ // Remove the descriptor from the set of known descriptors. The descriptor
+ // will be automatically removed from the kqueue set when it is closed.
+
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ {
+ while (reactor_op* op = descriptor_data->op_queue_[i].front())
+ {
+ op->ec_ = asio::error::operation_aborted;
+ descriptor_data->op_queue_[i].pop();
+ ops.push(op);
+ }
+ }
+
+ descriptor_data->shutdown_ = true;
+
+ descriptor_lock.unlock();
+
+ registered_descriptors_.free(descriptor_data);
+ descriptor_data = 0;
+
+ descriptors_lock.unlock();
+
+ io_service_.post_deferred_completions(ops);
+ }
+}
+
+void kqueue_reactor::run(bool block, op_queue<operation>& ops)
+{
+ mutex::scoped_lock lock(mutex_);
+
+ // Determine how long to block while waiting for events.
+ timespec timeout_buf = { 0, 0 };
+ timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf;
+
+ lock.unlock();
+
+ // Block on the kqueue descriptor.
+ struct kevent events[128];
+ int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout);
+
+ // Dispatch the waiting events.
+ for (int i = 0; i < num_events; ++i)
+ {
+ int descriptor = events[i].ident;
+ void* ptr = reinterpret_cast<void*>(events[i].udata);
+ if (ptr == &interrupter_)
+ {
+ // No need to reset the interrupter since we're leaving the descriptor
+ // in a ready-to-read state and relying on one-shot notifications.
+ }
+ else
+ {
+ descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ // Exception operations must be processed first to ensure that any
+ // out-of-band data is read before normal data.
+#if defined(__NetBSD__)
+ static const unsigned int filter[max_ops] =
+#else
+ static const int filter[max_ops] =
+#endif
+ { EVFILT_READ, EVFILT_WRITE, EVFILT_READ };
+ for (int j = max_ops - 1; j >= 0; --j)
+ {
+ if (events[i].filter == filter[j])
+ {
+ if (j != except_op || events[i].flags & EV_OOBAND)
+ {
+ while (reactor_op* op = descriptor_data->op_queue_[j].front())
+ {
+ if (events[i].flags & EV_ERROR)
+ {
+ op->ec_ = asio::error_code(events[i].data,
+ asio::error::get_system_category());
+ descriptor_data->op_queue_[j].pop();
+ ops.push(op);
+ }
+ if (op->perform())
+ {
+ descriptor_data->op_queue_[j].pop();
+ ops.push(op);
+ }
+ else
+ break;
+ }
+ }
+ }
+ }
+
+ // Renew registration for event notifications.
+ struct kevent event;
+ switch (events[i].filter)
+ {
+ case EVFILT_READ:
+ if (!descriptor_data->op_queue_[read_op].empty())
+ ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
+ EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+ else if (!descriptor_data->op_queue_[except_op].empty())
+ ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
+ EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data);
+ else
+ continue;
+ case EVFILT_WRITE:
+ if (!descriptor_data->op_queue_[write_op].empty())
+ ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_WRITE,
+ EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+ else
+ continue;
+ default:
+ break;
+ }
+ if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+ {
+ asio::error_code error(errno,
+ asio::error::get_system_category());
+ for (int j = 0; j < max_ops; ++j)
+ {
+ while (reactor_op* op = descriptor_data->op_queue_[j].front())
+ {
+ op->ec_ = error;
+ descriptor_data->op_queue_[j].pop();
+ ops.push(op);
+ }
+ }
+ }
+ }
+ }
+
+ lock.lock();
+ timer_queues_.get_ready_timers(ops);
+}
+
+void kqueue_reactor::interrupt()
+{
+ struct kevent event;
+ ASIO_KQUEUE_EV_SET(&event, interrupter_.read_descriptor(),
+ EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &interrupter_);
+ ::kevent(kqueue_fd_, &event, 1, 0, 0, 0);
+}
+
+int kqueue_reactor::do_kqueue_create()
+{
+ int fd = ::kqueue();
+ if (fd == -1)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "kqueue");
+ }
+ return fd;
+}
+
+void kqueue_reactor::do_add_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.insert(&queue);
+}
+
+void kqueue_reactor::do_remove_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.erase(&queue);
+}
+
+timespec* kqueue_reactor::get_timeout(timespec& ts)
+{
+ // By default we will wait no longer than 5 minutes. This will ensure that
+ // any changes to the system clock are detected after no longer than this.
+ long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
+ ts.tv_sec = usec / 1000000;
+ ts.tv_nsec = (usec % 1000000) * 1000;
+ return &ts;
+}
+
+} // namespace detail
+} // namespace asio
+
+#undef ASIO_KQUEUE_EV_SET
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_KQUEUE)
+
+#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP
diff --git a/ext/asio/asio/detail/impl/pipe_select_interrupter.ipp b/ext/asio/asio/detail/impl/pipe_select_interrupter.ipp
new file mode 100644
index 0000000..aac20d4
--- /dev/null
+++ b/ext/asio/asio/detail/impl/pipe_select_interrupter.ipp
@@ -0,0 +1,96 @@
+//
+// detail/impl/pipe_select_interrupter.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
+#define ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(BOOST_WINDOWS)
+#if !defined(__CYGWIN__)
+#if !defined(__SYMBIAN32__)
+#if !defined(ASIO_HAS_EVENTFD)
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "asio/detail/pipe_select_interrupter.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+pipe_select_interrupter::pipe_select_interrupter()
+{
+ int pipe_fds[2];
+ if (pipe(pipe_fds) == 0)
+ {
+ read_descriptor_ = pipe_fds[0];
+ ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
+ write_descriptor_ = pipe_fds[1];
+ ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
+ }
+ else
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "pipe_select_interrupter");
+ }
+}
+
+pipe_select_interrupter::~pipe_select_interrupter()
+{
+ if (read_descriptor_ != -1)
+ ::close(read_descriptor_);
+ if (write_descriptor_ != -1)
+ ::close(write_descriptor_);
+}
+
+void pipe_select_interrupter::interrupt()
+{
+ char byte = 0;
+ int result = ::write(write_descriptor_, &byte, 1);
+ (void)result;
+}
+
+bool pipe_select_interrupter::reset()
+{
+ for (;;)
+ {
+ char data[1024];
+ int bytes_read = ::read(read_descriptor_, data, sizeof(data));
+ if (bytes_read < 0 && errno == EINTR)
+ continue;
+ bool was_interrupted = (bytes_read > 0);
+ while (bytes_read == sizeof(data))
+ bytes_read = ::read(read_descriptor_, data, sizeof(data));
+ return was_interrupted;
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_EVENTFD)
+#endif // !defined(__SYMBIAN32__)
+#endif // !defined(__CYGWIN__)
+#endif // !defined(BOOST_WINDOWS)
+
+#endif // ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
diff --git a/ext/asio/asio/detail/impl/posix_event.ipp b/ext/asio/asio/detail/impl/posix_event.ipp
new file mode 100644
index 0000000..3206418
--- /dev/null
+++ b/ext/asio/asio/detail/impl/posix_event.ipp
@@ -0,0 +1,46 @@
+//
+// detail/impl/posix_event.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_POSIX_EVENT_IPP
+#define ASIO_DETAIL_IMPL_POSIX_EVENT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
+#include "asio/detail/posix_event.hpp"
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+posix_event::posix_event()
+ : signalled_(false)
+{
+ int error = ::pthread_cond_init(&cond_, 0);
+ asio::error_code ec(error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "event");
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
+#endif // ASIO_DETAIL_IMPL_POSIX_EVENT_IPP
diff --git a/ext/asio/asio/detail/impl/posix_mutex.ipp b/ext/asio/asio/detail/impl/posix_mutex.ipp
new file mode 100644
index 0000000..12b6659
--- /dev/null
+++ b/ext/asio/asio/detail/impl/posix_mutex.ipp
@@ -0,0 +1,46 @@
+//
+// detail/impl/posix_mutex.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP
+#define ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
+#include "asio/detail/posix_mutex.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+posix_mutex::posix_mutex()
+{
+ int error = ::pthread_mutex_init(&mutex_, 0);
+ asio::error_code ec(error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "mutex");
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
+#endif // ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP
diff --git a/ext/asio/asio/detail/impl/posix_thread.ipp b/ext/asio/asio/detail/impl/posix_thread.ipp
new file mode 100644
index 0000000..ce91c57
--- /dev/null
+++ b/ext/asio/asio/detail/impl/posix_thread.ipp
@@ -0,0 +1,74 @@
+//
+// detail/impl/posix_thread.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_POSIX_THREAD_IPP
+#define ASIO_DETAIL_IMPL_POSIX_THREAD_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
+#include "asio/detail/posix_thread.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+posix_thread::~posix_thread()
+{
+ if (!joined_)
+ ::pthread_detach(thread_);
+}
+
+void posix_thread::join()
+{
+ if (!joined_)
+ {
+ ::pthread_join(thread_, 0);
+ joined_ = true;
+ }
+}
+
+void posix_thread::start_thread(func_base* arg)
+{
+ int error = ::pthread_create(&thread_, 0,
+ asio_detail_posix_thread_function, arg);
+ if (error != 0)
+ {
+ delete arg;
+ asio::error_code ec(error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "thread");
+ }
+}
+
+void* asio_detail_posix_thread_function(void* arg)
+{
+ posix_thread::auto_func_base_ptr func = {
+ static_cast<posix_thread::func_base*>(arg) };
+ func.ptr->run();
+ return 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
+#endif // ASIO_DETAIL_IMPL_POSIX_THREAD_IPP
diff --git a/ext/asio/asio/detail/impl/posix_tss_ptr.ipp b/ext/asio/asio/detail/impl/posix_tss_ptr.ipp
new file mode 100644
index 0000000..89b40f7
--- /dev/null
+++ b/ext/asio/asio/detail/impl/posix_tss_ptr.ipp
@@ -0,0 +1,46 @@
+//
+// detail/impl/posix_tss_ptr.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP
+#define ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
+#include "asio/detail/posix_tss_ptr.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+void posix_tss_ptr_create(pthread_key_t& key)
+{
+ int error = ::pthread_key_create(&key, 0);
+ asio::error_code ec(error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "tss");
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
+#endif // ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP
diff --git a/ext/asio/asio/detail/impl/reactive_descriptor_service.ipp b/ext/asio/asio/detail/impl/reactive_descriptor_service.ipp
new file mode 100644
index 0000000..706d60f
--- /dev/null
+++ b/ext/asio/asio/detail/impl/reactive_descriptor_service.ipp
@@ -0,0 +1,136 @@
+//
+// detail/impl/reactive_descriptor_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include "asio/error.hpp"
+#include "asio/detail/reactive_descriptor_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+reactive_descriptor_service::reactive_descriptor_service(
+ asio::io_service& io_service)
+ : reactor_(asio::use_service<reactor>(io_service))
+{
+ reactor_.init_task();
+}
+
+void reactive_descriptor_service::shutdown_service()
+{
+}
+
+void reactive_descriptor_service::construct(
+ reactive_descriptor_service::implementation_type& impl)
+{
+ impl.descriptor_ = -1;
+ impl.state_ = 0;
+}
+
+void reactive_descriptor_service::destroy(
+ reactive_descriptor_service::implementation_type& impl)
+{
+ if (is_open(impl))
+ reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_);
+
+ asio::error_code ignored_ec;
+ descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec);
+}
+
+asio::error_code reactive_descriptor_service::assign(
+ reactive_descriptor_service::implementation_type& impl,
+ const native_type& native_descriptor, asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ if (int err = reactor_.register_descriptor(
+ native_descriptor, impl.reactor_data_))
+ {
+ ec = asio::error_code(err,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.descriptor_ = native_descriptor;
+ impl.state_ = 0;
+ ec = asio::error_code();
+ return ec;
+}
+
+asio::error_code reactive_descriptor_service::close(
+ reactive_descriptor_service::implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (is_open(impl))
+ reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_);
+
+ if (descriptor_ops::close(impl.descriptor_, impl.state_, ec) == 0)
+ construct(impl);
+
+ return ec;
+}
+
+asio::error_code reactive_descriptor_service::cancel(
+ reactive_descriptor_service::implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_);
+ ec = asio::error_code();
+ return ec;
+}
+
+void reactive_descriptor_service::start_op(
+ reactive_descriptor_service::implementation_type& impl,
+ int op_type, reactor_op* op, bool non_blocking, bool noop)
+{
+ if (!noop)
+ {
+ if ((impl.state_ & descriptor_ops::non_blocking) ||
+ descriptor_ops::set_internal_non_blocking(
+ impl.descriptor_, impl.state_, op->ec_))
+ {
+ reactor_.start_op(op_type, impl.descriptor_,
+ impl.reactor_data_, op, non_blocking);
+ return;
+ }
+ }
+
+ reactor_.post_immediate_completion(op);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP
diff --git a/ext/asio/asio/detail/impl/reactive_serial_port_service.ipp b/ext/asio/asio/detail/impl/reactive_serial_port_service.ipp
new file mode 100644
index 0000000..c4df793
--- /dev/null
+++ b/ext/asio/asio/detail/impl/reactive_serial_port_service.ipp
@@ -0,0 +1,151 @@
+//
+// detail/impl/reactive_serial_port_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_SERIAL_PORT)
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <cstring>
+#include "asio/detail/reactive_serial_port_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+reactive_serial_port_service::reactive_serial_port_service(
+ asio::io_service& io_service)
+ : descriptor_service_(io_service)
+{
+}
+
+void reactive_serial_port_service::shutdown_service()
+{
+ descriptor_service_.shutdown_service();
+}
+
+asio::error_code reactive_serial_port_service::open(
+ reactive_serial_port_service::implementation_type& impl,
+ const std::string& device, asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ descriptor_ops::state_type state = 0;
+ int fd = descriptor_ops::open(device.c_str(),
+ O_RDWR | O_NONBLOCK | O_NOCTTY, ec);
+ if (fd < 0)
+ return ec;
+
+ int s = descriptor_ops::fcntl(fd, F_GETFL, ec);
+ if (s >= 0)
+ s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec);
+ if (s < 0)
+ {
+ asio::error_code ignored_ec;
+ descriptor_ops::close(fd, state, ignored_ec);
+ return ec;
+ }
+
+ // Set up default serial port options.
+ termios ios;
+ errno = 0;
+ s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec);
+ if (s >= 0)
+ {
+#if defined(_BSD_SOURCE)
+ ::cfmakeraw(&ios);
+#else
+ ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK
+ | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
+ ios.c_oflag &= ~OPOST;
+ ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+ ios.c_cflag &= ~(CSIZE | PARENB);
+ ios.c_cflag |= CS8;
+#endif
+ ios.c_iflag |= IGNPAR;
+ ios.c_cflag |= CREAD | CLOCAL;
+ errno = 0;
+ s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec);
+ }
+ if (s < 0)
+ {
+ asio::error_code ignored_ec;
+ descriptor_ops::close(fd, state, ignored_ec);
+ return ec;
+ }
+
+ // We're done. Take ownership of the serial port descriptor.
+ if (descriptor_service_.assign(impl, fd, ec))
+ {
+ asio::error_code ignored_ec;
+ descriptor_ops::close(fd, state, ignored_ec);
+ }
+
+ return ec;
+}
+
+asio::error_code reactive_serial_port_service::do_set_option(
+ reactive_serial_port_service::implementation_type& impl,
+ reactive_serial_port_service::store_function_type store,
+ const void* option, asio::error_code& ec)
+{
+ termios ios;
+ errno = 0;
+ descriptor_ops::error_wrapper(::tcgetattr(
+ descriptor_service_.native(impl), &ios), ec);
+ if (ec)
+ return ec;
+
+ if (store(option, ios, ec))
+ return ec;
+
+ errno = 0;
+ descriptor_ops::error_wrapper(::tcsetattr(
+ descriptor_service_.native(impl), TCSANOW, &ios), ec);
+ return ec;
+}
+
+asio::error_code reactive_serial_port_service::do_get_option(
+ const reactive_serial_port_service::implementation_type& impl,
+ reactive_serial_port_service::load_function_type load,
+ void* option, asio::error_code& ec) const
+{
+ termios ios;
+ errno = 0;
+ descriptor_ops::error_wrapper(::tcgetattr(
+ descriptor_service_.native(impl), &ios), ec);
+ if (ec)
+ return ec;
+
+ return load(option, ios, ec);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#endif // defined(ASIO_HAS_SERIAL_PORT)
+
+#endif // ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
diff --git a/ext/asio/asio/detail/impl/reactive_socket_service_base.ipp b/ext/asio/asio/detail/impl/reactive_socket_service_base.ipp
new file mode 100644
index 0000000..54e7944
--- /dev/null
+++ b/ext/asio/asio/detail/impl/reactive_socket_service_base.ipp
@@ -0,0 +1,212 @@
+//
+// detail/reactive_socket_service_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
+#define ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/reactive_socket_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+reactive_socket_service_base::reactive_socket_service_base(
+ asio::io_service& io_service)
+ : reactor_(use_service<reactor>(io_service))
+{
+ reactor_.init_task();
+}
+
+void reactive_socket_service_base::shutdown_service()
+{
+}
+
+void reactive_socket_service_base::construct(
+ reactive_socket_service_base::base_implementation_type& impl)
+{
+ impl.socket_ = invalid_socket;
+ impl.state_ = 0;
+}
+
+void reactive_socket_service_base::destroy(
+ reactive_socket_service_base::base_implementation_type& impl)
+{
+ if (impl.socket_ != invalid_socket)
+ {
+ reactor_.close_descriptor(impl.socket_, impl.reactor_data_);
+
+ asio::error_code ignored_ec;
+ socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
+ }
+}
+
+asio::error_code reactive_socket_service_base::close(
+ reactive_socket_service_base::base_implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (is_open(impl))
+ reactor_.close_descriptor(impl.socket_, impl.reactor_data_);
+
+ if (socket_ops::close(impl.socket_, impl.state_, true, ec) == 0)
+ construct(impl);
+
+ return ec;
+}
+
+asio::error_code reactive_socket_service_base::cancel(
+ reactive_socket_service_base::base_implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
+ ec = asio::error_code();
+ return ec;
+}
+
+asio::error_code reactive_socket_service_base::do_open(
+ reactive_socket_service_base::base_implementation_type& impl,
+ int af, int type, int protocol, asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ socket_holder sock(socket_ops::socket(af, type, protocol, ec));
+ if (sock.get() == invalid_socket)
+ return ec;
+
+ if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_))
+ {
+ ec = asio::error_code(err,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.socket_ = sock.release();
+ switch (type)
+ {
+ case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+ case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+ default: impl.state_ = 0; break;
+ }
+ ec = asio::error_code();
+ return ec;
+}
+
+asio::error_code reactive_socket_service_base::do_assign(
+ reactive_socket_service_base::base_implementation_type& impl, int type,
+ const reactive_socket_service_base::native_type& native_socket,
+ asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ if (int err = reactor_.register_descriptor(
+ native_socket, impl.reactor_data_))
+ {
+ ec = asio::error_code(err,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.socket_ = native_socket;
+ switch (type)
+ {
+ case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+ case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+ default: impl.state_ = 0; break;
+ }
+ ec = asio::error_code();
+ return ec;
+}
+
+void reactive_socket_service_base::start_op(
+ reactive_socket_service_base::base_implementation_type& impl,
+ int op_type, reactor_op* op, bool non_blocking, bool noop)
+{
+ if (!noop)
+ {
+ if ((impl.state_ & socket_ops::non_blocking)
+ || socket_ops::set_internal_non_blocking(
+ impl.socket_, impl.state_, op->ec_))
+ {
+ reactor_.start_op(op_type, impl.socket_,
+ impl.reactor_data_, op, non_blocking);
+ return;
+ }
+ }
+
+ reactor_.post_immediate_completion(op);
+}
+
+void reactive_socket_service_base::start_accept_op(
+ reactive_socket_service_base::base_implementation_type& impl,
+ reactor_op* op, bool peer_is_open)
+{
+ if (!peer_is_open)
+ start_op(impl, reactor::read_op, op, true, false);
+ else
+ {
+ op->ec_ = asio::error::already_open;
+ reactor_.post_immediate_completion(op);
+ }
+}
+
+void reactive_socket_service_base::start_connect_op(
+ reactive_socket_service_base::base_implementation_type& impl,
+ reactor_op* op, const socket_addr_type* addr, size_t addrlen)
+{
+ if ((impl.state_ & socket_ops::non_blocking)
+ || socket_ops::set_internal_non_blocking(
+ impl.socket_, impl.state_, op->ec_))
+ {
+ if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
+ {
+ if (op->ec_ == asio::error::in_progress
+ || op->ec_ == asio::error::would_block)
+ {
+ op->ec_ = asio::error_code();
+ reactor_.start_op(reactor::connect_op,
+ impl.socket_, impl.reactor_data_, op, false);
+ return;
+ }
+ }
+ }
+
+ reactor_.post_immediate_completion(op);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
diff --git a/ext/asio/asio/detail/impl/resolver_service_base.ipp b/ext/asio/asio/detail/impl/resolver_service_base.ipp
new file mode 100644
index 0000000..a844a23
--- /dev/null
+++ b/ext/asio/asio/detail/impl/resolver_service_base.ipp
@@ -0,0 +1,106 @@
+//
+// detail/impl/resolver_service_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP
+#define ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/resolver_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class resolver_service_base::work_io_service_runner
+{
+public:
+ work_io_service_runner(asio::io_service& io_service)
+ : io_service_(io_service) {}
+ void operator()() { io_service_.run(); }
+private:
+ asio::io_service& io_service_;
+};
+
+resolver_service_base::resolver_service_base(
+ asio::io_service& io_service)
+ : io_service_impl_(asio::use_service<io_service_impl>(io_service)),
+ work_io_service_(new asio::io_service),
+ work_io_service_impl_(asio::use_service<
+ io_service_impl>(*work_io_service_)),
+ work_(new asio::io_service::work(*work_io_service_)),
+ work_thread_(0)
+{
+}
+
+resolver_service_base::~resolver_service_base()
+{
+ shutdown_service();
+}
+
+void resolver_service_base::shutdown_service()
+{
+ work_.reset();
+ if (work_io_service_)
+ {
+ work_io_service_->stop();
+ if (work_thread_)
+ {
+ work_thread_->join();
+ work_thread_.reset();
+ }
+ work_io_service_.reset();
+ }
+}
+
+void resolver_service_base::construct(
+ resolver_service_base::implementation_type& impl)
+{
+ impl.reset(static_cast<void*>(0), socket_ops::noop_deleter());
+}
+
+void resolver_service_base::destroy(
+ resolver_service_base::implementation_type&)
+{
+}
+
+void resolver_service_base::cancel(
+ resolver_service_base::implementation_type& impl)
+{
+ impl.reset(static_cast<void*>(0), socket_ops::noop_deleter());
+}
+
+void resolver_service_base::start_resolve_op(operation* op)
+{
+ start_work_thread();
+ io_service_impl_.work_started();
+ work_io_service_impl_.post_immediate_completion(op);
+}
+
+void resolver_service_base::start_work_thread()
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!work_thread_)
+ {
+ work_thread_.reset(new asio::detail::thread(
+ work_io_service_runner(*work_io_service_)));
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP
diff --git a/ext/asio/asio/detail/impl/select_reactor.hpp b/ext/asio/asio/detail/impl/select_reactor.hpp
new file mode 100644
index 0000000..50d3ad4
--- /dev/null
+++ b/ext/asio/asio/detail/impl/select_reactor.hpp
@@ -0,0 +1,84 @@
+//
+// detail/impl/select_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP
+#define ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) \
+ || (!defined(ASIO_HAS_DEV_POLL) \
+ && !defined(ASIO_HAS_EPOLL) \
+ && !defined(ASIO_HAS_KQUEUE))
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void select_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_add_timer_queue(queue);
+}
+
+// Remove a timer queue from the reactor.
+template <typename Time_Traits>
+void select_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void select_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ {
+ io_service_.post_immediate_completion(op);
+ return;
+ }
+
+ bool earliest = queue.enqueue_timer(time, timer, op);
+ io_service_.work_started();
+ if (earliest)
+ interrupter_.interrupt();
+}
+
+template <typename Time_Traits>
+std::size_t select_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ std::size_t n = queue.cancel_timer(timer, ops);
+ lock.unlock();
+ io_service_.post_deferred_completions(ops);
+ return n;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+ // || (!defined(ASIO_HAS_DEV_POLL)
+ // && !defined(ASIO_HAS_EPOLL)
+ // && !defined(ASIO_HAS_KQUEUE))
+
+#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP
diff --git a/ext/asio/asio/detail/impl/select_reactor.ipp b/ext/asio/asio/detail/impl/select_reactor.ipp
new file mode 100644
index 0000000..1a59be3
--- /dev/null
+++ b/ext/asio/asio/detail/impl/select_reactor.ipp
@@ -0,0 +1,273 @@
+//
+// detail/impl/select_reactor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP
+#define ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) \
+ || (!defined(ASIO_HAS_DEV_POLL) \
+ && !defined(ASIO_HAS_EPOLL) \
+ && !defined(ASIO_HAS_KQUEUE))
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fd_set_adapter.hpp"
+#include "asio/detail/select_reactor.hpp"
+#include "asio/detail/signal_blocker.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+select_reactor::select_reactor(asio::io_service& io_service)
+ : asio::detail::service_base<select_reactor>(io_service),
+ io_service_(use_service<io_service_impl>(io_service)),
+ mutex_(),
+ interrupter_(),
+#if defined(ASIO_HAS_IOCP)
+ stop_thread_(false),
+ thread_(0),
+#endif // defined(ASIO_HAS_IOCP)
+ shutdown_(false)
+{
+#if defined(ASIO_HAS_IOCP)
+ asio::detail::signal_blocker sb;
+ thread_ = new asio::detail::thread(
+ bind_handler(&select_reactor::call_run_thread, this));
+#endif // defined(ASIO_HAS_IOCP)
+}
+
+select_reactor::~select_reactor()
+{
+ shutdown_service();
+}
+
+void select_reactor::shutdown_service()
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+#if defined(ASIO_HAS_IOCP)
+ stop_thread_ = true;
+#endif // defined(ASIO_HAS_IOCP)
+ lock.unlock();
+
+#if defined(ASIO_HAS_IOCP)
+ if (thread_)
+ {
+ interrupter_.interrupt();
+ thread_->join();
+ delete thread_;
+ thread_ = 0;
+ }
+#endif // defined(ASIO_HAS_IOCP)
+
+ op_queue<operation> ops;
+
+ for (int i = 0; i < max_ops; ++i)
+ op_queue_[i].get_all_operations(ops);
+
+ timer_queues_.get_all_timers(ops);
+}
+
+void select_reactor::init_task()
+{
+ io_service_.init_task();
+}
+
+int select_reactor::register_descriptor(socket_type,
+ select_reactor::per_descriptor_data&)
+{
+ return 0;
+}
+
+void select_reactor::start_op(int op_type, socket_type descriptor,
+ select_reactor::per_descriptor_data&, reactor_op* op, bool)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ {
+ post_immediate_completion(op);
+ return;
+ }
+
+ bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
+ io_service_.work_started();
+ if (first)
+ interrupter_.interrupt();
+}
+
+void select_reactor::cancel_ops(socket_type descriptor,
+ select_reactor::per_descriptor_data&)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
+}
+
+void select_reactor::close_descriptor(socket_type descriptor,
+ select_reactor::per_descriptor_data&)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
+}
+
+void select_reactor::run(bool block, op_queue<operation>& ops)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+#if defined(ASIO_HAS_IOCP)
+ // Check if the thread is supposed to stop.
+ if (stop_thread_)
+ return;
+#endif // defined(ASIO_HAS_IOCP)
+
+ // Set up the descriptor sets.
+ fd_set_adapter fds[max_select_ops];
+ fds[read_op].set(interrupter_.read_descriptor());
+ socket_type max_fd = 0;
+ bool have_work_to_do = !timer_queues_.all_empty();
+ for (int i = 0; i < max_select_ops; ++i)
+ {
+ have_work_to_do = have_work_to_do || !op_queue_[i].empty();
+ op_queue_[i].get_descriptors(fds[i], ops);
+ if (fds[i].max_descriptor() > max_fd)
+ max_fd = fds[i].max_descriptor();
+ }
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ // Connection operations on Windows use both except and write fd_sets.
+ have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty();
+ op_queue_[connect_op].get_descriptors(fds[write_op], ops);
+ if (fds[write_op].max_descriptor() > max_fd)
+ max_fd = fds[write_op].max_descriptor();
+ op_queue_[connect_op].get_descriptors(fds[except_op], ops);
+ if (fds[except_op].max_descriptor() > max_fd)
+ max_fd = fds[except_op].max_descriptor();
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+ // We can return immediately if there's no work to do and the reactor is
+ // not supposed to block.
+ if (!block && !have_work_to_do)
+ return;
+
+ // Determine how long to block while waiting for events.
+ timeval tv_buf = { 0, 0 };
+ timeval* tv = block ? get_timeout(tv_buf) : &tv_buf;
+
+ lock.unlock();
+
+ // Block on the select call until descriptors become ready.
+ asio::error_code ec;
+ int retval = socket_ops::select(static_cast<int>(max_fd + 1),
+ fds[read_op], fds[write_op], fds[except_op], tv, ec);
+
+ // Reset the interrupter.
+ if (retval > 0 && fds[read_op].is_set(interrupter_.read_descriptor()))
+ interrupter_.reset();
+
+ lock.lock();
+
+ // Dispatch all ready operations.
+ if (retval > 0)
+ {
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ // Connection operations on Windows use both except and write fd_sets.
+ op_queue_[connect_op].perform_operations_for_descriptors(
+ fds[except_op], ops);
+ op_queue_[connect_op].perform_operations_for_descriptors(
+ fds[write_op], ops);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+ // Exception operations must be processed first to ensure that any
+ // out-of-band data is read before normal data.
+ for (int i = max_select_ops - 1; i >= 0; --i)
+ op_queue_[i].perform_operations_for_descriptors(fds[i], ops);
+ }
+ timer_queues_.get_ready_timers(ops);
+}
+
+void select_reactor::interrupt()
+{
+ interrupter_.interrupt();
+}
+
+#if defined(ASIO_HAS_IOCP)
+void select_reactor::run_thread()
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ while (!stop_thread_)
+ {
+ lock.unlock();
+ op_queue<operation> ops;
+ run(true, ops);
+ io_service_.post_deferred_completions(ops);
+ lock.lock();
+ }
+}
+
+void select_reactor::call_run_thread(select_reactor* reactor)
+{
+ reactor->run_thread();
+}
+#endif // defined(ASIO_HAS_IOCP)
+
+void select_reactor::do_add_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.insert(&queue);
+}
+
+void select_reactor::do_remove_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.erase(&queue);
+}
+
+timeval* select_reactor::get_timeout(timeval& tv)
+{
+ // By default we will wait no longer than 5 minutes. This will ensure that
+ // any changes to the system clock are detected after no longer than this.
+ long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
+ tv.tv_sec = usec / 1000000;
+ tv.tv_usec = usec % 1000000;
+ return &tv;
+}
+
+void select_reactor::cancel_ops_unlocked(socket_type descriptor,
+ const asio::error_code& ec)
+{
+ bool need_interrupt = false;
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ need_interrupt = op_queue_[i].cancel_operations(
+ descriptor, ops, ec) || need_interrupt;
+ io_service_.post_deferred_completions(ops);
+ if (need_interrupt)
+ interrupter_.interrupt();
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+ // || (!defined(ASIO_HAS_DEV_POLL)
+ // && !defined(ASIO_HAS_EPOLL)
+ // && !defined(ASIO_HAS_KQUEUE))
+
+#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP
diff --git a/ext/asio/asio/detail/impl/service_registry.hpp b/ext/asio/asio/detail/impl/service_registry.hpp
new file mode 100644
index 0000000..c2aa9ec
--- /dev/null
+++ b/ext/asio/asio/detail/impl/service_registry.hpp
@@ -0,0 +1,70 @@
+//
+// detail/impl/service_registry.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
+#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Service>
+Service& service_registry::use_service()
+{
+ asio::io_service::service::key key;
+ init_key(key, Service::id);
+ factory_type factory = &service_registry::create<Service>;
+ return *static_cast<Service*>(do_use_service(key, factory));
+}
+
+template <typename Service>
+void service_registry::add_service(Service* new_service)
+{
+ asio::io_service::service::key key;
+ init_key(key, Service::id);
+ return do_add_service(key, new_service);
+}
+
+template <typename Service>
+bool service_registry::has_service() const
+{
+ asio::io_service::service::key key;
+ init_key(key, Service::id);
+ return do_has_service(key);
+}
+
+#if !defined(ASIO_NO_TYPEID)
+template <typename Service>
+void service_registry::init_key(asio::io_service::service::key& key,
+ const asio::detail::service_id<Service>& /*id*/)
+{
+ key.type_info_ = &typeid(typeid_wrapper<Service>);
+ key.id_ = 0;
+}
+#endif // !defined(ASIO_NO_TYPEID)
+
+template <typename Service>
+asio::io_service::service* service_registry::create(
+ asio::io_service& owner)
+{
+ return new Service(owner);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
diff --git a/ext/asio/asio/detail/impl/service_registry.ipp b/ext/asio/asio/detail/impl/service_registry.ipp
new file mode 100644
index 0000000..57c57b8
--- /dev/null
+++ b/ext/asio/asio/detail/impl/service_registry.ipp
@@ -0,0 +1,164 @@
+//
+// detail/impl/service_registry.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
+#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/throw_exception.hpp>
+#include "asio/detail/service_registry.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+service_registry::service_registry(asio::io_service& o)
+ : owner_(o),
+ first_service_(0)
+{
+}
+
+service_registry::~service_registry()
+{
+ // Shutdown all services. This must be done in a separate loop before the
+ // services are destroyed since the destructors of user-defined handler
+ // objects may try to access other service objects.
+ asio::io_service::service* service = first_service_;
+ while (service)
+ {
+ service->shutdown_service();
+ service = service->next_;
+ }
+
+ // Destroy all services.
+ while (first_service_)
+ {
+ asio::io_service::service* next_service = first_service_->next_;
+ destroy(first_service_);
+ first_service_ = next_service;
+ }
+}
+
+void service_registry::init_key(asio::io_service::service::key& key,
+ const asio::io_service::id& id)
+{
+ key.type_info_ = 0;
+ key.id_ = &id;
+}
+
+bool service_registry::keys_match(
+ const asio::io_service::service::key& key1,
+ const asio::io_service::service::key& key2)
+{
+ if (key1.id_ && key2.id_)
+ if (key1.id_ == key2.id_)
+ return true;
+ if (key1.type_info_ && key2.type_info_)
+ if (*key1.type_info_ == *key2.type_info_)
+ return true;
+ return false;
+}
+
+void service_registry::destroy(asio::io_service::service* service)
+{
+ delete service;
+}
+
+asio::io_service::service* service_registry::do_use_service(
+ const asio::io_service::service::key& key,
+ factory_type factory)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // First see if there is an existing service object with the given key.
+ asio::io_service::service* service = first_service_;
+ while (service)
+ {
+ if (keys_match(service->key_, key))
+ return service;
+ service = service->next_;
+ }
+
+ // Create a new service object. The service registry's mutex is not locked
+ // at this time to allow for nested calls into this function from the new
+ // service's constructor.
+ lock.unlock();
+ auto_service_ptr new_service = { factory(owner_) };
+ new_service.ptr_->key_ = key;
+ lock.lock();
+
+ // Check that nobody else created another service object of the same type
+ // while the lock was released.
+ service = first_service_;
+ while (service)
+ {
+ if (keys_match(service->key_, key))
+ return service;
+ service = service->next_;
+ }
+
+ // Service was successfully initialised, pass ownership to registry.
+ new_service.ptr_->next_ = first_service_;
+ first_service_ = new_service.ptr_;
+ new_service.ptr_ = 0;
+ return first_service_;
+}
+
+void service_registry::do_add_service(
+ const asio::io_service::service::key& key,
+ asio::io_service::service* new_service)
+{
+ if (&owner_ != &new_service->io_service())
+ boost::throw_exception(invalid_service_owner());
+
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Check if there is an existing service object with the given key.
+ asio::io_service::service* service = first_service_;
+ while (service)
+ {
+ if (keys_match(service->key_, key))
+ boost::throw_exception(service_already_exists());
+ service = service->next_;
+ }
+
+ // Take ownership of the service object.
+ new_service->key_ = key;
+ new_service->next_ = first_service_;
+ first_service_ = new_service;
+}
+
+bool service_registry::do_has_service(
+ const asio::io_service::service::key& key) const
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ asio::io_service::service* service = first_service_;
+ while (service)
+ {
+ if (keys_match(service->key_, key))
+ return true;
+ service = service->next_;
+ }
+
+ return false;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
diff --git a/ext/asio/asio/detail/impl/socket_ops.ipp b/ext/asio/asio/detail/impl/socket_ops.ipp
new file mode 100644
index 0000000..66006ea
--- /dev/null
+++ b/ext/asio/asio/detail/impl/socket_ops.ipp
@@ -0,0 +1,2917 @@
+//
+// detail/impl/socket_ops.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SOCKET_OPS_IPP
+#define ASIO_DETAIL_SOCKET_OPS_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/assert.hpp>
+#include <boost/detail/workaround.hpp>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <new>
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace socket_ops {
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+struct msghdr { int msg_namelen; };
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#if defined(__hpux)
+// HP-UX doesn't declare these functions extern "C", so they are declared again
+// here to avoid linker errors about undefined symbols.
+extern "C" char* if_indextoname(unsigned int, char*);
+extern "C" unsigned int if_nametoindex(const char*);
+#endif // defined(__hpux)
+
+inline void clear_last_error()
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ WSASetLastError(0);
+#else
+ errno = 0;
+#endif
+}
+
+template <typename ReturnType>
+inline ReturnType error_wrapper(ReturnType return_value,
+ asio::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ ec = asio::error_code(WSAGetLastError(),
+ asio::error::get_system_category());
+#else
+ ec = asio::error_code(errno,
+ asio::error::get_system_category());
+#endif
+ return return_value;
+}
+
+template <typename SockLenType>
+inline socket_type call_accept(SockLenType msghdr::*,
+ socket_type s, socket_addr_type* addr, std::size_t* addrlen)
+{
+ SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;
+ socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0);
+ if (addrlen)
+ *addrlen = (std::size_t)tmp_addrlen;
+ return result;
+}
+
+ASIO_DECL
+socket_type accept(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return invalid_socket;
+ }
+
+ clear_last_error();
+
+ socket_type new_s = error_wrapper(call_accept(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+ if (new_s == invalid_socket)
+ return new_s;
+
+#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
+ int optval = 1;
+ int result = error_wrapper(::setsockopt(new_s,
+ SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
+ if (result != 0)
+ {
+ ::close(new_s);
+ return invalid_socket;
+ }
+#endif
+
+ ec = asio::error_code();
+ return new_s;
+}
+
+ASIO_DECL
+socket_type sync_accept(socket_type s, state_type state,
+ socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec)
+{
+ // Accept a socket.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ socket_type new_socket = socket_ops::accept(s, addr, addrlen, ec);
+
+ // Check if operation succeeded.
+ if (new_socket != invalid_socket)
+ return new_socket;
+
+ // Operation failed.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ {
+ if (state & user_set_non_blocking)
+ return invalid_socket;
+ // Fall through to retry operation.
+ }
+ else if (ec == asio::error::connection_aborted)
+ {
+ if (state & enable_connection_aborted)
+ return invalid_socket;
+ // Fall through to retry operation.
+ }
+#if defined(EPROTO)
+ else if (ec.value() == EPROTO)
+ {
+ if (state & enable_connection_aborted)
+ return invalid_socket;
+ // Fall through to retry operation.
+ }
+#endif // defined(EPROTO)
+ else
+ return invalid_socket;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_read(s, ec) < 0)
+ return invalid_socket;
+ }
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+void complete_iocp_accept(socket_type s,
+ void* output_buffer, DWORD address_length,
+ socket_addr_type* addr, std::size_t* addrlen,
+ socket_type new_socket, asio::error_code& ec)
+{
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ ec = asio::error::connection_aborted;
+
+ if (!ec)
+ {
+ // Get the address of the peer.
+ if (addr && addrlen)
+ {
+ LPSOCKADDR local_addr = 0;
+ int local_addr_length = 0;
+ LPSOCKADDR remote_addr = 0;
+ int remote_addr_length = 0;
+ GetAcceptExSockaddrs(output_buffer, 0, address_length,
+ address_length, &local_addr, &local_addr_length,
+ &remote_addr, &remote_addr_length);
+ if (static_cast<std::size_t>(remote_addr_length) > *addrlen)
+ {
+ ec = asio::error::invalid_argument;
+ }
+ else
+ {
+ using namespace std; // For memcpy.
+ memcpy(addr, remote_addr, remote_addr_length);
+ *addrlen = static_cast<std::size_t>(remote_addr_length);
+ }
+ }
+
+ // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
+ // and getpeername will work on the accepted socket.
+ SOCKET update_ctx_param = s;
+ socket_ops::state_type state = 0;
+ socket_ops::setsockopt(new_socket, state,
+ SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+ &update_ctx_param, sizeof(SOCKET), ec);
+ }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+bool non_blocking_accept(socket_type s,
+ state_type state, socket_addr_type* addr, std::size_t* addrlen,
+ asio::error_code& ec, socket_type& new_socket)
+{
+ for (;;)
+ {
+ // Accept the waiting connection.
+ new_socket = socket_ops::accept(s, addr, addrlen, ec);
+
+ // Check if operation succeeded.
+ if (new_socket != invalid_socket)
+ return true;
+
+ // Retry operation if interrupted by signal.
+ if (ec == asio::error::interrupted)
+ continue;
+
+ // Operation failed.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ {
+ if (state & user_set_non_blocking)
+ return true;
+ // Fall through to retry operation.
+ }
+ else if (ec == asio::error::connection_aborted)
+ {
+ if (state & enable_connection_aborted)
+ return true;
+ // Fall through to retry operation.
+ }
+#if defined(EPROTO)
+ else if (ec.value() == EPROTO)
+ {
+ if (state & enable_connection_aborted)
+ return true;
+ // Fall through to retry operation.
+ }
+#endif // defined(EPROTO)
+ else
+ return true;
+
+ return false;
+ }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+template <typename SockLenType>
+inline int call_bind(SockLenType msghdr::*,
+ socket_type s, const socket_addr_type* addr, std::size_t addrlen)
+{
+ return ::bind(s, addr, (SockLenType)addrlen);
+}
+
+ASIO_DECL
+int bind(socket_type s, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+ clear_last_error();
+ int result = error_wrapper(call_bind(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+}
+
+ASIO_DECL
+int close(socket_type s, state_type& state,
+ bool destruction, asio::error_code& ec)
+{
+ int result = 0;
+ if (s != invalid_socket)
+ {
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ if ((state & non_blocking) && (state & user_set_linger))
+ {
+ ioctl_arg_type arg = 0;
+ ::ioctlsocket(s, FIONBIO, &arg);
+ state &= ~non_blocking;
+ }
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ if (state & non_blocking)
+ {
+#if defined(__SYMBIAN32__)
+ int flags = ::fcntl(s, F_GETFL, 0);
+ if (flags >= 0)
+ ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK);
+#else // defined(__SYMBIAN32__)
+ ioctl_arg_type arg = 0;
+ ::ioctl(s, FIONBIO, &arg);
+#endif // defined(__SYMBIAN32__)
+ state &= ~non_blocking;
+ }
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+ if (destruction && (state & user_set_linger))
+ {
+ ::linger opt;
+ opt.l_onoff = 0;
+ opt.l_linger = 0;
+ asio::error_code ignored_ec;
+ socket_ops::setsockopt(s, state, SOL_SOCKET,
+ SO_LINGER, &opt, sizeof(opt), ignored_ec);
+ }
+
+ clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ result = error_wrapper(::closesocket(s), ec);
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ result = error_wrapper(::close(s), ec);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ }
+
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+}
+
+ASIO_DECL
+bool set_internal_non_blocking(socket_type s,
+ state_type& state, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return false;
+ }
+
+ clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ ioctl_arg_type arg = 1;
+ int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec);
+#elif defined(__SYMBIAN32__)
+ int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec);
+ if (result >= 0)
+ {
+ clear_last_error();
+ result = error_wrapper(::fcntl(s, F_SETFL, result | O_NONBLOCK), ec);
+ }
+#else
+ ioctl_arg_type arg = 1;
+ int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec);
+#endif
+
+ if (result >= 0)
+ {
+ ec = asio::error_code();
+ state |= internal_non_blocking;
+ return true;
+ }
+
+ return false;
+}
+
+ASIO_DECL
+int shutdown(socket_type s, int what, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+ clear_last_error();
+ int result = error_wrapper(::shutdown(s, what), ec);
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+}
+
+template <typename SockLenType>
+inline int call_connect(SockLenType msghdr::*,
+ socket_type s, const socket_addr_type* addr, std::size_t addrlen)
+{
+ return ::connect(s, addr, (SockLenType)addrlen);
+}
+
+ASIO_DECL
+int connect(socket_type s, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+ clear_last_error();
+ int result = error_wrapper(call_connect(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+}
+
+ASIO_DECL
+void sync_connect(socket_type s, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec)
+{
+ // Perform the connect operation.
+ socket_ops::connect(s, addr, addrlen, ec);
+ if (ec != asio::error::in_progress
+ && ec != asio::error::would_block)
+ {
+ // The connect operation finished immediately.
+ return;
+ }
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_connect(s, ec) < 0)
+ return;
+
+ // Get the error code from the connect operation.
+ int connect_error = 0;
+ size_t connect_error_len = sizeof(connect_error);
+ if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR,
+ &connect_error, &connect_error_len, ec) == socket_error_retval)
+ return;
+
+ // Return the result of the connect operation.
+ ec = asio::error_code(connect_error,
+ asio::error::get_system_category());
+}
+
+ASIO_DECL
+bool non_blocking_connect(socket_type s, asio::error_code& ec)
+{
+ // Get the error code from the connect operation.
+ int connect_error = 0;
+ size_t connect_error_len = sizeof(connect_error);
+ if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR,
+ &connect_error, &connect_error_len, ec) == 0)
+ {
+ if (connect_error)
+ {
+ ec = asio::error_code(connect_error,
+ asio::error::get_system_category());
+ }
+ else
+ ec = asio::error_code();
+ }
+
+ return true;
+}
+
+ASIO_DECL
+int socketpair(int af, int type, int protocol,
+ socket_type sv[2], asio::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ (void)(af);
+ (void)(type);
+ (void)(protocol);
+ (void)(sv);
+ ec = asio::error::operation_not_supported;
+ return socket_error_retval;
+#else
+ clear_last_error();
+ int result = error_wrapper(::socketpair(af, type, protocol, sv), ec);
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+#endif
+}
+
+ASIO_DECL
+bool sockatmark(socket_type s, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return false;
+ }
+
+#if defined(SIOCATMARK)
+ ioctl_arg_type value = 0;
+# if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::ioctlsocket(s, SIOCATMARK, &value), ec);
+# else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::ioctl(s, SIOCATMARK, &value), ec);
+# endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ if (result == 0)
+ ec = asio::error_code();
+# if defined(ENOTTY)
+ if (ec.value() == ENOTTY)
+ ec = asio::error::not_socket;
+# endif // defined(ENOTTY)
+#else // defined(SIOCATMARK)
+ int value = error_wrapper(::sockatmark(s), ec);
+ if (value != -1)
+ ec = asio::error_code();
+#endif // defined(SIOCATMARK)
+
+ return ec ? false : value != 0;
+}
+
+ASIO_DECL
+size_t available(socket_type s, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ ioctl_arg_type value = 0;
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::ioctlsocket(s, FIONREAD, &value), ec);
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::ioctl(s, FIONREAD, &value), ec);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ if (result == 0)
+ ec = asio::error_code();
+#if defined(ENOTTY)
+ if (ec.value() == ENOTTY)
+ ec = asio::error::not_socket;
+#endif // defined(ENOTTY)
+
+ return ec ? static_cast<size_t>(0) : static_cast<size_t>(value);
+}
+
+ASIO_DECL
+int listen(socket_type s, int backlog, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+ clear_last_error();
+ int result = error_wrapper(::listen(s, backlog), ec);
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+}
+
+inline void init_buf_iov_base(void*& base, void* addr)
+{
+ base = addr;
+}
+
+template <typename T>
+inline void init_buf_iov_base(T& base, void* addr)
+{
+ base = static_cast<T>(addr);
+}
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+typedef WSABUF buf;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+typedef iovec buf;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+ASIO_DECL
+void init_buf(buf& b, void* data, size_t size)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ b.buf = static_cast<char*>(data);
+ b.len = static_cast<u_long>(size);
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ init_buf_iov_base(b.iov_base, data);
+ b.iov_len = size;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+ASIO_DECL
+void init_buf(buf& b, const void* data, size_t size)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ b.buf = static_cast<char*>(const_cast<void*>(data));
+ b.len = static_cast<u_long>(size);
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ init_buf_iov_base(b.iov_base, const_cast<void*>(data));
+ b.iov_len = size;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr)
+{
+ name = addr;
+}
+
+inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr)
+{
+ name = const_cast<socket_addr_type*>(addr);
+}
+
+template <typename T>
+inline void init_msghdr_msg_name(T& name, socket_addr_type* addr)
+{
+ name = reinterpret_cast<T>(addr);
+}
+
+template <typename T>
+inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr)
+{
+ name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr));
+}
+
+ASIO_DECL
+int recv(socket_type s, buf* bufs, size_t count, int flags,
+ asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ // Receive some data.
+ DWORD recv_buf_count = static_cast<DWORD>(count);
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = error_wrapper(::WSARecv(s, bufs,
+ recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec);
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ ec = asio::error::connection_reset;
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ ec = asio::error::connection_refused;
+ if (result != 0)
+ return socket_error_retval;
+ ec = asio::error_code();
+ return bytes_transferred;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ msg.msg_iov = bufs;
+ msg.msg_iovlen = count;
+ int result = error_wrapper(::recvmsg(s, &msg, flags), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+ASIO_DECL
+size_t sync_recv(socket_type s, state_type state, buf* bufs,
+ size_t count, int flags, bool all_empty, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // A request to read 0 bytes on a stream is a no-op.
+ if (all_empty && (state & stream_oriented))
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // Read some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ int bytes = socket_ops::recv(s, bufs, count, flags, ec);
+
+ // Check if operation succeeded.
+ if (bytes > 0)
+ return bytes;
+
+ // Check for EOF.
+ if ((state & stream_oriented) && bytes == 0)
+ {
+ ec = asio::error::eof;
+ return 0;
+ }
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_read(s, ec) < 0)
+ return 0;
+ }
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+void complete_iocp_recv(state_type state,
+ const weak_cancel_token_type& cancel_token, bool all_empty,
+ asio::error_code& ec, size_t bytes_transferred)
+{
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (cancel_token.expired())
+ ec = asio::error::operation_aborted;
+ else
+ ec = asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = asio::error::connection_refused;
+ }
+
+ // Check for connection closed.
+ else if (!ec && bytes_transferred == 0
+ && (state & stream_oriented) != 0
+ && !all_empty)
+ {
+ ec = asio::error::eof;
+ }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+bool non_blocking_recv(socket_type s,
+ buf* bufs, size_t count, int flags, bool is_stream,
+ asio::error_code& ec, size_t& bytes_transferred)
+{
+ for (;;)
+ {
+ // Read some data.
+ int bytes = socket_ops::recv(s, bufs, count, flags, ec);
+
+ // Check for end of stream.
+ if (is_stream && bytes == 0)
+ {
+ ec = asio::error::eof;
+ return true;
+ }
+
+ // Retry operation if interrupted by signal.
+ if (ec == asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes >= 0)
+ {
+ ec = asio::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+int recvfrom(socket_type s, buf* bufs, size_t count, int flags,
+ socket_addr_type* addr, std::size_t* addrlen,
+ asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ // Receive some data.
+ DWORD recv_buf_count = static_cast<DWORD>(count);
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int tmp_addrlen = (int)*addrlen;
+ int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count,
+ &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec);
+ *addrlen = (std::size_t)tmp_addrlen;
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ ec = asio::error::connection_reset;
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ ec = asio::error::connection_refused;
+ if (result != 0)
+ return socket_error_retval;
+ ec = asio::error_code();
+ return bytes_transferred;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ init_msghdr_msg_name(msg.msg_name, addr);
+ msg.msg_namelen = *addrlen;
+ msg.msg_iov = bufs;
+ msg.msg_iovlen = count;
+ int result = error_wrapper(::recvmsg(s, &msg, flags), ec);
+ *addrlen = msg.msg_namelen;
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+ASIO_DECL
+size_t sync_recvfrom(socket_type s, state_type state, buf* bufs,
+ size_t count, int flags, socket_addr_type* addr,
+ std::size_t* addrlen, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Read some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ int bytes = socket_ops::recvfrom(s, bufs, count, flags, addr, addrlen, ec);
+
+ // Check if operation succeeded.
+ if (bytes >= 0)
+ return bytes;
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_read(s, ec) < 0)
+ return 0;
+ }
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+void complete_iocp_recvfrom(
+ const weak_cancel_token_type& cancel_token,
+ asio::error_code& ec)
+{
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (cancel_token.expired())
+ ec = asio::error::operation_aborted;
+ else
+ ec = asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = asio::error::connection_refused;
+ }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+bool non_blocking_recvfrom(socket_type s,
+ buf* bufs, size_t count, int flags,
+ socket_addr_type* addr, std::size_t* addrlen,
+ asio::error_code& ec, size_t& bytes_transferred)
+{
+ for (;;)
+ {
+ // Read some data.
+ int bytes = socket_ops::recvfrom(s, bufs, count, flags, addr, addrlen, ec);
+
+ // Retry operation if interrupted by signal.
+ if (ec == asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes >= 0)
+ {
+ ec = asio::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+int send(socket_type s, const buf* bufs, size_t count, int flags,
+ asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ // Send the data.
+ DWORD send_buf_count = static_cast<DWORD>(count);
+ DWORD bytes_transferred = 0;
+ DWORD send_flags = flags;
+ int result = error_wrapper(::WSASend(s, const_cast<buf*>(bufs),
+ send_buf_count, &bytes_transferred, send_flags, 0, 0), ec);
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ ec = asio::error::connection_reset;
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ ec = asio::error::connection_refused;
+ if (result != 0)
+ return socket_error_retval;
+ ec = asio::error_code();
+ return bytes_transferred;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ msg.msg_iov = const_cast<buf*>(bufs);
+ msg.msg_iovlen = count;
+#if defined(__linux__)
+ flags |= MSG_NOSIGNAL;
+#endif // defined(__linux__)
+ int result = error_wrapper(::sendmsg(s, &msg, flags), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+ASIO_DECL
+size_t sync_send(socket_type s, state_type state, const buf* bufs,
+ size_t count, int flags, bool all_empty, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // A request to write 0 bytes to a stream is a no-op.
+ if (all_empty && (state & stream_oriented))
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // Read some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ int bytes = socket_ops::send(s, bufs, count, flags, ec);
+
+ // Check if operation succeeded.
+ if (bytes >= 0)
+ return bytes;
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_write(s, ec) < 0)
+ return 0;
+ }
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+void complete_iocp_send(
+ const weak_cancel_token_type& cancel_token,
+ asio::error_code& ec)
+{
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (cancel_token.expired())
+ ec = asio::error::operation_aborted;
+ else
+ ec = asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = asio::error::connection_refused;
+ }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+bool non_blocking_send(socket_type s,
+ const buf* bufs, size_t count, int flags,
+ asio::error_code& ec, size_t& bytes_transferred)
+{
+ for (;;)
+ {
+ // Write some data.
+ int bytes = socket_ops::send(s, bufs, count, flags, ec);
+
+ // Retry operation if interrupted by signal.
+ if (ec == asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes >= 0)
+ {
+ ec = asio::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+int sendto(socket_type s, const buf* bufs, size_t count, int flags,
+ const socket_addr_type* addr, std::size_t addrlen,
+ asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ // Send the data.
+ DWORD send_buf_count = static_cast<DWORD>(count);
+ DWORD bytes_transferred = 0;
+ int result = error_wrapper(::WSASendTo(s, const_cast<buf*>(bufs),
+ send_buf_count, &bytes_transferred, flags, addr,
+ static_cast<int>(addrlen), 0, 0), ec);
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ ec = asio::error::connection_reset;
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ ec = asio::error::connection_refused;
+ if (result != 0)
+ return socket_error_retval;
+ ec = asio::error_code();
+ return bytes_transferred;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ init_msghdr_msg_name(msg.msg_name, addr);
+ msg.msg_namelen = addrlen;
+ msg.msg_iov = const_cast<buf*>(bufs);
+ msg.msg_iovlen = count;
+#if defined(__linux__)
+ flags |= MSG_NOSIGNAL;
+#endif // defined(__linux__)
+ int result = error_wrapper(::sendmsg(s, &msg, flags), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+ASIO_DECL
+size_t sync_sendto(socket_type s, state_type state, const buf* bufs,
+ size_t count, int flags, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Write some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ int bytes = socket_ops::sendto(s, bufs, count, flags, addr, addrlen, ec);
+
+ // Check if operation succeeded.
+ if (bytes >= 0)
+ return bytes;
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_write(s, ec) < 0)
+ return 0;
+ }
+}
+
+#if !defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+bool non_blocking_sendto(socket_type s,
+ const buf* bufs, size_t count, int flags,
+ const socket_addr_type* addr, std::size_t addrlen,
+ asio::error_code& ec, size_t& bytes_transferred)
+{
+ for (;;)
+ {
+ // Write some data.
+ int bytes = socket_ops::sendto(s, bufs, count, flags, addr, addrlen, ec);
+
+ // Retry operation if interrupted by signal.
+ if (ec == asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes >= 0)
+ {
+ ec = asio::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+#endif // !defined(ASIO_HAS_IOCP)
+
+ASIO_DECL
+socket_type socket(int af, int type, int protocol,
+ asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0,
+ WSA_FLAG_OVERLAPPED), ec);
+ if (s == invalid_socket)
+ return s;
+
+ if (af == AF_INET6)
+ {
+ // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to
+ // false. This will only succeed on Windows Vista and later versions of
+ // Windows, where a dual-stack IPv4/v6 implementation is available.
+ DWORD optval = 0;
+ ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
+ reinterpret_cast<const char*>(&optval), sizeof(optval));
+ }
+
+ ec = asio::error_code();
+
+ return s;
+#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
+ socket_type s = error_wrapper(::socket(af, type, protocol), ec);
+ if (s == invalid_socket)
+ return s;
+
+ int optval = 1;
+ int result = error_wrapper(::setsockopt(s,
+ SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
+ if (result != 0)
+ {
+ ::close(s);
+ return invalid_socket;
+ }
+
+ return s;
+#else
+ int s = error_wrapper(::socket(af, type, protocol), ec);
+ if (s >= 0)
+ ec = asio::error_code();
+ return s;
+#endif
+}
+
+template <typename SockLenType>
+inline int call_setsockopt(SockLenType msghdr::*,
+ socket_type s, int level, int optname,
+ const void* optval, std::size_t optlen)
+{
+ return ::setsockopt(s, level, optname,
+ (const char*)optval, (SockLenType)optlen);
+}
+
+ASIO_DECL
+int setsockopt(socket_type s, state_type& state, int level, int optname,
+ const void* optval, std::size_t optlen, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+ if (level == custom_socket_option_level && optname == always_fail_option)
+ {
+ ec = asio::error::invalid_argument;
+ return socket_error_retval;
+ }
+
+ if (level == custom_socket_option_level
+ && optname == enable_connection_aborted_option)
+ {
+ if (optlen != sizeof(int))
+ {
+ ec = asio::error::invalid_argument;
+ return socket_error_retval;
+ }
+
+ if (*static_cast<const int*>(optval))
+ state |= enable_connection_aborted;
+ else
+ state &= ~enable_connection_aborted;
+ ec = asio::error_code();
+ return 0;
+ }
+
+ if (level == SOL_SOCKET && optname == SO_LINGER)
+ state |= user_set_linger;
+
+#if defined(__BORLANDC__)
+ // Mysteriously, using the getsockopt and setsockopt functions directly with
+ // Borland C++ results in incorrect values being set and read. The bug can be
+ // worked around by using function addresses resolved with GetProcAddress.
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int);
+ if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt"))
+ {
+ clear_last_error();
+ return error_wrapper(sso(s, level, optname,
+ reinterpret_cast<const char*>(optval),
+ static_cast<int>(optlen)), ec);
+ }
+ }
+ ec = asio::error::fault;
+ return socket_error_retval;
+#else // defined(__BORLANDC__)
+ clear_last_error();
+ int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen,
+ s, level, optname, optval, optlen), ec);
+ if (result == 0)
+ {
+ ec = asio::error_code();
+
+#if defined(__MACH__) && defined(__APPLE__) \
+ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+ // To implement portable behaviour for SO_REUSEADDR with UDP sockets we
+ // need to also set SO_REUSEPORT on BSD-based platforms.
+ if ((state & datagram_oriented)
+ && level == SOL_SOCKET && optname == SO_REUSEADDR)
+ {
+ call_setsockopt(&msghdr::msg_namelen, s,
+ SOL_SOCKET, SO_REUSEPORT, optval, optlen);
+ }
+#endif
+ }
+
+ return result;
+#endif // defined(__BORLANDC__)
+}
+
+template <typename SockLenType>
+inline int call_getsockopt(SockLenType msghdr::*,
+ socket_type s, int level, int optname,
+ void* optval, std::size_t* optlen)
+{
+ SockLenType tmp_optlen = (SockLenType)*optlen;
+ int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen);
+ *optlen = (std::size_t)tmp_optlen;
+ return result;
+}
+
+ASIO_DECL
+int getsockopt(socket_type s, state_type state, int level, int optname,
+ void* optval, size_t* optlen, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+ if (level == custom_socket_option_level && optname == always_fail_option)
+ {
+ ec = asio::error::invalid_argument;
+ return socket_error_retval;
+ }
+
+ if (level == custom_socket_option_level
+ && optname == enable_connection_aborted_option)
+ {
+ if (*optlen != sizeof(int))
+ {
+ ec = asio::error::invalid_argument;
+ return socket_error_retval;
+ }
+
+ *static_cast<int*>(optval) = (state & enable_connection_aborted) ? 1 : 0;
+ ec = asio::error_code();
+ return 0;
+ }
+
+#if defined(__BORLANDC__)
+ // Mysteriously, using the getsockopt and setsockopt functions directly with
+ // Borland C++ results in incorrect values being set and read. The bug can be
+ // worked around by using function addresses resolved with GetProcAddress.
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*);
+ if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt"))
+ {
+ clear_last_error();
+ int tmp_optlen = static_cast<int>(*optlen);
+ int result = error_wrapper(gso(s, level, optname,
+ reinterpret_cast<char*>(optval), &tmp_optlen), ec);
+ *optlen = static_cast<size_t>(tmp_optlen);
+ if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
+ && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
+ {
+ // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are
+ // only supported on Windows Vista and later. To simplify program logic
+ // we will fake success of getting this option and specify that the
+ // value is non-zero (i.e. true). This corresponds to the behavior of
+ // IPv6 sockets on Windows platforms pre-Vista.
+ *static_cast<DWORD*>(optval) = 1;
+ ec = asio::error_code();
+ }
+ return result;
+ }
+ }
+ ec = asio::error::fault;
+ return socket_error_retval;
+#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ clear_last_error();
+ int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
+ s, level, optname, optval, optlen), ec);
+ if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
+ && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
+ {
+ // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only
+ // supported on Windows Vista and later. To simplify program logic we will
+ // fake success of getting this option and specify that the value is
+ // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets
+ // on Windows platforms pre-Vista.
+ *static_cast<DWORD*>(optval) = 1;
+ ec = asio::error_code();
+ }
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ clear_last_error();
+ int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
+ s, level, optname, optval, optlen), ec);
+#if defined(__linux__)
+ if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int)
+ && (optname == SO_SNDBUF || optname == SO_RCVBUF))
+ {
+ // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel
+ // to set the buffer size to N*2. Linux puts additional stuff into the
+ // buffers so that only about half is actually available to the application.
+ // The retrieved value is divided by 2 here to make it appear as though the
+ // correct value has been set.
+ *static_cast<int*>(optval) /= 2;
+ }
+#endif // defined(__linux__)
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+template <typename SockLenType>
+inline int call_getpeername(SockLenType msghdr::*,
+ socket_type s, socket_addr_type* addr, std::size_t* addrlen)
+{
+ SockLenType tmp_addrlen = (SockLenType)*addrlen;
+ int result = ::getpeername(s, addr, &tmp_addrlen);
+ *addrlen = (std::size_t)tmp_addrlen;
+ return result;
+}
+
+ASIO_DECL
+int getpeername(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, bool cached, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ if (cached)
+ {
+ // Check if socket is still connected.
+ DWORD connect_time = 0;
+ size_t connect_time_len = sizeof(connect_time);
+ if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_CONNECT_TIME,
+ &connect_time, &connect_time_len, ec) == socket_error_retval)
+ {
+ return socket_error_retval;
+ }
+ if (connect_time == 0xFFFFFFFF)
+ {
+ ec = asio::error::not_connected;
+ return socket_error_retval;
+ }
+
+ // The cached value is still valid.
+ ec = asio::error_code();
+ return 0;
+ }
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ (void)cached;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+ clear_last_error();
+ int result = error_wrapper(call_getpeername(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+}
+
+template <typename SockLenType>
+inline int call_getsockname(SockLenType msghdr::*,
+ socket_type s, socket_addr_type* addr, std::size_t* addrlen)
+{
+ SockLenType tmp_addrlen = (SockLenType)*addrlen;
+ int result = ::getsockname(s, addr, &tmp_addrlen);
+ *addrlen = (std::size_t)tmp_addrlen;
+ return result;
+}
+
+ASIO_DECL
+int getsockname(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+ clear_last_error();
+ int result = error_wrapper(call_getsockname(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+}
+
+ASIO_DECL
+int ioctl(socket_type s, state_type& state, int cmd,
+ ioctl_arg_type* arg, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+ clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec);
+#elif defined(__MACH__) && defined(__APPLE__) \
+ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+ int result = error_wrapper(::ioctl(s,
+ static_cast<unsigned int>(cmd), arg), ec);
+#else
+ int result = error_wrapper(::ioctl(s, cmd, arg), ec);
+#endif
+ if (result >= 0)
+ {
+ ec = asio::error_code();
+
+ // When updating the non-blocking mode we always perform the ioctl syscall,
+ // even if the flags would otherwise indicate that the socket is already in
+ // the correct state. This ensures that the underlying socket is put into
+ // the state that has been requested by the user. If the ioctl syscall was
+ // successful then we need to update the flags to match.
+ if (cmd == static_cast<int>(FIONBIO))
+ {
+ if (*arg)
+ {
+ state |= user_set_non_blocking;
+ }
+ else
+ {
+ // Clearing the non-blocking mode always overrides any internally-set
+ // non-blocking flag. Any subsequent asynchronous operations will need
+ // to re-enable non-blocking I/O.
+ state &= ~(user_set_non_blocking | internal_non_blocking);
+ }
+ }
+ }
+
+ return result;
+}
+
+ASIO_DECL
+int select(int nfds, fd_set* readfds, fd_set* writefds,
+ fd_set* exceptfds, timeval* timeout, asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ if (!readfds && !writefds && !exceptfds && timeout)
+ {
+ DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
+ if (milliseconds == 0)
+ milliseconds = 1; // Force context switch.
+ ::Sleep(milliseconds);
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // The select() call allows timeout values measured in microseconds, but the
+ // system clock (as wrapped by boost::posix_time::microsec_clock) typically
+ // has a resolution of 10 milliseconds. This can lead to a spinning select
+ // reactor, meaning increased CPU usage, when waiting for the earliest
+ // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight
+ // spin we'll use a minimum timeout of 1 millisecond.
+ if (timeout && timeout->tv_sec == 0
+ && timeout->tv_usec > 0 && timeout->tv_usec < 1000)
+ timeout->tv_usec = 1000;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#if defined(__hpux) && defined(__SELECT)
+ timespec ts;
+ ts.tv_sec = timeout ? timeout->tv_sec : 0;
+ ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0;
+ return error_wrapper(::pselect(nfds, readfds,
+ writefds, exceptfds, timeout ? &ts : 0, 0), ec);
+#else
+ int result = error_wrapper(::select(nfds, readfds,
+ writefds, exceptfds, timeout), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#endif
+}
+
+ASIO_DECL
+int poll_read(socket_type s, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+#if defined(BOOST_WINDOWS) \
+ || defined(__CYGWIN__) \
+ || defined(__SYMBIAN32__)
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(s, &fds);
+ clear_last_error();
+ int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#else // defined(BOOST_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+ pollfd fds;
+ fds.fd = s;
+ fds.events = POLLIN;
+ fds.revents = 0;
+ clear_last_error();
+ int result = error_wrapper(::poll(&fds, 1, -1), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#endif // defined(BOOST_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+}
+
+ASIO_DECL
+int poll_write(socket_type s, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+#if defined(BOOST_WINDOWS) \
+ || defined(__CYGWIN__) \
+ || defined(__SYMBIAN32__)
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(s, &fds);
+ clear_last_error();
+ int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#else // defined(BOOST_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+ pollfd fds;
+ fds.fd = s;
+ fds.events = POLLOUT;
+ fds.revents = 0;
+ clear_last_error();
+ int result = error_wrapper(::poll(&fds, 1, -1), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#endif // defined(BOOST_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+}
+
+ASIO_DECL
+int poll_connect(socket_type s, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+#if defined(BOOST_WINDOWS) \
+ || defined(__CYGWIN__) \
+ || defined(__SYMBIAN32__)
+ fd_set write_fds;
+ FD_ZERO(&write_fds);
+ FD_SET(s, &write_fds);
+ fd_set except_fds;
+ FD_ZERO(&except_fds);
+ FD_SET(s, &except_fds);
+ clear_last_error();
+ int result = error_wrapper(::select(s, 0, &write_fds, &except_fds, 0), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#else // defined(BOOST_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+ pollfd fds;
+ fds.fd = s;
+ fds.events = POLLOUT;
+ fds.revents = 0;
+ clear_last_error();
+ int result = error_wrapper(::poll(&fds, 1, -1), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#endif // defined(BOOST_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+}
+
+ASIO_DECL
+const char* inet_ntop(int af, const void* src, char* dest, size_t length,
+ unsigned long scope_id, asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ using namespace std; // For memcpy.
+
+ if (af != AF_INET && af != AF_INET6)
+ {
+ ec = asio::error::address_family_not_supported;
+ return 0;
+ }
+
+ union
+ {
+ socket_addr_type base;
+ sockaddr_storage_type storage;
+ sockaddr_in4_type v4;
+ sockaddr_in6_type v6;
+ } address;
+ DWORD address_length;
+ if (af == AF_INET)
+ {
+ address_length = sizeof(sockaddr_in4_type);
+ address.v4.sin_family = AF_INET;
+ address.v4.sin_port = 0;
+ memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type));
+ }
+ else // AF_INET6
+ {
+ address_length = sizeof(sockaddr_in6_type);
+ address.v6.sin6_family = AF_INET6;
+ address.v6.sin6_port = 0;
+ address.v6.sin6_flowinfo = 0;
+ address.v6.sin6_scope_id = scope_id;
+ memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type));
+ }
+
+ DWORD string_length = static_cast<DWORD>(length);
+#if defined(BOOST_NO_ANSI_APIS)
+ LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR));
+ int result = error_wrapper(::WSAAddressToStringW(&address.base,
+ address_length, 0, string_buffer, &string_length), ec);
+ ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0);
+#else
+ int result = error_wrapper(::WSAAddressToStringA(
+ &address.base, address_length, 0, dest, &string_length), ec);
+#endif
+
+ // Windows may set error code on success.
+ if (result != socket_error_retval)
+ ec = asio::error_code();
+
+ // Windows may not set an error code on failure.
+ else if (result == socket_error_retval && !ec)
+ ec = asio::error::invalid_argument;
+
+ return result == socket_error_retval ? 0 : dest;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec);
+ if (result == 0 && !ec)
+ ec = asio::error::invalid_argument;
+ if (result != 0 && af == AF_INET6 && scope_id != 0)
+ {
+ using namespace std; // For strcat and sprintf.
+ char if_name[IF_NAMESIZE + 1] = "%";
+ const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src);
+ bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
+ if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0)
+ sprintf(if_name + 1, "%lu", scope_id);
+ strcat(dest, if_name);
+ }
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+ASIO_DECL
+int inet_pton(int af, const char* src, void* dest,
+ unsigned long* scope_id, asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ using namespace std; // For memcpy and strcmp.
+
+ if (af != AF_INET && af != AF_INET6)
+ {
+ ec = asio::error::address_family_not_supported;
+ return -1;
+ }
+
+ union
+ {
+ socket_addr_type base;
+ sockaddr_storage_type storage;
+ sockaddr_in4_type v4;
+ sockaddr_in6_type v6;
+ } address;
+ int address_length = sizeof(sockaddr_storage_type);
+#if defined(BOOST_NO_ANSI_APIS)
+ int num_wide_chars = strlen(src) + 1;
+ LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR));
+ ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars);
+ int result = error_wrapper(::WSAStringToAddressW(
+ wide_buffer, af, 0, &address.base, &address_length), ec);
+#else
+ int result = error_wrapper(::WSAStringToAddressA(
+ const_cast<char*>(src), af, 0, &address.base, &address_length), ec);
+#endif
+
+ if (af == AF_INET)
+ {
+ if (result != socket_error_retval)
+ {
+ memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type));
+ ec = asio::error_code();
+ }
+ else if (strcmp(src, "255.255.255.255") == 0)
+ {
+ static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE;
+ ec = asio::error_code();
+ }
+ }
+ else // AF_INET6
+ {
+ if (result != socket_error_retval)
+ {
+ memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type));
+ if (scope_id)
+ *scope_id = address.v6.sin6_scope_id;
+ ec = asio::error_code();
+ }
+ }
+
+ // Windows may not set an error code on failure.
+ if (result == socket_error_retval && !ec)
+ ec = asio::error::invalid_argument;
+
+ if (result != socket_error_retval)
+ ec = asio::error_code();
+
+ return result == socket_error_retval ? -1 : 1;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::inet_pton(af, src, dest), ec);
+ if (result <= 0 && !ec)
+ ec = asio::error::invalid_argument;
+ if (result > 0 && af == AF_INET6 && scope_id)
+ {
+ using namespace std; // For strchr and atoi.
+ *scope_id = 0;
+ if (const char* if_name = strchr(src, '%'))
+ {
+ in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest);
+ bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
+ if (is_link_local)
+ *scope_id = if_nametoindex(if_name + 1);
+ if (*scope_id == 0)
+ *scope_id = atoi(if_name + 1);
+ }
+ }
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+ASIO_DECL
+int gethostname(char* name, int namelen, asio::error_code& ec)
+{
+ clear_last_error();
+ int result = error_wrapper(::gethostname(name, namelen), ec);
+#if defined(BOOST_WINDOWS)
+ if (result == 0)
+ ec = asio::error_code();
+#endif
+ return result;
+}
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \
+ || defined(__MACH__) && defined(__APPLE__)
+
+// The following functions are only needed for emulation of getaddrinfo and
+// getnameinfo.
+
+inline asio::error_code translate_netdb_error(int error)
+{
+ switch (error)
+ {
+ case 0:
+ return asio::error_code();
+ case HOST_NOT_FOUND:
+ return asio::error::host_not_found;
+ case TRY_AGAIN:
+ return asio::error::host_not_found_try_again;
+ case NO_RECOVERY:
+ return asio::error::no_recovery;
+ case NO_DATA:
+ return asio::error::no_data;
+ default:
+ BOOST_ASSERT(false);
+ return asio::error::invalid_argument;
+ }
+}
+
+inline hostent* gethostbyaddr(const char* addr, int length, int af,
+ hostent* result, char* buffer, int buflength, asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ (void)(buffer);
+ (void)(buflength);
+ hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec);
+ if (!retval)
+ return 0;
+ ec = asio::error_code();
+ *result = *retval;
+ return retval;
+#elif defined(__sun) || defined(__QNX__)
+ int error = 0;
+ hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result,
+ buffer, buflength, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ return retval;
+#elif defined(__MACH__) && defined(__APPLE__)
+ (void)(buffer);
+ (void)(buflength);
+ int error = 0;
+ hostent* retval = error_wrapper(::getipnodebyaddr(
+ addr, length, af, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ if (!retval)
+ return 0;
+ *result = *retval;
+ return retval;
+#else
+ hostent* retval = 0;
+ int error = 0;
+ error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer,
+ buflength, &retval, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ return retval;
+#endif
+}
+
+inline hostent* gethostbyname(const char* name, int af, struct hostent* result,
+ char* buffer, int buflength, int ai_flags, asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ (void)(buffer);
+ (void)(buflength);
+ (void)(ai_flags);
+ if (af != AF_INET)
+ {
+ ec = asio::error::address_family_not_supported;
+ return 0;
+ }
+ hostent* retval = error_wrapper(::gethostbyname(name), ec);
+ if (!retval)
+ return 0;
+ ec = asio::error_code();
+ *result = *retval;
+ return result;
+#elif defined(__sun) || defined(__QNX__)
+ (void)(ai_flags);
+ if (af != AF_INET)
+ {
+ ec = asio::error::address_family_not_supported;
+ return 0;
+ }
+ int error = 0;
+ hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer,
+ buflength, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ return retval;
+#elif defined(__MACH__) && defined(__APPLE__)
+ (void)(buffer);
+ (void)(buflength);
+ int error = 0;
+ hostent* retval = error_wrapper(::getipnodebyname(
+ name, af, ai_flags, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ if (!retval)
+ return 0;
+ *result = *retval;
+ return retval;
+#else
+ (void)(ai_flags);
+ if (af != AF_INET)
+ {
+ ec = asio::error::address_family_not_supported;
+ return 0;
+ }
+ hostent* retval = 0;
+ int error = 0;
+ error_wrapper(::gethostbyname_r(name, result,
+ buffer, buflength, &retval, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ return retval;
+#endif
+}
+
+inline void freehostent(hostent* h)
+{
+#if defined(__MACH__) && defined(__APPLE__)
+ if (h)
+ ::freehostent(h);
+#else
+ (void)(h);
+#endif
+}
+
+// Emulation of getaddrinfo based on implementation in:
+// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998.
+
+struct gai_search
+{
+ const char* host;
+ int family;
+};
+
+inline int gai_nsearch(const char* host,
+ const addrinfo_type* hints, gai_search (&search)[2])
+{
+ int search_count = 0;
+ if (host == 0 || host[0] == '\0')
+ {
+ if (hints->ai_flags & AI_PASSIVE)
+ {
+ // No host and AI_PASSIVE implies wildcard bind.
+ switch (hints->ai_family)
+ {
+ case AF_INET:
+ search[search_count].host = "0.0.0.0";
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ case AF_INET6:
+ search[search_count].host = "0::0";
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ break;
+ case AF_UNSPEC:
+ search[search_count].host = "0::0";
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ search[search_count].host = "0.0.0.0";
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // No host and not AI_PASSIVE means connect to local host.
+ switch (hints->ai_family)
+ {
+ case AF_INET:
+ search[search_count].host = "localhost";
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ case AF_INET6:
+ search[search_count].host = "localhost";
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ break;
+ case AF_UNSPEC:
+ search[search_count].host = "localhost";
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ search[search_count].host = "localhost";
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ // Host is specified.
+ switch (hints->ai_family)
+ {
+ case AF_INET:
+ search[search_count].host = host;
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ case AF_INET6:
+ search[search_count].host = host;
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ break;
+ case AF_UNSPEC:
+ search[search_count].host = host;
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ search[search_count].host = host;
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ default:
+ break;
+ }
+ }
+ return search_count;
+}
+
+template <typename T>
+inline T* gai_alloc(std::size_t size = sizeof(T))
+{
+ using namespace std;
+ T* p = static_cast<T*>(::operator new(size, std::nothrow));
+ if (p)
+ memset(p, 0, size);
+ return p;
+}
+
+inline void gai_free(void* p)
+{
+ ::operator delete(p);
+}
+
+inline void gai_strcpy(char* target, const char* source, std::size_t max_size)
+{
+ using namespace std;
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
+ strcpy_s(target, max_size, source);
+#else
+ *target = 0;
+ strncat(target, source, max_size);
+#endif
+}
+
+enum { gai_clone_flag = 1 << 30 };
+
+inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints,
+ const void* addr, int family)
+{
+ using namespace std;
+
+ addrinfo_type* ai = gai_alloc<addrinfo_type>();
+ if (ai == 0)
+ return EAI_MEMORY;
+
+ ai->ai_next = 0;
+ **next = ai;
+ *next = &ai->ai_next;
+
+ ai->ai_canonname = 0;
+ ai->ai_socktype = hints->ai_socktype;
+ if (ai->ai_socktype == 0)
+ ai->ai_flags |= gai_clone_flag;
+ ai->ai_protocol = hints->ai_protocol;
+ ai->ai_family = family;
+
+ switch (ai->ai_family)
+ {
+ case AF_INET:
+ {
+ sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>();
+ if (sinptr == 0)
+ return EAI_MEMORY;
+ sinptr->sin_family = AF_INET;
+ memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type));
+ ai->ai_addr = reinterpret_cast<sockaddr*>(sinptr);
+ ai->ai_addrlen = sizeof(sockaddr_in4_type);
+ break;
+ }
+ case AF_INET6:
+ {
+ sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>();
+ if (sin6ptr == 0)
+ return EAI_MEMORY;
+ sin6ptr->sin6_family = AF_INET6;
+ memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type));
+ ai->ai_addr = reinterpret_cast<sockaddr*>(sin6ptr);
+ ai->ai_addrlen = sizeof(sockaddr_in6_type);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+inline addrinfo_type* gai_clone(addrinfo_type* ai)
+{
+ using namespace std;
+
+ addrinfo_type* new_ai = gai_alloc<addrinfo_type>();
+ if (new_ai == 0)
+ return new_ai;
+
+ new_ai->ai_next = ai->ai_next;
+ ai->ai_next = new_ai;
+
+ new_ai->ai_flags = 0;
+ new_ai->ai_family = ai->ai_family;
+ new_ai->ai_socktype = ai->ai_socktype;
+ new_ai->ai_protocol = ai->ai_protocol;
+ new_ai->ai_canonname = 0;
+ new_ai->ai_addrlen = ai->ai_addrlen;
+ new_ai->ai_addr = gai_alloc<sockaddr>(ai->ai_addrlen);
+ memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen);
+
+ return new_ai;
+}
+
+inline int gai_port(addrinfo_type* aihead, int port, int socktype)
+{
+ int num_found = 0;
+
+ for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next)
+ {
+ if (ai->ai_flags & gai_clone_flag)
+ {
+ if (ai->ai_socktype != 0)
+ {
+ ai = gai_clone(ai);
+ if (ai == 0)
+ return -1;
+ // ai now points to newly cloned entry.
+ }
+ }
+ else if (ai->ai_socktype != socktype)
+ {
+ // Ignore if mismatch on socket type.
+ continue;
+ }
+
+ ai->ai_socktype = socktype;
+
+ switch (ai->ai_family)
+ {
+ case AF_INET:
+ {
+ sockaddr_in4_type* sinptr =
+ reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);
+ sinptr->sin_port = port;
+ ++num_found;
+ break;
+ }
+ case AF_INET6:
+ {
+ sockaddr_in6_type* sin6ptr =
+ reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);
+ sin6ptr->sin6_port = port;
+ ++num_found;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ return num_found;
+}
+
+inline int gai_serv(addrinfo_type* aihead,
+ const addrinfo_type* hints, const char* serv)
+{
+ using namespace std;
+
+ int num_found = 0;
+
+ if (
+#if defined(AI_NUMERICSERV)
+ (hints->ai_flags & AI_NUMERICSERV) ||
+#endif
+ isdigit(static_cast<unsigned char>(serv[0])))
+ {
+ int port = htons(atoi(serv));
+ if (hints->ai_socktype)
+ {
+ // Caller specifies socket type.
+ int rc = gai_port(aihead, port, hints->ai_socktype);
+ if (rc < 0)
+ return EAI_MEMORY;
+ num_found += rc;
+ }
+ else
+ {
+ // Caller does not specify socket type.
+ int rc = gai_port(aihead, port, SOCK_STREAM);
+ if (rc < 0)
+ return EAI_MEMORY;
+ num_found += rc;
+ rc = gai_port(aihead, port, SOCK_DGRAM);
+ if (rc < 0)
+ return EAI_MEMORY;
+ num_found += rc;
+ }
+ }
+ else
+ {
+ // Try service name with TCP first, then UDP.
+ if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM)
+ {
+ servent* sptr = getservbyname(serv, "tcp");
+ if (sptr != 0)
+ {
+ int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM);
+ if (rc < 0)
+ return EAI_MEMORY;
+ num_found += rc;
+ }
+ }
+ if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM)
+ {
+ servent* sptr = getservbyname(serv, "udp");
+ if (sptr != 0)
+ {
+ int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM);
+ if (rc < 0)
+ return EAI_MEMORY;
+ num_found += rc;
+ }
+ }
+ }
+
+ if (num_found == 0)
+ {
+ if (hints->ai_socktype == 0)
+ {
+ // All calls to getservbyname() failed.
+ return EAI_NONAME;
+ }
+ else
+ {
+ // Service not supported for socket type.
+ return EAI_SERVICE;
+ }
+ }
+
+ return 0;
+}
+
+inline int gai_echeck(const char* host, const char* service,
+ int flags, int family, int socktype, int protocol)
+{
+ (void)(flags);
+ (void)(protocol);
+
+ // Host or service must be specified.
+ if (host == 0 || host[0] == '\0')
+ if (service == 0 || service[0] == '\0')
+ return EAI_NONAME;
+
+ // Check combination of family and socket type.
+ switch (family)
+ {
+ case AF_UNSPEC:
+ break;
+ case AF_INET:
+ case AF_INET6:
+ if (service != 0 && service[0] != '\0')
+ if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
+ return EAI_SOCKTYPE;
+ break;
+ default:
+ return EAI_FAMILY;
+ }
+
+ return 0;
+}
+
+inline void freeaddrinfo_emulation(addrinfo_type* aihead)
+{
+ addrinfo_type* ai = aihead;
+ while (ai)
+ {
+ gai_free(ai->ai_addr);
+ gai_free(ai->ai_canonname);
+ addrinfo_type* ainext = ai->ai_next;
+ gai_free(ai);
+ ai = ainext;
+ }
+}
+
+inline int getaddrinfo_emulation(const char* host, const char* service,
+ const addrinfo_type* hintsp, addrinfo_type** result)
+{
+ // Set up linked list of addrinfo structures.
+ addrinfo_type* aihead = 0;
+ addrinfo_type** ainext = &aihead;
+ char* canon = 0;
+
+ // Supply default hints if not specified by caller.
+ addrinfo_type hints = addrinfo_type();
+ hints.ai_family = AF_UNSPEC;
+ if (hintsp)
+ hints = *hintsp;
+
+ // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED
+ // and AI_ALL flags.
+#if defined(AI_V4MAPPED)
+ if (hints.ai_family != AF_INET6)
+ hints.ai_flags &= ~AI_V4MAPPED;
+#endif
+#if defined(AI_ALL)
+ if (hints.ai_family != AF_INET6)
+ hints.ai_flags &= ~AI_ALL;
+#endif
+
+ // Basic error checking.
+ int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family,
+ hints.ai_socktype, hints.ai_protocol);
+ if (rc != 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ return rc;
+ }
+
+ gai_search search[2];
+ int search_count = gai_nsearch(host, &hints, search);
+ for (gai_search* sptr = search; sptr < search + search_count; ++sptr)
+ {
+ // Check for IPv4 dotted decimal string.
+ in4_addr_type inaddr;
+ asio::error_code ec;
+ if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1)
+ {
+ if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ return EAI_FAMILY;
+ }
+ if (sptr->family == AF_INET)
+ {
+ rc = gai_aistruct(&ainext, &hints, &inaddr, AF_INET);
+ if (rc != 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ return rc;
+ }
+ }
+ continue;
+ }
+
+ // Check for IPv6 hex string.
+ in6_addr_type in6addr;
+ if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr, 0, ec) == 1)
+ {
+ if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ return EAI_FAMILY;
+ }
+ if (sptr->family == AF_INET6)
+ {
+ rc = gai_aistruct(&ainext, &hints, &in6addr, AF_INET6);
+ if (rc != 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ return rc;
+ }
+ }
+ continue;
+ }
+
+ // Look up hostname.
+ hostent hent;
+ char hbuf[8192] = "";
+ hostent* hptr = socket_ops::gethostbyname(sptr->host,
+ sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec);
+ if (hptr == 0)
+ {
+ if (search_count == 2)
+ {
+ // Failure is OK if there are multiple searches.
+ continue;
+ }
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ if (ec == asio::error::host_not_found)
+ return EAI_NONAME;
+ if (ec == asio::error::host_not_found_try_again)
+ return EAI_AGAIN;
+ if (ec == asio::error::no_recovery)
+ return EAI_FAIL;
+ if (ec == asio::error::no_data)
+ return EAI_NONAME;
+ return EAI_NONAME;
+ }
+
+ // Check for address family mismatch if one was specified.
+ if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ socket_ops::freehostent(hptr);
+ return EAI_FAMILY;
+ }
+
+ // Save canonical name first time.
+ if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0]
+ && (hints.ai_flags & AI_CANONNAME) && canon == 0)
+ {
+ std::size_t canon_len = strlen(hptr->h_name) + 1;
+ canon = gai_alloc<char>(canon_len);
+ if (canon == 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ socket_ops::freehostent(hptr);
+ return EAI_MEMORY;
+ }
+ gai_strcpy(canon, hptr->h_name, canon_len);
+ }
+
+ // Create an addrinfo structure for each returned address.
+ for (char** ap = hptr->h_addr_list; *ap; ++ap)
+ {
+ rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype);
+ if (rc != 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ socket_ops::freehostent(hptr);
+ return EAI_FAMILY;
+ }
+ }
+
+ socket_ops::freehostent(hptr);
+ }
+
+ // Check if we found anything.
+ if (aihead == 0)
+ {
+ gai_free(canon);
+ return EAI_NONAME;
+ }
+
+ // Return canonical name in first entry.
+ if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME))
+ {
+ if (canon)
+ {
+ aihead->ai_canonname = canon;
+ canon = 0;
+ }
+ else
+ {
+ std::size_t canonname_len = strlen(search[0].host) + 1;
+ aihead->ai_canonname = gai_alloc<char>(canonname_len);
+ if (aihead->ai_canonname == 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ return EAI_MEMORY;
+ }
+ gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len);
+ }
+ }
+ gai_free(canon);
+
+ // Process the service name.
+ if (service != 0 && service[0] != '\0')
+ {
+ rc = gai_serv(aihead, &hints, service);
+ if (rc != 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ return rc;
+ }
+ }
+
+ // Return result to caller.
+ *result = aihead;
+ return 0;
+}
+
+inline asio::error_code getnameinfo_emulation(
+ const socket_addr_type* sa, std::size_t salen, char* host,
+ std::size_t hostlen, char* serv, std::size_t servlen, int flags,
+ asio::error_code& ec)
+{
+ using namespace std;
+
+ const char* addr;
+ size_t addr_len;
+ unsigned short port;
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ if (salen != sizeof(sockaddr_in4_type))
+ {
+ return ec = asio::error::invalid_argument;
+ }
+ addr = reinterpret_cast<const char*>(
+ &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr);
+ addr_len = sizeof(in4_addr_type);
+ port = reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_port;
+ break;
+ case AF_INET6:
+ if (salen != sizeof(sockaddr_in6_type))
+ {
+ return ec = asio::error::invalid_argument;
+ }
+ addr = reinterpret_cast<const char*>(
+ &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr);
+ addr_len = sizeof(in6_addr_type);
+ port = reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_port;
+ break;
+ default:
+ return ec = asio::error::address_family_not_supported;
+ }
+
+ if (host && hostlen > 0)
+ {
+ if (flags & NI_NUMERICHOST)
+ {
+ if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0)
+ {
+ return ec;
+ }
+ }
+ else
+ {
+ hostent hent;
+ char hbuf[8192] = "";
+ hostent* hptr = socket_ops::gethostbyaddr(addr,
+ static_cast<int>(addr_len), sa->sa_family,
+ &hent, hbuf, sizeof(hbuf), ec);
+ if (hptr && hptr->h_name && hptr->h_name[0] != '\0')
+ {
+ if (flags & NI_NOFQDN)
+ {
+ char* dot = strchr(hptr->h_name, '.');
+ if (dot)
+ {
+ *dot = 0;
+ }
+ }
+ gai_strcpy(host, hptr->h_name, hostlen);
+ socket_ops::freehostent(hptr);
+ }
+ else
+ {
+ socket_ops::freehostent(hptr);
+ if (flags & NI_NAMEREQD)
+ {
+ return ec = asio::error::host_not_found;
+ }
+ if (socket_ops::inet_ntop(sa->sa_family,
+ addr, host, hostlen, 0, ec) == 0)
+ {
+ return ec;
+ }
+ }
+ }
+ }
+
+ if (serv && servlen > 0)
+ {
+ if (flags & NI_NUMERICSERV)
+ {
+ if (servlen < 6)
+ {
+ return ec = asio::error::no_buffer_space;
+ }
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
+ sprintf_s(serv, servlen, "%u", ntohs(port));
+#else
+ sprintf(serv, "%u", ntohs(port));
+#endif
+ }
+ else
+ {
+#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) \
+ && !defined(ASIO_DISABLE_THREADS)
+ static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ ::pthread_mutex_lock(&mutex);
+#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
+ // && !defined(ASIO_DISABLE_THREADS)
+ servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0);
+ if (sptr && sptr->s_name && sptr->s_name[0] != '\0')
+ {
+ gai_strcpy(serv, sptr->s_name, servlen);
+ }
+ else
+ {
+ if (servlen < 6)
+ {
+ return ec = asio::error::no_buffer_space;
+ }
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
+ sprintf_s(serv, servlen, "%u", ntohs(port));
+#else
+ sprintf(serv, "%u", ntohs(port));
+#endif
+ }
+#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) \
+ && !defined(ASIO_DISABLE_THREADS)
+ ::pthread_mutex_unlock(&mutex);
+#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
+ // && !defined(ASIO_DISABLE_THREADS)
+ }
+ }
+
+ ec = asio::error_code();
+ return ec;
+}
+
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ // || defined(__MACH__) && defined(__APPLE__)
+
+inline asio::error_code translate_addrinfo_error(int error)
+{
+ switch (error)
+ {
+ case 0:
+ return asio::error_code();
+ case EAI_AGAIN:
+ return asio::error::host_not_found_try_again;
+ case EAI_BADFLAGS:
+ return asio::error::invalid_argument;
+ case EAI_FAIL:
+ return asio::error::no_recovery;
+ case EAI_FAMILY:
+ return asio::error::address_family_not_supported;
+ case EAI_MEMORY:
+ return asio::error::no_memory;
+ case EAI_NONAME:
+#if defined(EAI_ADDRFAMILY)
+ case EAI_ADDRFAMILY:
+#endif
+#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
+ case EAI_NODATA:
+#endif
+ return asio::error::host_not_found;
+ case EAI_SERVICE:
+ return asio::error::service_not_found;
+ case EAI_SOCKTYPE:
+ return asio::error::socket_type_not_supported;
+ default: // Possibly the non-portable EAI_SYSTEM.
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ return asio::error_code(
+ WSAGetLastError(), asio::error::get_system_category());
+#else
+ return asio::error_code(
+ errno, asio::error::get_system_category());
+#endif
+ }
+}
+
+ASIO_DECL
+asio::error_code getaddrinfo(const char* host,
+ const char* service, const addrinfo_type& hints,
+ addrinfo_type** result, asio::error_code& ec)
+{
+ host = (host && *host) ? host : 0;
+ service = (service && *service) ? service : 0;
+ clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
+ // Building for Windows XP, Windows Server 2003, or later.
+ int error = ::getaddrinfo(host, service, &hints, result);
+ return ec = translate_addrinfo_error(error);
+# else
+ // Building for Windows 2000 or earlier.
+ typedef int (WSAAPI *gai_t)(const char*,
+ const char*, const addrinfo_type*, addrinfo_type**);
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo"))
+ {
+ int error = gai(host, service, &hints, result);
+ return ec = translate_addrinfo_error(error);
+ }
+ }
+ int error = getaddrinfo_emulation(host, service, &hints, result);
+ return ec = translate_addrinfo_error(error);
+# endif
+#elif defined(__MACH__) && defined(__APPLE__)
+ int error = getaddrinfo_emulation(host, service, &hints, result);
+ return ec = translate_addrinfo_error(error);
+#else
+ int error = ::getaddrinfo(host, service, &hints, result);
+ return ec = translate_addrinfo_error(error);
+#endif
+}
+
+ASIO_DECL
+asio::error_code background_getaddrinfo(
+ const weak_cancel_token_type& cancel_token, const char* host,
+ const char* service, const addrinfo_type& hints,
+ addrinfo_type** result, asio::error_code& ec)
+{
+ if (cancel_token.expired())
+ ec = asio::error::operation_aborted;
+ else
+ socket_ops::getaddrinfo(host, service, hints, result, ec);
+ return ec;
+}
+
+ASIO_DECL
+void freeaddrinfo(addrinfo_type* ai)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
+ // Building for Windows XP, Windows Server 2003, or later.
+ ::freeaddrinfo(ai);
+# else
+ // Building for Windows 2000 or earlier.
+ typedef int (WSAAPI *fai_t)(addrinfo_type*);
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo"))
+ {
+ fai(ai);
+ return;
+ }
+ }
+ freeaddrinfo_emulation(ai);
+# endif
+#elif defined(__MACH__) && defined(__APPLE__)
+ freeaddrinfo_emulation(ai);
+#else
+ ::freeaddrinfo(ai);
+#endif
+}
+
+ASIO_DECL
+asio::error_code getnameinfo(const socket_addr_type* addr,
+ std::size_t addrlen, char* host, std::size_t hostlen,
+ char* serv, std::size_t servlen, int flags, asio::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
+ // Building for Windows XP, Windows Server 2003, or later.
+ clear_last_error();
+ int error = ::getnameinfo(addr, static_cast<socklen_t>(addrlen),
+ host, static_cast<DWORD>(hostlen),
+ serv, static_cast<DWORD>(servlen), flags);
+ return ec = translate_addrinfo_error(error);
+# else
+ // Building for Windows 2000 or earlier.
+ typedef int (WSAAPI *gni_t)(const socket_addr_type*,
+ int, char*, DWORD, char*, DWORD, int);
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo"))
+ {
+ clear_last_error();
+ int error = gni(addr, static_cast<int>(addrlen),
+ host, static_cast<DWORD>(hostlen),
+ serv, static_cast<DWORD>(servlen), flags);
+ return ec = translate_addrinfo_error(error);
+ }
+ }
+ clear_last_error();
+ return getnameinfo_emulation(addr, addrlen,
+ host, hostlen, serv, servlen, flags, ec);
+# endif
+#elif defined(__MACH__) && defined(__APPLE__)
+ using namespace std; // For memcpy.
+ sockaddr_storage_type tmp_addr;
+ memcpy(&tmp_addr, addr, addrlen);
+ tmp_addr.ss_len = addrlen;
+ addr = reinterpret_cast<socket_addr_type*>(&tmp_addr);
+ clear_last_error();
+ return getnameinfo_emulation(addr, addrlen,
+ host, hostlen, serv, servlen, flags, ec);
+#else
+ clear_last_error();
+ int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
+ return ec = translate_addrinfo_error(error);
+#endif
+}
+
+ASIO_DECL
+asio::error_code sync_getnameinfo(
+ const socket_addr_type* addr, std::size_t addrlen,
+ char* host, std::size_t hostlen, char* serv,
+ std::size_t servlen, int sock_type, asio::error_code& ec)
+{
+ // First try resolving with the service name. If that fails try resolving
+ // but allow the service to be returned as a number.
+ int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0;
+ socket_ops::getnameinfo(addr, addrlen, host,
+ hostlen, serv, servlen, flags, ec);
+ if (ec)
+ {
+ socket_ops::getnameinfo(addr, addrlen, host, hostlen,
+ serv, servlen, flags | NI_NUMERICSERV, ec);
+ }
+
+ return ec;
+}
+
+ASIO_DECL
+asio::error_code background_getnameinfo(
+ const weak_cancel_token_type& cancel_token,
+ const socket_addr_type* addr, std::size_t addrlen,
+ char* host, std::size_t hostlen, char* serv,
+ std::size_t servlen, int sock_type, asio::error_code& ec)
+{
+ if (cancel_token.expired())
+ {
+ ec = asio::error::operation_aborted;
+ }
+ else
+ {
+ // First try resolving with the service name. If that fails try resolving
+ // but allow the service to be returned as a number.
+ int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0;
+ socket_ops::getnameinfo(addr, addrlen, host,
+ hostlen, serv, servlen, flags, ec);
+ if (ec)
+ {
+ socket_ops::getnameinfo(addr, addrlen, host, hostlen,
+ serv, servlen, flags | NI_NUMERICSERV, ec);
+ }
+ }
+
+ return ec;
+}
+
+ASIO_DECL
+u_long_type network_to_host_long(u_long_type value)
+{
+ return ntohl(value);
+}
+
+ASIO_DECL
+u_long_type host_to_network_long(u_long_type value)
+{
+ return htonl(value);
+}
+
+ASIO_DECL
+u_short_type network_to_host_short(u_short_type value)
+{
+ return ntohs(value);
+}
+
+ASIO_DECL
+u_short_type host_to_network_short(u_short_type value)
+{
+ return htons(value);
+}
+
+} // namespace socket_ops
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SOCKET_OPS_IPP
diff --git a/ext/asio/asio/detail/impl/socket_select_interrupter.ipp b/ext/asio/asio/detail/impl/socket_select_interrupter.ipp
new file mode 100644
index 0000000..181c543
--- /dev/null
+++ b/ext/asio/asio/detail/impl/socket_select_interrupter.ipp
@@ -0,0 +1,151 @@
+//
+// detail/impl/socket_select_interrupter.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
+#define ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_WINDOWS) \
+ || defined(__CYGWIN__) \
+ || defined(__SYMBIAN32__)
+
+#include <cstdlib>
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_select_interrupter.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+socket_select_interrupter::socket_select_interrupter()
+{
+ asio::error_code ec;
+ socket_holder acceptor(socket_ops::socket(
+ AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
+ if (acceptor.get() == invalid_socket)
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ int opt = 1;
+ socket_ops::state_type acceptor_state = 0;
+ socket_ops::setsockopt(acceptor.get(), acceptor_state,
+ SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
+
+ using namespace std; // For memset.
+ sockaddr_in4_type addr;
+ std::size_t addr_len = sizeof(addr);
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ addr.sin_port = 0;
+ if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
+ addr_len, ec) == socket_error_retval)
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
+ &addr_len, ec) == socket_error_retval)
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ // Some broken firewalls on Windows will intermittently cause getsockname to
+ // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We
+ // explicitly specify the target address here to work around this problem.
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ if (socket_ops::listen(acceptor.get(),
+ SOMAXCONN, ec) == socket_error_retval)
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ socket_holder client(socket_ops::socket(
+ AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
+ if (client.get() == invalid_socket)
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
+ addr_len, ec) == socket_error_retval)
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
+ if (server.get() == invalid_socket)
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ ioctl_arg_type non_blocking = 1;
+ socket_ops::state_type client_state = 0;
+ if (socket_ops::ioctl(client.get(), client_state,
+ FIONBIO, &non_blocking, ec))
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ opt = 1;
+ socket_ops::setsockopt(client.get(), client_state,
+ IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
+
+ non_blocking = 1;
+ socket_ops::state_type server_state = 0;
+ if (socket_ops::ioctl(server.get(), server_state,
+ FIONBIO, &non_blocking, ec))
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ opt = 1;
+ socket_ops::setsockopt(server.get(), server_state,
+ IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
+
+ read_descriptor_ = server.release();
+ write_descriptor_ = client.release();
+}
+
+socket_select_interrupter::~socket_select_interrupter()
+{
+ asio::error_code ec;
+ socket_ops::state_type state = socket_ops::internal_non_blocking;
+ if (read_descriptor_ != invalid_socket)
+ socket_ops::close(read_descriptor_, state, true, ec);
+ if (write_descriptor_ != invalid_socket)
+ socket_ops::close(write_descriptor_, state, true, ec);
+}
+
+void socket_select_interrupter::interrupt()
+{
+ char byte = 0;
+ socket_ops::buf b;
+ socket_ops::init_buf(b, &byte, 1);
+ asio::error_code ec;
+ socket_ops::send(write_descriptor_, &b, 1, 0, ec);
+}
+
+bool socket_select_interrupter::reset()
+{
+ char data[1024];
+ socket_ops::buf b;
+ socket_ops::init_buf(b, data, sizeof(data));
+ asio::error_code ec;
+ int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
+ bool was_interrupted = (bytes_read > 0);
+ while (bytes_read == sizeof(data))
+ bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
+ return was_interrupted;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+
+#endif // ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
diff --git a/ext/asio/asio/detail/impl/strand_service.hpp b/ext/asio/asio/detail/impl/strand_service.hpp
new file mode 100644
index 0000000..81f438a
--- /dev/null
+++ b/ext/asio/asio/detail/impl/strand_service.hpp
@@ -0,0 +1,140 @@
+//
+// detail/impl/strand_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP
+#define ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/completion_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+inline strand_service::strand_impl::strand_impl()
+ : operation(&strand_service::do_complete),
+ count_(0)
+{
+}
+
+struct strand_service::on_dispatch_exit
+{
+ io_service_impl* io_service_;
+ strand_impl* impl_;
+
+ ~on_dispatch_exit()
+ {
+ impl_->mutex_.lock();
+ bool more_handlers = (--impl_->count_ > 0);
+ impl_->mutex_.unlock();
+
+ if (more_handlers)
+ io_service_->post_immediate_completion(impl_);
+ }
+};
+
+inline void strand_service::destroy(strand_service::implementation_type& impl)
+{
+ impl = 0;
+}
+
+template <typename Handler>
+void strand_service::dispatch(strand_service::implementation_type& impl,
+ Handler handler)
+{
+ // If we are already in the strand then the handler can run immediately.
+ if (call_stack<strand_impl>::contains(impl))
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler);
+ return;
+ }
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef completion_handler<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ // If we are running inside the io_service, and no other handler is queued
+ // or running, then the handler can run immediately.
+ bool can_dispatch = call_stack<io_service_impl>::contains(&io_service_);
+ impl->mutex_.lock();
+ bool first = (++impl->count_ == 1);
+ if (can_dispatch && first)
+ {
+ // Immediate invocation is allowed.
+ impl->mutex_.unlock();
+
+ // Memory must be releaesed before any upcall is made.
+ p.reset();
+
+ // Indicate that this strand is executing on the current thread.
+ call_stack<strand_impl>::context ctx(impl);
+
+ // Ensure the next handler, if any, is scheduled on block exit.
+ on_dispatch_exit on_exit = { &io_service_, impl };
+ (void)on_exit;
+
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler);
+ return;
+ }
+
+ // Immediate invocation is not allowed, so enqueue for later.
+ impl->queue_.push(p.p);
+ impl->mutex_.unlock();
+ p.v = p.p = 0;
+
+ // The first handler to be enqueued is responsible for scheduling the
+ // strand.
+ if (first)
+ io_service_.post_immediate_completion(impl);
+}
+
+// Request the io_service to invoke the given handler and return immediately.
+template <typename Handler>
+void strand_service::post(strand_service::implementation_type& impl,
+ Handler handler)
+{
+ // Allocate and construct an operation to wrap the handler.
+ typedef completion_handler<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ // Add the handler to the queue.
+ impl->mutex_.lock();
+ bool first = (++impl->count_ == 1);
+ impl->queue_.push(p.p);
+ impl->mutex_.unlock();
+ p.v = p.p = 0;
+
+ // The first handler to be enqueue is responsible for scheduling the strand.
+ if (first)
+ io_service_.post_immediate_completion(impl);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP
diff --git a/ext/asio/asio/detail/impl/strand_service.ipp b/ext/asio/asio/detail/impl/strand_service.ipp
new file mode 100644
index 0000000..84b806a
--- /dev/null
+++ b/ext/asio/asio/detail/impl/strand_service.ipp
@@ -0,0 +1,106 @@
+//
+// detail/impl/strand_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/strand_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct strand_service::on_do_complete_exit
+{
+ io_service_impl* owner_;
+ strand_impl* impl_;
+
+ ~on_do_complete_exit()
+ {
+ impl_->mutex_.lock();
+ bool more_handlers = (--impl_->count_ > 0);
+ impl_->mutex_.unlock();
+
+ if (more_handlers)
+ owner_->post_immediate_completion(impl_);
+ }
+};
+
+strand_service::strand_service(asio::io_service& io_service)
+ : asio::detail::service_base<strand_service>(io_service),
+ io_service_(asio::use_service<io_service_impl>(io_service)),
+ mutex_(),
+ salt_(0)
+{
+}
+
+void strand_service::shutdown_service()
+{
+ op_queue<operation> ops;
+
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ for (std::size_t i = 0; i < num_implementations; ++i)
+ if (strand_impl* impl = implementations_[i].get())
+ ops.push(impl->queue_);
+}
+
+void strand_service::construct(strand_service::implementation_type& impl)
+{
+ std::size_t salt = salt_++;
+ std::size_t index = reinterpret_cast<std::size_t>(&impl);
+ index += (reinterpret_cast<std::size_t>(&impl) >> 3);
+ index ^= salt + 0x9e3779b9 + (index << 6) + (index >> 2);
+ index = index % num_implementations;
+
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (!implementations_[index])
+ implementations_[index].reset(new strand_impl);
+ impl = implementations_[index].get();
+}
+
+void strand_service::do_complete(io_service_impl* owner, operation* base,
+ asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+{
+ if (owner)
+ {
+ strand_impl* impl = static_cast<strand_impl*>(base);
+
+ // Get the next handler to be executed.
+ impl->mutex_.lock();
+ operation* o = impl->queue_.front();
+ impl->queue_.pop();
+ impl->mutex_.unlock();
+
+ // Indicate that this strand is executing on the current thread.
+ call_stack<strand_impl>::context ctx(impl);
+
+ // Ensure the next handler, if any, is scheduled on block exit.
+ on_do_complete_exit on_exit = { owner, impl };
+ (void)on_exit;
+
+ o->complete(*owner);
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
diff --git a/ext/asio/asio/detail/impl/task_io_service.hpp b/ext/asio/asio/detail/impl/task_io_service.hpp
new file mode 100644
index 0000000..20ffd61
--- /dev/null
+++ b/ext/asio/asio/detail/impl/task_io_service.hpp
@@ -0,0 +1,60 @@
+//
+// detail/impl/task_io_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP
+#define ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/completion_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+void task_io_service::dispatch(Handler handler)
+{
+ if (call_stack<task_io_service>::contains(this))
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler);
+ }
+ else
+ post(handler);
+}
+
+template <typename Handler>
+void task_io_service::post(Handler handler)
+{
+ // Allocate and construct an operation to wrap the handler.
+ typedef completion_handler<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ post_immediate_completion(p.p);
+ p.v = p.p = 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP
diff --git a/ext/asio/asio/detail/impl/task_io_service.ipp b/ext/asio/asio/detail/impl/task_io_service.ipp
new file mode 100644
index 0000000..12a22be
--- /dev/null
+++ b/ext/asio/asio/detail/impl/task_io_service.ipp
@@ -0,0 +1,354 @@
+//
+// detail/impl/task_io_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_IOCP)
+
+#include <boost/limits.hpp>
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/event.hpp"
+#include "asio/detail/reactor.hpp"
+#include "asio/detail/task_io_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct task_io_service::task_cleanup
+{
+ ~task_cleanup()
+ {
+ // Enqueue the completed operations and reinsert the task at the end of
+ // the operation queue.
+ lock_->lock();
+ task_io_service_->task_interrupted_ = true;
+ task_io_service_->op_queue_.push(*ops_);
+ task_io_service_->op_queue_.push(&task_io_service_->task_operation_);
+ }
+
+ task_io_service* task_io_service_;
+ mutex::scoped_lock* lock_;
+ op_queue<operation>* ops_;
+};
+
+struct task_io_service::work_finished_on_block_exit
+{
+ ~work_finished_on_block_exit()
+ {
+ task_io_service_->work_finished();
+ }
+
+ task_io_service* task_io_service_;
+};
+
+struct task_io_service::idle_thread_info
+{
+ event wakeup_event;
+ idle_thread_info* next;
+};
+
+task_io_service::task_io_service(asio::io_service& io_service)
+ : asio::detail::service_base<task_io_service>(io_service),
+ mutex_(),
+ task_(0),
+ task_interrupted_(true),
+ outstanding_work_(0),
+ stopped_(false),
+ shutdown_(false),
+ first_idle_thread_(0)
+{
+}
+
+void task_io_service::init(std::size_t /*concurrency_hint*/)
+{
+}
+
+void task_io_service::shutdown_service()
+{
+ mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ lock.unlock();
+
+ // Destroy handler objects.
+ while (!op_queue_.empty())
+ {
+ operation* o = op_queue_.front();
+ op_queue_.pop();
+ if (o != &task_operation_)
+ o->destroy();
+ }
+
+ // Reset to initial state.
+ task_ = 0;
+}
+
+void task_io_service::init_task()
+{
+ mutex::scoped_lock lock(mutex_);
+ if (!shutdown_ && !task_)
+ {
+ task_ = &use_service<reactor>(this->get_io_service());
+ op_queue_.push(&task_operation_);
+ wake_one_thread_and_unlock(lock);
+ }
+}
+
+std::size_t task_io_service::run(asio::error_code& ec)
+{
+ ec = asio::error_code();
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ return 0;
+ }
+
+ call_stack<task_io_service>::context ctx(this);
+
+ idle_thread_info this_idle_thread;
+ this_idle_thread.next = 0;
+
+ mutex::scoped_lock lock(mutex_);
+
+ std::size_t n = 0;
+ for (; do_one(lock, &this_idle_thread); lock.lock())
+ if (n != (std::numeric_limits<std::size_t>::max)())
+ ++n;
+ return n;
+}
+
+std::size_t task_io_service::run_one(asio::error_code& ec)
+{
+ ec = asio::error_code();
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ return 0;
+ }
+
+ call_stack<task_io_service>::context ctx(this);
+
+ idle_thread_info this_idle_thread;
+ this_idle_thread.next = 0;
+
+ mutex::scoped_lock lock(mutex_);
+
+ return do_one(lock, &this_idle_thread);
+}
+
+std::size_t task_io_service::poll(asio::error_code& ec)
+{
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ ec = asio::error_code();
+ return 0;
+ }
+
+ call_stack<task_io_service>::context ctx(this);
+
+ mutex::scoped_lock lock(mutex_);
+
+ std::size_t n = 0;
+ for (; do_one(lock, 0); lock.lock())
+ if (n != (std::numeric_limits<std::size_t>::max)())
+ ++n;
+ return n;
+}
+
+std::size_t task_io_service::poll_one(asio::error_code& ec)
+{
+ ec = asio::error_code();
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ return 0;
+ }
+
+ call_stack<task_io_service>::context ctx(this);
+
+ mutex::scoped_lock lock(mutex_);
+
+ return do_one(lock, 0);
+}
+
+void task_io_service::stop()
+{
+ mutex::scoped_lock lock(mutex_);
+ stop_all_threads(lock);
+}
+
+void task_io_service::reset()
+{
+ mutex::scoped_lock lock(mutex_);
+ stopped_ = false;
+}
+
+void task_io_service::post_immediate_completion(task_io_service::operation* op)
+{
+ work_started();
+ post_deferred_completion(op);
+}
+
+void task_io_service::post_deferred_completion(task_io_service::operation* op)
+{
+ mutex::scoped_lock lock(mutex_);
+ op_queue_.push(op);
+ wake_one_thread_and_unlock(lock);
+}
+
+void task_io_service::post_deferred_completions(
+ op_queue<task_io_service::operation>& ops)
+{
+ if (!ops.empty())
+ {
+ mutex::scoped_lock lock(mutex_);
+ op_queue_.push(ops);
+ wake_one_thread_and_unlock(lock);
+ }
+}
+
+std::size_t task_io_service::do_one(mutex::scoped_lock& lock,
+ task_io_service::idle_thread_info* this_idle_thread)
+{
+ bool polling = !this_idle_thread;
+ bool task_has_run = false;
+ while (!stopped_)
+ {
+ if (!op_queue_.empty())
+ {
+ // Prepare to execute first handler from queue.
+ operation* o = op_queue_.front();
+ op_queue_.pop();
+ bool more_handlers = (!op_queue_.empty());
+
+ if (o == &task_operation_)
+ {
+ task_interrupted_ = more_handlers || polling;
+
+ // If the task has already run and we're polling then we're done.
+ if (task_has_run && polling)
+ {
+ task_interrupted_ = true;
+ op_queue_.push(&task_operation_);
+ return 0;
+ }
+ task_has_run = true;
+
+ if (!more_handlers || !wake_one_idle_thread_and_unlock(lock))
+ lock.unlock();
+
+ op_queue<operation> completed_ops;
+ task_cleanup c = { this, &lock, &completed_ops };
+ (void)c;
+
+ // Run the task. May throw an exception. Only block if the operation
+ // queue is empty and we're not polling, otherwise we want to return
+ // as soon as possible.
+ task_->run(!more_handlers && !polling, completed_ops);
+ }
+ else
+ {
+ if (more_handlers)
+ wake_one_thread_and_unlock(lock);
+ else
+ lock.unlock();
+
+ // Ensure the count of outstanding work is decremented on block exit.
+ work_finished_on_block_exit on_exit = { this };
+ (void)on_exit;
+
+ // Complete the operation. May throw an exception.
+ o->complete(*this); // deletes the operation object
+
+ return 1;
+ }
+ }
+ else if (this_idle_thread)
+ {
+ // Nothing to run right now, so just wait for work to do.
+ this_idle_thread->next = first_idle_thread_;
+ first_idle_thread_ = this_idle_thread;
+ this_idle_thread->wakeup_event.clear(lock);
+ this_idle_thread->wakeup_event.wait(lock);
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+void task_io_service::stop_all_threads(
+ mutex::scoped_lock& lock)
+{
+ stopped_ = true;
+
+ while (first_idle_thread_)
+ {
+ idle_thread_info* idle_thread = first_idle_thread_;
+ first_idle_thread_ = idle_thread->next;
+ idle_thread->next = 0;
+ idle_thread->wakeup_event.signal(lock);
+ }
+
+ if (!task_interrupted_ && task_)
+ {
+ task_interrupted_ = true;
+ task_->interrupt();
+ }
+}
+
+bool task_io_service::wake_one_idle_thread_and_unlock(
+ mutex::scoped_lock& lock)
+{
+ if (first_idle_thread_)
+ {
+ idle_thread_info* idle_thread = first_idle_thread_;
+ first_idle_thread_ = idle_thread->next;
+ idle_thread->next = 0;
+ idle_thread->wakeup_event.signal_and_unlock(lock);
+ return true;
+ }
+ return false;
+}
+
+void task_io_service::wake_one_thread_and_unlock(
+ mutex::scoped_lock& lock)
+{
+ if (!wake_one_idle_thread_and_unlock(lock))
+ {
+ if (!task_interrupted_ && task_)
+ {
+ task_interrupted_ = true;
+ task_->interrupt();
+ }
+ lock.unlock();
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP
diff --git a/ext/asio/asio/detail/impl/throw_error.ipp b/ext/asio/asio/detail/impl/throw_error.ipp
new file mode 100644
index 0000000..a04fbf4
--- /dev/null
+++ b/ext/asio/asio/detail/impl/throw_error.ipp
@@ -0,0 +1,47 @@
+//
+// detail/impl/throw_error.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_THROW_ERROR_IPP
+#define ASIO_DETAIL_IMPL_THROW_ERROR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/throw_exception.hpp>
+#include "asio/detail/throw_error.hpp"
+#include "asio/system_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+ASIO_DECL
+void do_throw_error(const asio::error_code& err)
+{
+ asio::system_error e(err);
+ boost::throw_exception(e);
+}
+
+ASIO_DECL
+void do_throw_error(const asio::error_code& err, const char* location)
+{
+ asio::system_error e(err, location);
+ boost::throw_exception(e);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_THROW_ERROR_IPP
diff --git a/ext/asio/asio/detail/impl/timer_queue.ipp b/ext/asio/asio/detail/impl/timer_queue.ipp
new file mode 100644
index 0000000..63fbd7e
--- /dev/null
+++ b/ext/asio/asio/detail/impl/timer_queue.ipp
@@ -0,0 +1,85 @@
+//
+// detail/impl/timer_queue.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP
+#define ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HEADER_ONLY)
+
+#include "asio/detail/timer_queue.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+timer_queue<time_traits<boost::posix_time::ptime> >::timer_queue()
+{
+}
+
+timer_queue<time_traits<boost::posix_time::ptime> >::~timer_queue()
+{
+}
+
+bool timer_queue<time_traits<boost::posix_time::ptime> >::enqueue_timer(
+ const time_type& time, per_timer_data& timer, timer_op* op)
+{
+ return impl_.enqueue_timer(time, timer, op);
+}
+
+bool timer_queue<time_traits<boost::posix_time::ptime> >::empty() const
+{
+ return impl_.empty();
+}
+
+long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_msec(
+ long max_duration) const
+{
+ return impl_.wait_duration_msec(max_duration);
+}
+
+long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_usec(
+ long max_duration) const
+{
+ return impl_.wait_duration_usec(max_duration);
+}
+
+void timer_queue<time_traits<boost::posix_time::ptime> >::get_ready_timers(
+ op_queue<operation>& ops)
+{
+ impl_.get_ready_timers(ops);
+}
+
+void timer_queue<time_traits<boost::posix_time::ptime> >::get_all_timers(
+ op_queue<operation>& ops)
+{
+ impl_.get_all_timers(ops);
+}
+
+std::size_t timer_queue<time_traits<boost::posix_time::ptime> >::cancel_timer(
+ per_timer_data& timer, op_queue<operation>& ops)
+{
+ return impl_.cancel_timer(timer, ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP
diff --git a/ext/asio/asio/detail/impl/timer_queue_set.ipp b/ext/asio/asio/detail/impl/timer_queue_set.ipp
new file mode 100644
index 0000000..81ab5a9
--- /dev/null
+++ b/ext/asio/asio/detail/impl/timer_queue_set.ipp
@@ -0,0 +1,101 @@
+//
+// detail/impl/timer_queue_set.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP
+#define ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/timer_queue_set.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+timer_queue_set::timer_queue_set()
+ : first_(0)
+{
+}
+
+void timer_queue_set::insert(timer_queue_base* q)
+{
+ q->next_ = first_;
+ first_ = q;
+}
+
+void timer_queue_set::erase(timer_queue_base* q)
+{
+ if (first_)
+ {
+ if (q == first_)
+ {
+ first_ = q->next_;
+ q->next_ = 0;
+ return;
+ }
+
+ for (timer_queue_base* p = first_; p->next_; p = p->next_)
+ {
+ if (p->next_ == q)
+ {
+ p->next_ = q->next_;
+ q->next_ = 0;
+ return;
+ }
+ }
+ }
+}
+
+bool timer_queue_set::all_empty() const
+{
+ for (timer_queue_base* p = first_; p; p = p->next_)
+ if (!p->empty())
+ return false;
+ return true;
+}
+
+long timer_queue_set::wait_duration_msec(long max_duration) const
+{
+ long min_duration = max_duration;
+ for (timer_queue_base* p = first_; p; p = p->next_)
+ min_duration = p->wait_duration_msec(min_duration);
+ return min_duration;
+}
+
+long timer_queue_set::wait_duration_usec(long max_duration) const
+{
+ long min_duration = max_duration;
+ for (timer_queue_base* p = first_; p; p = p->next_)
+ min_duration = p->wait_duration_usec(min_duration);
+ return min_duration;
+}
+
+void timer_queue_set::get_ready_timers(op_queue<operation>& ops)
+{
+ for (timer_queue_base* p = first_; p; p = p->next_)
+ p->get_ready_timers(ops);
+}
+
+void timer_queue_set::get_all_timers(op_queue<operation>& ops)
+{
+ for (timer_queue_base* p = first_; p; p = p->next_)
+ p->get_all_timers(ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP
diff --git a/ext/asio/asio/detail/impl/win_event.ipp b/ext/asio/asio/detail/impl/win_event.ipp
new file mode 100644
index 0000000..2b72f6e
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_event.ipp
@@ -0,0 +1,50 @@
+//
+// detail/win_event.ipp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_EVENT_IPP
+#define ASIO_DETAIL_IMPL_WIN_EVENT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_WINDOWS)
+
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_event.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_event::win_event()
+ : event_(::CreateEvent(0, true, false, 0))
+{
+ if (!event_)
+ {
+ DWORD last_error = ::GetLastError();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "event");
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_WINDOWS)
+
+#endif // ASIO_DETAIL_IMPL_WIN_EVENT_IPP
diff --git a/ext/asio/asio/detail/impl/win_iocp_handle_service.ipp b/ext/asio/asio/detail/impl/win_iocp_handle_service.ipp
new file mode 100644
index 0000000..3b30b1d
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_iocp_handle_service.ipp
@@ -0,0 +1,452 @@
+//
+// detail/impl/win_iocp_handle_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/win_iocp_handle_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_iocp_handle_service::overlapped_wrapper
+ : public OVERLAPPED
+{
+public:
+ explicit overlapped_wrapper(asio::error_code& ec)
+ {
+ Internal = 0;
+ InternalHigh = 0;
+ Offset = 0;
+ OffsetHigh = 0;
+
+ // Create a non-signalled manual-reset event, for GetOverlappedResult.
+ hEvent = ::CreateEvent(0, TRUE, FALSE, 0);
+ if (hEvent)
+ {
+ // As documented in GetQueuedCompletionStatus, setting the low order
+ // bit of this event prevents our synchronous writes from being treated
+ // as completion port events.
+ *reinterpret_cast<DWORD_PTR*>(&hEvent) |= 1;
+ }
+ else
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ }
+
+ ~overlapped_wrapper()
+ {
+ if (hEvent)
+ {
+ ::CloseHandle(hEvent);
+ }
+ }
+};
+
+win_iocp_handle_service::win_iocp_handle_service(
+ asio::io_service& io_service)
+ : iocp_service_(asio::use_service<win_iocp_io_service>(io_service)),
+ mutex_(),
+ impl_list_(0)
+{
+}
+
+void win_iocp_handle_service::shutdown_service()
+{
+ // Close all implementations, causing all operations to complete.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ implementation_type* impl = impl_list_;
+ while (impl)
+ {
+ close_for_destruction(*impl);
+ impl = impl->next_;
+ }
+}
+
+void win_iocp_handle_service::construct(
+ win_iocp_handle_service::implementation_type& impl)
+{
+ impl.handle_ = INVALID_HANDLE_VALUE;
+ impl.safe_cancellation_thread_id_ = 0;
+
+ // Insert implementation into linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ impl.next_ = impl_list_;
+ impl.prev_ = 0;
+ if (impl_list_)
+ impl_list_->prev_ = &impl;
+ impl_list_ = &impl;
+}
+
+void win_iocp_handle_service::destroy(
+ win_iocp_handle_service::implementation_type& impl)
+{
+ close_for_destruction(impl);
+
+ // Remove implementation from linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (impl_list_ == &impl)
+ impl_list_ = impl.next_;
+ if (impl.prev_)
+ impl.prev_->next_ = impl.next_;
+ if (impl.next_)
+ impl.next_->prev_= impl.prev_;
+ impl.next_ = 0;
+ impl.prev_ = 0;
+}
+
+asio::error_code win_iocp_handle_service::assign(
+ win_iocp_handle_service::implementation_type& impl,
+ const native_type& native_handle, asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ if (iocp_service_.register_handle(native_handle, ec))
+ return ec;
+
+ impl.handle_ = native_handle;
+ ec = asio::error_code();
+ return ec;
+}
+
+asio::error_code win_iocp_handle_service::close(
+ win_iocp_handle_service::implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ if (!::CloseHandle(impl.handle_))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.handle_ = INVALID_HANDLE_VALUE;
+ impl.safe_cancellation_thread_id_ = 0;
+ }
+
+ ec = asio::error_code();
+ return ec;
+}
+
+asio::error_code win_iocp_handle_service::cancel(
+ win_iocp_handle_service::implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ }
+ else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
+ ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
+ {
+ // The version of Windows supports cancellation from any thread.
+ typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
+ cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
+ if (!cancel_io_ex(impl.handle_, 0))
+ {
+ DWORD last_error = ::GetLastError();
+ if (last_error == ERROR_NOT_FOUND)
+ {
+ // ERROR_NOT_FOUND means that there were no operations to be
+ // cancelled. We swallow this error to match the behaviour on other
+ // platforms.
+ ec = asio::error_code();
+ }
+ else
+ {
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+ }
+ else if (impl.safe_cancellation_thread_id_ == 0)
+ {
+ // No operations have been started, so there's nothing to cancel.
+ ec = asio::error_code();
+ }
+ else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
+ {
+ // Asynchronous operations have been started from the current thread only,
+ // so it is safe to try to cancel them using CancelIo.
+ if (!::CancelIo(impl.handle_))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+ }
+ else
+ {
+ // Asynchronous operations have been started from more than one thread,
+ // so cancellation is not safe.
+ ec = asio::error::operation_not_supported;
+ }
+
+ return ec;
+}
+
+size_t win_iocp_handle_service::do_write(
+ win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset,
+ const asio::const_buffer& buffer, asio::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // A request to write 0 bytes on a handle is a no-op.
+ if (asio::buffer_size(buffer) == 0)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ overlapped_wrapper overlapped(ec);
+ if (ec)
+ {
+ return 0;
+ }
+
+ // Write the data.
+ overlapped.Offset = offset & 0xFFFFFFFF;
+ overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+ BOOL ok = ::WriteFile(impl.handle_,
+ asio::buffer_cast<LPCVOID>(buffer),
+ static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped);
+ if (!ok)
+ {
+ DWORD last_error = ::GetLastError();
+ if (last_error != ERROR_IO_PENDING)
+ {
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return 0;
+ }
+ }
+
+ // Wait for the operation to complete.
+ DWORD bytes_transferred = 0;
+ ok = ::GetOverlappedResult(impl.handle_,
+ &overlapped, &bytes_transferred, TRUE);
+ if (!ok)
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return 0;
+ }
+
+ ec = asio::error_code();
+ return bytes_transferred;
+}
+
+void win_iocp_handle_service::start_write_op(
+ win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset,
+ const asio::const_buffer& buffer, operation* op)
+{
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (!is_open(impl))
+ {
+ iocp_service_.on_completion(op, asio::error::bad_descriptor);
+ }
+ else if (asio::buffer_size(buffer) == 0)
+ {
+ // A request to write 0 bytes on a handle is a no-op.
+ iocp_service_.on_completion(op);
+ }
+ else
+ {
+ DWORD bytes_transferred = 0;
+ op->Offset = offset & 0xFFFFFFFF;
+ op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+ BOOL ok = ::WriteFile(impl.handle_,
+ asio::buffer_cast<LPCVOID>(buffer),
+ static_cast<DWORD>(asio::buffer_size(buffer)),
+ &bytes_transferred, op);
+ DWORD last_error = ::GetLastError();
+ if (!ok && last_error != ERROR_IO_PENDING
+ && last_error != ERROR_MORE_DATA)
+ {
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ }
+ else
+ {
+ iocp_service_.on_pending(op);
+ }
+ }
+}
+
+size_t win_iocp_handle_service::do_read(
+ win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset,
+ const asio::mutable_buffer& buffer, asio::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // A request to read 0 bytes on a stream handle is a no-op.
+ if (asio::buffer_size(buffer) == 0)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ overlapped_wrapper overlapped(ec);
+ if (ec)
+ {
+ return 0;
+ }
+
+ // Read some data.
+ overlapped.Offset = offset & 0xFFFFFFFF;
+ overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+ BOOL ok = ::ReadFile(impl.handle_,
+ asio::buffer_cast<LPVOID>(buffer),
+ static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped);
+ if (!ok)
+ {
+ DWORD last_error = ::GetLastError();
+ if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA)
+ {
+ if (last_error == ERROR_HANDLE_EOF)
+ {
+ ec = asio::error::eof;
+ }
+ else
+ {
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ return 0;
+ }
+ }
+
+ // Wait for the operation to complete.
+ DWORD bytes_transferred = 0;
+ ok = ::GetOverlappedResult(impl.handle_,
+ &overlapped, &bytes_transferred, TRUE);
+ if (!ok)
+ {
+ DWORD last_error = ::GetLastError();
+ if (last_error == ERROR_HANDLE_EOF)
+ {
+ ec = asio::error::eof;
+ }
+ else
+ {
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ return 0;
+ }
+
+ ec = asio::error_code();
+ return bytes_transferred;
+}
+
+void win_iocp_handle_service::start_read_op(
+ win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset,
+ const asio::mutable_buffer& buffer, operation* op)
+{
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (!is_open(impl))
+ {
+ iocp_service_.on_completion(op, asio::error::bad_descriptor);
+ }
+ else if (asio::buffer_size(buffer) == 0)
+ {
+ // A request to read 0 bytes on a handle is a no-op.
+ iocp_service_.on_completion(op);
+ }
+ else
+ {
+ DWORD bytes_transferred = 0;
+ op->Offset = offset & 0xFFFFFFFF;
+ op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+ BOOL ok = ::ReadFile(impl.handle_,
+ asio::buffer_cast<LPVOID>(buffer),
+ static_cast<DWORD>(asio::buffer_size(buffer)),
+ &bytes_transferred, op);
+ DWORD last_error = ::GetLastError();
+ if (!ok && last_error != ERROR_IO_PENDING
+ && last_error != ERROR_MORE_DATA)
+ {
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ }
+ else
+ {
+ iocp_service_.on_pending(op);
+ }
+ }
+}
+
+void win_iocp_handle_service::update_cancellation_thread_id(
+ win_iocp_handle_service::implementation_type& impl)
+{
+ if (impl.safe_cancellation_thread_id_ == 0)
+ impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+ else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+ impl.safe_cancellation_thread_id_ = ~DWORD(0);
+}
+
+void win_iocp_handle_service::close_for_destruction(implementation_type& impl)
+{
+ if (is_open(impl))
+ {
+ ::CloseHandle(impl.handle_);
+ impl.handle_ = INVALID_HANDLE_VALUE;
+ impl.safe_cancellation_thread_id_ = 0;
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP
diff --git a/ext/asio/asio/detail/impl/win_iocp_io_service.hpp b/ext/asio/asio/detail/impl/win_iocp_io_service.hpp
new file mode 100644
index 0000000..ab23547
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_iocp_io_service.hpp
@@ -0,0 +1,115 @@
+//
+// detail/impl/win_iocp_io_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/completion_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+void win_iocp_io_service::dispatch(Handler handler)
+{
+ if (call_stack<win_iocp_io_service>::contains(this))
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler);
+ }
+ else
+ post(handler);
+}
+
+template <typename Handler>
+void win_iocp_io_service::post(Handler handler)
+{
+ // Allocate and construct an operation to wrap the handler.
+ typedef completion_handler<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ post_immediate_completion(p.p);
+ p.v = p.p = 0;
+}
+
+template <typename Time_Traits>
+void win_iocp_io_service::add_timer_queue(
+ timer_queue<Time_Traits>& queue)
+{
+ do_add_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void win_iocp_io_service::remove_timer_queue(
+ timer_queue<Time_Traits>& queue)
+{
+ do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void win_iocp_io_service::schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op)
+{
+ // If the service has been shut down we silently discard the timer.
+ if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
+ {
+ post_immediate_completion(op);
+ return;
+ }
+
+ mutex::scoped_lock lock(dispatch_mutex_);
+
+ bool earliest = queue.enqueue_timer(time, timer, op);
+ work_started();
+ if (earliest)
+ update_timeout();
+}
+
+template <typename Time_Traits>
+std::size_t win_iocp_io_service::cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer)
+{
+ // If the service has been shut down we silently ignore the cancellation.
+ if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
+ return 0;
+
+ mutex::scoped_lock lock(dispatch_mutex_);
+ op_queue<win_iocp_operation> ops;
+ std::size_t n = queue.cancel_timer(timer, ops);
+ post_deferred_completions(ops);
+ return n;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP
diff --git a/ext/asio/asio/detail/impl/win_iocp_io_service.ipp b/ext/asio/asio/detail/impl/win_iocp_io_service.ipp
new file mode 100644
index 0000000..890e32f
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_iocp_io_service.ipp
@@ -0,0 +1,496 @@
+//
+// detail/impl/win_iocp_io_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include <boost/limits.hpp>
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_iocp_io_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct win_iocp_io_service::work_finished_on_block_exit
+{
+ ~work_finished_on_block_exit()
+ {
+ io_service_->work_finished();
+ }
+
+ win_iocp_io_service* io_service_;
+};
+
+struct win_iocp_io_service::timer_thread_function
+{
+ void operator()()
+ {
+ while (::InterlockedExchangeAdd(&io_service_->shutdown_, 0) == 0)
+ {
+ if (::WaitForSingleObject(io_service_->waitable_timer_.handle,
+ INFINITE) == WAIT_OBJECT_0)
+ {
+ ::InterlockedExchange(&io_service_->dispatch_required_, 1);
+ ::PostQueuedCompletionStatus(io_service_->iocp_.handle,
+ 0, wake_for_dispatch, 0);
+ }
+ }
+ }
+
+ win_iocp_io_service* io_service_;
+};
+
+win_iocp_io_service::win_iocp_io_service(asio::io_service& io_service)
+ : asio::detail::service_base<win_iocp_io_service>(io_service),
+ iocp_(),
+ outstanding_work_(0),
+ stopped_(0),
+ shutdown_(0),
+ dispatch_required_(0)
+{
+}
+
+void win_iocp_io_service::init(size_t concurrency_hint)
+{
+ iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,
+ static_cast<DWORD>((std::min<size_t>)(concurrency_hint, DWORD(~0))));
+ if (!iocp_.handle)
+ {
+ DWORD last_error = ::GetLastError();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "iocp");
+ }
+}
+
+void win_iocp_io_service::shutdown_service()
+{
+ ::InterlockedExchange(&shutdown_, 1);
+
+ if (timer_thread_)
+ {
+ LARGE_INTEGER timeout;
+ timeout.QuadPart = 1;
+ ::SetWaitableTimer(waitable_timer_.handle, &timeout, 1, 0, 0, FALSE);
+ }
+
+ while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0)
+ {
+ op_queue<win_iocp_operation> ops;
+ timer_queues_.get_all_timers(ops);
+ ops.push(completed_ops_);
+ if (!ops.empty())
+ {
+ while (win_iocp_operation* op = ops.front())
+ {
+ ops.pop();
+ ::InterlockedDecrement(&outstanding_work_);
+ op->destroy();
+ }
+ }
+ else
+ {
+ DWORD bytes_transferred = 0;
+ dword_ptr_t completion_key = 0;
+ LPOVERLAPPED overlapped = 0;
+ ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
+ &completion_key, &overlapped, gqcs_timeout);
+ if (overlapped)
+ {
+ ::InterlockedDecrement(&outstanding_work_);
+ static_cast<win_iocp_operation*>(overlapped)->destroy();
+ }
+ }
+ }
+
+ if (timer_thread_)
+ timer_thread_->join();
+}
+
+asio::error_code win_iocp_io_service::register_handle(
+ HANDLE handle, asio::error_code& ec)
+{
+ if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0)
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+ return ec;
+}
+
+size_t win_iocp_io_service::run(asio::error_code& ec)
+{
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ stop();
+ ec = asio::error_code();
+ return 0;
+ }
+
+ call_stack<win_iocp_io_service>::context ctx(this);
+
+ size_t n = 0;
+ while (do_one(true, ec))
+ if (n != (std::numeric_limits<size_t>::max)())
+ ++n;
+ return n;
+}
+
+size_t win_iocp_io_service::run_one(asio::error_code& ec)
+{
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ stop();
+ ec = asio::error_code();
+ return 0;
+ }
+
+ call_stack<win_iocp_io_service>::context ctx(this);
+
+ return do_one(true, ec);
+}
+
+size_t win_iocp_io_service::poll(asio::error_code& ec)
+{
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ stop();
+ ec = asio::error_code();
+ return 0;
+ }
+
+ call_stack<win_iocp_io_service>::context ctx(this);
+
+ size_t n = 0;
+ while (do_one(false, ec))
+ if (n != (std::numeric_limits<size_t>::max)())
+ ++n;
+ return n;
+}
+
+size_t win_iocp_io_service::poll_one(asio::error_code& ec)
+{
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ stop();
+ ec = asio::error_code();
+ return 0;
+ }
+
+ call_stack<win_iocp_io_service>::context ctx(this);
+
+ return do_one(false, ec);
+}
+
+void win_iocp_io_service::stop()
+{
+ if (::InterlockedExchange(&stopped_, 1) == 0)
+ {
+ if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
+ {
+ DWORD last_error = ::GetLastError();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "pqcs");
+ }
+ }
+}
+
+void win_iocp_io_service::post_deferred_completion(win_iocp_operation* op)
+{
+ // Flag the operation as ready.
+ op->ready_ = 1;
+
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle,
+ 0, overlapped_contains_result, op))
+ {
+ // Out of resources. Put on completed queue instead.
+ mutex::scoped_lock lock(dispatch_mutex_);
+ completed_ops_.push(op);
+ ::InterlockedExchange(&dispatch_required_, 1);
+ }
+}
+
+void win_iocp_io_service::post_deferred_completions(
+ op_queue<win_iocp_operation>& ops)
+{
+ while (win_iocp_operation* op = ops.front())
+ {
+ ops.pop();
+
+ // Flag the operation as ready.
+ op->ready_ = 1;
+
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle,
+ 0, overlapped_contains_result, op))
+ {
+ // Out of resources. Put on completed queue instead.
+ mutex::scoped_lock lock(dispatch_mutex_);
+ completed_ops_.push(op);
+ completed_ops_.push(ops);
+ ::InterlockedExchange(&dispatch_required_, 1);
+ }
+ }
+}
+
+void win_iocp_io_service::on_pending(win_iocp_operation* op)
+{
+ if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
+ {
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle,
+ 0, overlapped_contains_result, op))
+ {
+ // Out of resources. Put on completed queue instead.
+ mutex::scoped_lock lock(dispatch_mutex_);
+ completed_ops_.push(op);
+ ::InterlockedExchange(&dispatch_required_, 1);
+ }
+ }
+}
+
+void win_iocp_io_service::on_completion(win_iocp_operation* op,
+ DWORD last_error, DWORD bytes_transferred)
+{
+ // Flag that the operation is ready for invocation.
+ op->ready_ = 1;
+
+ // Store results in the OVERLAPPED structure.
+ op->Internal = asio::error::get_system_category();
+ op->Offset = last_error;
+ op->OffsetHigh = bytes_transferred;
+
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle,
+ 0, overlapped_contains_result, op))
+ {
+ // Out of resources. Put on completed queue instead.
+ mutex::scoped_lock lock(dispatch_mutex_);
+ completed_ops_.push(op);
+ ::InterlockedExchange(&dispatch_required_, 1);
+ }
+}
+
+void win_iocp_io_service::on_completion(win_iocp_operation* op,
+ const asio::error_code& ec, DWORD bytes_transferred)
+{
+ // Flag that the operation is ready for invocation.
+ op->ready_ = 1;
+
+ // Store results in the OVERLAPPED structure.
+ op->Internal = ec.category();
+ op->Offset = ec.value();
+ op->OffsetHigh = bytes_transferred;
+
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle,
+ 0, overlapped_contains_result, op))
+ {
+ // Out of resources. Put on completed queue instead.
+ mutex::scoped_lock lock(dispatch_mutex_);
+ completed_ops_.push(op);
+ ::InterlockedExchange(&dispatch_required_, 1);
+ }
+}
+
+size_t win_iocp_io_service::do_one(bool block, asio::error_code& ec)
+{
+ for (;;)
+ {
+ // Try to acquire responsibility for dispatching timers and completed ops.
+ if (::InterlockedCompareExchange(&dispatch_required_, 0, 1) == 1)
+ {
+ mutex::scoped_lock lock(dispatch_mutex_);
+
+ // Dispatch pending timers and operations.
+ op_queue<win_iocp_operation> ops;
+ ops.push(completed_ops_);
+ timer_queues_.get_ready_timers(ops);
+ post_deferred_completions(ops);
+ update_timeout();
+ }
+
+ // Get the next operation from the queue.
+ DWORD bytes_transferred = 0;
+ dword_ptr_t completion_key = 0;
+ LPOVERLAPPED overlapped = 0;
+ ::SetLastError(0);
+ BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
+ &completion_key, &overlapped, block ? gqcs_timeout : 0);
+ DWORD last_error = ::GetLastError();
+
+ if (overlapped)
+ {
+ win_iocp_operation* op = static_cast<win_iocp_operation*>(overlapped);
+ asio::error_code result_ec(last_error,
+ asio::error::get_system_category());
+
+ // We may have been passed the last_error and bytes_transferred in the
+ // OVERLAPPED structure itself.
+ if (completion_key == overlapped_contains_result)
+ {
+ result_ec = asio::error_code(static_cast<int>(op->Offset),
+ static_cast<asio::error_category>(op->Internal));
+ bytes_transferred = op->OffsetHigh;
+ }
+
+ // Otherwise ensure any result has been saved into the OVERLAPPED
+ // structure.
+ else
+ {
+ op->Internal = result_ec.category();
+ op->Offset = result_ec.value();
+ op->OffsetHigh = bytes_transferred;
+ }
+
+ // Dispatch the operation only if ready. The operation may not be ready
+ // if the initiating function (e.g. a call to WSARecv) has not yet
+ // returned. This is because the initiating function still wants access
+ // to the operation's OVERLAPPED structure.
+ if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
+ {
+ // Ensure the count of outstanding work is decremented on block exit.
+ work_finished_on_block_exit on_exit = { this };
+ (void)on_exit;
+
+ op->complete(*this, result_ec, bytes_transferred);
+ ec = asio::error_code();
+ return 1;
+ }
+ }
+ else if (!ok)
+ {
+ if (last_error != WAIT_TIMEOUT)
+ {
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return 0;
+ }
+
+ // If we're not polling we need to keep going until we get a real handler.
+ if (block)
+ continue;
+
+ ec = asio::error_code();
+ return 0;
+ }
+ else if (completion_key == wake_for_dispatch)
+ {
+ // We have been woken up to try to acquire responsibility for dispatching
+ // timers and completed operations.
+ }
+ else
+ {
+ // The stopped_ flag is always checked to ensure that any leftover
+ // interrupts from a previous run invocation are ignored.
+ if (::InterlockedExchangeAdd(&stopped_, 0) != 0)
+ {
+ // Wake up next thread that is blocked on GetQueuedCompletionStatus.
+ if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
+ {
+ last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return 0;
+ }
+
+ ec = asio::error_code();
+ return 0;
+ }
+ }
+ }
+}
+
+void win_iocp_io_service::do_add_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(dispatch_mutex_);
+
+ timer_queues_.insert(&queue);
+
+ if (!waitable_timer_.handle)
+ {
+ waitable_timer_.handle = ::CreateWaitableTimer(0, FALSE, 0);
+ if (waitable_timer_.handle == 0)
+ {
+ DWORD last_error = ::GetLastError();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "timer");
+ }
+
+ LARGE_INTEGER timeout;
+ timeout.QuadPart = -max_timeout_usec;
+ timeout.QuadPart *= 10;
+ ::SetWaitableTimer(waitable_timer_.handle,
+ &timeout, max_timeout_msec, 0, 0, FALSE);
+ }
+
+ if (!timer_thread_)
+ {
+ timer_thread_function thread_function = { this };
+ timer_thread_.reset(new thread(thread_function, 65536));
+ }
+}
+
+void win_iocp_io_service::do_remove_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(dispatch_mutex_);
+
+ timer_queues_.erase(&queue);
+}
+
+void win_iocp_io_service::update_timeout()
+{
+ if (timer_thread_)
+ {
+ // There's no point updating the waitable timer if the new timeout period
+ // exceeds the maximum timeout. In that case, we might as well wait for the
+ // existing period of the timer to expire.
+ long timeout_usec = timer_queues_.wait_duration_usec(max_timeout_usec);
+ if (timeout_usec < max_timeout_usec)
+ {
+ LARGE_INTEGER timeout;
+ timeout.QuadPart = -timeout_usec;
+ timeout.QuadPart *= 10;
+ ::SetWaitableTimer(waitable_timer_.handle,
+ &timeout, max_timeout_msec, 0, 0, FALSE);
+ }
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP
diff --git a/ext/asio/asio/detail/impl/win_iocp_serial_port_service.ipp b/ext/asio/asio/detail/impl/win_iocp_serial_port_service.ipp
new file mode 100644
index 0000000..7631514
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_iocp_serial_port_service.ipp
@@ -0,0 +1,180 @@
+//
+// detail/impl/win_iocp_serial_port_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
+
+#include <cstring>
+#include "asio/detail/win_iocp_serial_port_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_iocp_serial_port_service::win_iocp_serial_port_service(
+ asio::io_service& io_service)
+ : handle_service_(io_service)
+{
+}
+
+void win_iocp_serial_port_service::shutdown_service()
+{
+}
+
+asio::error_code win_iocp_serial_port_service::open(
+ win_iocp_serial_port_service::implementation_type& impl,
+ const std::string& device, asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ // For convenience, add a leading \\.\ sequence if not already present.
+ std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device;
+
+ // Open a handle to the serial port.
+ ::HANDLE handle = ::CreateFileA(name.c_str(),
+ GENERIC_READ | GENERIC_WRITE, 0, 0,
+ OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ // Determine the initial serial port parameters.
+ using namespace std; // For memset.
+ ::DCB dcb;
+ memset(&dcb, 0, sizeof(DCB));
+ dcb.DCBlength = sizeof(DCB);
+ if (!::GetCommState(handle, &dcb))
+ {
+ DWORD last_error = ::GetLastError();
+ ::CloseHandle(handle);
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ // Set some default serial port parameters. This implementation does not
+ // support changing these, so they might as well be in a known state.
+ dcb.fBinary = TRUE; // Win32 only supports binary mode.
+ dcb.fDsrSensitivity = FALSE;
+ dcb.fNull = FALSE; // Do not ignore NULL characters.
+ dcb.fAbortOnError = FALSE; // Ignore serial framing errors.
+ if (!::SetCommState(handle, &dcb))
+ {
+ DWORD last_error = ::GetLastError();
+ ::CloseHandle(handle);
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ // Set up timeouts so that the serial port will behave similarly to a
+ // network socket. Reads wait for at least one byte, then return with
+ // whatever they have. Writes return once everything is out the door.
+ ::COMMTIMEOUTS timeouts;
+ timeouts.ReadIntervalTimeout = 1;
+ timeouts.ReadTotalTimeoutMultiplier = 0;
+ timeouts.ReadTotalTimeoutConstant = 0;
+ timeouts.WriteTotalTimeoutMultiplier = 0;
+ timeouts.WriteTotalTimeoutConstant = 0;
+ if (!::SetCommTimeouts(handle, &timeouts))
+ {
+ DWORD last_error = ::GetLastError();
+ ::CloseHandle(handle);
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ // We're done. Take ownership of the serial port handle.
+ if (handle_service_.assign(impl, handle, ec))
+ ::CloseHandle(handle);
+ return ec;
+}
+
+asio::error_code win_iocp_serial_port_service::do_set_option(
+ win_iocp_serial_port_service::implementation_type& impl,
+ win_iocp_serial_port_service::store_function_type store,
+ const void* option, asio::error_code& ec)
+{
+ using namespace std; // For memcpy.
+
+ ::DCB dcb;
+ memset(&dcb, 0, sizeof(DCB));
+ dcb.DCBlength = sizeof(DCB);
+ if (!::GetCommState(handle_service_.native(impl), &dcb))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ if (store(option, dcb, ec))
+ return ec;
+
+ if (!::SetCommState(handle_service_.native(impl), &dcb))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ ec = asio::error_code();
+ return ec;
+}
+
+asio::error_code win_iocp_serial_port_service::do_get_option(
+ const win_iocp_serial_port_service::implementation_type& impl,
+ win_iocp_serial_port_service::load_function_type load,
+ void* option, asio::error_code& ec) const
+{
+ using namespace std; // For memset.
+
+ ::DCB dcb;
+ memset(&dcb, 0, sizeof(DCB));
+ dcb.DCBlength = sizeof(DCB);
+ if (!::GetCommState(handle_service_.native(impl), &dcb))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ return load(option, dcb, ec);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
diff --git a/ext/asio/asio/detail/impl/win_iocp_socket_service_base.ipp b/ext/asio/asio/detail/impl/win_iocp_socket_service_base.ipp
new file mode 100644
index 0000000..37c6f63
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_iocp_socket_service_base.ipp
@@ -0,0 +1,575 @@
+//
+// detail/impl/win_iocp_socket_service_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/win_iocp_socket_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_iocp_socket_service_base::win_iocp_socket_service_base(
+ asio::io_service& io_service)
+ : io_service_(io_service),
+ iocp_service_(use_service<win_iocp_io_service>(io_service)),
+ reactor_(0),
+ mutex_(),
+ impl_list_(0)
+{
+}
+
+void win_iocp_socket_service_base::shutdown_service()
+{
+ // Close all implementations, causing all operations to complete.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ base_implementation_type* impl = impl_list_;
+ while (impl)
+ {
+ asio::error_code ignored_ec;
+ close_for_destruction(*impl);
+ impl = impl->next_;
+ }
+}
+
+void win_iocp_socket_service_base::construct(
+ win_iocp_socket_service_base::base_implementation_type& impl)
+{
+ impl.socket_ = invalid_socket;
+ impl.state_ = 0;
+ impl.cancel_token_.reset();
+#if defined(ASIO_ENABLE_CANCELIO)
+ impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ // Insert implementation into linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ impl.next_ = impl_list_;
+ impl.prev_ = 0;
+ if (impl_list_)
+ impl_list_->prev_ = &impl;
+ impl_list_ = &impl;
+}
+
+void win_iocp_socket_service_base::destroy(
+ win_iocp_socket_service_base::base_implementation_type& impl)
+{
+ close_for_destruction(impl);
+
+ // Remove implementation from linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (impl_list_ == &impl)
+ impl_list_ = impl.next_;
+ if (impl.prev_)
+ impl.prev_->next_ = impl.next_;
+ if (impl.next_)
+ impl.next_->prev_= impl.prev_;
+ impl.next_ = 0;
+ impl.prev_ = 0;
+}
+
+asio::error_code win_iocp_socket_service_base::close(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ // Check if the reactor was created, in which case we need to close the
+ // socket on the reactor as well to cancel any operations that might be
+ // running there.
+ reactor* r = static_cast<reactor*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (r)
+ r->close_descriptor(impl.socket_, impl.reactor_data_);
+ }
+
+ if (socket_ops::close(impl.socket_, impl.state_, false, ec) == 0)
+ {
+ impl.socket_ = invalid_socket;
+ impl.state_ = 0;
+ impl.cancel_token_.reset();
+#if defined(ASIO_ENABLE_CANCELIO)
+ impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+ }
+
+ return ec;
+}
+
+asio::error_code win_iocp_socket_service_base::cancel(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+ else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
+ ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
+ {
+ // The version of Windows supports cancellation from any thread.
+ typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
+ cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
+ socket_type sock = impl.socket_;
+ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
+ if (!cancel_io_ex(sock_as_handle, 0))
+ {
+ DWORD last_error = ::GetLastError();
+ if (last_error == ERROR_NOT_FOUND)
+ {
+ // ERROR_NOT_FOUND means that there were no operations to be
+ // cancelled. We swallow this error to match the behaviour on other
+ // platforms.
+ ec = asio::error_code();
+ }
+ else
+ {
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+ }
+#if defined(ASIO_ENABLE_CANCELIO)
+ else if (impl.safe_cancellation_thread_id_ == 0)
+ {
+ // No operations have been started, so there's nothing to cancel.
+ ec = asio::error_code();
+ }
+ else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
+ {
+ // Asynchronous operations have been started from the current thread only,
+ // so it is safe to try to cancel them using CancelIo.
+ socket_type sock = impl.socket_;
+ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
+ if (!::CancelIo(sock_as_handle))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+ }
+ else
+ {
+ // Asynchronous operations have been started from more than one thread,
+ // so cancellation is not safe.
+ ec = asio::error::operation_not_supported;
+ }
+#else // defined(ASIO_ENABLE_CANCELIO)
+ else
+ {
+ // Cancellation is not supported as CancelIo may not be used.
+ ec = asio::error::operation_not_supported;
+ }
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ // Cancel any operations started via the reactor.
+ if (!ec)
+ {
+ reactor* r = static_cast<reactor*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (r)
+ r->cancel_ops(impl.socket_, impl.reactor_data_);
+ }
+
+ return ec;
+}
+
+asio::error_code win_iocp_socket_service_base::do_open(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ int family, int type, int protocol, asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ socket_holder sock(socket_ops::socket(family, type, protocol, ec));
+ if (sock.get() == invalid_socket)
+ return ec;
+
+ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock.get());
+ if (iocp_service_.register_handle(sock_as_handle, ec))
+ return ec;
+
+ impl.socket_ = sock.release();
+ switch (type)
+ {
+ case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+ case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+ default: impl.state_ = 0; break;
+ }
+ impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter());
+ ec = asio::error_code();
+ return ec;
+}
+
+asio::error_code win_iocp_socket_service_base::do_assign(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ int type, socket_type native_socket, asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(native_socket);
+ if (iocp_service_.register_handle(sock_as_handle, ec))
+ return ec;
+
+ impl.socket_ = native_socket;
+ switch (type)
+ {
+ case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+ case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+ default: impl.state_ = 0; break;
+ }
+ impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter());
+ ec = asio::error_code();
+ return ec;
+}
+
+void win_iocp_socket_service_base::start_send_op(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ WSABUF* buffers, std::size_t buffer_count,
+ socket_base::message_flags flags, bool noop, operation* op)
+{
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (noop)
+ iocp_service_.on_completion(op);
+ else if (!is_open(impl))
+ iocp_service_.on_completion(op, asio::error::bad_descriptor);
+ else
+ {
+ DWORD bytes_transferred = 0;
+ int result = ::WSASend(impl.socket_, buffers,
+ static_cast<DWORD>(buffer_count), &bytes_transferred, flags, op, 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ else
+ iocp_service_.on_pending(op);
+ }
+}
+
+void win_iocp_socket_service_base::start_send_to_op(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ WSABUF* buffers, std::size_t buffer_count,
+ const socket_addr_type* addr, int addrlen,
+ socket_base::message_flags flags, operation* op)
+{
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (!is_open(impl))
+ iocp_service_.on_completion(op, asio::error::bad_descriptor);
+ else
+ {
+ DWORD bytes_transferred = 0;
+ int result = ::WSASendTo(impl.socket_, buffers,
+ static_cast<DWORD>(buffer_count),
+ &bytes_transferred, flags, addr, addrlen, op, 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ else
+ iocp_service_.on_pending(op);
+ }
+}
+
+void win_iocp_socket_service_base::start_receive_op(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ WSABUF* buffers, std::size_t buffer_count,
+ socket_base::message_flags flags, bool noop, operation* op)
+{
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (noop)
+ iocp_service_.on_completion(op);
+ else if (!is_open(impl))
+ iocp_service_.on_completion(op, asio::error::bad_descriptor);
+ else
+ {
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = ::WSARecv(impl.socket_, buffers,
+ static_cast<DWORD>(buffer_count),
+ &bytes_transferred, &recv_flags, op, 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_NETNAME_DELETED)
+ last_error = WSAECONNRESET;
+ else if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ else
+ iocp_service_.on_pending(op);
+ }
+}
+
+void win_iocp_socket_service_base::start_null_buffers_receive_op(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ socket_base::message_flags flags, reactor_op* op)
+{
+ if ((impl.state_ & socket_ops::stream_oriented) != 0)
+ {
+ // For stream sockets on Windows, we may issue a 0-byte overlapped
+ // WSARecv to wait until there is data available on the socket.
+ ::WSABUF buf = { 0, 0 };
+ start_receive_op(impl, &buf, 1, flags, false, op);
+ }
+ else
+ {
+ start_reactor_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ op);
+ }
+}
+
+void win_iocp_socket_service_base::start_receive_from_op(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr,
+ socket_base::message_flags flags, int* addrlen, operation* op)
+{
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (!is_open(impl))
+ iocp_service_.on_completion(op, asio::error::bad_descriptor);
+ else
+ {
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = ::WSARecvFrom(impl.socket_, buffers,
+ static_cast<DWORD>(buffer_count),
+ &bytes_transferred, &recv_flags, addr, addrlen, op, 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ else
+ iocp_service_.on_pending(op);
+ }
+}
+
+void win_iocp_socket_service_base::start_accept_op(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ bool peer_is_open, socket_holder& new_socket, int family, int type,
+ int protocol, void* output_buffer, DWORD address_length, operation* op)
+{
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (!is_open(impl))
+ iocp_service_.on_completion(op, asio::error::bad_descriptor);
+ else if (peer_is_open)
+ iocp_service_.on_completion(op, asio::error::already_open);
+ else
+ {
+ asio::error_code ec;
+ new_socket.reset(socket_ops::socket(family, type, protocol, ec));
+ if (new_socket.get() == invalid_socket)
+ iocp_service_.on_completion(op, ec);
+ else
+ {
+ DWORD bytes_read = 0;
+ BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer,
+ 0, address_length, address_length, &bytes_read, op);
+ DWORD last_error = ::WSAGetLastError();
+ if (!result && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error);
+ else
+ iocp_service_.on_pending(op);
+ }
+ }
+}
+
+void win_iocp_socket_service_base::restart_accept_op(
+ socket_type s, socket_holder& new_socket, int family, int type,
+ int protocol, void* output_buffer, DWORD address_length, operation* op)
+{
+ new_socket.reset();
+ iocp_service_.work_started();
+
+ asio::error_code ec;
+ new_socket.reset(socket_ops::socket(family, type, protocol, ec));
+ if (new_socket.get() == invalid_socket)
+ iocp_service_.on_completion(op, ec);
+ else
+ {
+ DWORD bytes_read = 0;
+ BOOL result = ::AcceptEx(s, new_socket.get(), output_buffer,
+ 0, address_length, address_length, &bytes_read, op);
+ DWORD last_error = ::WSAGetLastError();
+ if (!result && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error);
+ else
+ iocp_service_.on_pending(op);
+ }
+}
+
+void win_iocp_socket_service_base::start_reactor_op(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ int op_type, reactor_op* op)
+{
+ reactor& r = get_reactor();
+ update_cancellation_thread_id(impl);
+
+ if (is_open(impl))
+ {
+ r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false);
+ return;
+ }
+ else
+ op->ec_ = asio::error::bad_descriptor;
+
+ iocp_service_.post_immediate_completion(op);
+}
+
+void win_iocp_socket_service_base::start_connect_op(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ reactor_op* op, const socket_addr_type* addr, std::size_t addrlen)
+{
+ reactor& r = get_reactor();
+ update_cancellation_thread_id(impl);
+
+ if ((impl.state_ & socket_ops::non_blocking) != 0
+ || socket_ops::set_internal_non_blocking(
+ impl.socket_, impl.state_, op->ec_))
+ {
+ if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
+ {
+ if (op->ec_ == asio::error::in_progress
+ || op->ec_ == asio::error::would_block)
+ {
+ op->ec_ = asio::error_code();
+ r.start_op(reactor::connect_op, impl.socket_,
+ impl.reactor_data_, op, false);
+ return;
+ }
+ }
+ }
+
+ r.post_immediate_completion(op);
+}
+
+void win_iocp_socket_service_base::close_for_destruction(
+ win_iocp_socket_service_base::base_implementation_type& impl)
+{
+ if (is_open(impl))
+ {
+ // Check if the reactor was created, in which case we need to close the
+ // socket on the reactor as well to cancel any operations that might be
+ // running there.
+ reactor* r = static_cast<reactor*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (r)
+ r->close_descriptor(impl.socket_, impl.reactor_data_);
+ }
+
+ asio::error_code ignored_ec;
+ socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
+ impl.socket_ = invalid_socket;
+ impl.state_ = 0;
+ impl.cancel_token_.reset();
+#if defined(ASIO_ENABLE_CANCELIO)
+ impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+}
+
+void win_iocp_socket_service_base::update_cancellation_thread_id(
+ win_iocp_socket_service_base::base_implementation_type& impl)
+{
+#if defined(ASIO_ENABLE_CANCELIO)
+ if (impl.safe_cancellation_thread_id_ == 0)
+ impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+ else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+ impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#else // defined(ASIO_ENABLE_CANCELIO)
+ (void)impl;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+}
+
+reactor& win_iocp_socket_service_base::get_reactor()
+{
+ reactor* r = static_cast<reactor*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (!r)
+ {
+ r = &(use_service<reactor>(io_service_));
+ interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r);
+ }
+ return *r;
+}
+
+void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer(
+ void** dest, void* exch, void* cmp)
+{
+#if defined(_M_IX86)
+ return reinterpret_cast<void*>(InterlockedCompareExchange(
+ reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch),
+ reinterpret_cast<LONG>(cmp)));
+#else
+ return InterlockedCompareExchangePointer(dest, exch, cmp);
+#endif
+}
+
+void* win_iocp_socket_service_base::interlocked_exchange_pointer(
+ void** dest, void* val)
+{
+#if defined(_M_IX86)
+ return reinterpret_cast<void*>(InterlockedExchange(
+ reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val)));
+#else
+ return InterlockedExchangePointer(dest, val);
+#endif
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
diff --git a/ext/asio/asio/detail/impl/win_mutex.ipp b/ext/asio/asio/detail/impl/win_mutex.ipp
new file mode 100644
index 0000000..910cc23
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_mutex.ipp
@@ -0,0 +1,78 @@
+//
+// detail/impl/win_mutex.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_MUTEX_IPP
+#define ASIO_DETAIL_IMPL_WIN_MUTEX_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_WINDOWS)
+
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_mutex.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_mutex::win_mutex()
+{
+ int error = do_init();
+ asio::error_code ec(error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "mutex");
+}
+
+int win_mutex::do_init()
+{
+#if defined(__MINGW32__)
+ // Not sure if MinGW supports structured exception handling, so for now
+ // we'll just call the Windows API and hope.
+# if defined(UNDER_CE)
+ ::InitializeCriticalSection(&crit_section_);
+# else
+ if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))
+ return ::GetLastError();
+# endif
+ return 0;
+#else
+ __try
+ {
+# if defined(UNDER_CE)
+ ::InitializeCriticalSection(&crit_section_);
+# else
+ if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))
+ return ::GetLastError();
+# endif
+ }
+ __except(GetExceptionCode() == STATUS_NO_MEMORY
+ ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
+ {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ return 0;
+#endif
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_WINDOWS)
+
+#endif // ASIO_DETAIL_IMPL_WIN_MUTEX_IPP
diff --git a/ext/asio/asio/detail/impl/win_thread.ipp b/ext/asio/asio/detail/impl/win_thread.ipp
new file mode 100644
index 0000000..65844c8
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_thread.ipp
@@ -0,0 +1,138 @@
+//
+// detail/impl/win_thread.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_THREAD_IPP
+#define ASIO_DETAIL_IMPL_WIN_THREAD_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_WINDOWS) && !defined(UNDER_CE)
+
+#include <process.h>
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_thread.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_thread::~win_thread()
+{
+ ::CloseHandle(thread_);
+
+ // The exit_event_ handle is deliberately allowed to leak here since it
+ // is an error for the owner of an internal thread not to join() it.
+}
+
+void win_thread::join()
+{
+ HANDLE handles[2] = { exit_event_, thread_ };
+ ::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+ ::CloseHandle(exit_event_);
+ if (terminate_threads())
+ {
+ ::TerminateThread(thread_, 0);
+ }
+ else
+ {
+ ::QueueUserAPC(apc_function, thread_, 0);
+ ::WaitForSingleObject(thread_, INFINITE);
+ }
+}
+
+void win_thread::start_thread(func_base* arg, unsigned int stack_size)
+{
+ ::HANDLE entry_event = 0;
+ arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0);
+ if (!entry_event)
+ {
+ DWORD last_error = ::GetLastError();
+ delete arg;
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "thread.entry_event");
+ }
+
+ arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0);
+ if (!exit_event_)
+ {
+ DWORD last_error = ::GetLastError();
+ delete arg;
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "thread.exit_event");
+ }
+
+ unsigned int thread_id = 0;
+ thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0,
+ stack_size, win_thread_function, arg, 0, &thread_id));
+ if (!thread_)
+ {
+ DWORD last_error = ::GetLastError();
+ delete arg;
+ if (entry_event)
+ ::CloseHandle(entry_event);
+ if (exit_event_)
+ ::CloseHandle(exit_event_);
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "thread");
+ }
+
+ if (entry_event)
+ {
+ ::WaitForSingleObject(entry_event, INFINITE);
+ ::CloseHandle(entry_event);
+ }
+}
+
+unsigned int __stdcall win_thread_function(void* arg)
+{
+ std::auto_ptr<win_thread::func_base> func(
+ static_cast<win_thread::func_base*>(arg));
+
+ ::SetEvent(func->entry_event_);
+
+ func->run();
+
+ // Signal that the thread has finished its work, but rather than returning go
+ // to sleep to put the thread into a well known state. If the thread is being
+ // joined during global object destruction then it may be killed using
+ // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx
+ // call will be interrupted using QueueUserAPC and the thread will shut down
+ // cleanly.
+ HANDLE exit_event = func->exit_event_;
+ func.reset();
+ ::SetEvent(exit_event);
+ ::SleepEx(INFINITE, TRUE);
+
+ return 0;
+}
+
+#if defined(WINVER) && (WINVER < 0x0500)
+void __stdcall apc_function(ULONG) {}
+#else
+void __stdcall apc_function(ULONG_PTR) {}
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE)
+
+#endif // ASIO_DETAIL_IMPL_WIN_THREAD_IPP
diff --git a/ext/asio/asio/detail/impl/win_tss_ptr.ipp b/ext/asio/asio/detail/impl/win_tss_ptr.ipp
new file mode 100644
index 0000000..de3ea3c
--- /dev/null
+++ b/ext/asio/asio/detail/impl/win_tss_ptr.ipp
@@ -0,0 +1,57 @@
+//
+// detail/impl/win_tss_ptr.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP
+#define ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_WINDOWS)
+
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_tss_ptr.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+DWORD win_tss_ptr_create()
+{
+#if defined(UNDER_CE)
+ enum { out_of_indexes = 0xFFFFFFFF };
+#else
+ enum { out_of_indexes = TLS_OUT_OF_INDEXES };
+#endif
+
+ DWORD tss_key = ::TlsAlloc();
+ if (tss_key == out_of_indexes)
+ {
+ DWORD last_error = ::GetLastError();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "tss");
+ }
+ return tss_key;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_WINDOWS)
+
+#endif // ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP
diff --git a/ext/asio/asio/detail/impl/winsock_init.ipp b/ext/asio/asio/detail/impl/winsock_init.ipp
new file mode 100644
index 0000000..3b20c98
--- /dev/null
+++ b/ext/asio/asio/detail/impl/winsock_init.ipp
@@ -0,0 +1,69 @@
+//
+// detail/impl/winsock_init.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP
+#define ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+void winsock_init_base::startup(data& d,
+ unsigned char major, unsigned char minor)
+{
+ if (::InterlockedIncrement(&d.init_count_) == 1)
+ {
+ WSADATA wsa_data;
+ long result = ::WSAStartup(MAKEWORD(major, minor), &wsa_data);
+ ::InterlockedExchange(&d.result_, result);
+ }
+}
+
+void winsock_init_base::cleanup(data& d)
+{
+ if (::InterlockedDecrement(&d.init_count_) == 0)
+ {
+ ::WSACleanup();
+ }
+}
+
+void winsock_init_base::throw_on_error(data& d)
+{
+ long result = ::InterlockedExchangeAdd(&d.result_, 0);
+ if (result != 0)
+ {
+ asio::error_code ec(result,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "winsock");
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP
diff --git a/ext/asio/asio/detail/io_control.hpp b/ext/asio/asio/detail/io_control.hpp
index df7171c..b3ef844 100644
--- a/ext/asio/asio/detail/io_control.hpp
+++ b/ext/asio/asio/detail/io_control.hpp
@@ -1,8 +1,8 @@
//
-// io_control.hpp
-// ~~~~~~~~~~~~~~
+// detail/io_control.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/detail/socket_types.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
namespace io_control {
diff --git a/ext/asio/asio/detail/kqueue_reactor.hpp b/ext/asio/asio/detail/kqueue_reactor.hpp
index bfa004d..07087dd 100644
--- a/ext/asio/asio/detail/kqueue_reactor.hpp
+++ b/ext/asio/asio/detail/kqueue_reactor.hpp
@@ -1,8 +1,8 @@
//
-// kqueue_reactor.hpp
-// ~~~~~~~~~~~~~~~~~~
+// detail/kqueue_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,41 +16,35 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/kqueue_reactor_fwd.hpp"
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_KQUEUE)
-#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
-#include <boost/config.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/io_service.hpp"
-#include "asio/system_error.hpp"
-#include "asio/detail/hash_map.hpp"
+#include "asio/detail/kqueue_reactor_fwd.hpp"
#include "asio/detail/mutex.hpp"
+#include "asio/detail/object_pool.hpp"
#include "asio/detail/op_queue.hpp"
#include "asio/detail/reactor_op.hpp"
#include "asio/detail/select_interrupter.hpp"
-#include "asio/detail/service_base.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_op.hpp"
#include "asio/detail/timer_queue_base.hpp"
#include "asio/detail/timer_queue_fwd.hpp"
#include "asio/detail/timer_queue_set.hpp"
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
// Older versions of Mac OS X may not define EV_OOBAND.
#if !defined(EV_OOBAND)
# define EV_OOBAND EV_FLAG1
#endif // !defined(EV_OOBAND)
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -64,384 +58,98 @@ public:
// Per-descriptor queues.
struct descriptor_state
{
- descriptor_state() {}
- descriptor_state(const descriptor_state&) {}
- void operator=(const descriptor_state&) {}
-
+ friend class kqueue_reactor;
+ friend class object_pool_access;
mutex mutex_;
op_queue<reactor_op> op_queue_[max_ops];
bool shutdown_;
+ descriptor_state* next_;
+ descriptor_state* prev_;
};
// Per-descriptor data.
typedef descriptor_state* per_descriptor_data;
// Constructor.
- kqueue_reactor(asio::io_service& io_service)
- : asio::detail::service_base<kqueue_reactor>(io_service),
- io_service_(use_service<io_service_impl>(io_service)),
- mutex_(),
- kqueue_fd_(do_kqueue_create()),
- interrupter_(),
- shutdown_(false)
- {
- // The interrupter is put into a permanently readable state. Whenever we
- // want to interrupt the blocked kevent call we register a one-shot read
- // operation against the descriptor.
- interrupter_.interrupt();
- }
+ ASIO_DECL kqueue_reactor(asio::io_service& io_service);
// Destructor.
- ~kqueue_reactor()
- {
- close(kqueue_fd_);
- }
+ ASIO_DECL ~kqueue_reactor();
// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- mutex::scoped_lock lock(mutex_);
- shutdown_ = true;
- lock.unlock();
-
- op_queue<operation> ops;
-
- descriptor_map::iterator iter = registered_descriptors_.begin();
- descriptor_map::iterator end = registered_descriptors_.end();
- while (iter != end)
- {
- for (int i = 0; i < max_ops; ++i)
- ops.push(iter->second.op_queue_[i]);
- iter->second.shutdown_ = true;
- ++iter;
- }
-
- timer_queues_.get_all_timers(ops);
- }
+ ASIO_DECL void shutdown_service();
// Initialise the task.
- void init_task()
- {
- io_service_.init_task();
- }
+ ASIO_DECL void init_task();
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
- int register_descriptor(socket_type descriptor,
- per_descriptor_data& descriptor_data)
- {
- mutex::scoped_lock lock(registered_descriptors_mutex_);
-
- descriptor_map::iterator new_entry = registered_descriptors_.insert(
- std::make_pair(descriptor, descriptor_state())).first;
- descriptor_data = &new_entry->second;
+ ASIO_DECL int register_descriptor(socket_type descriptor,
+ per_descriptor_data& descriptor_data);
- descriptor_data->shutdown_ = false;
-
- return 0;
+ // Post a reactor operation for immediate completion.
+ void post_immediate_completion(reactor_op* op)
+ {
+ io_service_.post_immediate_completion(op);
}
// Start a new operation. The reactor operation will be performed when the
// given descriptor is flagged as ready, or an error has occurred.
- void start_op(int op_type, socket_type descriptor,
+ ASIO_DECL void start_op(int op_type, socket_type descriptor,
per_descriptor_data& descriptor_data,
- reactor_op* op, bool allow_speculative)
- {
- mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
- if (descriptor_data->shutdown_)
- return;
-
- bool first = descriptor_data->op_queue_[op_type].empty();
- if (first)
- {
- if (allow_speculative)
- {
- if (op_type != read_op || descriptor_data->op_queue_[except_op].empty())
- {
- if (op->perform())
- {
- descriptor_lock.unlock();
- io_service_.post_immediate_completion(op);
- return;
- }
- }
- }
- }
-
- descriptor_data->op_queue_[op_type].push(op);
- io_service_.work_started();
-
- if (first)
- {
- struct kevent event;
- switch (op_type)
- {
- case read_op:
- EV_SET(&event, descriptor, EVFILT_READ,
- EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
- break;
- case write_op:
- EV_SET(&event, descriptor, EVFILT_WRITE,
- EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
- break;
- case except_op:
- if (!descriptor_data->op_queue_[read_op].empty())
- return; // Already registered for read events.
- EV_SET(&event, descriptor, EVFILT_READ,
- EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data);
- break;
- }
-
- if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
- {
- op->ec_ = asio::error_code(errno,
- asio::error::get_system_category());
- descriptor_data->op_queue_[op_type].pop();
- io_service_.post_deferred_completion(op);
- }
- }
- }
+ reactor_op* op, bool allow_speculative);
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
- void cancel_ops(socket_type , per_descriptor_data& descriptor_data)
- {
- mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
-
- op_queue<operation> ops;
- for (int i = 0; i < max_ops; ++i)
- {
- while (reactor_op* op = descriptor_data->op_queue_[i].front())
- {
- op->ec_ = asio::error::operation_aborted;
- descriptor_data->op_queue_[i].pop();
- ops.push(op);
- }
- }
-
- descriptor_lock.unlock();
-
- io_service_.post_deferred_completions(ops);
- }
+ ASIO_DECL void cancel_ops(socket_type descriptor,
+ per_descriptor_data& descriptor_data);
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor.
- void close_descriptor(socket_type descriptor,
- per_descriptor_data& descriptor_data)
- {
- mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
- mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
-
- // Remove the descriptor from the set of known descriptors. The descriptor
- // will be automatically removed from the kqueue set when it is closed.
- descriptor_data->shutdown_ = true;
-
- op_queue<operation> ops;
- for (int i = 0; i < max_ops; ++i)
- {
- while (reactor_op* op = descriptor_data->op_queue_[i].front())
- {
- op->ec_ = asio::error::operation_aborted;
- descriptor_data->op_queue_[i].pop();
- ops.push(op);
- }
- }
-
- descriptor_lock.unlock();
-
- registered_descriptors_.erase(descriptor);
-
- descriptors_lock.unlock();
-
- io_service_.post_deferred_completions(ops);
- }
+ ASIO_DECL void close_descriptor(socket_type descriptor,
+ per_descriptor_data& descriptor_data);
// Add a new timer queue to the reactor.
template <typename Time_Traits>
- void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
- {
- mutex::scoped_lock lock(mutex_);
- timer_queues_.insert(&timer_queue);
- }
+ void add_timer_queue(timer_queue<Time_Traits>& queue);
// Remove a timer queue from the reactor.
template <typename Time_Traits>
- void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
- {
- mutex::scoped_lock lock(mutex_);
- timer_queues_.erase(&timer_queue);
- }
+ void remove_timer_queue(timer_queue<Time_Traits>& queue);
// Schedule a new operation in the given timer queue to expire at the
// specified absolute time.
template <typename Time_Traits>
- void schedule_timer(timer_queue<Time_Traits>& timer_queue,
- const typename Time_Traits::time_type& time, timer_op* op, void* token)
- {
- mutex::scoped_lock lock(mutex_);
- if (!shutdown_)
- {
- bool earliest = timer_queue.enqueue_timer(time, op, token);
- io_service_.work_started();
- if (earliest)
- interrupt();
- }
- }
+ void schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op);
// Cancel the timer operations associated with the given token. Returns the
// number of operations that have been posted or dispatched.
template <typename Time_Traits>
- std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
- {
- mutex::scoped_lock lock(mutex_);
- op_queue<operation> ops;
- std::size_t n = timer_queue.cancel_timer(token, ops);
- lock.unlock();
- io_service_.post_deferred_completions(ops);
- return n;
- }
+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer);
// Run the kqueue loop.
- void run(bool block, op_queue<operation>& ops)
- {
- mutex::scoped_lock lock(mutex_);
-
- // Determine how long to block while waiting for events.
- timespec timeout_buf = { 0, 0 };
- timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf;
-
- lock.unlock();
-
- // Block on the kqueue descriptor.
- struct kevent events[128];
- int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout);
-
- // Dispatch the waiting events.
- for (int i = 0; i < num_events; ++i)
- {
- int descriptor = events[i].ident;
- void* ptr = events[i].udata;
- if (ptr == &interrupter_)
- {
- // No need to reset the interrupter since we're leaving the descriptor
- // in a ready-to-read state and relying on one-shot notifications.
- }
- else
- {
- descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
- mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
-
- // Exception operations must be processed first to ensure that any
- // out-of-band data is read before normal data.
- static const int filter[max_ops] =
- { EVFILT_READ, EVFILT_WRITE, EVFILT_READ };
- for (int j = max_ops - 1; j >= 0; --j)
- {
- if (events[i].filter == filter[j])
- {
- if (j != except_op || events[i].flags & EV_OOBAND)
- {
- while (reactor_op* op = descriptor_data->op_queue_[j].front())
- {
- if (events[i].flags & EV_ERROR)
- {
- op->ec_ = asio::error_code(events[i].data,
- asio::error::get_system_category());
- descriptor_data->op_queue_[j].pop();
- ops.push(op);
- }
- if (op->perform())
- {
- descriptor_data->op_queue_[j].pop();
- ops.push(op);
- }
- else
- break;
- }
- }
- }
- }
-
- // Renew registration for event notifications.
- struct kevent event;
- switch (events[i].filter)
- {
- case EVFILT_READ:
- if (!descriptor_data->op_queue_[read_op].empty())
- EV_SET(&event, descriptor, EVFILT_READ,
- EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
- else if (!descriptor_data->op_queue_[except_op].empty())
- EV_SET(&event, descriptor, EVFILT_READ,
- EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data);
- else
- continue;
- case EVFILT_WRITE:
- if (!descriptor_data->op_queue_[write_op].empty())
- EV_SET(&event, descriptor, EVFILT_WRITE,
- EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
- else
- continue;
- default:
- break;
- }
- if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
- {
- asio::error_code error(errno,
- asio::error::get_system_category());
- for (int j = 0; j < max_ops; ++j)
- {
- while (reactor_op* op = descriptor_data->op_queue_[j].front())
- {
- op->ec_ = error;
- descriptor_data->op_queue_[j].pop();
- ops.push(op);
- }
- }
- }
- }
- }
-
- lock.lock();
- timer_queues_.get_ready_timers(ops);
- }
+ ASIO_DECL void run(bool block, op_queue<operation>& ops);
// Interrupt the kqueue loop.
- void interrupt()
- {
- struct kevent event;
- EV_SET(&event, interrupter_.read_descriptor(),
- EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &interrupter_);
- ::kevent(kqueue_fd_, &event, 1, 0, 0, 0);
- }
+ ASIO_DECL void interrupt();
private:
// Create the kqueue file descriptor. Throws an exception if the descriptor
// cannot be created.
- static int do_kqueue_create()
- {
- int fd = kqueue();
- if (fd == -1)
- {
- boost::throw_exception(
- asio::system_error(
- asio::error_code(errno,
- asio::error::get_system_category()),
- "kqueue"));
- }
- return fd;
- }
+ ASIO_DECL static int do_kqueue_create();
+
+ // Helper function to add a new timer queue.
+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+ // Helper function to remove a timer queue.
+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
// Get the timeout value for the kevent call.
- timespec* get_timeout(timespec& ts)
- {
- // By default we will wait no longer than 5 minutes. This will ensure that
- // any changes to the system clock are detected after no longer than this.
- long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
- ts.tv_sec = usec / 1000000;
- ts.tv_nsec = (usec % 1000000) * 1000;
- return &ts;
- }
+ ASIO_DECL timespec* get_timeout(timespec& ts);
// The io_service implementation used to post completions.
io_service_impl& io_service_;
@@ -464,22 +172,20 @@ private:
// Mutex to protect access to the registered descriptors.
mutex registered_descriptors_mutex_;
- // Keep track of all registered descriptors. This code relies on the fact that
- // the hash_map implementation pools deleted nodes, meaning that we can assume
- // our descriptor_state pointer remains valid even after the entry is removed.
- // Technically this is not true for C++98, as that standard says that spliced
- // elements in a list are invalidated. However, C++0x fixes this shortcoming
- // so we'll just assume that C++98 std::list implementations will do the right
- // thing anyway.
- typedef detail::hash_map<socket_type, descriptor_state> descriptor_map;
- descriptor_map registered_descriptors_;
+ // Keep track of all registered descriptors.
+ object_pool<descriptor_state> registered_descriptors_;
};
} // namespace detail
} // namespace asio
-#endif // defined(ASIO_HAS_KQUEUE)
-
#include "asio/detail/pop_options.hpp"
+#include "asio/detail/impl/kqueue_reactor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/kqueue_reactor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_KQUEUE)
+
#endif // ASIO_DETAIL_KQUEUE_REACTOR_HPP
diff --git a/ext/asio/asio/detail/kqueue_reactor_fwd.hpp b/ext/asio/asio/detail/kqueue_reactor_fwd.hpp
index abbc0c7..fda59ce 100644
--- a/ext/asio/asio/detail/kqueue_reactor_fwd.hpp
+++ b/ext/asio/asio/detail/kqueue_reactor_fwd.hpp
@@ -1,8 +1,8 @@
//
-// kqueue_reactor_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~
+// detail/kqueue_reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,15 +16,9 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#if !defined(ASIO_DISABLE_KQUEUE)
-
-#if (defined(__MACH__) && defined(__APPLE__)) \
- || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
-
-// Define this to indicate that kqueue is supported on the target platform.
-#define ASIO_HAS_KQUEUE 1
+#if defined(ASIO_HAS_KQUEUE)
namespace asio {
namespace detail {
@@ -34,11 +28,6 @@ class kqueue_reactor;
} // namespace detail
} // namespace asio
-#endif // (defined(__MACH__) && defined(__APPLE__))
- // || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
-
-#endif // !defined(ASIO_DISABLE_KQUEUE)
-
-#include "asio/detail/pop_options.hpp"
+#endif // defined(ASIO_HAS_KQUEUE)
#endif // ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP
diff --git a/ext/asio/asio/detail/local_free_on_block_exit.hpp b/ext/asio/asio/detail/local_free_on_block_exit.hpp
index 554943c..a55bd4b 100644
--- a/ext/asio/asio/detail/local_free_on_block_exit.hpp
+++ b/ext/asio/asio/detail/local_free_on_block_exit.hpp
@@ -1,8 +1,8 @@
//
-// local_free_on_block_exit.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/local_free_on_block_exit.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -52,8 +50,8 @@ private:
} // namespace detail
} // namespace asio
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-
#include "asio/detail/pop_options.hpp"
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
#endif // ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
diff --git a/ext/asio/asio/detail/macos_fenced_block.hpp b/ext/asio/asio/detail/macos_fenced_block.hpp
index 3c303d6..fcb8bfc 100644
--- a/ext/asio/asio/detail/macos_fenced_block.hpp
+++ b/ext/asio/asio/detail/macos_fenced_block.hpp
@@ -1,8 +1,8 @@
//
-// macos_fenced_block.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~
+// detail/macos_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if defined(__MACH__) && defined(__APPLE__)
-#include "asio/detail/push_options.hpp"
#include <libkern/OSAtomic.h>
-#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -50,8 +46,8 @@ public:
} // namespace detail
} // namespace asio
-#endif // defined(__MACH__) && defined(__APPLE__)
-
#include "asio/detail/pop_options.hpp"
+#endif // defined(__MACH__) && defined(__APPLE__)
+
#endif // ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP
diff --git a/ext/asio/asio/detail/mutex.hpp b/ext/asio/asio/detail/mutex.hpp
index 024ec7f..dc478ff 100644
--- a/ext/asio/asio/detail/mutex.hpp
+++ b/ext/asio/asio/detail/mutex.hpp
@@ -1,8 +1,8 @@
//
-// mutex.hpp
-// ~~~~~~~~~
+// detail/mutex.hpp
+// ~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,7 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
# include "asio/detail/null_mutex.hpp"
@@ -45,6 +41,4 @@ typedef posix_mutex mutex;
} // namespace detail
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_MUTEX_HPP
diff --git a/ext/asio/asio/detail/noncopyable.hpp b/ext/asio/asio/detail/noncopyable.hpp
index 8b73ff0..e7f6437 100644
--- a/ext/asio/asio/detail/noncopyable.hpp
+++ b/ext/asio/asio/detail/noncopyable.hpp
@@ -1,8 +1,8 @@
//
-// noncopyable.hpp
-// ~~~~~~~~~~~~~~~
+// detail/noncopyable.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,13 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
+#include "asio/detail/config.hpp"
#include <boost/noncopyable.hpp>
#include <boost/detail/workaround.hpp>
-#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
diff --git a/ext/asio/asio/detail/null_event.hpp b/ext/asio/asio/detail/null_event.hpp
index bcea31b..db7b747 100644
--- a/ext/asio/asio/detail/null_event.hpp
+++ b/ext/asio/asio/detail/null_event.hpp
@@ -1,8 +1,8 @@
//
-// null_event.hpp
-// ~~~~~~~~~~~~~~
+// detail/null_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -70,8 +68,8 @@ public:
} // namespace detail
} // namespace asio
-#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
-
#include "asio/detail/pop_options.hpp"
+#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+
#endif // ASIO_DETAIL_NULL_EVENT_HPP
diff --git a/ext/asio/asio/detail/null_fenced_block.hpp b/ext/asio/asio/detail/null_fenced_block.hpp
index dd9a095..fbd025f 100644
--- a/ext/asio/asio/detail/null_fenced_block.hpp
+++ b/ext/asio/asio/detail/null_fenced_block.hpp
@@ -1,8 +1,8 @@
//
-// null_fenced_block.hpp
-// ~~~~~~~~~~~~~~~~~~~~~
+// detail/null_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
diff --git a/ext/asio/asio/detail/null_mutex.hpp b/ext/asio/asio/detail/null_mutex.hpp
index 6661ef8..bbceb7c 100644
--- a/ext/asio/asio/detail/null_mutex.hpp
+++ b/ext/asio/asio/detail/null_mutex.hpp
@@ -1,8 +1,8 @@
//
-// null_mutex.hpp
-// ~~~~~~~~~~~~~~
+// detail/null_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/scoped_lock.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -59,8 +57,8 @@ public:
} // namespace detail
} // namespace asio
-#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
-
#include "asio/detail/pop_options.hpp"
+#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+
#endif // ASIO_DETAIL_NULL_MUTEX_HPP
diff --git a/ext/asio/asio/detail/null_signal_blocker.hpp b/ext/asio/asio/detail/null_signal_blocker.hpp
index a5db315..e0d996f 100644
--- a/ext/asio/asio/detail/null_signal_blocker.hpp
+++ b/ext/asio/asio/detail/null_signal_blocker.hpp
@@ -1,8 +1,8 @@
//
-// null_signal_blocker.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~
+// detail/null_signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,18 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
-#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+#if !defined(BOOST_HAS_THREADS) \
+ || defined(ASIO_DISABLE_THREADS) \
+ || defined(BOOST_WINDOWS) \
+ || defined(__CYGWIN__) \
+ || defined(__SYMBIAN32__)
#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -56,8 +58,12 @@ public:
} // namespace detail
} // namespace asio
-#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
-
#include "asio/detail/pop_options.hpp"
+#endif // !defined(BOOST_HAS_THREADS)
+ // || defined(ASIO_DISABLE_THREADS)
+ // || defined(BOOST_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+
#endif // ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
diff --git a/ext/asio/asio/detail/null_thread.hpp b/ext/asio/asio/detail/null_thread.hpp
index ce3d470..bfe918e 100644
--- a/ext/asio/asio/detail/null_thread.hpp
+++ b/ext/asio/asio/detail/null_thread.hpp
@@ -1,8 +1,8 @@
//
-// null_thread.hpp
-// ~~~~~~~~~~~~~~~
+// detail/null_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,21 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
-#include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -40,11 +34,10 @@ class null_thread
public:
// Constructor.
template <typename Function>
- null_thread(Function )
+ null_thread(Function, unsigned int = 0)
{
- asio::system_error e(
+ asio::detail::throw_error(
asio::error::operation_not_supported, "thread");
- boost::throw_exception(e);
}
// Destructor.
@@ -61,8 +54,8 @@ public:
} // namespace detail
} // namespace asio
-#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
-
#include "asio/detail/pop_options.hpp"
+#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+
#endif // ASIO_DETAIL_NULL_THREAD_HPP
diff --git a/ext/asio/asio/detail/null_tss_ptr.hpp b/ext/asio/asio/detail/null_tss_ptr.hpp
index 112b476..d3456e6 100644
--- a/ext/asio/asio/detail/null_tss_ptr.hpp
+++ b/ext/asio/asio/detail/null_tss_ptr.hpp
@@ -1,8 +1,8 @@
//
-// null_tss_ptr.hpp
-// ~~~~~~~~~~~~~~~~
+// detail/null_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -63,8 +61,8 @@ private:
} // namespace detail
} // namespace asio
-#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
-
#include "asio/detail/pop_options.hpp"
+#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+
#endif // ASIO_DETAIL_NULL_TSS_PTR_HPP
diff --git a/ext/asio/asio/detail/object_pool.hpp b/ext/asio/asio/detail/object_pool.hpp
new file mode 100644
index 0000000..dc50feb
--- /dev/null
+++ b/ext/asio/asio/detail/object_pool.hpp
@@ -0,0 +1,146 @@
+//
+// detail/object_pool.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_OBJECT_POOL_HPP
+#define ASIO_DETAIL_OBJECT_POOL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Object>
+class object_pool;
+
+class object_pool_access
+{
+public:
+ template <typename Object>
+ static Object* create()
+ {
+ return new Object;
+ }
+
+ template <typename Object>
+ static void destroy(Object* o)
+ {
+ delete o;
+ }
+
+ template <typename Object>
+ static Object*& next(Object* o)
+ {
+ return o->next_;
+ }
+
+ template <typename Object>
+ static Object*& prev(Object* o)
+ {
+ return o->prev_;
+ }
+};
+
+template <typename Object>
+class object_pool
+ : private noncopyable
+{
+public:
+ // Constructor.
+ object_pool()
+ : live_list_(0),
+ free_list_(0)
+ {
+ }
+
+ // Destructor destroys all objects.
+ ~object_pool()
+ {
+ destroy_list(live_list_);
+ destroy_list(free_list_);
+ }
+
+ // Get the object at the start of the live list.
+ Object* first()
+ {
+ return live_list_;
+ }
+
+ // Allocate a new object.
+ Object* alloc()
+ {
+ Object* o = free_list_;
+ if (o)
+ free_list_ = object_pool_access::next(free_list_);
+ else
+ o = object_pool_access::create<Object>();
+
+ object_pool_access::next(o) = live_list_;
+ object_pool_access::prev(o) = 0;
+ if (live_list_)
+ object_pool_access::prev(live_list_) = o;
+ live_list_ = o;
+
+ return o;
+ }
+
+ // Free an object. Moves it to the free list. No destructors are run.
+ void free(Object* o)
+ {
+ if (live_list_ == o)
+ live_list_ = object_pool_access::next(o);
+
+ if (object_pool_access::prev(o))
+ {
+ object_pool_access::next(object_pool_access::prev(o))
+ = object_pool_access::next(o);
+ }
+
+ if (object_pool_access::next(o))
+ {
+ object_pool_access::prev(object_pool_access::next(o))
+ = object_pool_access::prev(o);
+ }
+
+ object_pool_access::next(o) = free_list_;
+ object_pool_access::prev(o) = 0;
+ free_list_ = o;
+ }
+
+private:
+ // Helper function to destroy all elements in a list.
+ void destroy_list(Object* list)
+ {
+ while (list)
+ {
+ Object* o = list;
+ list = object_pool_access::next(o);
+ object_pool_access::destroy(o);
+ }
+ }
+
+ // The list of live objects.
+ Object* live_list_;
+
+ // The free list.
+ Object* free_list_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_OBJECT_POOL_HPP
diff --git a/ext/asio/asio/detail/old_win_sdk_compat.hpp b/ext/asio/asio/detail/old_win_sdk_compat.hpp
index 70e5916..fb75579 100644
--- a/ext/asio/asio/detail/old_win_sdk_compat.hpp
+++ b/ext/asio/asio/detail/old_win_sdk_compat.hpp
@@ -1,8 +1,8 @@
//
-// old_win_sdk_compat.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~
+// detail/old_win_sdk_compat.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,7 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -36,6 +32,8 @@
// a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support
// in that case.
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -321,6 +319,8 @@ inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a)
} // namespace detail
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#endif // defined(ASIO_HAS_OLD_WIN_SDK)
// Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY.
@@ -335,6 +335,4 @@ inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a)
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
diff --git a/ext/asio/asio/detail/op_queue.hpp b/ext/asio/asio/detail/op_queue.hpp
index ccf8b9a..38278ea 100644
--- a/ext/asio/asio/detail/op_queue.hpp
+++ b/ext/asio/asio/detail/op_queue.hpp
@@ -1,8 +1,8 @@
//
-// op_queue.hpp
-// ~~~~~~~~~~~~
+// detail/op_queue.hpp
+// ~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,10 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
diff --git a/ext/asio/asio/detail/operation.hpp b/ext/asio/asio/detail/operation.hpp
index 6aba361..3435c05 100644
--- a/ext/asio/asio/detail/operation.hpp
+++ b/ext/asio/asio/detail/operation.hpp
@@ -1,8 +1,8 @@
//
-// operation.hpp
-// ~~~~~~~~~~~~~
+// detail/operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_operation.hpp"
#else
-# include "asio/detail/reactor_fwd.hpp"
# include "asio/detail/task_io_service_operation.hpp"
#endif
@@ -32,12 +29,10 @@ namespace detail {
#if defined(ASIO_HAS_IOCP)
typedef win_iocp_operation operation;
#else
-typedef task_io_service_operation<reactor> operation;
+typedef task_io_service_operation operation;
#endif
} // namespace detail
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_OPERATION_HPP
diff --git a/ext/asio/asio/detail/pipe_select_interrupter.hpp b/ext/asio/asio/detail/pipe_select_interrupter.hpp
index 7469599..bf39426 100644
--- a/ext/asio/asio/detail/pipe_select_interrupter.hpp
+++ b/ext/asio/asio/detail/pipe_select_interrupter.hpp
@@ -1,8 +1,8 @@
//
-// pipe_select_interrupter.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/pipe_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,22 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#if !defined(BOOST_WINDOWS)
+#if !defined(__CYGWIN__)
+#if !defined(__SYMBIAN32__)
+#if !defined(ASIO_HAS_EVENTFD)
#include "asio/detail/push_options.hpp"
-#include <fcntl.h>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
-#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
@@ -39,57 +31,16 @@ class pipe_select_interrupter
{
public:
// Constructor.
- pipe_select_interrupter()
- {
- int pipe_fds[2];
- if (pipe(pipe_fds) == 0)
- {
- read_descriptor_ = pipe_fds[0];
- ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
- write_descriptor_ = pipe_fds[1];
- ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
- }
- else
- {
- asio::error_code ec(errno,
- asio::error::get_system_category());
- asio::system_error e(ec, "pipe_select_interrupter");
- boost::throw_exception(e);
- }
- }
+ ASIO_DECL pipe_select_interrupter();
// Destructor.
- ~pipe_select_interrupter()
- {
- if (read_descriptor_ != -1)
- ::close(read_descriptor_);
- if (write_descriptor_ != -1)
- ::close(write_descriptor_);
- }
+ ASIO_DECL ~pipe_select_interrupter();
// Interrupt the select call.
- void interrupt()
- {
- char byte = 0;
- int result = ::write(write_descriptor_, &byte, 1);
- (void)result;
- }
+ ASIO_DECL void interrupt();
// Reset the select interrupt. Returns true if the call was interrupted.
- bool reset()
- {
- for (;;)
- {
- char data[1024];
- int bytes_read = ::read(read_descriptor_, data, sizeof(data));
- if (bytes_read < 0 && errno == EINTR)
- continue;
- bool was_interrupted = (bytes_read > 0);
- while (bytes_read == sizeof(data))
- bytes_read = ::read(read_descriptor_, data, sizeof(data));
- return was_interrupted;
- }
- }
+ ASIO_DECL bool reset();
// Get the read descriptor to be passed to select.
int read_descriptor() const
@@ -113,8 +64,15 @@ private:
} // namespace detail
} // namespace asio
-#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/pipe_select_interrupter.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_HAS_EVENTFD)
+#endif // !defined(__SYMBIAN32__)
+#endif // !defined(__CYGWIN__)
+#endif // !defined(BOOST_WINDOWS)
+
#endif // ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
diff --git a/ext/asio/asio/detail/pop_options.hpp b/ext/asio/asio/detail/pop_options.hpp
index a26b203..4e19336 100644
--- a/ext/asio/asio/detail/pop_options.hpp
+++ b/ext/asio/asio/detail/pop_options.hpp
@@ -1,8 +1,8 @@
//
-// pop_options.hpp
-// ~~~~~~~~~~~~~~~
+// detail/pop_options.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -31,6 +31,16 @@
# pragma pack (pop)
# endif
+# if defined(__OBJC__)
+# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1)
+# if defined(ASIO_OBJC_WORKAROUND)
+# undef Protocol
+# undef id
+# undef ASIO_OBJC_WORKAROUND
+# endif
+# endif
+# endif
+
#elif defined(__KCC)
// Kai C++
diff --git a/ext/asio/asio/detail/posix_event.hpp b/ext/asio/asio/detail/posix_event.hpp
index 49c15aa..d0ec8b0 100644
--- a/ext/asio/asio/detail/posix_event.hpp
+++ b/ext/asio/asio/detail/posix_event.hpp
@@ -1,8 +1,8 @@
//
-// posix_event.hpp
-// ~~~~~~~~~~~~~~~
+// detail/posix_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,24 +15,16 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
-#if defined(BOOST_HAS_PTHREADS)
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
-#include "asio/detail/push_options.hpp"
#include <boost/assert.hpp>
-#include <boost/throw_exception.hpp>
#include <pthread.h>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -41,19 +33,7 @@ class posix_event
{
public:
// Constructor.
- posix_event()
- : signalled_(false)
- {
- int error = ::pthread_cond_init(&cond_, 0);
- if (error != 0)
- {
- asio::system_error e(
- asio::error_code(error,
- asio::error::get_system_category()),
- "event");
- boost::throw_exception(e);
- }
- }
+ ASIO_DECL posix_event();
// Destructor.
~posix_event()
@@ -107,8 +87,12 @@ private:
} // namespace detail
} // namespace asio
-#endif // defined(BOOST_HAS_PTHREADS)
-
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/posix_event.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
#endif // ASIO_DETAIL_POSIX_EVENT_HPP
diff --git a/ext/asio/asio/detail/posix_fd_set_adapter.hpp b/ext/asio/asio/detail/posix_fd_set_adapter.hpp
index 17ef269..92d6bba 100644
--- a/ext/asio/asio/detail/posix_fd_set_adapter.hpp
+++ b/ext/asio/asio/detail/posix_fd_set_adapter.hpp
@@ -1,8 +1,8 @@
//
-// posix_fd_set_adapter.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/posix_fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
-#include <cstring>
-#include "asio/detail/pop_options.hpp"
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#include <cstring>
#include "asio/detail/socket_types.hpp"
-#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -74,8 +73,8 @@ private:
} // namespace detail
} // namespace asio
-#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-
#include "asio/detail/pop_options.hpp"
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
#endif // ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
diff --git a/ext/asio/asio/detail/posix_mutex.hpp b/ext/asio/asio/detail/posix_mutex.hpp
index 230b83a..bcdf6b2 100644
--- a/ext/asio/asio/detail/posix_mutex.hpp
+++ b/ext/asio/asio/detail/posix_mutex.hpp
@@ -1,8 +1,8 @@
//
-// posix_mutex.hpp
-// ~~~~~~~~~~~~~~~
+// detail/posix_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,24 +15,16 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
-#if defined(BOOST_HAS_PTHREADS)
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
-#include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
#include <pthread.h>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/scoped_lock.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -45,18 +37,7 @@ public:
typedef asio::detail::scoped_lock<posix_mutex> scoped_lock;
// Constructor.
- posix_mutex()
- {
- int error = ::pthread_mutex_init(&mutex_, 0);
- if (error != 0)
- {
- asio::system_error e(
- asio::error_code(error,
- asio::error::get_system_category()),
- "mutex");
- boost::throw_exception(e);
- }
- }
+ ASIO_DECL posix_mutex();
// Destructor.
~posix_mutex()
@@ -84,8 +65,12 @@ private:
} // namespace detail
} // namespace asio
-#endif // defined(BOOST_HAS_PTHREADS)
-
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/posix_mutex.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
#endif // ASIO_DETAIL_POSIX_MUTEX_HPP
diff --git a/ext/asio/asio/detail/posix_signal_blocker.hpp b/ext/asio/asio/detail/posix_signal_blocker.hpp
index 135ca41..d41f128 100644
--- a/ext/asio/asio/detail/posix_signal_blocker.hpp
+++ b/ext/asio/asio/detail/posix_signal_blocker.hpp
@@ -1,8 +1,8 @@
//
-// posix_signal_blocker.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/posix_signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,22 +15,17 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
-#if defined(BOOST_HAS_PTHREADS)
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
-#include "asio/detail/push_options.hpp"
#include <csignal>
#include <pthread.h>
#include <signal.h>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -83,8 +78,8 @@ private:
} // namespace detail
} // namespace asio
-#endif // defined(BOOST_HAS_PTHREADS)
-
#include "asio/detail/pop_options.hpp"
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
#endif // ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
diff --git a/ext/asio/asio/detail/posix_thread.hpp b/ext/asio/asio/detail/posix_thread.hpp
index e0fea75..743417c 100644
--- a/ext/asio/asio/detail/posix_thread.hpp
+++ b/ext/asio/asio/detail/posix_thread.hpp
@@ -1,8 +1,8 @@
//
-// posix_thread.hpp
-// ~~~~~~~~~~~~~~~~
+// detail/posix_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,28 +15,22 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
-#if defined(BOOST_HAS_PTHREADS)
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
-#include "asio/detail/push_options.hpp"
-#include <memory>
-#include <boost/throw_exception.hpp>
#include <pthread.h>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
-extern "C" void* asio_detail_posix_thread_function(void* arg);
+extern "C"
+{
+ ASIO_DECL void* asio_detail_posix_thread_function(void* arg);
+}
class posix_thread
: private noncopyable
@@ -47,36 +41,14 @@ public:
posix_thread(Function f)
: joined_(false)
{
- std::auto_ptr<func_base> arg(new func<Function>(f));
- int error = ::pthread_create(&thread_, 0,
- asio_detail_posix_thread_function, arg.get());
- if (error != 0)
- {
- asio::system_error e(
- asio::error_code(error,
- asio::error::get_system_category()),
- "thread");
- boost::throw_exception(e);
- }
- arg.release();
+ start_thread(new func<Function>(f));
}
// Destructor.
- ~posix_thread()
- {
- if (!joined_)
- ::pthread_detach(thread_);
- }
+ ASIO_DECL ~posix_thread();
// Wait for the thread to exit.
- void join()
- {
- if (!joined_)
- {
- ::pthread_join(thread_, 0);
- joined_ = true;
- }
- }
+ ASIO_DECL void join();
private:
friend void* asio_detail_posix_thread_function(void* arg);
@@ -88,6 +60,12 @@ private:
virtual void run() = 0;
};
+ struct auto_func_base_ptr
+ {
+ func_base* ptr;
+ ~auto_func_base_ptr() { delete ptr; }
+ };
+
template <typename Function>
class func
: public func_base
@@ -107,23 +85,21 @@ private:
Function f_;
};
+ ASIO_DECL void start_thread(func_base* arg);
+
::pthread_t thread_;
bool joined_;
};
-inline void* asio_detail_posix_thread_function(void* arg)
-{
- std::auto_ptr<posix_thread::func_base> f(
- static_cast<posix_thread::func_base*>(arg));
- f->run();
- return 0;
-}
-
} // namespace detail
} // namespace asio
-#endif // defined(BOOST_HAS_PTHREADS)
-
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/posix_thread.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
#endif // ASIO_DETAIL_POSIX_THREAD_HPP
diff --git a/ext/asio/asio/detail/posix_tss_ptr.hpp b/ext/asio/asio/detail/posix_tss_ptr.hpp
index 3b4ba07..30d9705 100644
--- a/ext/asio/asio/detail/posix_tss_ptr.hpp
+++ b/ext/asio/asio/detail/posix_tss_ptr.hpp
@@ -1,8 +1,8 @@
//
-// posix_tss_ptr.hpp
-// ~~~~~~~~~~~~~~~~~
+// detail/posix_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,26 +15,21 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
-#if defined(BOOST_HAS_PTHREADS)
+#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
-#include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
#include <pthread.h>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
+// Helper function to create thread-specific storage.
+ASIO_DECL void posix_tss_ptr_create(pthread_key_t& key);
+
template <typename T>
class posix_tss_ptr
: private noncopyable
@@ -43,15 +38,7 @@ public:
// Constructor.
posix_tss_ptr()
{
- int error = ::pthread_key_create(&tss_key_, 0);
- if (error != 0)
- {
- asio::system_error e(
- asio::error_code(error,
- asio::error::get_system_category()),
- "tss");
- boost::throw_exception(e);
- }
+ posix_tss_ptr_create(tss_key_);
}
// Destructor.
@@ -76,13 +63,18 @@ private:
// Thread-specific storage to allow unlocked access to determine whether a
// thread is a member of the pool.
pthread_key_t tss_key_;
+
};
} // namespace detail
} // namespace asio
-#endif // defined(BOOST_HAS_PTHREADS)
-
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/posix_tss_ptr.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
+
#endif // ASIO_DETAIL_POSIX_TSS_PTR_HPP
diff --git a/ext/asio/asio/detail/push_options.hpp b/ext/asio/asio/detail/push_options.hpp
index cb0e902..ebb3276 100644
--- a/ext/asio/asio/detail/push_options.hpp
+++ b/ext/asio/asio/detail/push_options.hpp
@@ -1,8 +1,8 @@
//
-// push_options.hpp
-// ~~~~~~~~~~~~~~~~
+// detail/push_options.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -31,6 +31,18 @@
# pragma pack (push, 8)
# endif
+# if defined(__OBJC__)
+# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1)
+# if !defined(ASIO_DISABLE_OBJC_WORKAROUND)
+# if !defined(Protocol) && !defined(id)
+# define Protocol cpp_Protocol
+# define id cpp_id
+# define ASIO_OBJC_WORKAROUND
+# endif
+# endif
+# endif
+# endif
+
#elif defined(__KCC)
// Kai C++
diff --git a/ext/asio/asio/detail/reactive_descriptor_service.hpp b/ext/asio/asio/detail/reactive_descriptor_service.hpp
index 7ad368d..f7e8bf5 100644
--- a/ext/asio/asio/detail/reactive_descriptor_service.hpp
+++ b/ext/asio/asio/detail/reactive_descriptor_service.hpp
@@ -1,8 +1,8 @@
//
-// reactive_descriptor_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/reactive_descriptor_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,21 +15,24 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#include <boost/utility/addressof.hpp>
#include "asio/buffer.hpp"
-#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffer_sequence_adapter.hpp"
#include "asio/detail/descriptor_ops.hpp"
+#include "asio/detail/descriptor_read_op.hpp"
+#include "asio/detail/descriptor_write_op.hpp"
#include "asio/detail/fenced_block.hpp"
#include "asio/detail/noncopyable.hpp"
-#include "asio/detail/null_buffers_op.hpp"
+#include "asio/detail/reactive_null_buffers_op.hpp"
#include "asio/detail/reactor.hpp"
-#include "asio/detail/reactor_op.hpp"
-#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -48,7 +51,7 @@ public:
// Default constructor.
implementation_type()
: descriptor_(-1),
- flags_(0)
+ state_(0)
{
}
@@ -59,94 +62,29 @@ public:
// The native descriptor representation.
int descriptor_;
- enum
- {
- // The user wants a non-blocking descriptor.
- user_set_non_blocking = 1,
-
- // The descriptor has been set non-blocking.
- internal_non_blocking = 2,
-
- // Helper "flag" used to determine whether the descriptor is non-blocking.
- non_blocking = user_set_non_blocking | internal_non_blocking
- };
-
- // Flags indicating the current state of the descriptor.
- unsigned char flags_;
+ // The current state of the descriptor.
+ descriptor_ops::state_type state_;
// Per-descriptor data used by the reactor.
reactor::per_descriptor_data reactor_data_;
};
- // The maximum number of buffers to support in a single operation.
- enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
-
// Constructor.
- reactive_descriptor_service(asio::io_service& io_service)
- : io_service_impl_(asio::use_service<io_service_impl>(io_service)),
- reactor_(asio::use_service<reactor>(io_service))
- {
- reactor_.init_task();
- }
+ ASIO_DECL reactive_descriptor_service(
+ asio::io_service& io_service);
// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- }
+ ASIO_DECL void shutdown_service();
// Construct a new descriptor implementation.
- void construct(implementation_type& impl)
- {
- impl.descriptor_ = -1;
- impl.flags_ = 0;
- }
+ ASIO_DECL void construct(implementation_type& impl);
// Destroy a descriptor implementation.
- void destroy(implementation_type& impl)
- {
- if (impl.descriptor_ != -1)
- {
- reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_);
-
- if (impl.flags_ & implementation_type::internal_non_blocking)
- {
- ioctl_arg_type non_blocking = 0;
- asio::error_code ignored_ec;
- descriptor_ops::ioctl(impl.descriptor_,
- FIONBIO, &non_blocking, ignored_ec);
- impl.flags_ &= ~implementation_type::internal_non_blocking;
- }
-
- asio::error_code ignored_ec;
- descriptor_ops::close(impl.descriptor_, ignored_ec);
-
- impl.descriptor_ = -1;
- }
- }
+ ASIO_DECL void destroy(implementation_type& impl);
// Assign a native descriptor to a descriptor implementation.
- asio::error_code assign(implementation_type& impl,
- const native_type& native_descriptor, asio::error_code& ec)
- {
- if (is_open(impl))
- {
- ec = asio::error::already_open;
- return ec;
- }
-
- if (int err = reactor_.register_descriptor(
- native_descriptor, impl.reactor_data_))
- {
- ec = asio::error_code(err,
- asio::error::get_system_category());
- return ec;
- }
-
- impl.descriptor_ = native_descriptor;
- impl.flags_ = 0;
- ec = asio::error_code();
- return ec;
- }
+ ASIO_DECL asio::error_code assign(implementation_type& impl,
+ const native_type& native_descriptor, asio::error_code& ec);
// Determine whether the descriptor is open.
bool is_open(const implementation_type& impl) const
@@ -155,31 +93,8 @@ public:
}
// Destroy a descriptor implementation.
- asio::error_code close(implementation_type& impl,
- asio::error_code& ec)
- {
- if (is_open(impl))
- {
- reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_);
-
- if (impl.flags_ & implementation_type::internal_non_blocking)
- {
- ioctl_arg_type non_blocking = 0;
- asio::error_code ignored_ec;
- descriptor_ops::ioctl(impl.descriptor_,
- FIONBIO, &non_blocking, ignored_ec);
- impl.flags_ &= ~implementation_type::internal_non_blocking;
- }
-
- if (descriptor_ops::close(impl.descriptor_, ec) == -1)
- return ec;
-
- impl.descriptor_ = -1;
- }
-
- ec = asio::error_code();
- return ec;
- }
+ ASIO_DECL asio::error_code close(implementation_type& impl,
+ asio::error_code& ec);
// Get the native descriptor representation.
native_type native(const implementation_type& impl) const
@@ -188,56 +103,16 @@ public:
}
// Cancel all operations associated with the descriptor.
- asio::error_code cancel(implementation_type& impl,
- asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
- reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_);
- ec = asio::error_code();
- return ec;
- }
+ ASIO_DECL asio::error_code cancel(implementation_type& impl,
+ asio::error_code& ec);
// Perform an IO control command on the descriptor.
template <typename IO_Control_Command>
asio::error_code io_control(implementation_type& impl,
IO_Control_Command& command, asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
- descriptor_ops::ioctl(impl.descriptor_, command.name(),
- static_cast<ioctl_arg_type*>(command.data()), ec);
-
- // When updating the non-blocking mode we always perform the ioctl syscall,
- // even if the flags would otherwise indicate that the descriptor is
- // already in the correct state. This ensures that the underlying
- // descriptor is put into the state that has been requested by the user. If
- // the ioctl syscall was successful then we need to update the flags to
- // match.
- if (!ec && command.name() == static_cast<int>(FIONBIO))
- {
- if (*static_cast<ioctl_arg_type*>(command.data()))
- {
- impl.flags_ |= implementation_type::user_set_non_blocking;
- }
- else
- {
- // Clearing the non-blocking mode always overrides any internally-set
- // non-blocking flag. Any subsequent asynchronous operations will need
- // to re-enable non-blocking I/O.
- impl.flags_ &= ~(implementation_type::user_set_non_blocking
- | implementation_type::internal_non_blocking);
- }
- }
-
+ descriptor_ops::ioctl(impl.descriptor_, impl.state_,
+ command.name(), static_cast<ioctl_arg_type*>(command.data()), ec);
return ec;
}
@@ -246,148 +121,23 @@ public:
size_t write_some(implementation_type& impl,
const ConstBufferSequence& buffers, asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
buffer_sequence_adapter<asio::const_buffer,
ConstBufferSequence> bufs(buffers);
- // A request to read_some 0 bytes on a stream is a no-op.
- if (bufs.all_empty())
- {
- ec = asio::error_code();
- return 0;
- }
-
- // Send the data.
- for (;;)
- {
- // Try to complete the operation without blocking.
- int bytes_sent = descriptor_ops::gather_write(
- impl.descriptor_, bufs.buffers(), bufs.count(), ec);
-
- // Check if operation succeeded.
- if (bytes_sent >= 0)
- return bytes_sent;
-
- // Operation failed.
- if ((impl.flags_ & implementation_type::user_set_non_blocking)
- || (ec != asio::error::would_block
- && ec != asio::error::try_again))
- return 0;
-
- // Wait for descriptor to become ready.
- if (descriptor_ops::poll_write(impl.descriptor_, ec) < 0)
- return 0;
- }
+ return descriptor_ops::sync_write(impl.descriptor_, impl.state_,
+ bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
}
// Wait until data can be written without blocking.
size_t write_some(implementation_type& impl,
const null_buffers&, asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
// Wait for descriptor to become ready.
descriptor_ops::poll_write(impl.descriptor_, ec);
return 0;
}
- template <typename ConstBufferSequence>
- class write_op_base : public reactor_op
- {
- public:
- write_op_base(int descriptor,
- const ConstBufferSequence& buffers, func_type complete_func)
- : reactor_op(&write_op_base::do_perform, complete_func),
- descriptor_(descriptor),
- buffers_(buffers)
- {
- }
-
- static bool do_perform(reactor_op* base)
- {
- write_op_base* o(static_cast<write_op_base*>(base));
-
- buffer_sequence_adapter<asio::const_buffer,
- ConstBufferSequence> bufs(o->buffers_);
-
- for (;;)
- {
- // Write the data.
- asio::error_code ec;
- int bytes = descriptor_ops::gather_write(
- o->descriptor_, bufs.buffers(), bufs.count(), ec);
-
- // Retry operation if interrupted by signal.
- if (ec == asio::error::interrupted)
- continue;
-
- // Check if we need to run the operation again.
- if (ec == asio::error::would_block
- || ec == asio::error::try_again)
- return false;
-
- o->ec_ = ec;
- o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
- return true;
- }
- }
-
- private:
- int descriptor_;
- ConstBufferSequence buffers_;
- };
-
- template <typename ConstBufferSequence, typename Handler>
- class write_op : public write_op_base<ConstBufferSequence>
- {
- public:
- write_op(int descriptor,
- const ConstBufferSequence& buffers, Handler handler)
- : write_op_base<ConstBufferSequence>(
- descriptor, buffers, &write_op::do_complete),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
- {
- // Take ownership of the handler object.
- write_op* o(static_cast<write_op*>(base));
- typedef handler_alloc_traits<Handler, write_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder2<Handler, asio::error_code, std::size_t>
- handler(o->handler_, o->ec_, o->bytes_transferred_);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- Handler handler_;
- };
-
// Start an asynchronous write. The data being sent must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
@@ -395,15 +145,16 @@ public:
const ConstBufferSequence& buffers, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef write_op<ConstBufferSequence, Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, impl.descriptor_, buffers, handler);
+ typedef descriptor_write_op<ConstBufferSequence, Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.descriptor_, buffers, handler);
- start_op(impl, reactor::write_op, ptr.get(), true,
+ start_op(impl, reactor::write_op, p.p, true,
buffer_sequence_adapter<asio::const_buffer,
ConstBufferSequence>::all_empty(buffers));
- ptr.release();
+ p.v = p.p = 0;
}
// Start an asynchronous wait until data can be written without blocking.
@@ -412,13 +163,14 @@ public:
const null_buffers&, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef null_buffers_op<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
- start_op(impl, reactor::write_op, ptr.get(), false, false);
- ptr.release();
+ start_op(impl, reactor::write_op, p.p, false, false);
+ p.v = p.p = 0;
}
// Read some data from the stream. Returns the number of bytes read.
@@ -426,157 +178,23 @@ public:
size_t read_some(implementation_type& impl,
const MutableBufferSequence& buffers, asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
buffer_sequence_adapter<asio::mutable_buffer,
MutableBufferSequence> bufs(buffers);
- // A request to read_some 0 bytes on a stream is a no-op.
- if (bufs.all_empty())
- {
- ec = asio::error_code();
- return 0;
- }
-
- // Read some data.
- for (;;)
- {
- // Try to complete the operation without blocking.
- int bytes_read = descriptor_ops::scatter_read(
- impl.descriptor_, bufs.buffers(), bufs.count(), ec);
-
- // Check if operation succeeded.
- if (bytes_read > 0)
- return bytes_read;
-
- // Check for EOF.
- if (bytes_read == 0)
- {
- ec = asio::error::eof;
- return 0;
- }
-
- // Operation failed.
- if ((impl.flags_ & implementation_type::user_set_non_blocking)
- || (ec != asio::error::would_block
- && ec != asio::error::try_again))
- return 0;
-
- // Wait for descriptor to become ready.
- if (descriptor_ops::poll_read(impl.descriptor_, ec) < 0)
- return 0;
- }
+ return descriptor_ops::sync_read(impl.descriptor_, impl.state_,
+ bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
}
// Wait until data can be read without blocking.
size_t read_some(implementation_type& impl,
const null_buffers&, asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
// Wait for descriptor to become ready.
descriptor_ops::poll_read(impl.descriptor_, ec);
return 0;
}
- template <typename MutableBufferSequence>
- class read_op_base : public reactor_op
- {
- public:
- read_op_base(int descriptor,
- const MutableBufferSequence& buffers, func_type complete_func)
- : reactor_op(&read_op_base::do_perform, complete_func),
- descriptor_(descriptor),
- buffers_(buffers)
- {
- }
-
- static bool do_perform(reactor_op* base)
- {
- read_op_base* o(static_cast<read_op_base*>(base));
-
- buffer_sequence_adapter<asio::mutable_buffer,
- MutableBufferSequence> bufs(o->buffers_);
-
- for (;;)
- {
- // Read some data.
- asio::error_code ec;
- int bytes = descriptor_ops::scatter_read(
- o->descriptor_, bufs.buffers(), bufs.count(), ec);
- if (bytes == 0)
- ec = asio::error::eof;
-
- // Retry operation if interrupted by signal.
- if (ec == asio::error::interrupted)
- continue;
-
- // Check if we need to run the operation again.
- if (ec == asio::error::would_block
- || ec == asio::error::try_again)
- return false;
-
- o->ec_ = ec;
- o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
- return true;
- }
- }
-
- private:
- int descriptor_;
- MutableBufferSequence buffers_;
- };
-
- template <typename MutableBufferSequence, typename Handler>
- class read_op : public read_op_base<MutableBufferSequence>
- {
- public:
- read_op(int descriptor,
- const MutableBufferSequence& buffers, Handler handler)
- : read_op_base<MutableBufferSequence>(
- descriptor, buffers, &read_op::do_complete),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
- {
- // Take ownership of the handler object.
- read_op* o(static_cast<read_op*>(base));
- typedef handler_alloc_traits<Handler, read_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder2<Handler, asio::error_code, std::size_t>
- handler(o->handler_, o->ec_, o->bytes_transferred_);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- Handler handler_;
- };
-
// Start an asynchronous read. The buffer for the data being read must be
// valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
@@ -584,16 +202,16 @@ public:
const MutableBufferSequence& buffers, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef read_op<MutableBufferSequence, Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr,
- impl.descriptor_, buffers, handler);
+ typedef descriptor_read_op<MutableBufferSequence, Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.descriptor_, buffers, handler);
- start_op(impl, reactor::read_op, ptr.get(), true,
+ start_op(impl, reactor::read_op, p.p, true,
buffer_sequence_adapter<asio::mutable_buffer,
MutableBufferSequence>::all_empty(buffers));
- ptr.release();
+ p.v = p.p = 0;
}
// Wait until data can be read without blocking.
@@ -602,57 +220,20 @@ public:
const null_buffers&, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef null_buffers_op<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
- start_op(impl, reactor::read_op, ptr.get(), false, false);
- ptr.release();
+ start_op(impl, reactor::read_op, p.p, false, false);
+ p.v = p.p = 0;
}
private:
// Start the asynchronous operation.
- void start_op(implementation_type& impl, int op_type,
- reactor_op* op, bool non_blocking, bool noop)
- {
- if (!noop)
- {
- if (is_open(impl))
- {
- if (is_non_blocking(impl) || set_non_blocking(impl, op->ec_))
- {
- reactor_.start_op(op_type, impl.descriptor_,
- impl.reactor_data_, op, non_blocking);
- return;
- }
- }
- else
- op->ec_ = asio::error::bad_descriptor;
- }
-
- io_service_impl_.post_immediate_completion(op);
- }
-
- // Determine whether the descriptor has been set non-blocking.
- bool is_non_blocking(implementation_type& impl) const
- {
- return (impl.flags_ & implementation_type::non_blocking);
- }
-
- // Set the internal non-blocking flag.
- bool set_non_blocking(implementation_type& impl,
- asio::error_code& ec)
- {
- ioctl_arg_type non_blocking = 1;
- if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
- return false;
- impl.flags_ |= implementation_type::internal_non_blocking;
- return true;
- }
-
- // The io_service implementation used to post completions.
- io_service_impl& io_service_impl_;
+ ASIO_DECL void start_op(implementation_type& impl, int op_type,
+ reactor_op* op, bool non_blocking, bool noop);
// The selector that performs event demultiplexing for the service.
reactor& reactor_;
@@ -661,8 +242,12 @@ private:
} // namespace detail
} // namespace asio
-#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/reactive_descriptor_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
#endif // ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
diff --git a/ext/asio/asio/detail/reactive_null_buffers_op.hpp b/ext/asio/asio/detail/reactive_null_buffers_op.hpp
new file mode 100644
index 0000000..0c83c61
--- /dev/null
+++ b/ext/asio/asio/detail/reactive_null_buffers_op.hpp
@@ -0,0 +1,83 @@
+//
+// detail/reactive_null_buffers_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP
+#define ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/reactor_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class reactive_null_buffers_op : public reactor_op
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op);
+
+ reactive_null_buffers_op(Handler handler)
+ : reactor_op(&reactive_null_buffers_op::do_perform,
+ &reactive_null_buffers_op::do_complete),
+ handler_(handler)
+ {
+ }
+
+ static bool do_perform(reactor_op*)
+ {
+ return true;
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_null_buffers_op* o(static_cast<reactive_null_buffers_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP
diff --git a/ext/asio/asio/detail/reactive_serial_port_service.hpp b/ext/asio/asio/detail/reactive_serial_port_service.hpp
index 186460f..556ea06 100644
--- a/ext/asio/asio/detail/reactive_serial_port_service.hpp
+++ b/ext/asio/asio/detail/reactive_serial_port_service.hpp
@@ -1,8 +1,8 @@
//
-// reactive_serial_port_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/reactive_serial_port_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,23 +16,20 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <cstring>
-#include <string>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/serial_port_base.hpp"
-
-#if defined(ASIO_HAS_SERIAL_PORT) \
- && !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#if defined(ASIO_HAS_SERIAL_PORT)
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#include <string>
#include "asio/error.hpp"
#include "asio/io_service.hpp"
+#include "asio/serial_port_base.hpp"
#include "asio/detail/descriptor_ops.hpp"
#include "asio/detail/reactive_descriptor_service.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -46,119 +43,55 @@ public:
// The implementation type of the serial port.
typedef reactive_descriptor_service::implementation_type implementation_type;
- reactive_serial_port_service(asio::io_service& io_service)
- : descriptor_service_(io_service)
- {
- }
+ ASIO_DECL reactive_serial_port_service(
+ asio::io_service& io_service);
// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- descriptor_service_.shutdown_service();
- }
+ ASIO_DECL void shutdown_service();
- // Construct a new handle implementation.
+ // Construct a new serial port implementation.
void construct(implementation_type& impl)
{
descriptor_service_.construct(impl);
}
- // Destroy a handle implementation.
+ // Destroy a serial port implementation.
void destroy(implementation_type& impl)
{
descriptor_service_.destroy(impl);
}
// Open the serial port using the specified device name.
- asio::error_code open(implementation_type& impl,
- const std::string& device, asio::error_code& ec)
- {
- if (is_open(impl))
- {
- ec = asio::error::already_open;
- return ec;
- }
-
- int fd = descriptor_ops::open(device.c_str(),
- O_RDWR | O_NONBLOCK | O_NOCTTY, ec);
- if (fd < 0)
- return ec;
-
- int s = descriptor_ops::fcntl(fd, F_GETFL, ec);
- if (s >= 0)
- s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec);
- if (s < 0)
- {
- asio::error_code ignored_ec;
- descriptor_ops::close(fd, ignored_ec);
- return ec;
- }
-
- // Set up default serial port options.
- termios ios;
- descriptor_ops::clear_error(ec);
- s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec);
- if (s >= 0)
- {
-#if defined(_BSD_SOURCE)
- ::cfmakeraw(&ios);
-#else
- ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK
- | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
- ios.c_oflag &= ~OPOST;
- ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
- ios.c_cflag &= ~(CSIZE | PARENB);
- ios.c_cflag |= CS8;
-#endif
- ios.c_iflag |= IGNPAR;
- ios.c_cflag |= CREAD | CLOCAL;
- descriptor_ops::clear_error(ec);
- s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec);
- }
- if (s < 0)
- {
- asio::error_code ignored_ec;
- descriptor_ops::close(fd, ignored_ec);
- return ec;
- }
-
- // We're done. Take ownership of the serial port descriptor.
- if (descriptor_service_.assign(impl, fd, ec))
- {
- asio::error_code ignored_ec;
- descriptor_ops::close(fd, ignored_ec);
- }
-
- return ec;
- }
+ ASIO_DECL asio::error_code open(implementation_type& impl,
+ const std::string& device, asio::error_code& ec);
- // Assign a native handle to a handle implementation.
+ // Assign a native descriptor to a serial port implementation.
asio::error_code assign(implementation_type& impl,
const native_type& native_descriptor, asio::error_code& ec)
{
return descriptor_service_.assign(impl, native_descriptor, ec);
}
- // Determine whether the handle is open.
+ // Determine whether the serial port is open.
bool is_open(const implementation_type& impl) const
{
return descriptor_service_.is_open(impl);
}
- // Destroy a handle implementation.
+ // Destroy a serial port implementation.
asio::error_code close(implementation_type& impl,
asio::error_code& ec)
{
return descriptor_service_.close(impl, ec);
}
- // Get the native handle representation.
+ // Get the native serial port representation.
native_type native(implementation_type& impl)
{
return descriptor_service_.native(impl);
}
- // Cancel all operations associated with the handle.
+ // Cancel all operations associated with the serial port.
asio::error_code cancel(implementation_type& impl,
asio::error_code& ec)
{
@@ -170,20 +103,9 @@ public:
asio::error_code set_option(implementation_type& impl,
const SettableSerialPortOption& option, asio::error_code& ec)
{
- termios ios;
- descriptor_ops::clear_error(ec);
- descriptor_ops::error_wrapper(::tcgetattr(
- descriptor_service_.native(impl), &ios), ec);
- if (ec)
- return ec;
-
- if (option.store(ios, ec))
- return ec;
-
- descriptor_ops::clear_error(ec);
- descriptor_ops::error_wrapper(::tcsetattr(
- descriptor_service_.native(impl), TCSANOW, &ios), ec);
- return ec;
+ return do_set_option(impl,
+ &reactive_serial_port_service::store_option<SettableSerialPortOption>,
+ &option, ec);
}
// Get an option from the serial port.
@@ -191,21 +113,16 @@ public:
asio::error_code get_option(const implementation_type& impl,
GettableSerialPortOption& option, asio::error_code& ec) const
{
- termios ios;
- descriptor_ops::clear_error(ec);
- descriptor_ops::error_wrapper(::tcgetattr(
- descriptor_service_.native(impl), &ios), ec);
- if (ec)
- return ec;
-
- return option.load(ios, ec);
+ return do_get_option(impl,
+ &reactive_serial_port_service::load_option<GettableSerialPortOption>,
+ &option, ec);
}
// Send a break sequence to the serial port.
asio::error_code send_break(implementation_type& impl,
asio::error_code& ec)
{
- descriptor_ops::clear_error(ec);
+ errno = 0;
descriptor_ops::error_wrapper(::tcsendbreak(
descriptor_service_.native(impl), 0), ec);
return ec;
@@ -246,6 +163,41 @@ public:
}
private:
+ // Function pointer type for storing a serial port option.
+ typedef asio::error_code (*store_function_type)(
+ const void*, termios&, asio::error_code&);
+
+ // Helper function template to store a serial port option.
+ template <typename SettableSerialPortOption>
+ static asio::error_code store_option(const void* option,
+ termios& storage, asio::error_code& ec)
+ {
+ return static_cast<const SettableSerialPortOption*>(option)->store(
+ storage, ec);
+ }
+
+ // Helper function to set a serial port option.
+ ASIO_DECL asio::error_code do_set_option(
+ implementation_type& impl, store_function_type store,
+ const void* option, asio::error_code& ec);
+
+ // Function pointer type for loading a serial port option.
+ typedef asio::error_code (*load_function_type)(
+ void*, const termios&, asio::error_code&);
+
+ // Helper function template to load a serial port option.
+ template <typename GettableSerialPortOption>
+ static asio::error_code load_option(void* option,
+ const termios& storage, asio::error_code& ec)
+ {
+ return static_cast<GettableSerialPortOption*>(option)->load(storage, ec);
+ }
+
+ // Helper function to get a serial port option.
+ ASIO_DECL asio::error_code do_get_option(
+ const implementation_type& impl, load_function_type load,
+ void* option, asio::error_code& ec) const;
+
// The implementation used for initiating asynchronous operations.
reactive_descriptor_service descriptor_service_;
};
@@ -253,9 +205,13 @@ private:
} // namespace detail
} // namespace asio
-#endif // defined(ASIO_HAS_SERIAL_PORT)
- // && !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/reactive_serial_port_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#endif // defined(ASIO_HAS_SERIAL_PORT)
+
#endif // ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP
diff --git a/ext/asio/asio/detail/reactive_socket_accept_op.hpp b/ext/asio/asio/detail/reactive_socket_accept_op.hpp
new file mode 100644
index 0000000..76c6741
--- /dev/null
+++ b/ext/asio/asio/detail/reactive_socket_accept_op.hpp
@@ -0,0 +1,131 @@
+//
+// detail/reactive_socket_accept_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Socket, typename Protocol>
+class reactive_socket_accept_op_base : public reactor_op
+{
+public:
+ reactive_socket_accept_op_base(socket_type socket,
+ socket_ops::state_type state, Socket& peer, const Protocol& protocol,
+ typename Protocol::endpoint* peer_endpoint, func_type complete_func)
+ : reactor_op(&reactive_socket_accept_op_base::do_perform, complete_func),
+ socket_(socket),
+ state_(state),
+ peer_(peer),
+ protocol_(protocol),
+ peer_endpoint_(peer_endpoint)
+ {
+ }
+
+ static bool do_perform(reactor_op* base)
+ {
+ reactive_socket_accept_op_base* o(
+ static_cast<reactive_socket_accept_op_base*>(base));
+
+ std::size_t addrlen = o->peer_endpoint_ ? o->peer_endpoint_->capacity() : 0;
+ socket_type new_socket = invalid_socket;
+ bool result = socket_ops::non_blocking_accept(o->socket_,
+ o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0,
+ o->peer_endpoint_ ? &addrlen : 0, o->ec_, new_socket);
+
+ // On success, assign new connection to peer socket object.
+ if (new_socket >= 0)
+ {
+ socket_holder new_socket_holder(new_socket);
+ if (o->peer_endpoint_)
+ o->peer_endpoint_->resize(addrlen);
+ if (!o->peer_.assign(o->protocol_, new_socket, o->ec_))
+ new_socket_holder.release();
+ }
+
+ return result;
+ }
+
+private:
+ socket_type socket_;
+ socket_ops::state_type state_;
+ Socket& peer_;
+ Protocol protocol_;
+ typename Protocol::endpoint* peer_endpoint_;
+};
+
+template <typename Socket, typename Protocol, typename Handler>
+class reactive_socket_accept_op :
+ public reactive_socket_accept_op_base<Socket, Protocol>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op);
+
+ reactive_socket_accept_op(socket_type socket,
+ socket_ops::state_type state, Socket& peer, const Protocol& protocol,
+ typename Protocol::endpoint* peer_endpoint, Handler handler)
+ : reactive_socket_accept_op_base<Socket, Protocol>(socket, state, peer,
+ protocol, peer_endpoint, &reactive_socket_accept_op::do_complete),
+ handler_(handler)
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_accept_op* o(static_cast<reactive_socket_accept_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder1<Handler, asio::error_code>
+ handler(o->handler_, o->ec_);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP
diff --git a/ext/asio/asio/detail/reactive_socket_connect_op.hpp b/ext/asio/asio/detail/reactive_socket_connect_op.hpp
new file mode 100644
index 0000000..8267091
--- /dev/null
+++ b/ext/asio/asio/detail/reactive_socket_connect_op.hpp
@@ -0,0 +1,101 @@
+//
+// detail/reactive_socket_connect_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class reactive_socket_connect_op_base : public reactor_op
+{
+public:
+ reactive_socket_connect_op_base(socket_type socket, func_type complete_func)
+ : reactor_op(&reactive_socket_connect_op_base::do_perform, complete_func),
+ socket_(socket)
+ {
+ }
+
+ static bool do_perform(reactor_op* base)
+ {
+ reactive_socket_connect_op_base* o(
+ static_cast<reactive_socket_connect_op_base*>(base));
+
+ return socket_ops::non_blocking_connect(o->socket_, o->ec_);
+ }
+
+private:
+ socket_type socket_;
+};
+
+template <typename Handler>
+class reactive_socket_connect_op : public reactive_socket_connect_op_base
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op);
+
+ reactive_socket_connect_op(socket_type socket, Handler handler)
+ : reactive_socket_connect_op_base(socket,
+ &reactive_socket_connect_op::do_complete),
+ handler_(handler)
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_connect_op* o
+ (static_cast<reactive_socket_connect_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder1<Handler, asio::error_code>
+ handler(o->handler_, o->ec_);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler);
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP
diff --git a/ext/asio/asio/detail/reactive_socket_recv_op.hpp b/ext/asio/asio/detail/reactive_socket_recv_op.hpp
new file mode 100644
index 0000000..91a30a8
--- /dev/null
+++ b/ext/asio/asio/detail/reactive_socket_recv_op.hpp
@@ -0,0 +1,118 @@
+//
+// detail/reactive_socket_recv_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class reactive_socket_recv_op_base : public reactor_op
+{
+public:
+ reactive_socket_recv_op_base(socket_type socket,
+ socket_ops::state_type state, const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op(&reactive_socket_recv_op_base::do_perform, complete_func),
+ socket_(socket),
+ state_(state),
+ buffers_(buffers),
+ flags_(flags)
+ {
+ }
+
+ static bool do_perform(reactor_op* base)
+ {
+ reactive_socket_recv_op_base* o(
+ static_cast<reactive_socket_recv_op_base*>(base));
+
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
+
+ return socket_ops::non_blocking_recv(o->socket_,
+ bufs.buffers(), bufs.count(), o->flags_,
+ (o->state_ & socket_ops::stream_oriented),
+ o->ec_, o->bytes_transferred_);
+ }
+
+private:
+ socket_type socket_;
+ socket_ops::state_type state_;
+ MutableBufferSequence buffers_;
+ socket_base::message_flags flags_;
+};
+
+template <typename MutableBufferSequence, typename Handler>
+class reactive_socket_recv_op :
+ public reactive_socket_recv_op_base<MutableBufferSequence>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op);
+
+ reactive_socket_recv_op(socket_type socket,
+ socket_ops::state_type state, const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ : reactive_socket_recv_op_base<MutableBufferSequence>(socket, state,
+ buffers, flags, &reactive_socket_recv_op::do_complete),
+ handler_(handler)
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recv_op* o(static_cast<reactive_socket_recv_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP
diff --git a/ext/asio/asio/detail/reactive_socket_recvfrom_op.hpp b/ext/asio/asio/detail/reactive_socket_recvfrom_op.hpp
new file mode 100644
index 0000000..121d6ec
--- /dev/null
+++ b/ext/asio/asio/detail/reactive_socket_recvfrom_op.hpp
@@ -0,0 +1,128 @@
+//
+// detail/reactive_socket_recvfrom_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Endpoint>
+class reactive_socket_recvfrom_op_base : public reactor_op
+{
+public:
+ reactive_socket_recvfrom_op_base(socket_type socket, int protocol_type,
+ const MutableBufferSequence& buffers, Endpoint& endpoint,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op(&reactive_socket_recvfrom_op_base::do_perform, complete_func),
+ socket_(socket),
+ protocol_type_(protocol_type),
+ buffers_(buffers),
+ sender_endpoint_(endpoint),
+ flags_(flags)
+ {
+ }
+
+ static bool do_perform(reactor_op* base)
+ {
+ reactive_socket_recvfrom_op_base* o(
+ static_cast<reactive_socket_recvfrom_op_base*>(base));
+
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
+
+ std::size_t addr_len = o->sender_endpoint_.capacity();
+ bool result = socket_ops::non_blocking_recvfrom(o->socket_,
+ bufs.buffers(), bufs.count(), o->flags_,
+ o->sender_endpoint_.data(), &addr_len,
+ o->ec_, o->bytes_transferred_);
+
+ if (result && !o->ec_)
+ o->sender_endpoint_.resize(addr_len);
+
+ return result;
+ }
+
+private:
+ socket_type socket_;
+ int protocol_type_;
+ MutableBufferSequence buffers_;
+ Endpoint& sender_endpoint_;
+ socket_base::message_flags flags_;
+};
+
+template <typename MutableBufferSequence, typename Endpoint, typename Handler>
+class reactive_socket_recvfrom_op :
+ public reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op);
+
+ reactive_socket_recvfrom_op(socket_type socket, int protocol_type,
+ const MutableBufferSequence& buffers, Endpoint& endpoint,
+ socket_base::message_flags flags, Handler handler)
+ : reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint>(
+ socket, protocol_type, buffers, endpoint, flags,
+ &reactive_socket_recvfrom_op::do_complete),
+ handler_(handler)
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recvfrom_op* o(
+ static_cast<reactive_socket_recvfrom_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP
diff --git a/ext/asio/asio/detail/reactive_socket_send_op.hpp b/ext/asio/asio/detail/reactive_socket_send_op.hpp
new file mode 100644
index 0000000..9a68dac
--- /dev/null
+++ b/ext/asio/asio/detail/reactive_socket_send_op.hpp
@@ -0,0 +1,115 @@
+//
+// detail/reactive_socket_send_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence>
+class reactive_socket_send_op_base : public reactor_op
+{
+public:
+ reactive_socket_send_op_base(socket_type socket,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op(&reactive_socket_send_op_base::do_perform, complete_func),
+ socket_(socket),
+ buffers_(buffers),
+ flags_(flags)
+ {
+ }
+
+ static bool do_perform(reactor_op* base)
+ {
+ reactive_socket_send_op_base* o(
+ static_cast<reactive_socket_send_op_base*>(base));
+
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence> bufs(o->buffers_);
+
+ return socket_ops::non_blocking_send(o->socket_,
+ bufs.buffers(), bufs.count(), o->flags_,
+ o->ec_, o->bytes_transferred_);
+ }
+
+private:
+ socket_type socket_;
+ ConstBufferSequence buffers_;
+ socket_base::message_flags flags_;
+};
+
+template <typename ConstBufferSequence, typename Handler>
+class reactive_socket_send_op :
+ public reactive_socket_send_op_base<ConstBufferSequence>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op);
+
+ reactive_socket_send_op(socket_type socket,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ : reactive_socket_send_op_base<ConstBufferSequence>(socket,
+ buffers, flags, &reactive_socket_send_op::do_complete),
+ handler_(handler)
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_send_op* o(static_cast<reactive_socket_send_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP
diff --git a/ext/asio/asio/detail/reactive_socket_sendto_op.hpp b/ext/asio/asio/detail/reactive_socket_sendto_op.hpp
new file mode 100644
index 0000000..e466a25
--- /dev/null
+++ b/ext/asio/asio/detail/reactive_socket_sendto_op.hpp
@@ -0,0 +1,118 @@
+//
+// detail/reactive_socket_sendto_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence, typename Endpoint>
+class reactive_socket_sendto_op_base : public reactor_op
+{
+public:
+ reactive_socket_sendto_op_base(socket_type socket,
+ const ConstBufferSequence& buffers, const Endpoint& endpoint,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op(&reactive_socket_sendto_op_base::do_perform, complete_func),
+ socket_(socket),
+ buffers_(buffers),
+ destination_(endpoint),
+ flags_(flags)
+ {
+ }
+
+ static bool do_perform(reactor_op* base)
+ {
+ reactive_socket_sendto_op_base* o(
+ static_cast<reactive_socket_sendto_op_base*>(base));
+
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence> bufs(o->buffers_);
+
+ return socket_ops::non_blocking_sendto(o->socket_,
+ bufs.buffers(), bufs.count(), o->flags_,
+ o->destination_.data(), o->destination_.size(),
+ o->ec_, o->bytes_transferred_);
+ }
+
+private:
+ socket_type socket_;
+ ConstBufferSequence buffers_;
+ Endpoint destination_;
+ socket_base::message_flags flags_;
+};
+
+template <typename ConstBufferSequence, typename Endpoint, typename Handler>
+class reactive_socket_sendto_op :
+ public reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_sendto_op);
+
+ reactive_socket_sendto_op(socket_type socket,
+ const ConstBufferSequence& buffers, const Endpoint& endpoint,
+ socket_base::message_flags flags, Handler handler)
+ : reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint>(socket,
+ buffers, endpoint, flags, &reactive_socket_sendto_op::do_complete),
+ handler_(handler)
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_sendto_op* o(static_cast<reactive_socket_sendto_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP
diff --git a/ext/asio/asio/detail/reactive_socket_service.hpp b/ext/asio/asio/detail/reactive_socket_service.hpp
index 20bd512..daa9f60 100644
--- a/ext/asio/asio/detail/reactive_socket_service.hpp
+++ b/ext/asio/asio/detail/reactive_socket_service.hpp
@@ -1,8 +1,8 @@
//
-// reactive_socket_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/reactive_socket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,28 +15,37 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_IOCP)
+#include <boost/utility/addressof.hpp>
#include "asio/buffer.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/socket_base.hpp"
-#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffer_sequence_adapter.hpp"
-#include "asio/detail/fenced_block.hpp"
#include "asio/detail/noncopyable.hpp"
-#include "asio/detail/null_buffers_op.hpp"
+#include "asio/detail/reactive_null_buffers_op.hpp"
+#include "asio/detail/reactive_socket_accept_op.hpp"
+#include "asio/detail/reactive_socket_connect_op.hpp"
+#include "asio/detail/reactive_socket_recvfrom_op.hpp"
+#include "asio/detail/reactive_socket_sendto_op.hpp"
+#include "asio/detail/reactive_socket_service_base.hpp"
#include "asio/detail/reactor.hpp"
#include "asio/detail/reactor_op.hpp"
#include "asio/detail/socket_holder.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_types.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
template <typename Protocol>
-class reactive_socket_service
+class reactive_socket_service :
+ public reactive_socket_service_base
{
public:
// The protocol type.
@@ -49,132 +58,32 @@ public:
typedef socket_type native_type;
// The implementation type of the socket.
- class implementation_type
- : private asio::detail::noncopyable
+ struct implementation_type :
+ reactive_socket_service_base::base_implementation_type
{
- public:
// Default constructor.
implementation_type()
- : socket_(invalid_socket),
- flags_(0),
- protocol_(endpoint_type().protocol())
+ : protocol_(endpoint_type().protocol())
{
}
- private:
- // Only this service will have access to the internal values.
- friend class reactive_socket_service<Protocol>;
-
- // The native socket representation.
- socket_type socket_;
-
- enum
- {
- // The user wants a non-blocking socket.
- user_set_non_blocking = 1,
-
- // The implementation wants a non-blocking socket (in order to be able to
- // perform asynchronous read and write operations).
- internal_non_blocking = 2,
-
- // Helper "flag" used to determine whether the socket is non-blocking.
- non_blocking = user_set_non_blocking | internal_non_blocking,
-
- // User wants connection_aborted errors, which are disabled by default.
- enable_connection_aborted = 4,
-
- // The user set the linger option. Needs to be checked when closing.
- user_set_linger = 8
- };
-
- // Flags indicating the current state of the socket.
- unsigned char flags_;
-
// The protocol associated with the socket.
protocol_type protocol_;
-
- // Per-descriptor data used by the reactor.
- reactor::per_descriptor_data reactor_data_;
};
// Constructor.
reactive_socket_service(asio::io_service& io_service)
- : io_service_impl_(use_service<io_service_impl>(io_service)),
- reactor_(use_service<reactor>(io_service))
- {
- reactor_.init_task();
- }
-
- // Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- }
-
- // Construct a new socket implementation.
- void construct(implementation_type& impl)
+ : reactive_socket_service_base(io_service)
{
- impl.socket_ = invalid_socket;
- impl.flags_ = 0;
- }
-
- // Destroy a socket implementation.
- void destroy(implementation_type& impl)
- {
- if (impl.socket_ != invalid_socket)
- {
- reactor_.close_descriptor(impl.socket_, impl.reactor_data_);
-
- if (impl.flags_ & implementation_type::non_blocking)
- {
- ioctl_arg_type non_blocking = 0;
- asio::error_code ignored_ec;
- socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec);
- impl.flags_ &= ~implementation_type::non_blocking;
- }
-
- if (impl.flags_ & implementation_type::user_set_linger)
- {
- ::linger opt;
- opt.l_onoff = 0;
- opt.l_linger = 0;
- asio::error_code ignored_ec;
- socket_ops::setsockopt(impl.socket_,
- SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec);
- }
-
- asio::error_code ignored_ec;
- socket_ops::close(impl.socket_, ignored_ec);
-
- impl.socket_ = invalid_socket;
- }
}
// Open a new socket implementation.
asio::error_code open(implementation_type& impl,
const protocol_type& protocol, asio::error_code& ec)
{
- if (is_open(impl))
- {
- ec = asio::error::already_open;
- return ec;
- }
-
- socket_holder sock(socket_ops::socket(protocol.family(),
- protocol.type(), protocol.protocol(), ec));
- if (sock.get() == invalid_socket)
- return ec;
-
- if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_))
- {
- ec = asio::error_code(err,
- asio::error::get_system_category());
- return ec;
- }
-
- impl.socket_ = sock.release();
- impl.flags_ = 0;
- impl.protocol_ = protocol;
- ec = asio::error_code();
+ if (!do_open(impl, protocol.family(),
+ protocol.type(), protocol.protocol(), ec))
+ impl.protocol_ = protocol;
return ec;
}
@@ -183,56 +92,8 @@ public:
const protocol_type& protocol, const native_type& native_socket,
asio::error_code& ec)
{
- if (is_open(impl))
- {
- ec = asio::error::already_open;
- return ec;
- }
-
- if (int err = reactor_.register_descriptor(
- native_socket, impl.reactor_data_))
- {
- ec = asio::error_code(err,
- asio::error::get_system_category());
- return ec;
- }
-
- impl.socket_ = native_socket;
- impl.flags_ = 0;
- impl.protocol_ = protocol;
- ec = asio::error_code();
- return ec;
- }
-
- // Determine whether the socket is open.
- bool is_open(const implementation_type& impl) const
- {
- return impl.socket_ != invalid_socket;
- }
-
- // Destroy a socket implementation.
- asio::error_code close(implementation_type& impl,
- asio::error_code& ec)
- {
- if (is_open(impl))
- {
- reactor_.close_descriptor(impl.socket_, impl.reactor_data_);
-
- if (impl.flags_ & implementation_type::non_blocking)
- {
- ioctl_arg_type non_blocking = 0;
- asio::error_code ignored_ec;
- socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec);
- impl.flags_ &= ~implementation_type::non_blocking;
- }
-
- if (socket_ops::close(impl.socket_, ec) == socket_error_retval)
- return ec;
-
- impl.socket_ = invalid_socket;
- }
-
- ec = asio::error_code();
+ if (!do_assign(impl, protocol.type(), native_socket, ec))
+ impl.protocol_ = protocol;
return ec;
}
@@ -242,153 +103,23 @@ public:
return impl.socket_;
}
- // Cancel all operations associated with the socket.
- asio::error_code cancel(implementation_type& impl,
- asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
- reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
- ec = asio::error_code();
- return ec;
- }
-
- // Determine whether the socket is at the out-of-band data mark.
- bool at_mark(const implementation_type& impl,
- asio::error_code& ec) const
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return false;
- }
-
-#if defined(SIOCATMARK)
- asio::detail::ioctl_arg_type value = 0;
- socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec);
-# if defined(ENOTTY)
- if (ec.value() == ENOTTY)
- ec = asio::error::not_socket;
-# endif // defined(ENOTTY)
-#else // defined(SIOCATMARK)
- int value = sockatmark(impl.socket_);
- if (value == -1)
- ec = asio::error_code(errno,
- asio::error::get_system_category());
- else
- ec = asio::error_code();
-#endif // defined(SIOCATMARK)
- return ec ? false : value != 0;
- }
-
- // Determine the number of bytes available for reading.
- std::size_t available(const implementation_type& impl,
- asio::error_code& ec) const
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
- asio::detail::ioctl_arg_type value = 0;
- socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec);
-#if defined(ENOTTY)
- if (ec.value() == ENOTTY)
- ec = asio::error::not_socket;
-#endif // defined(ENOTTY)
- return ec ? static_cast<std::size_t>(0) : static_cast<std::size_t>(value);
- }
-
// Bind the socket to the specified local endpoint.
asio::error_code bind(implementation_type& impl,
const endpoint_type& endpoint, asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
return ec;
}
- // Place the socket into the state where it will listen for new connections.
- asio::error_code listen(implementation_type& impl, int backlog,
- asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
- socket_ops::listen(impl.socket_, backlog, ec);
- return ec;
- }
-
// Set a socket option.
template <typename Option>
asio::error_code set_option(implementation_type& impl,
const Option& option, asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
- if (option.level(impl.protocol_) == custom_socket_option_level
- && option.name(impl.protocol_) == enable_connection_aborted_option)
- {
- if (option.size(impl.protocol_) != sizeof(int))
- {
- ec = asio::error::invalid_argument;
- }
- else
- {
- if (*reinterpret_cast<const int*>(option.data(impl.protocol_)))
- impl.flags_ |= implementation_type::enable_connection_aborted;
- else
- impl.flags_ &= ~implementation_type::enable_connection_aborted;
- ec = asio::error_code();
- }
- return ec;
- }
- else
- {
- if (option.level(impl.protocol_) == SOL_SOCKET
- && option.name(impl.protocol_) == SO_LINGER)
- {
- impl.flags_ |= implementation_type::user_set_linger;
- }
-
- socket_ops::setsockopt(impl.socket_,
- option.level(impl.protocol_), option.name(impl.protocol_),
- option.data(impl.protocol_), option.size(impl.protocol_), ec);
-
-#if defined(__MACH__) && defined(__APPLE__) \
-|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
- // To implement portable behaviour for SO_REUSEADDR with UDP sockets we
- // need to also set SO_REUSEPORT on BSD-based platforms.
- if (!ec && impl.protocol_.type() == SOCK_DGRAM
- && option.level(impl.protocol_) == SOL_SOCKET
- && option.name(impl.protocol_) == SO_REUSEADDR)
- {
- asio::error_code ignored_ec;
- socket_ops::setsockopt(impl.socket_, SOL_SOCKET, SO_REUSEPORT,
- option.data(impl.protocol_), option.size(impl.protocol_),
- ignored_ec);
- }
-#endif
-
- return ec;
- }
+ socket_ops::setsockopt(impl.socket_, impl.state_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), option.size(impl.protocol_), ec);
+ return ec;
}
// Set a socket option.
@@ -396,78 +127,12 @@ public:
asio::error_code get_option(const implementation_type& impl,
Option& option, asio::error_code& ec) const
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
- if (option.level(impl.protocol_) == custom_socket_option_level
- && option.name(impl.protocol_) == enable_connection_aborted_option)
- {
- if (option.size(impl.protocol_) != sizeof(int))
- {
- ec = asio::error::invalid_argument;
- }
- else
- {
- int* target = reinterpret_cast<int*>(option.data(impl.protocol_));
- if (impl.flags_ & implementation_type::enable_connection_aborted)
- *target = 1;
- else
- *target = 0;
- option.resize(impl.protocol_, sizeof(int));
- ec = asio::error_code();
- }
- return ec;
- }
- else
- {
- size_t size = option.size(impl.protocol_);
- socket_ops::getsockopt(impl.socket_,
- option.level(impl.protocol_), option.name(impl.protocol_),
- option.data(impl.protocol_), &size, ec);
- if (!ec)
- option.resize(impl.protocol_, size);
- return ec;
- }
- }
-
- // Perform an IO control command on the socket.
- template <typename IO_Control_Command>
- asio::error_code io_control(implementation_type& impl,
- IO_Control_Command& command, asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
- socket_ops::ioctl(impl.socket_, command.name(),
- static_cast<ioctl_arg_type*>(command.data()), ec);
-
- // When updating the non-blocking mode we always perform the ioctl
- // syscall, even if the flags would otherwise indicate that the socket is
- // already in the correct state. This ensures that the underlying socket
- // is put into the state that has been requested by the user. If the ioctl
- // syscall was successful then we need to update the flags to match.
- if (!ec && command.name() == static_cast<int>(FIONBIO))
- {
- if (*static_cast<ioctl_arg_type*>(command.data()))
- {
- impl.flags_ |= implementation_type::user_set_non_blocking;
- }
- else
- {
- // Clearing the non-blocking mode always overrides any internally-set
- // non-blocking flag. Any subsequent asynchronous operations will need
- // to re-enable non-blocking I/O.
- impl.flags_ &= ~(implementation_type::user_set_non_blocking
- | implementation_type::internal_non_blocking);
- }
- }
-
+ std::size_t size = option.size(impl.protocol_);
+ socket_ops::getsockopt(impl.socket_, impl.state_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), &size, ec);
+ if (!ec)
+ option.resize(impl.protocol_, size);
return ec;
}
@@ -475,12 +140,6 @@ public:
endpoint_type local_endpoint(const implementation_type& impl,
asio::error_code& ec) const
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return endpoint_type();
- }
-
endpoint_type endpoint;
std::size_t addr_len = endpoint.capacity();
if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
@@ -493,218 +152,15 @@ public:
endpoint_type remote_endpoint(const implementation_type& impl,
asio::error_code& ec) const
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return endpoint_type();
- }
-
endpoint_type endpoint;
std::size_t addr_len = endpoint.capacity();
- if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec))
+ if (socket_ops::getpeername(impl.socket_,
+ endpoint.data(), &addr_len, false, ec))
return endpoint_type();
endpoint.resize(addr_len);
return endpoint;
}
- /// Disable sends or receives on the socket.
- asio::error_code shutdown(implementation_type& impl,
- socket_base::shutdown_type what, asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
- socket_ops::shutdown(impl.socket_, what, ec);
- return ec;
- }
-
- // Send the given data to the peer.
- template <typename ConstBufferSequence>
- size_t send(implementation_type& impl, const ConstBufferSequence& buffers,
- socket_base::message_flags flags, asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
- buffer_sequence_adapter<asio::const_buffer,
- ConstBufferSequence> bufs(buffers);
-
- // A request to receive 0 bytes on a stream socket is a no-op.
- if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty())
- {
- ec = asio::error_code();
- return 0;
- }
-
- // Send the data.
- for (;;)
- {
- // Try to complete the operation without blocking.
- int bytes_sent = socket_ops::send(impl.socket_,
- bufs.buffers(), bufs.count(), flags, ec);
-
- // Check if operation succeeded.
- if (bytes_sent >= 0)
- return bytes_sent;
-
- // Operation failed.
- if ((impl.flags_ & implementation_type::user_set_non_blocking)
- || (ec != asio::error::would_block
- && ec != asio::error::try_again))
- return 0;
-
- // Wait for socket to become ready.
- if (socket_ops::poll_write(impl.socket_, ec) < 0)
- return 0;
- }
- }
-
- // Wait until data can be sent without blocking.
- size_t send(implementation_type& impl, const null_buffers&,
- socket_base::message_flags, asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
- // Wait for socket to become ready.
- socket_ops::poll_write(impl.socket_, ec);
-
- return 0;
- }
-
- template <typename ConstBufferSequence>
- class send_op_base : public reactor_op
- {
- public:
- send_op_base(socket_type socket, const ConstBufferSequence& buffers,
- socket_base::message_flags flags, func_type complete_func)
- : reactor_op(&send_op_base::do_perform, complete_func),
- socket_(socket),
- buffers_(buffers),
- flags_(flags)
- {
- }
-
- static bool do_perform(reactor_op* base)
- {
- send_op_base* o(static_cast<send_op_base*>(base));
-
- buffer_sequence_adapter<asio::const_buffer,
- ConstBufferSequence> bufs(o->buffers_);
-
- for (;;)
- {
- // Send the data.
- asio::error_code ec;
- int bytes = socket_ops::send(o->socket_,
- bufs.buffers(), bufs.count(), o->flags_, ec);
-
- // Retry operation if interrupted by signal.
- if (ec == asio::error::interrupted)
- continue;
-
- // Check if we need to run the operation again.
- if (ec == asio::error::would_block
- || ec == asio::error::try_again)
- return false;
-
- o->ec_ = ec;
- o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
- return true;
- }
- }
-
- private:
- socket_type socket_;
- ConstBufferSequence buffers_;
- socket_base::message_flags flags_;
- };
-
- template <typename ConstBufferSequence, typename Handler>
- class send_op : public send_op_base<ConstBufferSequence>
- {
- public:
- send_op(socket_type socket, const ConstBufferSequence& buffers,
- socket_base::message_flags flags, Handler handler)
- : send_op_base<ConstBufferSequence>(socket,
- buffers, flags, &send_op::do_complete),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
- {
- // Take ownership of the handler object.
- send_op* o(static_cast<send_op*>(base));
- typedef handler_alloc_traits<Handler, send_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder2<Handler, asio::error_code, std::size_t>
- handler(o->handler_, o->ec_, o->bytes_transferred_);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- Handler handler_;
- };
-
- // Start an asynchronous send. The data being sent must be valid for the
- // lifetime of the asynchronous operation.
- template <typename ConstBufferSequence, typename Handler>
- void async_send(implementation_type& impl, const ConstBufferSequence& buffers,
- socket_base::message_flags flags, Handler handler)
- {
- // Allocate and construct an operation to wrap the handler.
- typedef send_op<ConstBufferSequence, Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr,
- impl.socket_, buffers, flags, handler);
-
- start_op(impl, reactor::write_op, ptr.get(), true,
- (impl.protocol_.type() == SOCK_STREAM
- && buffer_sequence_adapter<asio::const_buffer,
- ConstBufferSequence>::all_empty(buffers)));
- ptr.release();
- }
-
- // Start an asynchronous wait until data can be sent without blocking.
- template <typename Handler>
- void async_send(implementation_type& impl, const null_buffers&,
- socket_base::message_flags, Handler handler)
- {
- // Allocate and construct an operation to wrap the handler.
- typedef null_buffers_op<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
- start_op(impl, reactor::write_op, ptr.get(), false, false);
- ptr.release();
- }
-
// Send a datagram to the specified endpoint. Returns the number of bytes
// sent.
template <typename ConstBufferSequence>
@@ -712,148 +168,25 @@ public:
const endpoint_type& destination, socket_base::message_flags flags,
asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
buffer_sequence_adapter<asio::const_buffer,
ConstBufferSequence> bufs(buffers);
- // Send the data.
- for (;;)
- {
- // Try to complete the operation without blocking.
- int bytes_sent = socket_ops::sendto(impl.socket_, bufs.buffers(),
- bufs.count(), flags, destination.data(), destination.size(), ec);
-
- // Check if operation succeeded.
- if (bytes_sent >= 0)
- return bytes_sent;
-
- // Operation failed.
- if ((impl.flags_ & implementation_type::user_set_non_blocking)
- || (ec != asio::error::would_block
- && ec != asio::error::try_again))
- return 0;
-
- // Wait for socket to become ready.
- if (socket_ops::poll_write(impl.socket_, ec) < 0)
- return 0;
- }
+ return socket_ops::sync_sendto(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags,
+ destination.data(), destination.size(), ec);
}
// Wait until data can be sent without blocking.
size_t send_to(implementation_type& impl, const null_buffers&,
- socket_base::message_flags, const endpoint_type&,
+ const endpoint_type&, socket_base::message_flags,
asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
// Wait for socket to become ready.
socket_ops::poll_write(impl.socket_, ec);
return 0;
}
- template <typename ConstBufferSequence>
- class send_to_op_base : public reactor_op
- {
- public:
- send_to_op_base(socket_type socket, const ConstBufferSequence& buffers,
- const endpoint_type& endpoint, socket_base::message_flags flags,
- func_type complete_func)
- : reactor_op(&send_to_op_base::do_perform, complete_func),
- socket_(socket),
- buffers_(buffers),
- destination_(endpoint),
- flags_(flags)
- {
- }
-
- static bool do_perform(reactor_op* base)
- {
- send_to_op_base* o(static_cast<send_to_op_base*>(base));
-
- buffer_sequence_adapter<asio::const_buffer,
- ConstBufferSequence> bufs(o->buffers_);
-
- for (;;)
- {
- // Send the data.
- asio::error_code ec;
- int bytes = socket_ops::sendto(o->socket_, bufs.buffers(), bufs.count(),
- o->flags_, o->destination_.data(), o->destination_.size(), ec);
-
- // Retry operation if interrupted by signal.
- if (ec == asio::error::interrupted)
- continue;
-
- // Check if we need to run the operation again.
- if (ec == asio::error::would_block
- || ec == asio::error::try_again)
- return false;
-
- o->ec_ = ec;
- o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
- return true;
- }
- }
-
- private:
- socket_type socket_;
- ConstBufferSequence buffers_;
- endpoint_type destination_;
- socket_base::message_flags flags_;
- };
-
- template <typename ConstBufferSequence, typename Handler>
- class send_to_op : public send_to_op_base<ConstBufferSequence>
- {
- public:
- send_to_op(socket_type socket, const ConstBufferSequence& buffers,
- const endpoint_type& endpoint, socket_base::message_flags flags,
- Handler handler)
- : send_to_op_base<ConstBufferSequence>(socket,
- buffers, endpoint, flags, &send_to_op::do_complete),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
- {
- // Take ownership of the handler object.
- send_to_op* o(static_cast<send_to_op*>(base));
- typedef handler_alloc_traits<Handler, send_to_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder2<Handler, asio::error_code, std::size_t>
- handler(o->handler_, o->ec_, o->bytes_transferred_);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- Handler handler_;
- };
-
// Start an asynchronous send. The data being sent must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
@@ -863,235 +196,31 @@ public:
Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef send_to_op<ConstBufferSequence, Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_,
- buffers, destination, flags, handler);
+ typedef reactive_socket_sendto_op<ConstBufferSequence,
+ endpoint_type, Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, buffers, destination, flags, handler);
- start_op(impl, reactor::write_op, ptr.get(), true, false);
- ptr.release();
+ start_op(impl, reactor::write_op, p.p, true, false);
+ p.v = p.p = 0;
}
// Start an asynchronous wait until data can be sent without blocking.
template <typename Handler>
void async_send_to(implementation_type& impl, const null_buffers&,
- socket_base::message_flags, const endpoint_type&, Handler handler)
+ const endpoint_type&, socket_base::message_flags, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef null_buffers_op<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
- start_op(impl, reactor::write_op, ptr.get(), false, false);
- ptr.release();
- }
-
- // Receive some data from the peer. Returns the number of bytes received.
- template <typename MutableBufferSequence>
- size_t receive(implementation_type& impl,
- const MutableBufferSequence& buffers,
- socket_base::message_flags flags, asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
- buffer_sequence_adapter<asio::mutable_buffer,
- MutableBufferSequence> bufs(buffers);
-
- // A request to receive 0 bytes on a stream socket is a no-op.
- if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty())
- {
- ec = asio::error_code();
- return 0;
- }
-
- // Receive some data.
- for (;;)
- {
- // Try to complete the operation without blocking.
- int bytes_recvd = socket_ops::recv(impl.socket_,
- bufs.buffers(), bufs.count(), flags, ec);
-
- // Check if operation succeeded.
- if (bytes_recvd > 0)
- return bytes_recvd;
-
- // Check for EOF.
- if (bytes_recvd == 0 && impl.protocol_.type() == SOCK_STREAM)
- {
- ec = asio::error::eof;
- return 0;
- }
-
- // Operation failed.
- if ((impl.flags_ & implementation_type::user_set_non_blocking)
- || (ec != asio::error::would_block
- && ec != asio::error::try_again))
- return 0;
-
- // Wait for socket to become ready.
- if (socket_ops::poll_read(impl.socket_, ec) < 0)
- return 0;
- }
- }
-
- // Wait until data can be received without blocking.
- size_t receive(implementation_type& impl, const null_buffers&,
- socket_base::message_flags, asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
- // Wait for socket to become ready.
- socket_ops::poll_read(impl.socket_, ec);
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
- return 0;
- }
-
- template <typename MutableBufferSequence>
- class receive_op_base : public reactor_op
- {
- public:
- receive_op_base(socket_type socket, int protocol_type,
- const MutableBufferSequence& buffers,
- socket_base::message_flags flags, func_type complete_func)
- : reactor_op(&receive_op_base::do_perform, complete_func),
- socket_(socket),
- protocol_type_(protocol_type),
- buffers_(buffers),
- flags_(flags)
- {
- }
-
- static bool do_perform(reactor_op* base)
- {
- receive_op_base* o(static_cast<receive_op_base*>(base));
-
- buffer_sequence_adapter<asio::mutable_buffer,
- MutableBufferSequence> bufs(o->buffers_);
-
- for (;;)
- {
- // Receive some data.
- asio::error_code ec;
- int bytes = socket_ops::recv(o->socket_,
- bufs.buffers(), bufs.count(), o->flags_, ec);
- if (bytes == 0 && o->protocol_type_ == SOCK_STREAM)
- ec = asio::error::eof;
-
- // Retry operation if interrupted by signal.
- if (ec == asio::error::interrupted)
- continue;
-
- // Check if we need to run the operation again.
- if (ec == asio::error::would_block
- || ec == asio::error::try_again)
- return false;
-
- o->ec_ = ec;
- o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
- return true;
- }
- }
-
- private:
- socket_type socket_;
- int protocol_type_;
- MutableBufferSequence buffers_;
- socket_base::message_flags flags_;
- };
-
- template <typename MutableBufferSequence, typename Handler>
- class receive_op : public receive_op_base<MutableBufferSequence>
- {
- public:
- receive_op(socket_type socket, int protocol_type,
- const MutableBufferSequence& buffers,
- socket_base::message_flags flags, Handler handler)
- : receive_op_base<MutableBufferSequence>(socket,
- protocol_type, buffers, flags, &receive_op::do_complete),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
- {
- // Take ownership of the handler object.
- receive_op* o(static_cast<receive_op*>(base));
- typedef handler_alloc_traits<Handler, receive_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder2<Handler, asio::error_code, std::size_t>
- handler(o->handler_, o->ec_, o->bytes_transferred_);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- Handler handler_;
- };
-
- // Start an asynchronous receive. The buffer for the data being received
- // must be valid for the lifetime of the asynchronous operation.
- template <typename MutableBufferSequence, typename Handler>
- void async_receive(implementation_type& impl,
- const MutableBufferSequence& buffers,
- socket_base::message_flags flags, Handler handler)
- {
- // Allocate and construct an operation to wrap the handler.
- typedef receive_op<MutableBufferSequence, Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- int protocol_type = impl.protocol_.type();
- handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_,
- protocol_type, buffers, flags, handler);
-
- start_op(impl,
- (flags & socket_base::message_out_of_band)
- ? reactor::except_op : reactor::read_op,
- ptr.get(), (flags & socket_base::message_out_of_band) == 0,
- (impl.protocol_.type() == SOCK_STREAM
- && buffer_sequence_adapter<asio::mutable_buffer,
- MutableBufferSequence>::all_empty(buffers)));
- ptr.release();
- }
-
- // Wait until data can be received without blocking.
- template <typename Handler>
- void async_receive(implementation_type& impl, const null_buffers&,
- socket_base::message_flags flags, Handler handler)
- {
- // Allocate and construct an operation to wrap the handler.
- typedef null_buffers_op<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
- start_op(impl,
- (flags & socket_base::message_out_of_band)
- ? reactor::except_op : reactor::read_op,
- ptr.get(), false, false);
- ptr.release();
+ start_op(impl, reactor::write_op, p.p, false, false);
+ p.v = p.p = 0;
}
// Receive a datagram with the endpoint of the sender. Returns the number of
@@ -1102,47 +231,18 @@ public:
endpoint_type& sender_endpoint, socket_base::message_flags flags,
asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
buffer_sequence_adapter<asio::mutable_buffer,
MutableBufferSequence> bufs(buffers);
- // Receive some data.
- for (;;)
- {
- // Try to complete the operation without blocking.
- std::size_t addr_len = sender_endpoint.capacity();
- int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs.buffers(),
- bufs.count(), flags, sender_endpoint.data(), &addr_len, ec);
+ std::size_t addr_len = sender_endpoint.capacity();
+ std::size_t bytes_recvd = socket_ops::sync_recvfrom(
+ impl.socket_, impl.state_, bufs.buffers(), bufs.count(),
+ flags, sender_endpoint.data(), &addr_len, ec);
- // Check if operation succeeded.
- if (bytes_recvd > 0)
- {
- sender_endpoint.resize(addr_len);
- return bytes_recvd;
- }
+ if (!ec)
+ sender_endpoint.resize(addr_len);
- // Check for EOF.
- if (bytes_recvd == 0 && impl.protocol_.type() == SOCK_STREAM)
- {
- ec = asio::error::eof;
- return 0;
- }
-
- // Operation failed.
- if ((impl.flags_ & implementation_type::user_set_non_blocking)
- || (ec != asio::error::would_block
- && ec != asio::error::try_again))
- return 0;
-
- // Wait for socket to become ready.
- if (socket_ops::poll_read(impl.socket_, ec) < 0)
- return 0;
- }
+ return bytes_recvd;
}
// Wait until data can be received without blocking.
@@ -1150,12 +250,6 @@ public:
endpoint_type& sender_endpoint, socket_base::message_flags,
asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
// Wait for socket to become ready.
socket_ops::poll_read(impl.socket_, ec);
@@ -1165,105 +259,6 @@ public:
return 0;
}
- template <typename MutableBufferSequence>
- class receive_from_op_base : public reactor_op
- {
- public:
- receive_from_op_base(socket_type socket, int protocol_type,
- const MutableBufferSequence& buffers, endpoint_type& endpoint,
- socket_base::message_flags flags, func_type complete_func)
- : reactor_op(&receive_from_op_base::do_perform, complete_func),
- socket_(socket),
- protocol_type_(protocol_type),
- buffers_(buffers),
- sender_endpoint_(endpoint),
- flags_(flags)
- {
- }
-
- static bool do_perform(reactor_op* base)
- {
- receive_from_op_base* o(static_cast<receive_from_op_base*>(base));
-
- buffer_sequence_adapter<asio::mutable_buffer,
- MutableBufferSequence> bufs(o->buffers_);
-
- for (;;)
- {
- // Receive some data.
- asio::error_code ec;
- std::size_t addr_len = o->sender_endpoint_.capacity();
- int bytes = socket_ops::recvfrom(o->socket_, bufs.buffers(),
- bufs.count(), o->flags_, o->sender_endpoint_.data(), &addr_len, ec);
- if (bytes == 0 && o->protocol_type_ == SOCK_STREAM)
- ec = asio::error::eof;
-
- // Retry operation if interrupted by signal.
- if (ec == asio::error::interrupted)
- continue;
-
- // Check if we need to run the operation again.
- if (ec == asio::error::would_block
- || ec == asio::error::try_again)
- return false;
-
- o->sender_endpoint_.resize(addr_len);
- o->ec_ = ec;
- o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
- return true;
- }
- }
-
- private:
- socket_type socket_;
- int protocol_type_;
- MutableBufferSequence buffers_;
- endpoint_type& sender_endpoint_;
- socket_base::message_flags flags_;
- };
-
- template <typename MutableBufferSequence, typename Handler>
- class receive_from_op : public receive_from_op_base<MutableBufferSequence>
- {
- public:
- receive_from_op(socket_type socket, int protocol_type,
- const MutableBufferSequence& buffers, endpoint_type& endpoint,
- socket_base::message_flags flags, Handler handler)
- : receive_from_op_base<MutableBufferSequence>(socket, protocol_type,
- buffers, endpoint, flags, &receive_from_op::do_complete),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
- {
- // Take ownership of the handler object.
- receive_from_op* o(static_cast<receive_from_op*>(base));
- typedef handler_alloc_traits<Handler, receive_from_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder2<Handler, asio::error_code, std::size_t>
- handler(o->handler_, o->ec_, o->bytes_transferred_);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- Handler handler_;
- };
-
// Start an asynchronous receive. The buffer for the data being received and
// the sender_endpoint object must both be valid for the lifetime of the
// asynchronous operation.
@@ -1273,18 +268,20 @@ public:
socket_base::message_flags flags, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef receive_from_op<MutableBufferSequence, Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ typedef reactive_socket_recvfrom_op<MutableBufferSequence,
+ endpoint_type, Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
int protocol_type = impl.protocol_.type();
- handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_,
- protocol_type, buffers, sender_endpoint, flags, handler);
+ p.p = new (p.v) op(impl.socket_, protocol_type,
+ buffers, sender_endpoint, flags, handler);
start_op(impl,
(flags & socket_base::message_out_of_band)
? reactor::except_op : reactor::read_op,
- ptr.get(), true, false);
- ptr.release();
+ p.p, true, false);
+ p.v = p.p = 0;
}
// Wait until data can be received without blocking.
@@ -1294,10 +291,11 @@ public:
socket_base::message_flags flags, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef null_buffers_op<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
// Reset endpoint since it can be given no sensible value at this time.
sender_endpoint = endpoint_type();
@@ -1305,8 +303,8 @@ public:
start_op(impl,
(flags & socket_base::message_out_of_band)
? reactor::except_op : reactor::read_op,
- ptr.get(), false, false);
- ptr.release();
+ p.p, false, false);
+ p.v = p.p = 0;
}
// Accept a new connection.
@@ -1314,12 +312,6 @@ public:
asio::error_code accept(implementation_type& impl,
Socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
// We cannot accept a socket that is already open.
if (peer.is_open())
{
@@ -1327,181 +319,22 @@ public:
return ec;
}
- // Accept a socket.
- for (;;)
- {
- // Try to complete the operation without blocking.
- socket_holder new_socket;
- std::size_t addr_len = 0;
- if (peer_endpoint)
- {
- addr_len = peer_endpoint->capacity();
- new_socket.reset(socket_ops::accept(impl.socket_,
- peer_endpoint->data(), &addr_len, ec));
- }
- else
- {
- new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec));
- }
-
- // Check if operation succeeded.
- if (new_socket.get() >= 0)
- {
- if (peer_endpoint)
- peer_endpoint->resize(addr_len);
- peer.assign(impl.protocol_, new_socket.get(), ec);
- if (!ec)
- new_socket.release();
- return ec;
- }
+ std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;
+ socket_holder new_socket(socket_ops::sync_accept(impl.socket_,
+ impl.state_, peer_endpoint ? peer_endpoint->data() : 0,
+ peer_endpoint ? &addr_len : 0, ec));
- // Operation failed.
- if (ec == asio::error::would_block
- || ec == asio::error::try_again)
- {
- if (impl.flags_ & implementation_type::user_set_non_blocking)
- return ec;
- // Fall through to retry operation.
- }
- else if (ec == asio::error::connection_aborted)
- {
- if (impl.flags_ & implementation_type::enable_connection_aborted)
- return ec;
- // Fall through to retry operation.
- }
-#if defined(EPROTO)
- else if (ec.value() == EPROTO)
- {
- if (impl.flags_ & implementation_type::enable_connection_aborted)
- return ec;
- // Fall through to retry operation.
- }
-#endif // defined(EPROTO)
- else
- return ec;
-
- // Wait for socket to become ready.
- if (socket_ops::poll_read(impl.socket_, ec) < 0)
- return ec;
- }
- }
-
- template <typename Socket>
- class accept_op_base : public reactor_op
- {
- public:
- accept_op_base(socket_type socket, Socket& peer,
- const protocol_type& protocol, endpoint_type* peer_endpoint,
- bool enable_connection_aborted, func_type complete_func)
- : reactor_op(&accept_op_base::do_perform, complete_func),
- socket_(socket),
- peer_(peer),
- protocol_(protocol),
- peer_endpoint_(peer_endpoint),
- enable_connection_aborted_(enable_connection_aborted)
- {
- }
-
- static bool do_perform(reactor_op* base)
+ // On success, assign new connection to peer socket object.
+ if (new_socket.get() != invalid_socket)
{
- accept_op_base* o(static_cast<accept_op_base*>(base));
-
- for (;;)
- {
- // Accept the waiting connection.
- asio::error_code ec;
- socket_holder new_socket;
- std::size_t addr_len = 0;
- std::size_t* addr_len_p = 0;
- socket_addr_type* addr = 0;
- if (o->peer_endpoint_)
- {
- addr_len = o->peer_endpoint_->capacity();
- addr_len_p = &addr_len;
- addr = o->peer_endpoint_->data();
- }
- new_socket.reset(socket_ops::accept(o->socket_, addr, addr_len_p, ec));
-
- // Retry operation if interrupted by signal.
- if (ec == asio::error::interrupted)
- continue;
-
- // Check if we need to run the operation again.
- if (ec == asio::error::would_block
- || ec == asio::error::try_again)
- return false;
- if (ec == asio::error::connection_aborted
- && !o->enable_connection_aborted_)
- return false;
-#if defined(EPROTO)
- if (ec.value() == EPROTO && !o->enable_connection_aborted_)
- return false;
-#endif // defined(EPROTO)
-
- // Transfer ownership of the new socket to the peer object.
- if (!ec)
- {
- if (o->peer_endpoint_)
- o->peer_endpoint_->resize(addr_len);
- o->peer_.assign(o->protocol_, new_socket.get(), ec);
- if (!ec)
- new_socket.release();
- }
-
- o->ec_ = ec;
- return true;
- }
- }
-
- private:
- socket_type socket_;
- Socket& peer_;
- protocol_type protocol_;
- endpoint_type* peer_endpoint_;
- bool enable_connection_aborted_;
- };
-
- template <typename Socket, typename Handler>
- class accept_op : public accept_op_base<Socket>
- {
- public:
- accept_op(socket_type socket, Socket& peer, const protocol_type& protocol,
- endpoint_type* peer_endpoint, bool enable_connection_aborted,
- Handler handler)
- : accept_op_base<Socket>(socket, peer, protocol, peer_endpoint,
- enable_connection_aborted, &accept_op::do_complete),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
- {
- // Take ownership of the handler object.
- accept_op* o(static_cast<accept_op*>(base));
- typedef handler_alloc_traits<Handler, accept_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder1<Handler, asio::error_code>
- handler(o->handler_, o->ec_);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
+ if (peer_endpoint)
+ peer_endpoint->resize(addr_len);
+ if (!peer.assign(impl.protocol_, new_socket.get(), ec))
+ new_socket.release();
}
- private:
- Handler handler_;
- };
+ return ec;
+ }
// Start an asynchronous accept. The peer and peer_endpoint objects
// must be valid until the accept's handler is invoked.
@@ -1510,230 +343,41 @@ public:
endpoint_type* peer_endpoint, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef accept_op<Socket, Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- bool enable_connection_aborted =
- (impl.flags_ & implementation_type::enable_connection_aborted) != 0;
- handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_, peer,
- impl.protocol_, peer_endpoint, enable_connection_aborted, handler);
+ typedef reactive_socket_accept_op<Socket, Protocol, Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, impl.state_, peer,
+ impl.protocol_, peer_endpoint, handler);
- start_accept_op(impl, ptr.get(), peer.is_open());
- ptr.release();
+ start_accept_op(impl, p.p, peer.is_open());
+ p.v = p.p = 0;
}
// Connect the socket to the specified endpoint.
asio::error_code connect(implementation_type& impl,
const endpoint_type& peer_endpoint, asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
- // Perform the connect operation.
- socket_ops::connect(impl.socket_,
+ socket_ops::sync_connect(impl.socket_,
peer_endpoint.data(), peer_endpoint.size(), ec);
- if (ec != asio::error::in_progress
- && ec != asio::error::would_block)
- {
- // The connect operation finished immediately.
- return ec;
- }
-
- // Wait for socket to become ready.
- if (socket_ops::poll_connect(impl.socket_, ec) < 0)
- return ec;
-
- // Get the error code from the connect operation.
- int connect_error = 0;
- size_t connect_error_len = sizeof(connect_error);
- if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_ERROR,
- &connect_error, &connect_error_len, ec) == socket_error_retval)
- return ec;
-
- // Return the result of the connect operation.
- ec = asio::error_code(connect_error,
- asio::error::get_system_category());
return ec;
}
- class connect_op_base : public reactor_op
- {
- public:
- connect_op_base(socket_type socket, func_type complete_func)
- : reactor_op(&connect_op_base::do_perform, complete_func),
- socket_(socket)
- {
- }
-
- static bool do_perform(reactor_op* base)
- {
- connect_op_base* o(static_cast<connect_op_base*>(base));
-
- // Get the error code from the connect operation.
- int connect_error = 0;
- size_t connect_error_len = sizeof(connect_error);
- if (socket_ops::getsockopt(o->socket_, SOL_SOCKET, SO_ERROR,
- &connect_error, &connect_error_len, o->ec_) == socket_error_retval)
- return true;
-
- // The connection failed so the handler will be posted with an error code.
- if (connect_error)
- {
- o->ec_ = asio::error_code(connect_error,
- asio::error::get_system_category());
- }
-
- return true;
- }
-
- private:
- socket_type socket_;
- };
-
- template <typename Handler>
- class connect_op : public connect_op_base
- {
- public:
- connect_op(socket_type socket, Handler handler)
- : connect_op_base(socket, &connect_op::do_complete),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
- {
- // Take ownership of the handler object.
- connect_op* o(static_cast<connect_op*>(base));
- typedef handler_alloc_traits<Handler, connect_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder1<Handler, asio::error_code>
- handler(o->handler_, o->ec_);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- Handler handler_;
- };
-
// Start an asynchronous connect.
template <typename Handler>
void async_connect(implementation_type& impl,
const endpoint_type& peer_endpoint, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef connect_op<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_, handler);
-
- start_connect_op(impl, ptr.get(), peer_endpoint);
- ptr.release();
- }
-
-private:
- // Start the asynchronous read or write operation.
- void start_op(implementation_type& impl, int op_type,
- reactor_op* op, bool non_blocking, bool noop)
- {
- if (!noop)
- {
- if (is_open(impl))
- {
- if (!non_blocking || is_non_blocking(impl)
- || set_non_blocking(impl, op->ec_))
- {
- reactor_.start_op(op_type, impl.socket_,
- impl.reactor_data_, op, non_blocking);
- return;
- }
- }
- else
- op->ec_ = asio::error::bad_descriptor;
- }
+ typedef reactive_socket_connect_op<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, handler);
- io_service_impl_.post_immediate_completion(op);
+ start_connect_op(impl, p.p, peer_endpoint.data(), peer_endpoint.size());
+ p.v = p.p = 0;
}
-
- // Start the asynchronous accept operation.
- void start_accept_op(implementation_type& impl,
- reactor_op* op, bool peer_is_open)
- {
- if (!peer_is_open)
- start_op(impl, reactor::read_op, op, true, false);
- else
- {
- op->ec_ = asio::error::already_open;
- io_service_impl_.post_immediate_completion(op);
- }
- }
-
- // Start the asynchronous connect operation.
- void start_connect_op(implementation_type& impl,
- reactor_op* op, const endpoint_type& peer_endpoint)
- {
- if (is_open(impl))
- {
- if (is_non_blocking(impl) || set_non_blocking(impl, op->ec_))
- {
- if (socket_ops::connect(impl.socket_, peer_endpoint.data(),
- peer_endpoint.size(), op->ec_) != 0)
- {
- if (op->ec_ == asio::error::in_progress
- || op->ec_ == asio::error::would_block)
- {
- op->ec_ = asio::error_code();
- reactor_.start_op(reactor::connect_op,
- impl.socket_, impl.reactor_data_, op, false);
- return;
- }
- }
- }
- }
- else
- op->ec_ = asio::error::bad_descriptor;
-
- io_service_impl_.post_immediate_completion(op);
- }
-
- // Determine whether the socket has been set non-blocking.
- bool is_non_blocking(implementation_type& impl) const
- {
- return (impl.flags_ & implementation_type::non_blocking);
- }
-
- // Set the internal non-blocking flag.
- bool set_non_blocking(implementation_type& impl,
- asio::error_code& ec)
- {
- ioctl_arg_type non_blocking = 1;
- if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
- return false;
- impl.flags_ |= implementation_type::internal_non_blocking;
- return true;
- }
-
- // The io_service implementation used to post completions.
- io_service_impl& io_service_impl_;
-
- // The selector that performs event demultiplexing for the service.
- reactor& reactor_;
};
} // namespace detail
@@ -1741,4 +385,6 @@ private:
#include "asio/detail/pop_options.hpp"
+#endif // !defined(ASIO_HAS_IOCP)
+
#endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
diff --git a/ext/asio/asio/detail/reactive_socket_service_base.hpp b/ext/asio/asio/detail/reactive_socket_service_base.hpp
new file mode 100644
index 0000000..b26d73e
--- /dev/null
+++ b/ext/asio/asio/detail/reactive_socket_service_base.hpp
@@ -0,0 +1,298 @@
+//
+// detail/reactive_socket_service_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_IOCP)
+
+#include <boost/utility/addressof.hpp>
+#include "asio/buffer.hpp"
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/reactive_null_buffers_op.hpp"
+#include "asio/detail/reactive_socket_recv_op.hpp"
+#include "asio/detail/reactive_socket_send_op.hpp"
+#include "asio/detail/reactor.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class reactive_socket_service_base
+{
+public:
+ // The native type of a socket.
+ typedef socket_type native_type;
+
+ // The implementation type of the socket.
+ struct base_implementation_type
+ {
+ // The native socket representation.
+ socket_type socket_;
+
+ // The current state of the socket.
+ socket_ops::state_type state_;
+
+ // Per-descriptor data used by the reactor.
+ reactor::per_descriptor_data reactor_data_;
+ };
+
+ // Constructor.
+ ASIO_DECL reactive_socket_service_base(
+ asio::io_service& io_service);
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown_service();
+
+ // Construct a new socket implementation.
+ ASIO_DECL void construct(base_implementation_type& impl);
+
+ // Destroy a socket implementation.
+ ASIO_DECL void destroy(base_implementation_type& impl);
+
+ // Determine whether the socket is open.
+ bool is_open(const base_implementation_type& impl) const
+ {
+ return impl.socket_ != invalid_socket;
+ }
+
+ // Destroy a socket implementation.
+ ASIO_DECL asio::error_code close(
+ base_implementation_type& impl, asio::error_code& ec);
+
+ // Get the native socket representation.
+ native_type native(base_implementation_type& impl)
+ {
+ return impl.socket_;
+ }
+
+ // Cancel all operations associated with the socket.
+ ASIO_DECL asio::error_code cancel(
+ base_implementation_type& impl, asio::error_code& ec);
+
+ // Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const base_implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ return socket_ops::sockatmark(impl.socket_, ec);
+ }
+
+ // Determine the number of bytes available for reading.
+ std::size_t available(const base_implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ return socket_ops::available(impl.socket_, ec);
+ }
+
+ // Place the socket into the state where it will listen for new connections.
+ asio::error_code listen(base_implementation_type& impl,
+ int backlog, asio::error_code& ec)
+ {
+ socket_ops::listen(impl.socket_, backlog, ec);
+ return ec;
+ }
+
+ // Perform an IO control command on the socket.
+ template <typename IO_Control_Command>
+ asio::error_code io_control(base_implementation_type& impl,
+ IO_Control_Command& command, asio::error_code& ec)
+ {
+ socket_ops::ioctl(impl.socket_, impl.state_, command.name(),
+ static_cast<ioctl_arg_type*>(command.data()), ec);
+ return ec;
+ }
+
+ /// Disable sends or receives on the socket.
+ asio::error_code shutdown(base_implementation_type& impl,
+ socket_base::shutdown_type what, asio::error_code& ec)
+ {
+ socket_ops::shutdown(impl.socket_, what, ec);
+ return ec;
+ }
+
+ // Send the given data to the peer.
+ template <typename ConstBufferSequence>
+ size_t send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_send(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, asio::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous send. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_send_op<ConstBufferSequence, Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, buffers, flags, handler);
+
+ start_op(impl, reactor::write_op, p.p, true,
+ ((impl.state_ & socket_ops::stream_oriented)
+ && buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence>::all_empty(buffers)));
+ p.v = p.p = 0;
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ start_op(impl, reactor::write_op, p.p, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Receive some data from the peer. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_recv(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, asio::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous receive. The buffer for the data being received
+ // must be valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_receive(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_recv_op<MutableBufferSequence, Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler);
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, (flags & socket_base::message_out_of_band) == 0,
+ ((impl.state_ & socket_ops::stream_oriented)
+ && buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::all_empty(buffers)));
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags flags, Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, false, false);
+ p.v = p.p = 0;
+ }
+
+protected:
+ // Open a new socket implementation.
+ ASIO_DECL asio::error_code do_open(
+ base_implementation_type& impl, int af,
+ int type, int protocol, asio::error_code& ec);
+
+ // Assign a native socket to a socket implementation.
+ ASIO_DECL asio::error_code do_assign(
+ base_implementation_type& impl, int type,
+ const native_type& native_socket, asio::error_code& ec);
+
+ // Start the asynchronous read or write operation.
+ ASIO_DECL void start_op(base_implementation_type& impl, int op_type,
+ reactor_op* op, bool non_blocking, bool noop);
+
+ // Start the asynchronous accept operation.
+ ASIO_DECL void start_accept_op(base_implementation_type& impl,
+ reactor_op* op, bool peer_is_open);
+
+ // Start the asynchronous connect operation.
+ ASIO_DECL void start_connect_op(base_implementation_type& impl,
+ reactor_op* op, const socket_addr_type* addr, size_t addrlen);
+
+ // The selector that performs event demultiplexing for the service.
+ reactor& reactor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/reactive_socket_service_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
diff --git a/ext/asio/asio/detail/reactor.hpp b/ext/asio/asio/detail/reactor.hpp
index 98ac360..0e938c9 100644
--- a/ext/asio/asio/detail/reactor.hpp
+++ b/ext/asio/asio/detail/reactor.hpp
@@ -1,8 +1,8 @@
//
-// reactor.hpp
-// ~~~~~~~~~~~
+// detail/reactor.hpp
+// ~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,8 +15,6 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
#include "asio/detail/reactor_fwd.hpp"
#if defined(ASIO_HAS_EPOLL)
@@ -29,6 +27,4 @@
# include "asio/detail/select_reactor.hpp"
#endif
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_REACTOR_HPP
diff --git a/ext/asio/asio/detail/reactor_fwd.hpp b/ext/asio/asio/detail/reactor_fwd.hpp
index 9c33be5..d45d768 100644
--- a/ext/asio/asio/detail/reactor_fwd.hpp
+++ b/ext/asio/asio/detail/reactor_fwd.hpp
@@ -1,8 +1,8 @@
//
-// reactor_fwd.hpp
-// ~~~~~~~~~~~~~~~
+// detail/reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,19 +15,25 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/dev_poll_reactor_fwd.hpp"
-#include "asio/detail/epoll_reactor_fwd.hpp"
-#include "asio/detail/kqueue_reactor_fwd.hpp"
-#include "asio/detail/select_reactor_fwd.hpp"
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/select_reactor_fwd.hpp"
+#elif defined(ASIO_HAS_EPOLL)
+# include "asio/detail/epoll_reactor_fwd.hpp"
+#elif defined(ASIO_HAS_KQUEUE)
+# include "asio/detail/kqueue_reactor_fwd.hpp"
+#elif defined(ASIO_HAS_DEV_POLL)
+# include "asio/detail/dev_poll_reactor_fwd.hpp"
+#else
+# include "asio/detail/select_reactor_fwd.hpp"
+#endif
namespace asio {
namespace detail {
#if defined(ASIO_HAS_IOCP)
-typedef select_reactor<true> reactor;
+typedef select_reactor reactor;
#elif defined(ASIO_HAS_EPOLL)
typedef epoll_reactor reactor;
#elif defined(ASIO_HAS_KQUEUE)
@@ -35,12 +41,10 @@ typedef kqueue_reactor reactor;
#elif defined(ASIO_HAS_DEV_POLL)
typedef dev_poll_reactor reactor;
#else
-typedef select_reactor<false> reactor;
+typedef select_reactor reactor;
#endif
} // namespace detail
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_REACTOR_FWD_HPP
diff --git a/ext/asio/asio/detail/reactor_op.hpp b/ext/asio/asio/detail/reactor_op.hpp
index cd557fa..3009cf9 100644
--- a/ext/asio/asio/detail/reactor_op.hpp
+++ b/ext/asio/asio/detail/reactor_op.hpp
@@ -1,8 +1,8 @@
//
-// reactor_op.hpp
-// ~~~~~~~~~~~~
+// detail/reactor_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,10 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/detail/operation.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
diff --git a/ext/asio/asio/detail/reactor_op_queue.hpp b/ext/asio/asio/detail/reactor_op_queue.hpp
index 233c0ae..6eed398 100644
--- a/ext/asio/asio/detail/reactor_op_queue.hpp
+++ b/ext/asio/asio/detail/reactor_op_queue.hpp
@@ -1,8 +1,8 @@
//
-// reactor_op_queue.hpp
-// ~~~~~~~~~~~~~~~~~~~~
+// detail/reactor_op_queue.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,13 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/error.hpp"
+#include "asio/detail/config.hpp"
#include "asio/detail/hash_map.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/op_queue.hpp"
#include "asio/detail/reactor_op.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
diff --git a/ext/asio/asio/detail/regex_fwd.hpp b/ext/asio/asio/detail/regex_fwd.hpp
new file mode 100644
index 0000000..9da295b
--- /dev/null
+++ b/ext/asio/asio/detail/regex_fwd.hpp
@@ -0,0 +1,31 @@
+//
+// detail/regex_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REGEX_FWD_HPP
+#define ASIO_DETAIL_REGEX_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/regex_fwd.hpp>
+#include <boost/regex/v4/match_flags.hpp>
+
+namespace boost {
+
+template <class BidiIterator>
+struct sub_match;
+
+template <class BidiIterator, class Allocator>
+class match_results;
+
+} // namespace boost
+
+#endif // ASIO_DETAIL_REGEX_FWD_HPP
diff --git a/ext/asio/asio/detail/resolve_endpoint_op.hpp b/ext/asio/asio/detail/resolve_endpoint_op.hpp
new file mode 100644
index 0000000..0931fd0
--- /dev/null
+++ b/ext/asio/asio/detail/resolve_endpoint_op.hpp
@@ -0,0 +1,116 @@
+//
+// detail/resolve_endpoint_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP
+#define ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/ip/basic_resolver_iterator.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol, typename Handler>
+class resolve_endpoint_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(resolve_endpoint_op);
+
+ typedef typename Protocol::endpoint endpoint_type;
+ typedef asio::ip::basic_resolver_iterator<Protocol> iterator_type;
+
+ resolve_endpoint_op(socket_ops::weak_cancel_token_type cancel_token,
+ const endpoint_type& endpoint, io_service_impl& ios, Handler handler)
+ : operation(&resolve_endpoint_op::do_complete),
+ cancel_token_(cancel_token),
+ endpoint_(endpoint),
+ io_service_impl_(ios),
+ handler_(handler)
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the operation object.
+ resolve_endpoint_op* o(static_cast<resolve_endpoint_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+ if (owner && owner != &o->io_service_impl_)
+ {
+ // The operation is being run on the worker io_service. Time to perform
+ // the resolver operation.
+
+ // Perform the blocking endpoint resolution operation.
+ char host_name[NI_MAXHOST];
+ char service_name[NI_MAXSERV];
+ socket_ops::background_getnameinfo(o->cancel_token_, o->endpoint_.data(),
+ o->endpoint_.size(), host_name, NI_MAXHOST, service_name, NI_MAXSERV,
+ o->endpoint_.protocol().type(), o->ec_);
+ o->iter_ = iterator_type::create(o->endpoint_, host_name, service_name);
+
+ // Pass operation back to main io_service for completion.
+ o->io_service_impl_.post_deferred_completion(o);
+ p.v = p.p = 0;
+ }
+ else
+ {
+ // The operation has been returned to the main io_service. The completion
+ // handler is ready to be delivered.
+
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an upcall,
+ // a sub-object of the handler may be the true owner of the memory
+ // associated with the handler. Consequently, a local copy of the handler
+ // is required to ensure that any owning sub-object remains valid until
+ // after we have deallocated the memory here.
+ detail::binder2<Handler, asio::error_code, iterator_type>
+ handler(o->handler_, o->ec_, o->iter_);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+ }
+
+private:
+ socket_ops::weak_cancel_token_type cancel_token_;
+ endpoint_type endpoint_;
+ io_service_impl& io_service_impl_;
+ Handler handler_;
+ asio::error_code ec_;
+ iterator_type iter_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP
diff --git a/ext/asio/asio/detail/resolve_op.hpp b/ext/asio/asio/detail/resolve_op.hpp
new file mode 100644
index 0000000..a04fbc3
--- /dev/null
+++ b/ext/asio/asio/detail/resolve_op.hpp
@@ -0,0 +1,126 @@
+//
+// detail/resolve_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_RESOLVE_OP_HPP
+#define ASIO_DETAIL_RESOLVE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/ip/basic_resolver_iterator.hpp"
+#include "asio/ip/basic_resolver_query.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol, typename Handler>
+class resolve_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(resolve_op);
+
+ typedef asio::ip::basic_resolver_query<Protocol> query_type;
+ typedef asio::ip::basic_resolver_iterator<Protocol> iterator_type;
+
+ resolve_op(socket_ops::weak_cancel_token_type cancel_token,
+ const query_type& query, io_service_impl& ios, Handler handler)
+ : operation(&resolve_op::do_complete),
+ cancel_token_(cancel_token),
+ query_(query),
+ io_service_impl_(ios),
+ handler_(handler),
+ addrinfo_(0)
+ {
+ }
+
+ ~resolve_op()
+ {
+ if (addrinfo_)
+ socket_ops::freeaddrinfo(addrinfo_);
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the operation object.
+ resolve_op* o(static_cast<resolve_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+ if (owner && owner != &o->io_service_impl_)
+ {
+ // The operation is being run on the worker io_service. Time to perform
+ // the resolver operation.
+
+ // Perform the blocking host resolution operation.
+ socket_ops::background_getaddrinfo(o->cancel_token_,
+ o->query_.host_name().c_str(), o->query_.service_name().c_str(),
+ o->query_.hints(), &o->addrinfo_, o->ec_);
+
+ // Pass operation back to main io_service for completion.
+ o->io_service_impl_.post_deferred_completion(o);
+ p.v = p.p = 0;
+ }
+ else
+ {
+ // The operation has been returned to the main io_service. The completion
+ // handler is ready to be delivered.
+
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an upcall,
+ // a sub-object of the handler may be the true owner of the memory
+ // associated with the handler. Consequently, a local copy of the handler
+ // is required to ensure that any owning sub-object remains valid until
+ // after we have deallocated the memory here.
+ detail::binder2<Handler, asio::error_code, iterator_type>
+ handler(o->handler_, o->ec_, iterator_type());
+ p.h = boost::addressof(handler.handler_);
+ if (o->addrinfo_)
+ {
+ handler.arg2_ = iterator_type::create(o->addrinfo_,
+ o->query_.host_name(), o->query_.service_name());
+ }
+ p.reset();
+
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+ }
+
+private:
+ socket_ops::weak_cancel_token_type cancel_token_;
+ query_type query_;
+ io_service_impl& io_service_impl_;
+ Handler handler_;
+ asio::error_code ec_;
+ asio::detail::addrinfo_type* addrinfo_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_RESOLVE_OP_HPP
diff --git a/ext/asio/asio/detail/resolver_service.hpp b/ext/asio/asio/detail/resolver_service.hpp
index 562dc10..c2c3b0c 100644
--- a/ext/asio/asio/detail/resolver_service.hpp
+++ b/ext/asio/asio/detail/resolver_service.hpp
@@ -1,8 +1,8 @@
//
-// resolver_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~
+// detail/resolver_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,68 +15,25 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <cstring>
-#include <boost/scoped_ptr.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/weak_ptr.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/io_service.hpp"
+#include "asio/detail/config.hpp"
#include "asio/ip/basic_resolver_iterator.hpp"
#include "asio/ip/basic_resolver_query.hpp"
-#include "asio/detail/bind_handler.hpp"
-#include "asio/detail/fenced_block.hpp"
-#include "asio/detail/mutex.hpp"
-#include "asio/detail/noncopyable.hpp"
-#include "asio/detail/operation.hpp"
-#include "asio/detail/service_base.hpp"
-#include "asio/detail/socket_ops.hpp"
-#include "asio/detail/socket_types.hpp"
-#include "asio/detail/thread.hpp"
+#include "asio/detail/resolve_endpoint_op.hpp"
+#include "asio/detail/resolve_op.hpp"
+#include "asio/detail/resolver_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Protocol>
-class resolver_service
- : public asio::detail::service_base<resolver_service<Protocol> >
+class resolver_service : public resolver_service_base
{
-private:
- // Helper class to perform exception-safe cleanup of addrinfo objects.
- class auto_addrinfo
- : private asio::detail::noncopyable
- {
- public:
- explicit auto_addrinfo(asio::detail::addrinfo_type* ai)
- : ai_(ai)
- {
- }
-
- ~auto_addrinfo()
- {
- if (ai_)
- socket_ops::freeaddrinfo(ai_);
- }
-
- operator asio::detail::addrinfo_type*()
- {
- return ai_;
- }
-
- private:
- asio::detail::addrinfo_type* ai_;
- };
-
public:
- // The implementation type of the resolver. The shared pointer is used as a
- // cancellation token to indicate to the background thread that the operation
- // has been cancelled.
- typedef boost::shared_ptr<void> implementation_type;
- struct noop_deleter { void operator()(void*) {} };
+ // The implementation type of the resolver. A cancellation token is used to
+ // indicate to the background thread that the operation has been cancelled.
+ typedef socket_ops::shared_cancel_token_type implementation_type;
// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
@@ -89,55 +46,8 @@ public:
// Constructor.
resolver_service(asio::io_service& io_service)
- : asio::detail::service_base<
- resolver_service<Protocol> >(io_service),
- mutex_(),
- io_service_impl_(asio::use_service<io_service_impl>(io_service)),
- work_io_service_(new asio::io_service),
- work_io_service_impl_(asio::use_service<
- io_service_impl>(*work_io_service_)),
- work_(new asio::io_service::work(*work_io_service_)),
- work_thread_(0)
- {
- }
-
- // Destructor.
- ~resolver_service()
+ : resolver_service_base(io_service)
{
- shutdown_service();
- }
-
- // Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- work_.reset();
- if (work_io_service_)
- {
- work_io_service_->stop();
- if (work_thread_)
- {
- work_thread_->join();
- work_thread_.reset();
- }
- work_io_service_.reset();
- }
- }
-
- // Construct a new resolver implementation.
- void construct(implementation_type& impl)
- {
- impl.reset(static_cast<void*>(0), noop_deleter());
- }
-
- // Destroy a resolver implementation.
- void destroy(implementation_type&)
- {
- }
-
- // Cancel pending asynchronous operations.
- void cancel(implementation_type& impl)
- {
- impl.reset(static_cast<void*>(0), noop_deleter());
}
// Resolve a query to a list of entries.
@@ -145,293 +55,60 @@ public:
asio::error_code& ec)
{
asio::detail::addrinfo_type* address_info = 0;
- std::string host_name = query.host_name();
- std::string service_name = query.service_name();
- asio::detail::addrinfo_type hints = query.hints();
- socket_ops::getaddrinfo(!host_name.empty() ? host_name.c_str() : 0,
- service_name.c_str(), &hints, &address_info, ec);
+ socket_ops::getaddrinfo(query.host_name().c_str(),
+ query.service_name().c_str(), query.hints(), &address_info, ec);
auto_addrinfo auto_address_info(address_info);
- if (ec)
- return iterator_type();
-
- return iterator_type::create(address_info, host_name, service_name);
+ return ec ? iterator_type() : iterator_type::create(
+ address_info, query.host_name(), query.service_name());
}
- template <typename Handler>
- class resolve_op
- : public operation
- {
- public:
- resolve_op(implementation_type impl, const query_type& query,
- io_service_impl& io_service_impl, Handler handler)
- : operation(&resolve_op::do_complete),
- impl_(impl),
- query_(query),
- io_service_impl_(io_service_impl),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
- {
- // Take ownership of the operation object.
- resolve_op* o(static_cast<resolve_op*>(base));
- typedef handler_alloc_traits<Handler, resolve_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- if (owner)
- {
- if (owner != &o->io_service_impl_)
- {
- // The operation is being run on the worker io_service. Time to
- // perform the resolver operation.
-
- if (o->impl_.expired())
- {
- // THe operation has been cancelled.
- o->ec_ = asio::error::operation_aborted;
- }
- else
- {
- // Perform the blocking host resolution operation.
- asio::detail::addrinfo_type* address_info = 0;
- std::string host_name = o->query_.host_name();
- std::string service_name = o->query_.service_name();
- asio::detail::addrinfo_type hints = o->query_.hints();
- socket_ops::getaddrinfo(!host_name.empty() ? host_name.c_str() : 0,
- service_name.c_str(), &hints, &address_info, o->ec_);
- auto_addrinfo auto_address_info(address_info);
- o->iter_ = iterator_type::create(
- address_info, host_name, service_name);
- }
-
- o->io_service_impl_.post_deferred_completion(o);
- ptr.release();
- }
- else
- {
- // The operation has been returned to the main io_serice. The
- // completion handler is ready to be delivered.
-
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object
- // remains valid until after we have deallocated the memory here.
- detail::binder2<Handler, asio::error_code, iterator_type>
- handler(o->handler_, o->ec_, o->iter_);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
- }
-
- private:
- boost::weak_ptr<void> impl_;
- query_type query_;
- io_service_impl& io_service_impl_;
- Handler handler_;
- asio::error_code ec_;
- iterator_type iter_;
- };
-
// Asynchronously resolve a query to a list of entries.
template <typename Handler>
void async_resolve(implementation_type& impl, const query_type& query,
Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef resolve_op<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr,
- impl, query, io_service_impl_, handler);
-
- if (work_io_service_)
- {
- start_work_thread();
- io_service_impl_.work_started();
- work_io_service_impl_.post_immediate_completion(ptr.get());
- ptr.release();
- }
+ typedef resolve_op<Protocol, Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl, query, io_service_impl_, handler);
+
+ start_resolve_op(p.p);
+ p.v = p.p = 0;
}
// Resolve an endpoint to a list of entries.
iterator_type resolve(implementation_type&,
const endpoint_type& endpoint, asio::error_code& ec)
{
- // First try resolving with the service name. If that fails try resolving
- // but allow the service to be returned as a number.
char host_name[NI_MAXHOST];
char service_name[NI_MAXSERV];
- int flags = endpoint.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
- socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
- host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
- if (ec)
- {
- flags |= NI_NUMERICSERV;
- socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
- host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
- }
+ socket_ops::sync_getnameinfo(endpoint.data(), endpoint.size(),
+ host_name, NI_MAXHOST, service_name, NI_MAXSERV,
+ endpoint.protocol().type(), ec);
- if (ec)
- return iterator_type();
-
- return iterator_type::create(endpoint, host_name, service_name);
+ return ec ? iterator_type() : iterator_type::create(
+ endpoint, host_name, service_name);
}
- template <typename Handler>
- class resolve_endpoint_op
- : public operation
- {
- public:
- resolve_endpoint_op(implementation_type impl, const endpoint_type& ep,
- io_service_impl& io_service_impl, Handler handler)
- : operation(&resolve_endpoint_op::do_complete),
- impl_(impl),
- ep_(ep),
- io_service_impl_(io_service_impl),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
- {
- // Take ownership of the operation object.
- resolve_endpoint_op* o(static_cast<resolve_endpoint_op*>(base));
- typedef handler_alloc_traits<Handler, resolve_endpoint_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- if (owner)
- {
- if (owner != &o->io_service_impl_)
- {
- // The operation is being run on the worker io_service. Time to
- // perform the resolver operation.
-
- if (o->impl_.expired())
- {
- // THe operation has been cancelled.
- o->ec_ = asio::error::operation_aborted;
- }
- else
- {
- // Perform the blocking endoint resolution operation.
- char host_name[NI_MAXHOST];
- char service_name[NI_MAXSERV];
- int flags = o->ep_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
- socket_ops::getnameinfo(o->ep_.data(), o->ep_.size(),
- host_name, NI_MAXHOST, service_name,
- NI_MAXSERV, flags, o->ec_);
- if (o->ec_)
- {
- flags |= NI_NUMERICSERV;
- socket_ops::getnameinfo(o->ep_.data(), o->ep_.size(),
- host_name, NI_MAXHOST, service_name,
- NI_MAXSERV, flags, o->ec_);
- }
- o->iter_ = iterator_type::create(o->ep_, host_name, service_name);
- }
-
- o->io_service_impl_.post_deferred_completion(o);
- ptr.release();
- }
- else
- {
- // The operation has been returned to the main io_serice. The
- // completion handler is ready to be delivered.
-
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object
- // remains valid until after we have deallocated the memory here.
- detail::binder2<Handler, asio::error_code, iterator_type>
- handler(o->handler_, o->ec_, o->iter_);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
- }
-
- private:
- boost::weak_ptr<void> impl_;
- endpoint_type ep_;
- io_service_impl& io_service_impl_;
- Handler handler_;
- asio::error_code ec_;
- iterator_type iter_;
- };
-
// Asynchronously resolve an endpoint to a list of entries.
template <typename Handler>
void async_resolve(implementation_type& impl, const endpoint_type& endpoint,
Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef resolve_endpoint_op<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr,
- impl, endpoint, io_service_impl_, handler);
-
- if (work_io_service_)
- {
- start_work_thread();
- io_service_impl_.work_started();
- work_io_service_impl_.post_immediate_completion(ptr.get());
- ptr.release();
- }
- }
-
-private:
- // Helper class to run the work io_service in a thread.
- class work_io_service_runner
- {
- public:
- work_io_service_runner(asio::io_service& io_service)
- : io_service_(io_service) {}
- void operator()() { io_service_.run(); }
- private:
- asio::io_service& io_service_;
- };
-
- // Start the work thread if it's not already running.
- void start_work_thread()
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- if (!work_thread_)
- {
- work_thread_.reset(new asio::detail::thread(
- work_io_service_runner(*work_io_service_)));
- }
+ typedef resolve_endpoint_op<Protocol, Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl, endpoint, io_service_impl_, handler);
+
+ start_resolve_op(p.p);
+ p.v = p.p = 0;
}
-
- // Mutex to protect access to internal data.
- asio::detail::mutex mutex_;
-
- // The io_service implementation used to post completions.
- io_service_impl& io_service_impl_;
-
- // Private io_service used for performing asynchronous host resolution.
- boost::scoped_ptr<asio::io_service> work_io_service_;
-
- // The work io_service implementation used to post completions.
- io_service_impl& work_io_service_impl_;
-
- // Work for the private io_service to perform.
- boost::scoped_ptr<asio::io_service::work> work_;
-
- // Thread used for running the work io_service's run loop.
- boost::scoped_ptr<asio::detail::thread> work_thread_;
};
} // namespace detail
diff --git a/ext/asio/asio/detail/resolver_service_base.hpp b/ext/asio/asio/detail/resolver_service_base.hpp
new file mode 100644
index 0000000..d6f20bd
--- /dev/null
+++ b/ext/asio/asio/detail/resolver_service_base.hpp
@@ -0,0 +1,123 @@
+//
+// detail/resolver_service_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP
+#define ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/scoped_ptr.hpp>
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/thread.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class resolver_service_base
+{
+public:
+ // The implementation type of the resolver. A cancellation token is used to
+ // indicate to the background thread that the operation has been cancelled.
+ typedef socket_ops::shared_cancel_token_type implementation_type;
+
+ // Constructor.
+ ASIO_DECL resolver_service_base(asio::io_service& io_service);
+
+ // Destructor.
+ ASIO_DECL ~resolver_service_base();
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown_service();
+
+ // Construct a new resolver implementation.
+ ASIO_DECL void construct(implementation_type& impl);
+
+ // Destroy a resolver implementation.
+ ASIO_DECL void destroy(implementation_type&);
+
+ // Cancel pending asynchronous operations.
+ ASIO_DECL void cancel(implementation_type& impl);
+
+protected:
+ // Helper function to start an asynchronous resolve operation.
+ ASIO_DECL void start_resolve_op(operation* op);
+
+ // Helper class to perform exception-safe cleanup of addrinfo objects.
+ class auto_addrinfo
+ : private asio::detail::noncopyable
+ {
+ public:
+ explicit auto_addrinfo(asio::detail::addrinfo_type* ai)
+ : ai_(ai)
+ {
+ }
+
+ ~auto_addrinfo()
+ {
+ if (ai_)
+ socket_ops::freeaddrinfo(ai_);
+ }
+
+ operator asio::detail::addrinfo_type*()
+ {
+ return ai_;
+ }
+
+ private:
+ asio::detail::addrinfo_type* ai_;
+ };
+
+ // Helper class to run the work io_service in a thread.
+ class work_io_service_runner;
+
+ // Start the work thread if it's not already running.
+ ASIO_DECL void start_work_thread();
+
+ // The io_service implementation used to post completions.
+ io_service_impl& io_service_impl_;
+
+private:
+ // Mutex to protect access to internal data.
+ asio::detail::mutex mutex_;
+
+ // Private io_service used for performing asynchronous host resolution.
+ boost::scoped_ptr<asio::io_service> work_io_service_;
+
+ // The work io_service implementation used to post completions.
+ io_service_impl& work_io_service_impl_;
+
+ // Work for the private io_service to perform.
+ boost::scoped_ptr<asio::io_service::work> work_;
+
+ // Thread used for running the work io_service's run loop.
+ boost::scoped_ptr<asio::detail::thread> work_thread_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/resolver_service_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP
diff --git a/ext/asio/asio/detail/scoped_lock.hpp b/ext/asio/asio/detail/scoped_lock.hpp
index e6f6ba5..69b5725 100644
--- a/ext/asio/asio/detail/scoped_lock.hpp
+++ b/ext/asio/asio/detail/scoped_lock.hpp
@@ -1,8 +1,8 @@
//
-// scoped_lock.hpp
-// ~~~~~~~~~~~~~~~
+// detail/scoped_lock.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,10 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
diff --git a/ext/asio/asio/detail/select_interrupter.hpp b/ext/asio/asio/detail/select_interrupter.hpp
index ff5505b..e975ddc 100644
--- a/ext/asio/asio/detail/select_interrupter.hpp
+++ b/ext/asio/asio/detail/select_interrupter.hpp
@@ -1,8 +1,8 @@
//
-// select_interrupter.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~
+// detail/select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,23 +15,20 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__)
# include "asio/detail/socket_select_interrupter.hpp"
-#else
+#elif defined(ASIO_HAS_EVENTFD)
# include "asio/detail/eventfd_select_interrupter.hpp"
+#else
# include "asio/detail/pipe_select_interrupter.hpp"
#endif
namespace asio {
namespace detail {
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__)
typedef socket_select_interrupter select_interrupter;
#elif defined(ASIO_HAS_EVENTFD)
typedef eventfd_select_interrupter select_interrupter;
@@ -42,6 +39,4 @@ typedef pipe_select_interrupter select_interrupter;
} // namespace detail
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_SELECT_INTERRUPTER_HPP
diff --git a/ext/asio/asio/detail/select_reactor.hpp b/ext/asio/asio/detail/select_reactor.hpp
index 798611b..161305f 100644
--- a/ext/asio/asio/detail/select_reactor.hpp
+++ b/ext/asio/asio/detail/select_reactor.hpp
@@ -1,8 +1,8 @@
//
-// select_reactor.hpp
-// ~~~~~~~~~~~~~~~~~~
+// detail/select_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,41 +15,38 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/socket_types.hpp" // Must come before posix_time.
+#if defined(ASIO_HAS_IOCP) \
+ || (!defined(ASIO_HAS_DEV_POLL) \
+ && !defined(ASIO_HAS_EPOLL) \
+ && !defined(ASIO_HAS_KQUEUE))
-#include "asio/detail/push_options.hpp"
#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/io_service.hpp"
-#include "asio/detail/bind_handler.hpp"
-#include "asio/detail/fd_set_adapter.hpp"
#include "asio/detail/mutex.hpp"
-#include "asio/detail/noncopyable.hpp"
#include "asio/detail/op_queue.hpp"
#include "asio/detail/reactor_op.hpp"
#include "asio/detail/reactor_op_queue.hpp"
#include "asio/detail/select_interrupter.hpp"
#include "asio/detail/select_reactor_fwd.hpp"
-#include "asio/detail/service_base.hpp"
-#include "asio/detail/signal_blocker.hpp"
-#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_types.hpp"
-#include "asio/detail/thread.hpp"
#include "asio/detail/timer_op.hpp"
#include "asio/detail/timer_queue_base.hpp"
#include "asio/detail/timer_queue_fwd.hpp"
#include "asio/detail/timer_queue_set.hpp"
+#include "asio/io_service.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/thread.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
-template <bool Own_Thread>
class select_reactor
- : public asio::detail::service_base<select_reactor<Own_Thread> >
+ : public asio::detail::service_base<select_reactor>
{
public:
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -66,280 +63,91 @@ public:
};
// Constructor.
- select_reactor(asio::io_service& io_service)
- : asio::detail::service_base<
- select_reactor<Own_Thread> >(io_service),
- io_service_(use_service<io_service_impl>(io_service)),
- mutex_(),
- interrupter_(),
- stop_thread_(false),
- thread_(0),
- shutdown_(false)
- {
- if (Own_Thread)
- {
- asio::detail::signal_blocker sb;
- thread_ = new asio::detail::thread(
- bind_handler(&select_reactor::call_run_thread, this));
- }
- }
+ ASIO_DECL select_reactor(asio::io_service& io_service);
// Destructor.
- ~select_reactor()
- {
- shutdown_service();
- }
+ ASIO_DECL ~select_reactor();
// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- shutdown_ = true;
- stop_thread_ = true;
- lock.unlock();
-
- if (Own_Thread)
- {
- if (thread_)
- {
- interrupter_.interrupt();
- thread_->join();
- delete thread_;
- thread_ = 0;
- }
- }
-
- op_queue<operation> ops;
-
- for (int i = 0; i < max_ops; ++i)
- op_queue_[i].get_all_operations(ops);
-
- timer_queues_.get_all_timers(ops);
- }
+ ASIO_DECL void shutdown_service();
// Initialise the task, but only if the reactor is not in its own thread.
- void init_task()
- {
- io_service_.init_task();
- }
+ ASIO_DECL void init_task();
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
- int register_descriptor(socket_type, per_descriptor_data&)
+ ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&);
+
+ // Post a reactor operation for immediate completion.
+ void post_immediate_completion(reactor_op* op)
{
- return 0;
+ io_service_.post_immediate_completion(op);
}
// Start a new operation. The reactor operation will be performed when the
// given descriptor is flagged as ready, or an error has occurred.
- void start_op(int op_type, socket_type descriptor,
- per_descriptor_data&, reactor_op* op, bool)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- if (!shutdown_)
- {
- bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
- io_service_.work_started();
- if (first)
- interrupter_.interrupt();
- }
- }
+ ASIO_DECL void start_op(int op_type, socket_type descriptor,
+ per_descriptor_data&, reactor_op* op, bool);
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
- void cancel_ops(socket_type descriptor, per_descriptor_data&)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
- }
+ ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&);
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor.
- void close_descriptor(socket_type descriptor, per_descriptor_data&)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
- }
+ ASIO_DECL void close_descriptor(socket_type descriptor,
+ per_descriptor_data&);
// Add a new timer queue to the reactor.
template <typename Time_Traits>
- void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- timer_queues_.insert(&timer_queue);
- }
+ void add_timer_queue(timer_queue<Time_Traits>& queue);
// Remove a timer queue from the reactor.
template <typename Time_Traits>
- void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- timer_queues_.erase(&timer_queue);
- }
+ void remove_timer_queue(timer_queue<Time_Traits>& queue);
// Schedule a new operation in the given timer queue to expire at the
// specified absolute time.
template <typename Time_Traits>
- void schedule_timer(timer_queue<Time_Traits>& timer_queue,
- const typename Time_Traits::time_type& time, timer_op* op, void* token)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- if (!shutdown_)
- {
- bool earliest = timer_queue.enqueue_timer(time, op, token);
- io_service_.work_started();
- if (earliest)
- interrupter_.interrupt();
- }
- }
+ void schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op);
// Cancel the timer operations associated with the given token. Returns the
// number of operations that have been posted or dispatched.
template <typename Time_Traits>
- std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- op_queue<operation> ops;
- std::size_t n = timer_queue.cancel_timer(token, ops);
- lock.unlock();
- io_service_.post_deferred_completions(ops);
- return n;
- }
+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer);
// Run select once until interrupted or events are ready to be dispatched.
- void run(bool block, op_queue<operation>& ops)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
-
- // Check if the thread is supposed to stop.
- if (Own_Thread)
- if (stop_thread_)
- return;
-
- // Set up the descriptor sets.
- fd_set_adapter fds[max_select_ops];
- fds[read_op].set(interrupter_.read_descriptor());
- socket_type max_fd = 0;
- bool have_work_to_do = !timer_queues_.all_empty();
- for (int i = 0; i < max_select_ops; ++i)
- {
- have_work_to_do = have_work_to_do || !op_queue_[i].empty();
- op_queue_[i].get_descriptors(fds[i], ops);
- if (fds[i].max_descriptor() > max_fd)
- max_fd = fds[i].max_descriptor();
- }
-
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- // Connection operations on Windows use both except and write fd_sets.
- have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty();
- op_queue_[connect_op].get_descriptors(fds[write_op], ops);
- if (fds[write_op].max_descriptor() > max_fd)
- max_fd = fds[write_op].max_descriptor();
- op_queue_[connect_op].get_descriptors(fds[except_op], ops);
- if (fds[except_op].max_descriptor() > max_fd)
- max_fd = fds[except_op].max_descriptor();
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-
- // We can return immediately if there's no work to do and the reactor is
- // not supposed to block.
- if (!block && !have_work_to_do)
- return;
-
- // Determine how long to block while waiting for events.
- timeval tv_buf = { 0, 0 };
- timeval* tv = block ? get_timeout(tv_buf) : &tv_buf;
-
- lock.unlock();
-
- // Block on the select call until descriptors become ready.
- asio::error_code ec;
- int retval = socket_ops::select(static_cast<int>(max_fd + 1),
- fds[read_op], fds[write_op], fds[except_op], tv, ec);
-
- // Reset the interrupter.
- if (retval > 0 && fds[read_op].is_set(interrupter_.read_descriptor()))
- interrupter_.reset();
-
- lock.lock();
-
- // Dispatch all ready operations.
- if (retval > 0)
- {
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- // Connection operations on Windows use both except and write fd_sets.
- op_queue_[connect_op].perform_operations_for_descriptors(
- fds[except_op], ops);
- op_queue_[connect_op].perform_operations_for_descriptors(
- fds[write_op], ops);
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-
- // Exception operations must be processed first to ensure that any
- // out-of-band data is read before normal data.
- for (int i = max_select_ops - 1; i >= 0; --i)
- op_queue_[i].perform_operations_for_descriptors(fds[i], ops);
- }
- timer_queues_.get_ready_timers(ops);
- }
+ ASIO_DECL void run(bool block, op_queue<operation>& ops);
// Interrupt the select loop.
- void interrupt()
- {
- interrupter_.interrupt();
- }
+ ASIO_DECL void interrupt();
private:
+#if defined(ASIO_HAS_IOCP)
// Run the select loop in the thread.
- void run_thread()
- {
- if (Own_Thread)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- while (!stop_thread_)
- {
- lock.unlock();
- op_queue<operation> ops;
- run(true, ops);
- io_service_.post_deferred_completions(ops);
- lock.lock();
- }
- }
- }
+ ASIO_DECL void run_thread();
// Entry point for the select loop thread.
- static void call_run_thread(select_reactor* reactor)
- {
- if (Own_Thread)
- {
- reactor->run_thread();
- }
- }
+ ASIO_DECL static void call_run_thread(select_reactor* reactor);
+#endif // defined(ASIO_HAS_IOCP)
+
+ // Helper function to add a new timer queue.
+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+ // Helper function to remove a timer queue.
+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
// Get the timeout value for the select call.
- timeval* get_timeout(timeval& tv)
- {
- // By default we will wait no longer than 5 minutes. This will ensure that
- // any changes to the system clock are detected after no longer than this.
- long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
- tv.tv_sec = usec / 1000000;
- tv.tv_usec = usec % 1000000;
- return &tv;
- }
+ ASIO_DECL timeval* get_timeout(timeval& tv);
// Cancel all operations associated with the given descriptor. This function
// does not acquire the select_reactor's mutex.
- void cancel_ops_unlocked(socket_type descriptor,
- const asio::error_code& ec)
- {
- bool need_interrupt = false;
- op_queue<operation> ops;
- for (int i = 0; i < max_ops; ++i)
- need_interrupt = op_queue_[i].cancel_operations(
- descriptor, ops, ec) || need_interrupt;
- io_service_.post_deferred_completions(ops);
- if (need_interrupt)
- interrupter_.interrupt();
- }
+ ASIO_DECL void cancel_ops_unlocked(socket_type descriptor,
+ const asio::error_code& ec);
// The io_service implementation used to post completions.
io_service_impl& io_service_;
@@ -356,11 +164,13 @@ private:
// The timer queues.
timer_queue_set timer_queues_;
+#if defined(ASIO_HAS_IOCP)
// Does the reactor loop thread need to stop.
bool stop_thread_;
// The thread that is running the reactor loop.
asio::detail::thread* thread_;
+#endif // defined(ASIO_HAS_IOCP)
// Whether the service has been shut down.
bool shutdown_;
@@ -371,4 +181,14 @@ private:
#include "asio/detail/pop_options.hpp"
+#include "asio/detail/impl/select_reactor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/select_reactor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP)
+ // || (!defined(ASIO_HAS_DEV_POLL)
+ // && !defined(ASIO_HAS_EPOLL)
+ // && !defined(ASIO_HAS_KQUEUE))
+
#endif // ASIO_DETAIL_SELECT_REACTOR_HPP
diff --git a/ext/asio/asio/detail/select_reactor_fwd.hpp b/ext/asio/asio/detail/select_reactor_fwd.hpp
index 0b72e7e..04e5ecd 100644
--- a/ext/asio/asio/detail/select_reactor_fwd.hpp
+++ b/ext/asio/asio/detail/select_reactor_fwd.hpp
@@ -1,8 +1,8 @@
//
-// select_reactor_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~
+// detail/select_reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
namespace asio {
namespace detail {
-template <bool Own_Thread>
class select_reactor;
} // namespace detail
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_SELECT_REACTOR_FWD_HPP
diff --git a/ext/asio/asio/detail/service_registry.hpp b/ext/asio/asio/detail/service_registry.hpp
index f80b4b6..34b946d 100644
--- a/ext/asio/asio/detail/service_registry.hpp
+++ b/ext/asio/asio/detail/service_registry.hpp
@@ -1,8 +1,8 @@
//
-// service_registry.hpp
-// ~~~~~~~~~~~~~~~~~~~~
+// detail/service_registry.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <typeinfo>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/io_service.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/noncopyable.hpp"
-#include "asio/detail/service_id.hpp"
+#include "asio/io_service.hpp"
#if defined(BOOST_NO_TYPEID)
# if !defined(ASIO_NO_TYPEID)
@@ -32,6 +27,8 @@
# endif // !defined(ASIO_NO_TYPEID)
#endif // defined(BOOST_NO_TYPEID)
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -55,98 +52,43 @@ class service_registry
{
public:
// Constructor.
- service_registry(asio::io_service& o)
- : owner_(o),
- first_service_(0)
- {
- }
+ ASIO_DECL service_registry(asio::io_service& o);
// Destructor.
- ~service_registry()
- {
- // Shutdown all services. This must be done in a separate loop before the
- // services are destroyed since the destructors of user-defined handler
- // objects may try to access other service objects.
- asio::io_service::service* service = first_service_;
- while (service)
- {
- service->shutdown_service();
- service = service->next_;
- }
-
- // Destroy all services.
- while (first_service_)
- {
- asio::io_service::service* next_service = first_service_->next_;
- destroy(first_service_);
- first_service_ = next_service;
- }
- }
+ ASIO_DECL ~service_registry();
// Get the service object corresponding to the specified service type. Will
// create a new service object automatically if no such object already
// exists. Ownership of the service object is not transferred to the caller.
template <typename Service>
- Service& use_service()
- {
- asio::io_service::service::key key;
- init_key(key, Service::id);
- factory_type factory = &service_registry::create<Service>;
- return *static_cast<Service*>(do_use_service(key, factory));
- }
+ Service& use_service();
- // Add a service object. Returns false on error, in which case ownership of
- // the object is retained by the caller.
+ // Add a service object. Throws on error, in which case ownership of the
+ // object is retained by the caller.
template <typename Service>
- bool add_service(Service* new_service)
- {
- asio::io_service::service::key key;
- init_key(key, Service::id);
- return do_add_service(key, new_service);
- }
+ void add_service(Service* new_service);
// Check whether a service object of the specified type already exists.
template <typename Service>
- bool has_service() const
- {
- asio::io_service::service::key key;
- init_key(key, Service::id);
- return do_has_service(key);
- }
+ bool has_service() const;
private:
// Initialise a service's key based on its id.
- void init_key(asio::io_service::service::key& key,
- const asio::io_service::id& id)
- {
- key.type_info_ = 0;
- key.id_ = &id;
- }
+ ASIO_DECL static void init_key(
+ asio::io_service::service::key& key,
+ const asio::io_service::id& id);
#if !defined(ASIO_NO_TYPEID)
// Initialise a service's key based on its id.
template <typename Service>
- void init_key(asio::io_service::service::key& key,
- const asio::detail::service_id<Service>& /*id*/)
- {
- key.type_info_ = &typeid(typeid_wrapper<Service>);
- key.id_ = 0;
- }
+ static void init_key(asio::io_service::service::key& key,
+ const asio::detail::service_id<Service>& /*id*/);
#endif // !defined(ASIO_NO_TYPEID)
// Check if a service matches the given id.
- static bool keys_match(
+ ASIO_DECL static bool keys_match(
const asio::io_service::service::key& key1,
- const asio::io_service::service::key& key2)
- {
- if (key1.id_ && key2.id_)
- if (key1.id_ == key2.id_)
- return true;
- if (key1.type_info_ && key2.type_info_)
- if (*key1.type_info_ == *key2.type_info_)
- return true;
- return false;
- }
+ const asio::io_service::service::key& key2);
// The type of a factory function used for creating a service instance.
typedef asio::io_service::service*
@@ -155,18 +97,15 @@ private:
// Factory function for creating a service instance.
template <typename Service>
static asio::io_service::service* create(
- asio::io_service& owner)
- {
- return new Service(owner);
- }
+ asio::io_service& owner);
// Destroy a service instance.
- static void destroy(asio::io_service::service* service)
- {
- delete service;
- }
+ ASIO_DECL static void destroy(
+ asio::io_service::service* service);
// Helper class to manage service pointers.
+ struct auto_service_ptr;
+ friend struct auto_service_ptr;
struct auto_service_ptr
{
asio::io_service::service* ptr_;
@@ -176,86 +115,19 @@ private:
// Get the service object corresponding to the specified service key. Will
// create a new service object automatically if no such object already
// exists. Ownership of the service object is not transferred to the caller.
- asio::io_service::service* do_use_service(
+ ASIO_DECL asio::io_service::service* do_use_service(
const asio::io_service::service::key& key,
- factory_type factory)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
-
- // First see if there is an existing service object with the given key.
- asio::io_service::service* service = first_service_;
- while (service)
- {
- if (keys_match(service->key_, key))
- return service;
- service = service->next_;
- }
-
- // Create a new service object. The service registry's mutex is not locked
- // at this time to allow for nested calls into this function from the new
- // service's constructor.
- lock.unlock();
- auto_service_ptr new_service = { factory(owner_) };
- new_service.ptr_->key_ = key;
- lock.lock();
-
- // Check that nobody else created another service object of the same type
- // while the lock was released.
- service = first_service_;
- while (service)
- {
- if (keys_match(service->key_, key))
- return service;
- service = service->next_;
- }
-
- // Service was successfully initialised, pass ownership to registry.
- new_service.ptr_->next_ = first_service_;
- first_service_ = new_service.ptr_;
- new_service.ptr_ = 0;
- return first_service_;
- }
+ factory_type factory);
// Add a service object. Returns false on error, in which case ownership of
// the object is retained by the caller.
- bool do_add_service(
+ ASIO_DECL void do_add_service(
const asio::io_service::service::key& key,
- asio::io_service::service* new_service)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
-
- // Check if there is an existing service object with the given key.
- asio::io_service::service* service = first_service_;
- while (service)
- {
- if (keys_match(service->key_, key))
- return false;
- service = service->next_;
- }
-
- // Take ownership of the service object.
- new_service->key_ = key;
- new_service->next_ = first_service_;
- first_service_ = new_service;
-
- return true;
- }
+ asio::io_service::service* new_service);
// Check whether a service object with the specified key already exists.
- bool do_has_service(const asio::io_service::service::key& key) const
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
-
- asio::io_service::service* service = first_service_;
- while (service)
- {
- if (keys_match(service->key_, key))
- return true;
- service = service->next_;
- }
-
- return false;
- }
+ ASIO_DECL bool do_has_service(
+ const asio::io_service::service::key& key) const;
// Mutex to protect access to internal data.
mutable asio::detail::mutex mutex_;
@@ -272,4 +144,9 @@ private:
#include "asio/detail/pop_options.hpp"
+#include "asio/detail/impl/service_registry.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/service_registry.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
#endif // ASIO_DETAIL_SERVICE_REGISTRY_HPP
diff --git a/ext/asio/asio/detail/service_registry_fwd.hpp b/ext/asio/asio/detail/service_registry_fwd.hpp
index 423bb4b..4108c1a 100644
--- a/ext/asio/asio/detail/service_registry_fwd.hpp
+++ b/ext/asio/asio/detail/service_registry_fwd.hpp
@@ -1,8 +1,8 @@
//
-// service_registry_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/service_registry_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,8 +15,6 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
namespace asio {
namespace detail {
@@ -25,6 +23,4 @@ class service_registry;
} // namespace detail
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP
diff --git a/ext/asio/asio/detail/shared_ptr.hpp b/ext/asio/asio/detail/shared_ptr.hpp
new file mode 100644
index 0000000..cd496f5
--- /dev/null
+++ b/ext/asio/asio/detail/shared_ptr.hpp
@@ -0,0 +1,38 @@
+//
+// detail/shared_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SHARED_PTR_HPP
+#define ASIO_DETAIL_SHARED_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1600)
+# include <memory>
+#else
+# include <boost/shared_ptr.hpp>
+#endif
+
+namespace asio {
+namespace detail {
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1600)
+using std::shared_ptr;
+#else
+using boost::shared_ptr;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_SHARED_PTR_HPP
diff --git a/ext/asio/asio/detail/signal_blocker.hpp b/ext/asio/asio/detail/signal_blocker.hpp
index 52f70c8..89f45ca 100644
--- a/ext/asio/asio/detail/signal_blocker.hpp
+++ b/ext/asio/asio/detail/signal_blocker.hpp
@@ -1,8 +1,8 @@
//
-// signal_blocker.hpp
-// ~~~~~~~~~~~~~~~~~~
+// detail/signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) \
+ || defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__)
# include "asio/detail/null_signal_blocker.hpp"
-#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-# include "asio/detail/win_signal_blocker.hpp"
#elif defined(BOOST_HAS_PTHREADS)
# include "asio/detail/posix_signal_blocker.hpp"
#else
@@ -34,10 +29,9 @@
namespace asio {
namespace detail {
-#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) \
+ || defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__)
typedef null_signal_blocker signal_blocker;
-#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-typedef win_signal_blocker signal_blocker;
#elif defined(BOOST_HAS_PTHREADS)
typedef posix_signal_blocker signal_blocker;
#endif
@@ -45,6 +39,4 @@ typedef posix_signal_blocker signal_blocker;
} // namespace detail
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_SIGNAL_BLOCKER_HPP
diff --git a/ext/asio/asio/detail/signal_init.hpp b/ext/asio/asio/detail/signal_init.hpp
index 12f17d3..80925f6 100644
--- a/ext/asio/asio/detail/signal_init.hpp
+++ b/ext/asio/asio/detail/signal_init.hpp
@@ -1,8 +1,8 @@
//
-// signal_init.hpp
-// ~~~~~~~~~~~~~~~
+// detail/signal_init.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-#include "asio/detail/push_options.hpp"
#include <csignal>
-#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -44,8 +40,8 @@ public:
} // namespace detail
} // namespace asio
-#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-
#include "asio/detail/pop_options.hpp"
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
#endif // ASIO_DETAIL_SIGNAL_INIT_HPP
diff --git a/ext/asio/asio/detail/socket_holder.hpp b/ext/asio/asio/detail/socket_holder.hpp
index 82a3884..cb40175 100644
--- a/ext/asio/asio/detail/socket_holder.hpp
+++ b/ext/asio/asio/detail/socket_holder.hpp
@@ -1,8 +1,8 @@
//
-// socket_holder.hpp
-// ~~~~~~~~~~~~~~~~~
+// detail/socket_holder.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -46,7 +47,8 @@ public:
if (socket_ != invalid_socket)
{
asio::error_code ec;
- socket_ops::close(socket_, ec);
+ socket_ops::state_type state = 0;
+ socket_ops::close(socket_, state, true, ec);
}
}
@@ -62,7 +64,8 @@ public:
if (socket_ != invalid_socket)
{
asio::error_code ec;
- socket_ops::close(socket_, ec);
+ socket_ops::state_type state = 0;
+ socket_ops::close(socket_, state, true, ec);
socket_ = invalid_socket;
}
}
diff --git a/ext/asio/asio/detail/socket_ops.hpp b/ext/asio/asio/detail/socket_ops.hpp
index 1a863a9..8ad464c 100644
--- a/ext/asio/asio/detail/socket_ops.hpp
+++ b/ext/asio/asio/detail/socket_ops.hpp
@@ -1,8 +1,8 @@
//
-// socket_ops.hpp
-// ~~~~~~~~~~~~~~
+// detail/socket_ops.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,193 +15,102 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include <boost/assert.hpp>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <cerrno>
-#include <boost/detail/workaround.hpp>
-#include <new>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/error.hpp"
+#include "asio/error_code.hpp"
+#include "asio/detail/shared_ptr.hpp"
#include "asio/detail/socket_types.hpp"
+#include "asio/detail/weak_ptr.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
namespace socket_ops {
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-struct msghdr { int msg_namelen; };
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+// Socket state bits.
+enum
+{
+ // The user wants a non-blocking socket.
+ user_set_non_blocking = 1,
-#if defined(__hpux)
-// HP-UX doesn't declare these functions extern "C", so they are declared again
-// here to avoid linker errors about undefined symbols.
-extern "C" char* if_indextoname(unsigned int, char*);
-extern "C" unsigned int if_nametoindex(const char*);
-#endif // defined(__hpux)
+ // The socket has been set non-blocking.
+ internal_non_blocking = 2,
-inline void clear_error(asio::error_code& ec)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- WSASetLastError(0);
-#else
- errno = 0;
-#endif
- ec = asio::error_code();
-}
-
-template <typename ReturnType>
-inline ReturnType error_wrapper(ReturnType return_value,
- asio::error_code& ec)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- ec = asio::error_code(WSAGetLastError(),
- asio::error::get_system_category());
-#else
- ec = asio::error_code(errno,
- asio::error::get_system_category());
-#endif
- return return_value;
-}
-
-template <typename SockLenType>
-inline socket_type call_accept(SockLenType msghdr::*,
- socket_type s, socket_addr_type* addr, std::size_t* addrlen)
-{
- SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;
- socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0);
- if (addrlen)
- *addrlen = (std::size_t)tmp_addrlen;
- return result;
-}
-
-inline socket_type accept(socket_type s, socket_addr_type* addr,
- std::size_t* addrlen, asio::error_code& ec)
-{
- clear_error(ec);
-
- socket_type new_s = error_wrapper(call_accept(
- &msghdr::msg_namelen, s, addr, addrlen), ec);
- if (new_s == invalid_socket)
- return new_s;
-
-#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
- int optval = 1;
- int result = error_wrapper(::setsockopt(new_s,
- SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
- if (result != 0)
- {
- ::close(new_s);
- return invalid_socket;
- }
-#endif
-
- clear_error(ec);
- return new_s;
-}
-
-template <typename SockLenType>
-inline int call_bind(SockLenType msghdr::*,
- socket_type s, const socket_addr_type* addr, std::size_t addrlen)
-{
- return ::bind(s, addr, (SockLenType)addrlen);
-}
+ // Helper "state" used to determine whether the socket is non-blocking.
+ non_blocking = user_set_non_blocking | internal_non_blocking,
-inline int bind(socket_type s, const socket_addr_type* addr,
- std::size_t addrlen, asio::error_code& ec)
-{
- clear_error(ec);
- int result = error_wrapper(call_bind(
- &msghdr::msg_namelen, s, addr, addrlen), ec);
- if (result == 0)
- clear_error(ec);
- return result;
-}
-
-inline int close(socket_type s, asio::error_code& ec)
-{
- clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- int result = error_wrapper(::closesocket(s), ec);
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- int result = error_wrapper(::close(s), ec);
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- if (result == 0)
- clear_error(ec);
- return result;
-}
+ // User wants connection_aborted errors, which are disabled by default.
+ enable_connection_aborted = 4,
-inline int shutdown(socket_type s, int what, asio::error_code& ec)
-{
- clear_error(ec);
- int result = error_wrapper(::shutdown(s, what), ec);
- if (result == 0)
- clear_error(ec);
- return result;
-}
-
-template <typename SockLenType>
-inline int call_connect(SockLenType msghdr::*,
- socket_type s, const socket_addr_type* addr, std::size_t addrlen)
-{
- return ::connect(s, addr, (SockLenType)addrlen);
-}
+ // The user set the linger option. Needs to be checked when closing.
+ user_set_linger = 8,
-inline int connect(socket_type s, const socket_addr_type* addr,
- std::size_t addrlen, asio::error_code& ec)
-{
- clear_error(ec);
- int result = error_wrapper(call_connect(
- &msghdr::msg_namelen, s, addr, addrlen), ec);
- if (result == 0)
- clear_error(ec);
- return result;
-}
-
-inline int socketpair(int af, int type, int protocol,
- socket_type sv[2], asio::error_code& ec)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- (void)(af);
- (void)(type);
- (void)(protocol);
- (void)(sv);
- ec = asio::error::operation_not_supported;
- return -1;
-#else
- clear_error(ec);
- int result = error_wrapper(::socketpair(af, type, protocol, sv), ec);
- if (result == 0)
- clear_error(ec);
- return result;
-#endif
-}
-
-inline int listen(socket_type s, int backlog, asio::error_code& ec)
-{
- clear_error(ec);
- int result = error_wrapper(::listen(s, backlog), ec);
- if (result == 0)
- clear_error(ec);
- return result;
-}
-
-inline void init_buf_iov_base(void*& base, void* addr)
-{
- base = addr;
-}
+ // The socket is stream-oriented.
+ stream_oriented = 16,
-template <typename T>
-inline void init_buf_iov_base(T& base, void* addr)
-{
- base = static_cast<T>(addr);
-}
+ // The socket is datagram-oriented.
+ datagram_oriented = 32
+};
+
+typedef unsigned char state_type;
+
+struct noop_deleter { void operator()(void*) {} };
+typedef shared_ptr<void> shared_cancel_token_type;
+typedef weak_ptr<void> weak_cancel_token_type;
+
+ASIO_DECL socket_type accept(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, asio::error_code& ec);
+
+ASIO_DECL socket_type sync_accept(socket_type s,
+ state_type state, socket_addr_type* addr,
+ std::size_t* addrlen, asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_accept(socket_type s,
+ void* output_buffer, DWORD address_length,
+ socket_addr_type* addr, std::size_t* addrlen,
+ socket_type new_socket, asio::error_code& ec);
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_accept(socket_type s,
+ state_type state, socket_addr_type* addr, std::size_t* addrlen,
+ asio::error_code& ec, socket_type& new_socket);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL int bind(socket_type s, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec);
+
+ASIO_DECL int close(socket_type s, state_type& state,
+ bool destruction, asio::error_code& ec);
+
+ASIO_DECL bool set_internal_non_blocking(socket_type s,
+ state_type& state, asio::error_code& ec);
+
+ASIO_DECL int shutdown(socket_type s,
+ int what, asio::error_code& ec);
+
+ASIO_DECL int connect(socket_type s, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec);
+
+ASIO_DECL void sync_connect(socket_type s, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec);
+
+ASIO_DECL bool non_blocking_connect(
+ socket_type s, asio::error_code& ec);
+
+ASIO_DECL int socketpair(int af, int type, int protocol,
+ socket_type sv[2], asio::error_code& ec);
+
+ASIO_DECL bool sockatmark(socket_type s, asio::error_code& ec);
+
+ASIO_DECL size_t available(socket_type s, asio::error_code& ec);
+
+ASIO_DECL int listen(socket_type s,
+ int backlog, asio::error_code& ec);
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
typedef WSABUF buf;
@@ -209,1699 +118,163 @@ typedef WSABUF buf;
typedef iovec buf;
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-inline void init_buf(buf& b, void* data, size_t size)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- b.buf = static_cast<char*>(data);
- b.len = static_cast<u_long>(size);
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- init_buf_iov_base(b.iov_base, data);
- b.iov_len = size;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL void init_buf(buf& b, void* data, size_t size);
-inline void init_buf(buf& b, const void* data, size_t size)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- b.buf = static_cast<char*>(const_cast<void*>(data));
- b.len = static_cast<u_long>(size);
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- init_buf_iov_base(b.iov_base, const_cast<void*>(data));
- b.iov_len = size;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL void init_buf(buf& b, const void* data, size_t size);
-inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr)
-{
- name = addr;
-}
+ASIO_DECL int recv(socket_type s, buf* bufs, size_t count, int flags,
+ asio::error_code& ec);
-inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr)
-{
- name = const_cast<socket_addr_type*>(addr);
-}
+ASIO_DECL size_t sync_recv(socket_type s, state_type state, buf* bufs,
+ size_t count, int flags, bool all_empty, asio::error_code& ec);
-template <typename T>
-inline void init_msghdr_msg_name(T& name, socket_addr_type* addr)
-{
- name = reinterpret_cast<T>(addr);
-}
+#if defined(ASIO_HAS_IOCP)
-template <typename T>
-inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr)
-{
- name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr));
-}
+ASIO_DECL void complete_iocp_recv(state_type state,
+ const weak_cancel_token_type& cancel_token, bool all_empty,
+ asio::error_code& ec, size_t bytes_transferred);
-inline int recv(socket_type s, buf* bufs, size_t count, int flags,
- asio::error_code& ec)
-{
- clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- // Receive some data.
- DWORD recv_buf_count = static_cast<DWORD>(count);
- DWORD bytes_transferred = 0;
- DWORD recv_flags = flags;
- int result = error_wrapper(::WSARecv(s, bufs,
- recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec);
- if (result != 0)
- return -1;
- clear_error(ec);
- return bytes_transferred;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- msghdr msg = msghdr();
- msg.msg_iov = bufs;
- msg.msg_iovlen = count;
- int result = error_wrapper(::recvmsg(s, &msg, flags), ec);
- if (result >= 0)
- clear_error(ec);
- return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_recv(socket_type s,
+ buf* bufs, size_t count, int flags, bool is_stream,
+ asio::error_code& ec, size_t& bytes_transferred);
+
+#endif // defined(ASIO_HAS_IOCP)
-inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags,
+ASIO_DECL int recvfrom(socket_type s, buf* bufs, size_t count, int flags,
socket_addr_type* addr, std::size_t* addrlen,
- asio::error_code& ec)
-{
- clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- // Receive some data.
- DWORD recv_buf_count = static_cast<DWORD>(count);
- DWORD bytes_transferred = 0;
- DWORD recv_flags = flags;
- int tmp_addrlen = (int)*addrlen;
- int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count,
- &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec);
- *addrlen = (std::size_t)tmp_addrlen;
- if (result != 0)
- return -1;
- clear_error(ec);
- return bytes_transferred;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- msghdr msg = msghdr();
- init_msghdr_msg_name(msg.msg_name, addr);
- msg.msg_namelen = *addrlen;
- msg.msg_iov = bufs;
- msg.msg_iovlen = count;
- int result = error_wrapper(::recvmsg(s, &msg, flags), ec);
- *addrlen = msg.msg_namelen;
- if (result >= 0)
- clear_error(ec);
- return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ asio::error_code& ec);
-inline int send(socket_type s, const buf* bufs, size_t count, int flags,
- asio::error_code& ec)
-{
- clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- // Send the data.
- DWORD send_buf_count = static_cast<DWORD>(count);
- DWORD bytes_transferred = 0;
- DWORD send_flags = flags;
- int result = error_wrapper(::WSASend(s, const_cast<buf*>(bufs),
- send_buf_count, &bytes_transferred, send_flags, 0, 0), ec);
- if (result != 0)
- return -1;
- clear_error(ec);
- return bytes_transferred;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- msghdr msg = msghdr();
- msg.msg_iov = const_cast<buf*>(bufs);
- msg.msg_iovlen = count;
-#if defined(__linux__)
- flags |= MSG_NOSIGNAL;
-#endif // defined(__linux__)
- int result = error_wrapper(::sendmsg(s, &msg, flags), ec);
- if (result >= 0)
- clear_error(ec);
- return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state,
+ buf* bufs, size_t count, int flags, socket_addr_type* addr,
+ std::size_t* addrlen, asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_recvfrom(
+ const weak_cancel_token_type& cancel_token,
+ asio::error_code& ec);
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_recvfrom(socket_type s,
+ buf* bufs, size_t count, int flags,
+ socket_addr_type* addr, std::size_t* addrlen,
+ asio::error_code& ec, size_t& bytes_transferred);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL int send(socket_type s, const buf* bufs,
+ size_t count, int flags, asio::error_code& ec);
+
+ASIO_DECL size_t sync_send(socket_type s, state_type state,
+ const buf* bufs, size_t count, int flags,
+ bool all_empty, asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_send(
+ const weak_cancel_token_type& cancel_token,
+ asio::error_code& ec);
+
+#else // defined(ASIO_HAS_IOCP)
-inline int sendto(socket_type s, const buf* bufs, size_t count, int flags,
+ASIO_DECL bool non_blocking_send(socket_type s,
+ const buf* bufs, size_t count, int flags,
+ asio::error_code& ec, size_t& bytes_transferred);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL int sendto(socket_type s, const buf* bufs, size_t count,
+ int flags, const socket_addr_type* addr, std::size_t addrlen,
+ asio::error_code& ec);
+
+ASIO_DECL size_t sync_sendto(socket_type s, state_type state,
+ const buf* bufs, size_t count, int flags, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec);
+
+#if !defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_sendto(socket_type s,
+ const buf* bufs, size_t count, int flags,
const socket_addr_type* addr, std::size_t addrlen,
- asio::error_code& ec)
-{
- clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- // Send the data.
- DWORD send_buf_count = static_cast<DWORD>(count);
- DWORD bytes_transferred = 0;
- int result = error_wrapper(::WSASendTo(s, const_cast<buf*>(bufs),
- send_buf_count, &bytes_transferred, flags, addr,
- static_cast<int>(addrlen), 0, 0), ec);
- if (result != 0)
- return -1;
- clear_error(ec);
- return bytes_transferred;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- msghdr msg = msghdr();
- init_msghdr_msg_name(msg.msg_name, addr);
- msg.msg_namelen = addrlen;
- msg.msg_iov = const_cast<buf*>(bufs);
- msg.msg_iovlen = count;
-#if defined(__linux__)
- flags |= MSG_NOSIGNAL;
-#endif // defined(__linux__)
- int result = error_wrapper(::sendmsg(s, &msg, flags), ec);
- if (result >= 0)
- clear_error(ec);
- return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ asio::error_code& ec, size_t& bytes_transferred);
-inline socket_type socket(int af, int type, int protocol,
- asio::error_code& ec)
-{
- clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0,
- WSA_FLAG_OVERLAPPED), ec);
- if (s == invalid_socket)
- return s;
-
- if (af == AF_INET6)
- {
- // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to
- // false. This will only succeed on Windows Vista and later versions of
- // Windows, where a dual-stack IPv4/v6 implementation is available.
- DWORD optval = 0;
- ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
- reinterpret_cast<const char*>(&optval), sizeof(optval));
- }
-
- clear_error(ec);
-
- return s;
-#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
- socket_type s = error_wrapper(::socket(af, type, protocol), ec);
- if (s == invalid_socket)
- return s;
-
- int optval = 1;
- int result = error_wrapper(::setsockopt(s,
- SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
- if (result != 0)
- {
- ::close(s);
- return invalid_socket;
- }
-
- return s;
-#else
- int s = error_wrapper(::socket(af, type, protocol), ec);
- if (s >= 0)
- clear_error(ec);
- return s;
-#endif
-}
-
-template <typename SockLenType>
-inline int call_setsockopt(SockLenType msghdr::*,
- socket_type s, int level, int optname,
- const void* optval, std::size_t optlen)
-{
- return ::setsockopt(s, level, optname,
- (const char*)optval, (SockLenType)optlen);
-}
+#endif // !defined(ASIO_HAS_IOCP)
-inline int setsockopt(socket_type s, int level, int optname,
- const void* optval, std::size_t optlen, asio::error_code& ec)
-{
- if (level == custom_socket_option_level && optname == always_fail_option)
- {
- ec = asio::error::invalid_argument;
- return -1;
- }
-
-#if defined(__BORLANDC__)
- // Mysteriously, using the getsockopt and setsockopt functions directly with
- // Borland C++ results in incorrect values being set and read. The bug can be
- // worked around by using function addresses resolved with GetProcAddress.
- if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
- {
- typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int);
- if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt"))
- {
- clear_error(ec);
- return error_wrapper(sso(s, level, optname,
- reinterpret_cast<const char*>(optval),
- static_cast<int>(optlen)), ec);
- }
- }
- ec = asio::error::fault;
- return -1;
-#else // defined(__BORLANDC__)
- clear_error(ec);
- int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen,
- s, level, optname, optval, optlen), ec);
- if (result == 0)
- clear_error(ec);
- return result;
-#endif // defined(__BORLANDC__)
-}
-
-template <typename SockLenType>
-inline int call_getsockopt(SockLenType msghdr::*,
- socket_type s, int level, int optname,
- void* optval, std::size_t* optlen)
-{
- SockLenType tmp_optlen = (SockLenType)*optlen;
- int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen);
- *optlen = (std::size_t)tmp_optlen;
- return result;
-}
-
-inline int getsockopt(socket_type s, int level, int optname, void* optval,
- size_t* optlen, asio::error_code& ec)
-{
- if (level == custom_socket_option_level && optname == always_fail_option)
- {
- ec = asio::error::invalid_argument;
- return -1;
- }
-
-#if defined(__BORLANDC__)
- // Mysteriously, using the getsockopt and setsockopt functions directly with
- // Borland C++ results in incorrect values being set and read. The bug can be
- // worked around by using function addresses resolved with GetProcAddress.
- if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
- {
- typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*);
- if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt"))
- {
- clear_error(ec);
- int tmp_optlen = static_cast<int>(*optlen);
- int result = error_wrapper(gso(s, level, optname,
- reinterpret_cast<char*>(optval), &tmp_optlen), ec);
- *optlen = static_cast<size_t>(tmp_optlen);
- if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
- && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
- {
- // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are
- // only supported on Windows Vista and later. To simplify program logic
- // we will fake success of getting this option and specify that the
- // value is non-zero (i.e. true). This corresponds to the behavior of
- // IPv6 sockets on Windows platforms pre-Vista.
- *static_cast<DWORD*>(optval) = 1;
- clear_error(ec);
- }
- return result;
- }
- }
- ec = asio::error::fault;
- return -1;
-#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- clear_error(ec);
- int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
- s, level, optname, optval, optlen), ec);
- if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
- && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
- {
- // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only
- // supported on Windows Vista and later. To simplify program logic we will
- // fake success of getting this option and specify that the value is
- // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets
- // on Windows platforms pre-Vista.
- *static_cast<DWORD*>(optval) = 1;
- clear_error(ec);
- }
- if (result == 0)
- clear_error(ec);
- return result;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- clear_error(ec);
- int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
- s, level, optname, optval, optlen), ec);
-#if defined(__linux__)
- if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int)
- && (optname == SO_SNDBUF || optname == SO_RCVBUF))
- {
- // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel
- // to set the buffer size to N*2. Linux puts additional stuff into the
- // buffers so that only about half is actually available to the application.
- // The retrieved value is divided by 2 here to make it appear as though the
- // correct value has been set.
- *static_cast<int*>(optval) /= 2;
- }
-#endif // defined(__linux__)
- if (result == 0)
- clear_error(ec);
- return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL socket_type socket(int af, int type, int protocol,
+ asio::error_code& ec);
-template <typename SockLenType>
-inline int call_getpeername(SockLenType msghdr::*,
- socket_type s, socket_addr_type* addr, std::size_t* addrlen)
-{
- SockLenType tmp_addrlen = (SockLenType)*addrlen;
- int result = ::getpeername(s, addr, &tmp_addrlen);
- *addrlen = (std::size_t)tmp_addrlen;
- return result;
-}
-
-inline int getpeername(socket_type s, socket_addr_type* addr,
- std::size_t* addrlen, asio::error_code& ec)
-{
- clear_error(ec);
- int result = error_wrapper(call_getpeername(
- &msghdr::msg_namelen, s, addr, addrlen), ec);
- if (result == 0)
- clear_error(ec);
- return result;
-}
-
-template <typename SockLenType>
-inline int call_getsockname(SockLenType msghdr::*,
- socket_type s, socket_addr_type* addr, std::size_t* addrlen)
-{
- SockLenType tmp_addrlen = (SockLenType)*addrlen;
- int result = ::getsockname(s, addr, &tmp_addrlen);
- *addrlen = (std::size_t)tmp_addrlen;
- return result;
-}
-
-inline int getsockname(socket_type s, socket_addr_type* addr,
- std::size_t* addrlen, asio::error_code& ec)
-{
- clear_error(ec);
- int result = error_wrapper(call_getsockname(
- &msghdr::msg_namelen, s, addr, addrlen), ec);
- if (result == 0)
- clear_error(ec);
- return result;
-}
-
-inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg,
- asio::error_code& ec)
-{
- clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec);
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- int result = error_wrapper(::ioctl(s, cmd, arg), ec);
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- if (result >= 0)
- clear_error(ec);
- return result;
-}
+ASIO_DECL int setsockopt(socket_type s, state_type& state,
+ int level, int optname, const void* optval,
+ std::size_t optlen, asio::error_code& ec);
-inline int select(int nfds, fd_set* readfds, fd_set* writefds,
- fd_set* exceptfds, timeval* timeout, asio::error_code& ec)
-{
- clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- if (!readfds && !writefds && !exceptfds && timeout)
- {
- DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
- if (milliseconds == 0)
- milliseconds = 1; // Force context switch.
- ::Sleep(milliseconds);
- ec = asio::error_code();
- return 0;
- }
-
- // The select() call allows timeout values measured in microseconds, but the
- // system clock (as wrapped by boost::posix_time::microsec_clock) typically
- // has a resolution of 10 milliseconds. This can lead to a spinning select
- // reactor, meaning increased CPU usage, when waiting for the earliest
- // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight
- // spin we'll use a minimum timeout of 1 millisecond.
- if (timeout && timeout->tv_sec == 0
- && timeout->tv_usec > 0 && timeout->tv_usec < 1000)
- timeout->tv_usec = 1000;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ASIO_DECL int getsockopt(socket_type s, state_type state,
+ int level, int optname, void* optval,
+ size_t* optlen, asio::error_code& ec);
-#if defined(__hpux) && defined(__HP_aCC)
- timespec ts;
- ts.tv_sec = timeout ? timeout->tv_sec : 0;
- ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0;
- return error_wrapper(::pselect(nfds, readfds,
- writefds, exceptfds, timeout ? &ts : 0, 0), ec);
-#else
- int result = error_wrapper(::select(nfds, readfds,
- writefds, exceptfds, timeout), ec);
- if (result >= 0)
- clear_error(ec);
- return result;
-#endif
-}
-
-inline int poll_read(socket_type s, asio::error_code& ec)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- FD_SET fds;
- FD_ZERO(&fds);
- FD_SET(s, &fds);
- clear_error(ec);
- int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec);
- if (result >= 0)
- clear_error(ec);
- return result;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- pollfd fds;
- fds.fd = s;
- fds.events = POLLIN;
- fds.revents = 0;
- clear_error(ec);
- int result = error_wrapper(::poll(&fds, 1, -1), ec);
- if (result >= 0)
- clear_error(ec);
- return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL int getpeername(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, bool cached, asio::error_code& ec);
-inline int poll_write(socket_type s, asio::error_code& ec)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- FD_SET fds;
- FD_ZERO(&fds);
- FD_SET(s, &fds);
- clear_error(ec);
- int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec);
- if (result >= 0)
- clear_error(ec);
- return result;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- pollfd fds;
- fds.fd = s;
- fds.events = POLLOUT;
- fds.revents = 0;
- clear_error(ec);
- int result = error_wrapper(::poll(&fds, 1, -1), ec);
- if (result >= 0)
- clear_error(ec);
- return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL int getsockname(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, asio::error_code& ec);
-inline int poll_connect(socket_type s, asio::error_code& ec)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- FD_SET write_fds;
- FD_ZERO(&write_fds);
- FD_SET(s, &write_fds);
- FD_SET except_fds;
- FD_ZERO(&except_fds);
- FD_SET(s, &except_fds);
- clear_error(ec);
- int result = error_wrapper(::select(s, 0, &write_fds, &except_fds, 0), ec);
- if (result >= 0)
- clear_error(ec);
- return result;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- pollfd fds;
- fds.fd = s;
- fds.events = POLLOUT;
- fds.revents = 0;
- clear_error(ec);
- int result = error_wrapper(::poll(&fds, 1, -1), ec);
- if (result >= 0)
- clear_error(ec);
- return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL int ioctl(socket_type s, state_type& state,
+ int cmd, ioctl_arg_type* arg, asio::error_code& ec);
-inline const char* inet_ntop(int af, const void* src, char* dest, size_t length,
- unsigned long scope_id, asio::error_code& ec)
-{
- clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- using namespace std; // For memcpy.
-
- if (af != AF_INET && af != AF_INET6)
- {
- ec = asio::error::address_family_not_supported;
- return 0;
- }
-
- union
- {
- socket_addr_type base;
- sockaddr_storage_type storage;
- sockaddr_in4_type v4;
- sockaddr_in6_type v6;
- } address;
- DWORD address_length;
- if (af == AF_INET)
- {
- address_length = sizeof(sockaddr_in4_type);
- address.v4.sin_family = AF_INET;
- address.v4.sin_port = 0;
- memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type));
- }
- else // AF_INET6
- {
- address_length = sizeof(sockaddr_in6_type);
- address.v6.sin6_family = AF_INET6;
- address.v6.sin6_port = 0;
- address.v6.sin6_flowinfo = 0;
- address.v6.sin6_scope_id = scope_id;
- memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type));
- }
-
- DWORD string_length = static_cast<DWORD>(length);
-#if defined(BOOST_NO_ANSI_APIS)
- LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR));
- int result = error_wrapper(::WSAAddressToStringW(&address.base,
- address_length, 0, string_buffer, &string_length), ec);
- ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0);
-#else
- int result = error_wrapper(::WSAAddressToStringA(
- &address.base, address_length, 0, dest, &string_length), ec);
-#endif
-
- // Windows may set error code on success.
- if (result != socket_error_retval)
- clear_error(ec);
-
- // Windows may not set an error code on failure.
- else if (result == socket_error_retval && !ec)
- ec = asio::error::invalid_argument;
-
- return result == socket_error_retval ? 0 : dest;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec);
- if (result == 0 && !ec)
- ec = asio::error::invalid_argument;
- if (result != 0 && af == AF_INET6 && scope_id != 0)
- {
- using namespace std; // For strcat and sprintf.
- char if_name[IF_NAMESIZE + 1] = "%";
- const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src);
- bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
- if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0)
- sprintf(if_name + 1, "%lu", scope_id);
- strcat(dest, if_name);
- }
- return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL int select(int nfds, fd_set* readfds, fd_set* writefds,
+ fd_set* exceptfds, timeval* timeout, asio::error_code& ec);
-inline int inet_pton(int af, const char* src, void* dest,
- unsigned long* scope_id, asio::error_code& ec)
-{
- clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- using namespace std; // For memcpy and strcmp.
-
- if (af != AF_INET && af != AF_INET6)
- {
- ec = asio::error::address_family_not_supported;
- return -1;
- }
-
- union
- {
- socket_addr_type base;
- sockaddr_storage_type storage;
- sockaddr_in4_type v4;
- sockaddr_in6_type v6;
- } address;
- int address_length = sizeof(sockaddr_storage_type);
-#if defined(BOOST_NO_ANSI_APIS)
- int num_wide_chars = strlen(src) + 1;
- LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR));
- ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars);
- int result = error_wrapper(::WSAStringToAddressW(
- wide_buffer, af, 0, &address.base, &address_length), ec);
-#else
- int result = error_wrapper(::WSAStringToAddressA(
- const_cast<char*>(src), af, 0, &address.base, &address_length), ec);
-#endif
-
- if (af == AF_INET)
- {
- if (result != socket_error_retval)
- {
- memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type));
- clear_error(ec);
- }
- else if (strcmp(src, "255.255.255.255") == 0)
- {
- static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE;
- clear_error(ec);
- }
- }
- else // AF_INET6
- {
- if (result != socket_error_retval)
- {
- memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type));
- if (scope_id)
- *scope_id = address.v6.sin6_scope_id;
- clear_error(ec);
- }
- }
-
- // Windows may not set an error code on failure.
- if (result == socket_error_retval && !ec)
- ec = asio::error::invalid_argument;
-
- if (result != socket_error_retval)
- clear_error(ec);
-
- return result == socket_error_retval ? -1 : 1;
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- int result = error_wrapper(::inet_pton(af, src, dest), ec);
- if (result <= 0 && !ec)
- ec = asio::error::invalid_argument;
- if (result > 0 && af == AF_INET6 && scope_id)
- {
- using namespace std; // For strchr and atoi.
- *scope_id = 0;
- if (const char* if_name = strchr(src, '%'))
- {
- in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest);
- bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
- if (is_link_local)
- *scope_id = if_nametoindex(if_name + 1);
- if (*scope_id == 0)
- *scope_id = atoi(if_name + 1);
- }
- }
- return result;
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-}
+ASIO_DECL int poll_read(socket_type s, asio::error_code& ec);
-inline int gethostname(char* name, int namelen, asio::error_code& ec)
-{
- clear_error(ec);
- int result = error_wrapper(::gethostname(name, namelen), ec);
-#if defined(BOOST_WINDOWS)
- if (result == 0)
- clear_error(ec);
-#endif
- return result;
-}
-
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \
- || defined(__MACH__) && defined(__APPLE__)
-
-// The following functions are only needed for emulation of getaddrinfo and
-// getnameinfo.
-
-inline asio::error_code translate_netdb_error(int error)
-{
- switch (error)
- {
- case 0:
- return asio::error_code();
- case HOST_NOT_FOUND:
- return asio::error::host_not_found;
- case TRY_AGAIN:
- return asio::error::host_not_found_try_again;
- case NO_RECOVERY:
- return asio::error::no_recovery;
- case NO_DATA:
- return asio::error::no_data;
- default:
- BOOST_ASSERT(false);
- return asio::error::invalid_argument;
- }
-}
-
-inline hostent* gethostbyaddr(const char* addr, int length, int af,
- hostent* result, char* buffer, int buflength, asio::error_code& ec)
-{
- clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- (void)(buffer);
- (void)(buflength);
- hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec);
- if (!retval)
- return 0;
- clear_error(ec);
- *result = *retval;
- return retval;
-#elif defined(__sun) || defined(__QNX__)
- int error = 0;
- hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result,
- buffer, buflength, &error), ec);
- if (error)
- ec = translate_netdb_error(error);
- return retval;
-#elif defined(__MACH__) && defined(__APPLE__)
- (void)(buffer);
- (void)(buflength);
- int error = 0;
- hostent* retval = error_wrapper(::getipnodebyaddr(
- addr, length, af, &error), ec);
- if (error)
- ec = translate_netdb_error(error);
- if (!retval)
- return 0;
- *result = *retval;
- return retval;
-#else
- hostent* retval = 0;
- int error = 0;
- error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer,
- buflength, &retval, &error), ec);
- if (error)
- ec = translate_netdb_error(error);
- return retval;
-#endif
-}
-
-inline hostent* gethostbyname(const char* name, int af, struct hostent* result,
- char* buffer, int buflength, int ai_flags, asio::error_code& ec)
-{
- clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- (void)(buffer);
- (void)(buflength);
- (void)(ai_flags);
- if (af != AF_INET)
- {
- ec = asio::error::address_family_not_supported;
- return 0;
- }
- hostent* retval = error_wrapper(::gethostbyname(name), ec);
- if (!retval)
- return 0;
- clear_error(ec);
- *result = *retval;
- return result;
-#elif defined(__sun) || defined(__QNX__)
- (void)(ai_flags);
- if (af != AF_INET)
- {
- ec = asio::error::address_family_not_supported;
- return 0;
- }
- int error = 0;
- hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer,
- buflength, &error), ec);
- if (error)
- ec = translate_netdb_error(error);
- return retval;
-#elif defined(__MACH__) && defined(__APPLE__)
- (void)(buffer);
- (void)(buflength);
- int error = 0;
- hostent* retval = error_wrapper(::getipnodebyname(
- name, af, ai_flags, &error), ec);
- if (error)
- ec = translate_netdb_error(error);
- if (!retval)
- return 0;
- *result = *retval;
- return retval;
-#else
- (void)(ai_flags);
- if (af != AF_INET)
- {
- ec = asio::error::address_family_not_supported;
- return 0;
- }
- hostent* retval = 0;
- int error = 0;
- error_wrapper(::gethostbyname_r(name, result,
- buffer, buflength, &retval, &error), ec);
- if (error)
- ec = translate_netdb_error(error);
- return retval;
-#endif
-}
-
-inline void freehostent(hostent* h)
-{
-#if defined(__MACH__) && defined(__APPLE__)
- if (h)
- ::freehostent(h);
-#else
- (void)(h);
-#endif
-}
-
-// Emulation of getaddrinfo based on implementation in:
-// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998.
-
-struct gai_search
-{
- const char* host;
- int family;
-};
+ASIO_DECL int poll_write(socket_type s, asio::error_code& ec);
-inline int gai_nsearch(const char* host,
- const addrinfo_type* hints, gai_search (&search)[2])
-{
- int search_count = 0;
- if (host == 0 || host[0] == '\0')
- {
- if (hints->ai_flags & AI_PASSIVE)
- {
- // No host and AI_PASSIVE implies wildcard bind.
- switch (hints->ai_family)
- {
- case AF_INET:
- search[search_count].host = "0.0.0.0";
- search[search_count].family = AF_INET;
- ++search_count;
- break;
- case AF_INET6:
- search[search_count].host = "0::0";
- search[search_count].family = AF_INET6;
- ++search_count;
- break;
- case AF_UNSPEC:
- search[search_count].host = "0::0";
- search[search_count].family = AF_INET6;
- ++search_count;
- search[search_count].host = "0.0.0.0";
- search[search_count].family = AF_INET;
- ++search_count;
- break;
- default:
- break;
- }
- }
- else
- {
- // No host and not AI_PASSIVE means connect to local host.
- switch (hints->ai_family)
- {
- case AF_INET:
- search[search_count].host = "localhost";
- search[search_count].family = AF_INET;
- ++search_count;
- break;
- case AF_INET6:
- search[search_count].host = "localhost";
- search[search_count].family = AF_INET6;
- ++search_count;
- break;
- case AF_UNSPEC:
- search[search_count].host = "localhost";
- search[search_count].family = AF_INET6;
- ++search_count;
- search[search_count].host = "localhost";
- search[search_count].family = AF_INET;
- ++search_count;
- break;
- default:
- break;
- }
- }
- }
- else
- {
- // Host is specified.
- switch (hints->ai_family)
- {
- case AF_INET:
- search[search_count].host = host;
- search[search_count].family = AF_INET;
- ++search_count;
- break;
- case AF_INET6:
- search[search_count].host = host;
- search[search_count].family = AF_INET6;
- ++search_count;
- break;
- case AF_UNSPEC:
- search[search_count].host = host;
- search[search_count].family = AF_INET6;
- ++search_count;
- search[search_count].host = host;
- search[search_count].family = AF_INET;
- ++search_count;
- break;
- default:
- break;
- }
- }
- return search_count;
-}
-
-template <typename T>
-inline T* gai_alloc(std::size_t size = sizeof(T))
-{
- using namespace std;
- T* p = static_cast<T*>(::operator new(size, std::nothrow));
- if (p)
- memset(p, 0, size);
- return p;
-}
-
-inline void gai_free(void* p)
-{
- ::operator delete(p);
-}
+ASIO_DECL int poll_connect(socket_type s, asio::error_code& ec);
-inline void gai_strcpy(char* target, const char* source, std::size_t max_size)
-{
- using namespace std;
-#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
- strcpy_s(target, max_size, source);
-#else
- *target = 0;
- strncat(target, source, max_size);
-#endif
-}
-
-enum { gai_clone_flag = 1 << 30 };
-
-inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints,
- const void* addr, int family)
-{
- using namespace std;
-
- addrinfo_type* ai = gai_alloc<addrinfo_type>();
- if (ai == 0)
- return EAI_MEMORY;
-
- ai->ai_next = 0;
- **next = ai;
- *next = &ai->ai_next;
-
- ai->ai_canonname = 0;
- ai->ai_socktype = hints->ai_socktype;
- if (ai->ai_socktype == 0)
- ai->ai_flags |= gai_clone_flag;
- ai->ai_protocol = hints->ai_protocol;
- ai->ai_family = family;
-
- switch (ai->ai_family)
- {
- case AF_INET:
- {
- sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>();
- if (sinptr == 0)
- return EAI_MEMORY;
- sinptr->sin_family = AF_INET;
- memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type));
- ai->ai_addr = reinterpret_cast<sockaddr*>(sinptr);
- ai->ai_addrlen = sizeof(sockaddr_in4_type);
- break;
- }
- case AF_INET6:
- {
- sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>();
- if (sin6ptr == 0)
- return EAI_MEMORY;
- sin6ptr->sin6_family = AF_INET6;
- memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type));
- ai->ai_addr = reinterpret_cast<sockaddr*>(sin6ptr);
- ai->ai_addrlen = sizeof(sockaddr_in6_type);
- break;
- }
- default:
- break;
- }
-
- return 0;
-}
-
-inline addrinfo_type* gai_clone(addrinfo_type* ai)
-{
- using namespace std;
+ASIO_DECL const char* inet_ntop(int af, const void* src, char* dest,
+ size_t length, unsigned long scope_id, asio::error_code& ec);
- addrinfo_type* new_ai = gai_alloc<addrinfo_type>();
- if (new_ai == 0)
- return new_ai;
+ASIO_DECL int inet_pton(int af, const char* src, void* dest,
+ unsigned long* scope_id, asio::error_code& ec);
- new_ai->ai_next = ai->ai_next;
- ai->ai_next = new_ai;
+ASIO_DECL int gethostname(char* name,
+ int namelen, asio::error_code& ec);
- new_ai->ai_flags = 0;
- new_ai->ai_family = ai->ai_family;
- new_ai->ai_socktype = ai->ai_socktype;
- new_ai->ai_protocol = ai->ai_protocol;
- new_ai->ai_canonname = 0;
- new_ai->ai_addrlen = ai->ai_addrlen;
- new_ai->ai_addr = gai_alloc<sockaddr>(ai->ai_addrlen);
- memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen);
+ASIO_DECL asio::error_code getaddrinfo(const char* host,
+ const char* service, const addrinfo_type& hints,
+ addrinfo_type** result, asio::error_code& ec);
- return new_ai;
-}
+ASIO_DECL asio::error_code background_getaddrinfo(
+ const weak_cancel_token_type& cancel_token, const char* host,
+ const char* service, const addrinfo_type& hints,
+ addrinfo_type** result, asio::error_code& ec);
-inline int gai_port(addrinfo_type* aihead, int port, int socktype)
-{
- int num_found = 0;
-
- for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next)
- {
- if (ai->ai_flags & gai_clone_flag)
- {
- if (ai->ai_socktype != 0)
- {
- ai = gai_clone(ai);
- if (ai == 0)
- return -1;
- // ai now points to newly cloned entry.
- }
- }
- else if (ai->ai_socktype != socktype)
- {
- // Ignore if mismatch on socket type.
- continue;
- }
-
- ai->ai_socktype = socktype;
-
- switch (ai->ai_family)
- {
- case AF_INET:
- {
- sockaddr_in4_type* sinptr =
- reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);
- sinptr->sin_port = port;
- ++num_found;
- break;
- }
- case AF_INET6:
- {
- sockaddr_in6_type* sin6ptr =
- reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);
- sin6ptr->sin6_port = port;
- ++num_found;
- break;
- }
- default:
- break;
- }
- }
-
- return num_found;
-}
-
-inline int gai_serv(addrinfo_type* aihead,
- const addrinfo_type* hints, const char* serv)
-{
- using namespace std;
-
- int num_found = 0;
-
- if (
-#if defined(AI_NUMERICSERV)
- (hints->ai_flags & AI_NUMERICSERV) ||
-#endif
- isdigit(serv[0]))
- {
- int port = htons(atoi(serv));
- if (hints->ai_socktype)
- {
- // Caller specifies socket type.
- int rc = gai_port(aihead, port, hints->ai_socktype);
- if (rc < 0)
- return EAI_MEMORY;
- num_found += rc;
- }
- else
- {
- // Caller does not specify socket type.
- int rc = gai_port(aihead, port, SOCK_STREAM);
- if (rc < 0)
- return EAI_MEMORY;
- num_found += rc;
- rc = gai_port(aihead, port, SOCK_DGRAM);
- if (rc < 0)
- return EAI_MEMORY;
- num_found += rc;
- }
- }
- else
- {
- // Try service name with TCP first, then UDP.
- if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM)
- {
- servent* sptr = getservbyname(serv, "tcp");
- if (sptr != 0)
- {
- int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM);
- if (rc < 0)
- return EAI_MEMORY;
- num_found += rc;
- }
- }
- if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM)
- {
- servent* sptr = getservbyname(serv, "udp");
- if (sptr != 0)
- {
- int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM);
- if (rc < 0)
- return EAI_MEMORY;
- num_found += rc;
- }
- }
- }
-
- if (num_found == 0)
- {
- if (hints->ai_socktype == 0)
- {
- // All calls to getservbyname() failed.
- return EAI_NONAME;
- }
- else
- {
- // Service not supported for socket type.
- return EAI_SERVICE;
- }
- }
-
- return 0;
-}
-
-inline int gai_echeck(const char* host, const char* service,
- int flags, int family, int socktype, int protocol)
-{
- (void)(flags);
- (void)(protocol);
-
- // Host or service must be specified.
- if (host == 0 || host[0] == '\0')
- if (service == 0 || service[0] == '\0')
- return EAI_NONAME;
-
- // Check combination of family and socket type.
- switch (family)
- {
- case AF_UNSPEC:
- break;
- case AF_INET:
- case AF_INET6:
- if (service != 0 && service[0] != '\0')
- if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
- return EAI_SOCKTYPE;
- break;
- default:
- return EAI_FAMILY;
- }
-
- return 0;
-}
-
-inline void freeaddrinfo_emulation(addrinfo_type* aihead)
-{
- addrinfo_type* ai = aihead;
- while (ai)
- {
- gai_free(ai->ai_addr);
- gai_free(ai->ai_canonname);
- addrinfo_type* ainext = ai->ai_next;
- gai_free(ai);
- ai = ainext;
- }
-}
-
-inline int getaddrinfo_emulation(const char* host, const char* service,
- const addrinfo_type* hintsp, addrinfo_type** result)
-{
- // Set up linked list of addrinfo structures.
- addrinfo_type* aihead = 0;
- addrinfo_type** ainext = &aihead;
- char* canon = 0;
-
- // Supply default hints if not specified by caller.
- addrinfo_type hints = addrinfo_type();
- hints.ai_family = AF_UNSPEC;
- if (hintsp)
- hints = *hintsp;
-
- // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED
- // and AI_ALL flags.
-#if defined(AI_V4MAPPED)
- if (hints.ai_family != AF_INET6)
- hints.ai_flags &= ~AI_V4MAPPED;
-#endif
-#if defined(AI_ALL)
- if (hints.ai_family != AF_INET6)
- hints.ai_flags &= ~AI_ALL;
-#endif
-
- // Basic error checking.
- int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family,
- hints.ai_socktype, hints.ai_protocol);
- if (rc != 0)
- {
- freeaddrinfo_emulation(aihead);
- return rc;
- }
-
- gai_search search[2];
- int search_count = gai_nsearch(host, &hints, search);
- for (gai_search* sptr = search; sptr < search + search_count; ++sptr)
- {
- // Check for IPv4 dotted decimal string.
- in4_addr_type inaddr;
- asio::error_code ec;
- if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1)
- {
- if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET)
- {
- freeaddrinfo_emulation(aihead);
- gai_free(canon);
- return EAI_FAMILY;
- }
- if (sptr->family == AF_INET)
- {
- rc = gai_aistruct(&ainext, &hints, &inaddr, AF_INET);
- if (rc != 0)
- {
- freeaddrinfo_emulation(aihead);
- gai_free(canon);
- return rc;
- }
- }
- continue;
- }
-
- // Check for IPv6 hex string.
- in6_addr_type in6addr;
- if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr, 0, ec) == 1)
- {
- if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6)
- {
- freeaddrinfo_emulation(aihead);
- gai_free(canon);
- return EAI_FAMILY;
- }
- if (sptr->family == AF_INET6)
- {
- rc = gai_aistruct(&ainext, &hints, &in6addr, AF_INET6);
- if (rc != 0)
- {
- freeaddrinfo_emulation(aihead);
- gai_free(canon);
- return rc;
- }
- }
- continue;
- }
-
- // Look up hostname.
- hostent hent;
- char hbuf[8192] = "";
- hostent* hptr = socket_ops::gethostbyname(sptr->host,
- sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec);
- if (hptr == 0)
- {
- if (search_count == 2)
- {
- // Failure is OK if there are multiple searches.
- continue;
- }
- freeaddrinfo_emulation(aihead);
- gai_free(canon);
- if (ec == asio::error::host_not_found)
- return EAI_NONAME;
- if (ec == asio::error::host_not_found_try_again)
- return EAI_AGAIN;
- if (ec == asio::error::no_recovery)
- return EAI_FAIL;
- if (ec == asio::error::no_data)
- return EAI_NONAME;
- return EAI_NONAME;
- }
-
- // Check for address family mismatch if one was specified.
- if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype)
- {
- freeaddrinfo_emulation(aihead);
- gai_free(canon);
- socket_ops::freehostent(hptr);
- return EAI_FAMILY;
- }
-
- // Save canonical name first time.
- if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0]
- && (hints.ai_flags & AI_CANONNAME) && canon == 0)
- {
- std::size_t canon_len = strlen(hptr->h_name) + 1;
- canon = gai_alloc<char>(canon_len);
- if (canon == 0)
- {
- freeaddrinfo_emulation(aihead);
- socket_ops::freehostent(hptr);
- return EAI_MEMORY;
- }
- gai_strcpy(canon, hptr->h_name, canon_len);
- }
-
- // Create an addrinfo structure for each returned address.
- for (char** ap = hptr->h_addr_list; *ap; ++ap)
- {
- rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype);
- if (rc != 0)
- {
- freeaddrinfo_emulation(aihead);
- gai_free(canon);
- socket_ops::freehostent(hptr);
- return EAI_FAMILY;
- }
- }
-
- socket_ops::freehostent(hptr);
- }
-
- // Check if we found anything.
- if (aihead == 0)
- {
- gai_free(canon);
- return EAI_NONAME;
- }
-
- // Return canonical name in first entry.
- if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME))
- {
- if (canon)
- {
- aihead->ai_canonname = canon;
- canon = 0;
- }
- else
- {
- std::size_t canonname_len = strlen(search[0].host) + 1;
- aihead->ai_canonname = gai_alloc<char>(canonname_len);
- if (aihead->ai_canonname == 0)
- {
- freeaddrinfo_emulation(aihead);
- return EAI_MEMORY;
- }
- gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len);
- }
- }
- gai_free(canon);
-
- // Process the service name.
- if (service != 0 && service[0] != '\0')
- {
- rc = gai_serv(aihead, &hints, service);
- if (rc != 0)
- {
- freeaddrinfo_emulation(aihead);
- return rc;
- }
- }
-
- // Return result to caller.
- *result = aihead;
- return 0;
-}
-
-inline asio::error_code getnameinfo_emulation(
- const socket_addr_type* sa, std::size_t salen, char* host,
- std::size_t hostlen, char* serv, std::size_t servlen, int flags,
- asio::error_code& ec)
-{
- using namespace std;
-
- const char* addr;
- size_t addr_len;
- unsigned short port;
- switch (sa->sa_family)
- {
- case AF_INET:
- if (salen != sizeof(sockaddr_in4_type))
- {
- return ec = asio::error::invalid_argument;
- }
- addr = reinterpret_cast<const char*>(
- &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr);
- addr_len = sizeof(in4_addr_type);
- port = reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_port;
- break;
- case AF_INET6:
- if (salen != sizeof(sockaddr_in6_type))
- {
- return ec = asio::error::invalid_argument;
- }
- addr = reinterpret_cast<const char*>(
- &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr);
- addr_len = sizeof(in6_addr_type);
- port = reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_port;
- break;
- default:
- return ec = asio::error::address_family_not_supported;
- }
-
- if (host && hostlen > 0)
- {
- if (flags & NI_NUMERICHOST)
- {
- if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0)
- {
- return ec;
- }
- }
- else
- {
- hostent hent;
- char hbuf[8192] = "";
- hostent* hptr = socket_ops::gethostbyaddr(addr,
- static_cast<int>(addr_len), sa->sa_family,
- &hent, hbuf, sizeof(hbuf), ec);
- if (hptr && hptr->h_name && hptr->h_name[0] != '\0')
- {
- if (flags & NI_NOFQDN)
- {
- char* dot = strchr(hptr->h_name, '.');
- if (dot)
- {
- *dot = 0;
- }
- }
- gai_strcpy(host, hptr->h_name, hostlen);
- socket_ops::freehostent(hptr);
- }
- else
- {
- socket_ops::freehostent(hptr);
- if (flags & NI_NAMEREQD)
- {
- return ec = asio::error::host_not_found;
- }
- if (socket_ops::inet_ntop(sa->sa_family,
- addr, host, hostlen, 0, ec) == 0)
- {
- return ec;
- }
- }
- }
- }
-
- if (serv && servlen > 0)
- {
- if (flags & NI_NUMERICSERV)
- {
- if (servlen < 6)
- {
- return ec = asio::error::no_buffer_space;
- }
-#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
- sprintf_s(serv, servlen, "%u", ntohs(port));
-#else
- sprintf(serv, "%u", ntohs(port));
-#endif
- }
- else
- {
-#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
- static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- ::pthread_mutex_lock(&mutex);
-#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
- servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0);
- if (sptr && sptr->s_name && sptr->s_name[0] != '\0')
- {
- gai_strcpy(serv, sptr->s_name, servlen);
- }
- else
- {
- if (servlen < 6)
- {
- return ec = asio::error::no_buffer_space;
- }
-#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
- sprintf_s(serv, servlen, "%u", ntohs(port));
-#else
- sprintf(serv, "%u", ntohs(port));
-#endif
- }
-#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
- ::pthread_mutex_unlock(&mutex);
-#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
- }
- }
-
- clear_error(ec);
- return ec;
-}
+ASIO_DECL void freeaddrinfo(addrinfo_type* ai);
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- // || defined(__MACH__) && defined(__APPLE__)
+ASIO_DECL asio::error_code getnameinfo(
+ const socket_addr_type* addr, std::size_t addrlen,
+ char* host, std::size_t hostlen, char* serv,
+ std::size_t servlen, int flags, asio::error_code& ec);
-inline asio::error_code translate_addrinfo_error(int error)
-{
- switch (error)
- {
- case 0:
- return asio::error_code();
- case EAI_AGAIN:
- return asio::error::host_not_found_try_again;
- case EAI_BADFLAGS:
- return asio::error::invalid_argument;
- case EAI_FAIL:
- return asio::error::no_recovery;
- case EAI_FAMILY:
- return asio::error::address_family_not_supported;
- case EAI_MEMORY:
- return asio::error::no_memory;
- case EAI_NONAME:
-#if defined(EAI_ADDRFAMILY)
- case EAI_ADDRFAMILY:
-#endif
-#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
- case EAI_NODATA:
-#endif
- return asio::error::host_not_found;
- case EAI_SERVICE:
- return asio::error::service_not_found;
- case EAI_SOCKTYPE:
- return asio::error::socket_type_not_supported;
- default: // Possibly the non-portable EAI_SYSTEM.
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- return asio::error_code(
- WSAGetLastError(), asio::error::get_system_category());
-#else
- return asio::error_code(
- errno, asio::error::get_system_category());
-#endif
- }
-}
-
-inline asio::error_code getaddrinfo(const char* host,
- const char* service, const addrinfo_type* hints, addrinfo_type** result,
- asio::error_code& ec)
-{
- clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
- // Building for Windows XP, Windows Server 2003, or later.
- int error = ::getaddrinfo(host, service, hints, result);
- return ec = translate_addrinfo_error(error);
-# else
- // Building for Windows 2000 or earlier.
- typedef int (WSAAPI *gai_t)(const char*,
- const char*, const addrinfo_type*, addrinfo_type**);
- if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
- {
- if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo"))
- {
- int error = gai(host, service, hints, result);
- return ec = translate_addrinfo_error(error);
- }
- }
- int error = getaddrinfo_emulation(host, service, hints, result);
- return ec = translate_addrinfo_error(error);
-# endif
-#elif defined(__MACH__) && defined(__APPLE__)
- int error = getaddrinfo_emulation(host, service, hints, result);
- return ec = translate_addrinfo_error(error);
-#else
- int error = ::getaddrinfo(host, service, hints, result);
- return ec = translate_addrinfo_error(error);
-#endif
-}
-
-inline void freeaddrinfo(addrinfo_type* ai)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
- // Building for Windows XP, Windows Server 2003, or later.
- ::freeaddrinfo(ai);
-# else
- // Building for Windows 2000 or earlier.
- typedef int (WSAAPI *fai_t)(addrinfo_type*);
- if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
- {
- if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo"))
- {
- fai(ai);
- return;
- }
- }
- freeaddrinfo_emulation(ai);
-# endif
-#elif defined(__MACH__) && defined(__APPLE__)
- freeaddrinfo_emulation(ai);
-#else
- ::freeaddrinfo(ai);
-#endif
-}
-
-inline asio::error_code getnameinfo(const socket_addr_type* addr,
- std::size_t addrlen, char* host, std::size_t hostlen,
- char* serv, std::size_t servlen, int flags, asio::error_code& ec)
-{
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
- // Building for Windows XP, Windows Server 2003, or later.
- clear_error(ec);
- int error = ::getnameinfo(addr, static_cast<socklen_t>(addrlen),
- host, static_cast<DWORD>(hostlen),
- serv, static_cast<DWORD>(servlen), flags);
- return ec = translate_addrinfo_error(error);
-# else
- // Building for Windows 2000 or earlier.
- typedef int (WSAAPI *gni_t)(const socket_addr_type*,
- int, char*, DWORD, char*, DWORD, int);
- if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
- {
- if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo"))
- {
- clear_error(ec);
- int error = gni(addr, static_cast<int>(addrlen),
- host, static_cast<DWORD>(hostlen),
- serv, static_cast<DWORD>(servlen), flags);
- return ec = translate_addrinfo_error(error);
- }
- }
- clear_error(ec);
- return getnameinfo_emulation(addr, addrlen,
- host, hostlen, serv, servlen, flags, ec);
-# endif
-#elif defined(__MACH__) && defined(__APPLE__)
- using namespace std; // For memcpy.
- sockaddr_storage_type tmp_addr;
- memcpy(&tmp_addr, addr, addrlen);
- tmp_addr.ss_len = addrlen;
- addr = reinterpret_cast<socket_addr_type*>(&tmp_addr);
- clear_error(ec);
- return getnameinfo_emulation(addr, addrlen,
- host, hostlen, serv, servlen, flags, ec);
-#else
- clear_error(ec);
- int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
- return ec = translate_addrinfo_error(error);
-#endif
-}
-
-inline u_long_type network_to_host_long(u_long_type value)
-{
- return ntohl(value);
-}
+ASIO_DECL asio::error_code sync_getnameinfo(
+ const socket_addr_type* addr, std::size_t addrlen,
+ char* host, std::size_t hostlen, char* serv,
+ std::size_t servlen, int sock_type, asio::error_code& ec);
-inline u_long_type host_to_network_long(u_long_type value)
-{
- return htonl(value);
-}
+ASIO_DECL asio::error_code background_getnameinfo(
+ const weak_cancel_token_type& cancel_token,
+ const socket_addr_type* addr, std::size_t addrlen,
+ char* host, std::size_t hostlen, char* serv,
+ std::size_t servlen, int sock_type, asio::error_code& ec);
-inline u_short_type network_to_host_short(u_short_type value)
-{
- return ntohs(value);
-}
+ASIO_DECL u_long_type network_to_host_long(u_long_type value);
-inline u_short_type host_to_network_short(u_short_type value)
-{
- return htons(value);
-}
+ASIO_DECL u_long_type host_to_network_long(u_long_type value);
+
+ASIO_DECL u_short_type network_to_host_short(u_short_type value);
+
+ASIO_DECL u_short_type host_to_network_short(u_short_type value);
} // namespace socket_ops
} // namespace detail
@@ -1909,4 +282,8 @@ inline u_short_type host_to_network_short(u_short_type value)
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/socket_ops.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
#endif // ASIO_DETAIL_SOCKET_OPS_HPP
diff --git a/ext/asio/asio/detail/socket_option.hpp b/ext/asio/asio/detail/socket_option.hpp
index ac070b7..c9d7896 100644
--- a/ext/asio/asio/detail/socket_option.hpp
+++ b/ext/asio/asio/detail/socket_option.hpp
@@ -1,8 +1,8 @@
//
-// socket_option.hpp
-// ~~~~~~~~~~~~~~~~~
+// detail/socket_option.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
#include <stdexcept>
#include <boost/config.hpp>
#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/detail/socket_types.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
namespace socket_option {
diff --git a/ext/asio/asio/detail/socket_select_interrupter.hpp b/ext/asio/asio/detail/socket_select_interrupter.hpp
index 62e1063..b05a4ff 100644
--- a/ext/asio/asio/detail/socket_select_interrupter.hpp
+++ b/ext/asio/asio/detail/socket_select_interrupter.hpp
@@ -1,8 +1,8 @@
//
-// socket_select_interrupter.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/socket_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,19 +15,16 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
-#include <cstdlib>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(BOOST_WINDOWS) \
+ || defined(__CYGWIN__) \
+ || defined(__SYMBIAN32__)
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
-#include "asio/detail/socket_holder.hpp"
-#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_types.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -35,135 +32,16 @@ class socket_select_interrupter
{
public:
// Constructor.
- socket_select_interrupter()
- {
- asio::error_code ec;
- socket_holder acceptor(socket_ops::socket(
- AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
- if (acceptor.get() == invalid_socket)
- {
- asio::system_error e(ec, "socket_select_interrupter");
- boost::throw_exception(e);
- }
-
- int opt = 1;
- socket_ops::setsockopt(acceptor.get(),
- SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
-
- using namespace std; // For memset.
- sockaddr_in4_type addr;
- std::size_t addr_len = sizeof(addr);
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- addr.sin_port = 0;
- if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
- addr_len, ec) == socket_error_retval)
- {
- asio::system_error e(ec, "socket_select_interrupter");
- boost::throw_exception(e);
- }
-
- if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
- &addr_len, ec) == socket_error_retval)
- {
- asio::system_error e(ec, "socket_select_interrupter");
- boost::throw_exception(e);
- }
-
- // Some broken firewalls on Windows will intermittently cause getsockname to
- // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We
- // explicitly specify the target address here to work around this problem.
- addr.sin_addr.s_addr = inet_addr("127.0.0.1");
-
- if (socket_ops::listen(acceptor.get(),
- SOMAXCONN, ec) == socket_error_retval)
- {
- asio::system_error e(ec, "socket_select_interrupter");
- boost::throw_exception(e);
- }
-
- socket_holder client(socket_ops::socket(
- AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
- if (client.get() == invalid_socket)
- {
- asio::system_error e(ec, "socket_select_interrupter");
- boost::throw_exception(e);
- }
-
- if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
- addr_len, ec) == socket_error_retval)
- {
- asio::system_error e(ec, "socket_select_interrupter");
- boost::throw_exception(e);
- }
-
- socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
- if (server.get() == invalid_socket)
- {
- asio::system_error e(ec, "socket_select_interrupter");
- boost::throw_exception(e);
- }
-
- ioctl_arg_type non_blocking = 1;
- if (socket_ops::ioctl(client.get(), FIONBIO, &non_blocking, ec))
- {
- asio::system_error e(ec, "socket_select_interrupter");
- boost::throw_exception(e);
- }
-
- opt = 1;
- socket_ops::setsockopt(client.get(),
- IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
-
- non_blocking = 1;
- if (socket_ops::ioctl(server.get(), FIONBIO, &non_blocking, ec))
- {
- asio::system_error e(ec, "socket_select_interrupter");
- boost::throw_exception(e);
- }
-
- opt = 1;
- socket_ops::setsockopt(server.get(),
- IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
-
- read_descriptor_ = server.release();
- write_descriptor_ = client.release();
- }
+ ASIO_DECL socket_select_interrupter();
// Destructor.
- ~socket_select_interrupter()
- {
- asio::error_code ec;
- if (read_descriptor_ != invalid_socket)
- socket_ops::close(read_descriptor_, ec);
- if (write_descriptor_ != invalid_socket)
- socket_ops::close(write_descriptor_, ec);
- }
+ ASIO_DECL ~socket_select_interrupter();
// Interrupt the select call.
- void interrupt()
- {
- char byte = 0;
- socket_ops::buf b;
- socket_ops::init_buf(b, &byte, 1);
- asio::error_code ec;
- socket_ops::send(write_descriptor_, &b, 1, 0, ec);
- }
+ ASIO_DECL void interrupt();
// Reset the select interrupt. Returns true if the call was interrupted.
- bool reset()
- {
- char data[1024];
- socket_ops::buf b;
- socket_ops::init_buf(b, data, sizeof(data));
- asio::error_code ec;
- int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
- bool was_interrupted = (bytes_read > 0);
- while (bytes_read == sizeof(data))
- bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
- return was_interrupted;
- }
+ ASIO_DECL bool reset();
// Get the read descriptor to be passed to select.
socket_type read_descriptor() const
@@ -189,4 +67,12 @@ private:
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/socket_select_interrupter.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+
#endif // ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
diff --git a/ext/asio/asio/detail/socket_types.hpp b/ext/asio/asio/detail/socket_types.hpp
index 34b3d3e..4e29e51 100644
--- a/ext/asio/asio/detail/socket_types.hpp
+++ b/ext/asio/asio/detail/socket_types.hpp
@@ -1,8 +1,8 @@
//
-// socket_types.hpp
-// ~~~~~~~~~~~~~~~~
+// detail/socket_types.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,69 +15,19 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
# error WinSock.h has already been included
# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
-# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
-# if defined(_MSC_VER) || defined(__BORLANDC__)
-# pragma message( \
- "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\
- "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\
- "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\
- "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).")
-# else // defined(_MSC_VER) || defined(__BORLANDC__)
-# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately.
-# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line.
-# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).
-# endif // defined(_MSC_VER) || defined(__BORLANDC__)
-# define _WIN32_WINNT 0x0501
-# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
-# if defined(_MSC_VER)
-# if defined(_WIN32) && !defined(WIN32)
-# if !defined(_WINSOCK2API_)
-# define WIN32 // Needed for correct types in winsock2.h
-# else // !defined(_WINSOCK2API_)
-# error Please define the macro WIN32 in your compiler options
-# endif // !defined(_WINSOCK2API_)
-# endif // defined(_WIN32) && !defined(WIN32)
-# endif // defined(_MSC_VER)
# if defined(__BORLANDC__)
# include <stdlib.h> // Needed for __errno
-# if defined(__WIN32__) && !defined(WIN32)
-# if !defined(_WINSOCK2API_)
-# define WIN32 // Needed for correct types in winsock2.h
-# else // !defined(_WINSOCK2API_)
-# error Please define the macro WIN32 in your compiler options
-# endif // !defined(_WINSOCK2API_)
-# endif // defined(__WIN32__) && !defined(WIN32)
# if !defined(_WSPIAPI_H_)
# define _WSPIAPI_H_
# define ASIO_WSPIAPI_H_DEFINED
# endif // !defined(_WSPIAPI_H_)
# endif // defined(__BORLANDC__)
-# if !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
-# if !defined(WIN32_LEAN_AND_MEAN)
-# define WIN32_LEAN_AND_MEAN
-# endif // !defined(WIN32_LEAN_AND_MEAN)
-# endif // !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
-# if !defined(ASIO_NO_NOMINMAX)
-# if !defined(NOMINMAX)
-# define NOMINMAX 1
-# endif // !defined(NOMINMAX)
-# endif // !defined(ASIO_NO_NOMINMAX)
-# if defined(__CYGWIN__)
-# if !defined(__USE_W32_SOCKETS)
-# error You must add -D__USE_W32_SOCKETS to your compiler options.
-# endif // !defined(__USE_W32_SOCKETS)
-# endif // defined(__CYGWIN__)
# include <winsock2.h>
# include <ws2tcpip.h>
# include <mswsock.h>
@@ -96,18 +46,25 @@
# include "asio/detail/old_win_sdk_compat.hpp"
#else
# include <sys/ioctl.h>
-# include <sys/poll.h>
+# if !defined(__SYMBIAN32__)
+# include <sys/poll.h>
+# endif
# include <sys/types.h>
-# if defined(__hpux) && !defined(__HP_aCC)
+# include <sys/stat.h>
+# include <fcntl.h>
+# if defined(__hpux)
# include <sys/time.h>
-# else
+# endif
+# if !defined(__hpux) || defined(__SELECT)
# include <sys/select.h>
# endif
# include <sys/socket.h>
# include <sys/uio.h>
# include <sys/un.h>
# include <netinet/in.h>
-# include <netinet/tcp.h>
+# if !defined(__SYMBIAN32__)
+# include <netinet/tcp.h>
+# endif
# include <arpa/inet.h>
# include <netdb.h>
# include <net/if.h>
@@ -117,7 +74,8 @@
# include <sys/sockio.h>
# endif
#endif
-#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
diff --git a/ext/asio/asio/detail/solaris_fenced_block.hpp b/ext/asio/asio/detail/solaris_fenced_block.hpp
index d337f3b..411c824 100644
--- a/ext/asio/asio/detail/solaris_fenced_block.hpp
+++ b/ext/asio/asio/detail/solaris_fenced_block.hpp
@@ -1,8 +1,8 @@
//
-// solaris_fenced_block.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/solaris_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if defined(__sun)
-#include "asio/detail/push_options.hpp"
#include <atomic.h>
-#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -50,8 +46,8 @@ public:
} // namespace detail
} // namespace asio
-#endif // defined(__sun)
-
#include "asio/detail/pop_options.hpp"
+#endif // defined(__sun)
+
#endif // ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP
diff --git a/ext/asio/asio/detail/strand_service.hpp b/ext/asio/asio/detail/strand_service.hpp
index ea50f41..4885b93 100644
--- a/ext/asio/asio/detail/strand_service.hpp
+++ b/ext/asio/asio/detail/strand_service.hpp
@@ -1,8 +1,8 @@
//
-// strand_service.hpp
-// ~~~~~~~~~~~~~~~~~~
+// detail/strand_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,23 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/functional/hash.hpp>
+#include "asio/detail/config.hpp"
#include <boost/scoped_ptr.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/io_service.hpp"
-#include "asio/detail/call_stack.hpp"
-#include "asio/detail/completion_handler.hpp"
-#include "asio/detail/fenced_block.hpp"
-#include "asio/detail/handler_alloc_helpers.hpp"
-#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/op_queue.hpp"
#include "asio/detail/operation.hpp"
-#include "asio/detail/service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -41,7 +32,10 @@ class strand_service
: public asio::detail::service_base<strand_service>
{
private:
+ // Helper class to re-post the strand on exit.
struct on_do_complete_exit;
+
+ // Helper class to re-post the strand on exit.
struct on_dispatch_exit;
public:
@@ -51,11 +45,7 @@ public:
: public operation
{
public:
- strand_impl()
- : operation(&strand_service::do_complete),
- count_(0)
- {
- }
+ strand_impl();
private:
// Only this service will have access to the internal values.
@@ -76,180 +66,29 @@ public:
typedef strand_impl* implementation_type;
// Construct a new strand service for the specified io_service.
- explicit strand_service(asio::io_service& io_service)
- : asio::detail::service_base<strand_service>(io_service),
- io_service_(asio::use_service<io_service_impl>(io_service)),
- mutex_(),
- salt_(0)
- {
- }
+ ASIO_DECL explicit strand_service(asio::io_service& io_service);
// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- op_queue<operation> ops;
-
- asio::detail::mutex::scoped_lock lock(mutex_);
-
- for (std::size_t i = 0; i < num_implementations; ++i)
- if (strand_impl* impl = implementations_[i].get())
- ops.push(impl->queue_);
- }
+ ASIO_DECL void shutdown_service();
// Construct a new strand implementation.
- void construct(implementation_type& impl)
- {
- std::size_t index = boost::hash_value(&impl);
- boost::hash_combine(index, salt_++);
- index = index % num_implementations;
-
- asio::detail::mutex::scoped_lock lock(mutex_);
-
- if (!implementations_[index])
- implementations_[index].reset(new strand_impl);
- impl = implementations_[index].get();
- }
+ ASIO_DECL void construct(implementation_type& impl);
// Destroy a strand implementation.
- void destroy(implementation_type& impl)
- {
- impl = 0;
- }
+ void destroy(implementation_type& impl);
// Request the io_service to invoke the given handler.
template <typename Handler>
- void dispatch(implementation_type& impl, Handler handler)
- {
- // If we are already in the strand then the handler can run immediately.
- if (call_stack<strand_impl>::contains(impl))
- {
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- return;
- }
-
- // Allocate and construct an object to wrap the handler.
- typedef completion_handler<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
- // If we are running inside the io_service, and no other handler is queued
- // or running, then the handler can run immediately.
- bool can_dispatch = call_stack<io_service_impl>::contains(&io_service_);
- impl->mutex_.lock();
- bool first = (++impl->count_ == 1);
- if (can_dispatch && first)
- {
- // Immediate invocation is allowed.
- impl->mutex_.unlock();
-
- // Memory must be releaesed before any upcall is made.
- ptr.reset();
-
- // Indicate that this strand is executing on the current thread.
- call_stack<strand_impl>::context ctx(impl);
-
- // Ensure the next handler, if any, is scheduled on block exit.
- on_dispatch_exit on_exit = { &io_service_, impl };
- (void)on_exit;
-
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- return;
- }
-
- // Immediate invocation is not allowed, so enqueue for later.
- impl->queue_.push(ptr.get());
- impl->mutex_.unlock();
- ptr.release();
-
- // The first handler to be enqueued is responsible for scheduling the
- // strand.
- if (first)
- io_service_.post_immediate_completion(impl);
- }
+ void dispatch(implementation_type& impl, Handler handler);
// Request the io_service to invoke the given handler and return immediately.
template <typename Handler>
- void post(implementation_type& impl, Handler handler)
- {
- // Allocate and construct an object to wrap the handler.
- typedef completion_handler<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
- // Add the handler to the queue.
- impl->mutex_.lock();
- bool first = (++impl->count_ == 1);
- impl->queue_.push(ptr.get());
- impl->mutex_.unlock();
- ptr.release();
-
- // The first handler to be enqueue is responsible for scheduling the strand.
- if (first)
- io_service_.post_immediate_completion(impl);
- }
+ void post(implementation_type& impl, Handler handler);
private:
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
- {
- if (owner)
- {
- strand_impl* impl = static_cast<strand_impl*>(base);
-
- // Get the next handler to be executed.
- impl->mutex_.lock();
- operation* o = impl->queue_.front();
- impl->queue_.pop();
- impl->mutex_.unlock();
-
- // Indicate that this strand is executing on the current thread.
- call_stack<strand_impl>::context ctx(impl);
-
- // Ensure the next handler, if any, is scheduled on block exit.
- on_do_complete_exit on_exit = { owner, impl };
- (void)on_exit;
-
- o->complete(*owner);
- }
- }
-
- // Helper class to re-post the strand on exit.
- struct on_do_complete_exit
- {
- io_service_impl* owner_;
- strand_impl* impl_;
-
- ~on_do_complete_exit()
- {
- impl_->mutex_.lock();
- bool more_handlers = (--impl_->count_ > 0);
- impl_->mutex_.unlock();
-
- if (more_handlers)
- owner_->post_immediate_completion(impl_);
- }
- };
-
- // Helper class to re-post the strand on exit.
- struct on_dispatch_exit
- {
- io_service_impl* io_service_;
- strand_impl* impl_;
-
- ~on_dispatch_exit()
- {
- impl_->mutex_.lock();
- bool more_handlers = (--impl_->count_ > 0);
- impl_->mutex_.unlock();
-
- if (more_handlers)
- io_service_->post_immediate_completion(impl_);
- }
- };
+ ASIO_DECL static void do_complete(io_service_impl* owner,
+ operation* base, asio::error_code ec,
+ std::size_t bytes_transferred);
// The io_service implementation used to post completions.
io_service_impl& io_service_;
@@ -273,4 +112,9 @@ private:
#include "asio/detail/pop_options.hpp"
+#include "asio/detail/impl/strand_service.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/strand_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
#endif // ASIO_DETAIL_STRAND_SERVICE_HPP
diff --git a/ext/asio/asio/detail/task_io_service.hpp b/ext/asio/asio/detail/task_io_service.hpp
index eb77c1d..2d69513 100644
--- a/ext/asio/asio/detail/task_io_service.hpp
+++ b/ext/asio/asio/detail/task_io_service.hpp
@@ -1,8 +1,8 @@
//
-// task_io_service.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// detail/task_io_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,180 +15,59 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_IOCP)
+#include <boost/detail/atomic_count.hpp>
#include "asio/error_code.hpp"
#include "asio/io_service.hpp"
-#include "asio/detail/call_stack.hpp"
-#include "asio/detail/completion_handler.hpp"
-#include "asio/detail/event.hpp"
-#include "asio/detail/fenced_block.hpp"
-#include "asio/detail/handler_alloc_helpers.hpp"
-#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/op_queue.hpp"
-#include "asio/detail/service_base.hpp"
+#include "asio/detail/reactor_fwd.hpp"
#include "asio/detail/task_io_service_fwd.hpp"
#include "asio/detail/task_io_service_operation.hpp"
#include "asio/detail/push_options.hpp"
-#include <boost/detail/atomic_count.hpp>
-#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
-template <typename Task>
class task_io_service
- : public asio::detail::service_base<task_io_service<Task> >
+ : public asio::detail::service_base<task_io_service>
{
public:
- typedef task_io_service_operation<Task> operation;
+ typedef task_io_service_operation operation;
// Constructor.
- task_io_service(asio::io_service& io_service)
- : asio::detail::service_base<task_io_service<Task> >(io_service),
- mutex_(),
- task_(0),
- task_interrupted_(true),
- outstanding_work_(0),
- stopped_(false),
- shutdown_(false),
- first_idle_thread_(0)
- {
- }
+ ASIO_DECL task_io_service(asio::io_service& io_service);
- void init(size_t /*concurrency_hint*/)
- {
- }
+ // How many concurrent threads are likely to run the io_service.
+ ASIO_DECL void init(std::size_t concurrency_hint);
// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- shutdown_ = true;
- lock.unlock();
-
- // Destroy handler objects.
- while (!op_queue_.empty())
- {
- operation* o = op_queue_.front();
- op_queue_.pop();
- if (o != &task_operation_)
- o->destroy();
- }
-
- // Reset to initial state.
- task_ = 0;
- }
+ ASIO_DECL void shutdown_service();
// Initialise the task, if required.
- void init_task()
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- if (!shutdown_ && !task_)
- {
- task_ = &use_service<Task>(this->get_io_service());
- op_queue_.push(&task_operation_);
- wake_one_thread_and_unlock(lock);
- }
- }
+ ASIO_DECL void init_task();
// Run the event loop until interrupted or no more work.
- size_t run(asio::error_code& ec)
- {
- ec = asio::error_code();
- if (outstanding_work_ == 0)
- {
- stop();
- return 0;
- }
-
- typename call_stack<task_io_service>::context ctx(this);
-
- idle_thread_info this_idle_thread;
- this_idle_thread.next = 0;
-
- asio::detail::mutex::scoped_lock lock(mutex_);
-
- size_t n = 0;
- for (; do_one(lock, &this_idle_thread); lock.lock())
- if (n != (std::numeric_limits<size_t>::max)())
- ++n;
- return n;
- }
+ ASIO_DECL std::size_t run(asio::error_code& ec);
// Run until interrupted or one operation is performed.
- size_t run_one(asio::error_code& ec)
- {
- ec = asio::error_code();
- if (outstanding_work_ == 0)
- {
- stop();
- return 0;
- }
-
- typename call_stack<task_io_service>::context ctx(this);
-
- idle_thread_info this_idle_thread;
- this_idle_thread.next = 0;
-
- asio::detail::mutex::scoped_lock lock(mutex_);
-
- return do_one(lock, &this_idle_thread);
- }
+ ASIO_DECL std::size_t run_one(asio::error_code& ec);
// Poll for operations without blocking.
- size_t poll(asio::error_code& ec)
- {
- if (outstanding_work_ == 0)
- {
- stop();
- ec = asio::error_code();
- return 0;
- }
-
- typename call_stack<task_io_service>::context ctx(this);
-
- asio::detail::mutex::scoped_lock lock(mutex_);
-
- size_t n = 0;
- for (; do_one(lock, 0); lock.lock())
- if (n != (std::numeric_limits<size_t>::max)())
- ++n;
- return n;
- }
+ ASIO_DECL std::size_t poll(asio::error_code& ec);
// Poll for one operation without blocking.
- size_t poll_one(asio::error_code& ec)
- {
- ec = asio::error_code();
- if (outstanding_work_ == 0)
- {
- stop();
- return 0;
- }
-
- typename call_stack<task_io_service>::context ctx(this);
-
- asio::detail::mutex::scoped_lock lock(mutex_);
-
- return do_one(lock, 0);
- }
+ ASIO_DECL std::size_t poll_one(asio::error_code& ec);
// Interrupt the event processing loop.
- void stop()
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- stop_all_threads(lock);
- }
+ ASIO_DECL void stop();
// Reset in preparation for a subsequent run invocation.
- void reset()
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- stopped_ = false;
- }
+ ASIO_DECL void reset();
// Notify that some work has started.
void work_started()
@@ -205,228 +84,60 @@ public:
// Request invocation of the given handler.
template <typename Handler>
- void dispatch(Handler handler)
- {
- if (call_stack<task_io_service>::contains(this))
- {
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- else
- post(handler);
- }
+ void dispatch(Handler handler);
// Request invocation of the given handler and return immediately.
template <typename Handler>
- void post(Handler handler)
- {
- // Allocate and construct an operation to wrap the handler.
- typedef completion_handler<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
- post_immediate_completion(ptr.get());
- ptr.release();
- }
+ void post(Handler handler);
// Request invocation of the given operation and return immediately. Assumes
// that work_started() has not yet been called for the operation.
- void post_immediate_completion(operation* op)
- {
- work_started();
- post_deferred_completion(op);
- }
+ ASIO_DECL void post_immediate_completion(operation* op);
// Request invocation of the given operation and return immediately. Assumes
// that work_started() was previously called for the operation.
- void post_deferred_completion(operation* op)
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- op_queue_.push(op);
- wake_one_thread_and_unlock(lock);
- }
+ ASIO_DECL void post_deferred_completion(operation* op);
// Request invocation of the given operations and return immediately. Assumes
// that work_started() was previously called for each operation.
- void post_deferred_completions(op_queue<operation>& ops)
- {
- if (!ops.empty())
- {
- asio::detail::mutex::scoped_lock lock(mutex_);
- op_queue_.push(ops);
- wake_one_thread_and_unlock(lock);
- }
- }
+ ASIO_DECL void post_deferred_completions(op_queue<operation>& ops);
private:
+ // Structure containing information about an idle thread.
struct idle_thread_info;
- size_t do_one(asio::detail::mutex::scoped_lock& lock,
- idle_thread_info* this_idle_thread)
- {
- bool polling = !this_idle_thread;
- bool task_has_run = false;
- while (!stopped_)
- {
- if (!op_queue_.empty())
- {
- // Prepare to execute first handler from queue.
- operation* o = op_queue_.front();
- op_queue_.pop();
- bool more_handlers = (!op_queue_.empty());
-
- if (o == &task_operation_)
- {
- task_interrupted_ = more_handlers || polling;
-
- // If the task has already run and we're polling then we're done.
- if (task_has_run && polling)
- {
- task_interrupted_ = true;
- op_queue_.push(&task_operation_);
- return 0;
- }
- task_has_run = true;
-
- if (!more_handlers || !wake_one_idle_thread_and_unlock(lock))
- lock.unlock();
-
- op_queue<operation> completed_ops;
- task_cleanup c = { this, &lock, &completed_ops };
- (void)c;
-
- // Run the task. May throw an exception. Only block if the operation
- // queue is empty and we're not polling, otherwise we want to return
- // as soon as possible.
- task_->run(!more_handlers && !polling, completed_ops);
- }
- else
- {
- if (more_handlers)
- wake_one_thread_and_unlock(lock);
- else
- lock.unlock();
-
- // Ensure the count of outstanding work is decremented on block exit.
- work_finished_on_block_exit on_exit = { this };
- (void)on_exit;
-
- // Complete the operation. May throw an exception.
- o->complete(*this); // deletes the operation object
-
- return 1;
- }
- }
- else if (this_idle_thread)
- {
- // Nothing to run right now, so just wait for work to do.
- this_idle_thread->next = first_idle_thread_;
- first_idle_thread_ = this_idle_thread;
- this_idle_thread->wakeup_event.clear(lock);
- this_idle_thread->wakeup_event.wait(lock);
- }
- else
- {
- return 0;
- }
- }
-
- return 0;
- }
+ // Run at most one operation. Blocks only if this_idle_thread is non-null.
+ ASIO_DECL std::size_t do_one(mutex::scoped_lock& lock,
+ idle_thread_info* this_idle_thread);
// Stop the task and all idle threads.
- void stop_all_threads(
- asio::detail::mutex::scoped_lock& lock)
- {
- stopped_ = true;
-
- while (first_idle_thread_)
- {
- idle_thread_info* idle_thread = first_idle_thread_;
- first_idle_thread_ = idle_thread->next;
- idle_thread->next = 0;
- idle_thread->wakeup_event.signal(lock);
- }
-
- if (!task_interrupted_ && task_)
- {
- task_interrupted_ = true;
- task_->interrupt();
- }
- }
+ ASIO_DECL void stop_all_threads(mutex::scoped_lock& lock);
// Wakes a single idle thread and unlocks the mutex. Returns true if an idle
// thread was found. If there is no idle thread, returns false and leaves the
// mutex locked.
- bool wake_one_idle_thread_and_unlock(
- asio::detail::mutex::scoped_lock& lock)
- {
- if (first_idle_thread_)
- {
- idle_thread_info* idle_thread = first_idle_thread_;
- first_idle_thread_ = idle_thread->next;
- idle_thread->next = 0;
- idle_thread->wakeup_event.signal_and_unlock(lock);
- return true;
- }
- return false;
- }
+ ASIO_DECL bool wake_one_idle_thread_and_unlock(
+ mutex::scoped_lock& lock);
// Wake a single idle thread, or the task, and always unlock the mutex.
- void wake_one_thread_and_unlock(
- asio::detail::mutex::scoped_lock& lock)
- {
- if (!wake_one_idle_thread_and_unlock(lock))
- {
- if (!task_interrupted_ && task_)
- {
- task_interrupted_ = true;
- task_->interrupt();
- }
- lock.unlock();
- }
- }
+ ASIO_DECL void wake_one_thread_and_unlock(
+ mutex::scoped_lock& lock);
// Helper class to perform task-related operations on block exit.
struct task_cleanup;
friend struct task_cleanup;
- struct task_cleanup
- {
- ~task_cleanup()
- {
- // Enqueue the completed operations and reinsert the task at the end of
- // the operation queue.
- lock_->lock();
- task_io_service_->task_interrupted_ = true;
- task_io_service_->op_queue_.push(*ops_);
- task_io_service_->op_queue_.push(&task_io_service_->task_operation_);
- }
-
- task_io_service* task_io_service_;
- asio::detail::mutex::scoped_lock* lock_;
- op_queue<operation>* ops_;
- };
// Helper class to call work_finished() on block exit.
- struct work_finished_on_block_exit
- {
- ~work_finished_on_block_exit()
- {
- task_io_service_->work_finished();
- }
-
- task_io_service* task_io_service_;
- };
+ struct work_finished_on_block_exit;
// Mutex to protect access to internal data.
- asio::detail::mutex mutex_;
+ mutex mutex_;
// The task to be run by this service.
- Task* task_;
+ reactor* task_;
// Operation object to represent the position of the task in the queue.
- struct task_operation : public operation
+ struct task_operation : operation
{
task_operation() : operation(0) {}
} task_operation_;
@@ -446,13 +157,6 @@ private:
// Flag to indicate that the dispatcher has been shut down.
bool shutdown_;
- // Structure containing information about an idle thread.
- struct idle_thread_info
- {
- event wakeup_event;
- idle_thread_info* next;
- };
-
// The threads that are currently idle.
idle_thread_info* first_idle_thread_;
};
@@ -462,4 +166,11 @@ private:
#include "asio/detail/pop_options.hpp"
+#include "asio/detail/impl/task_io_service.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/task_io_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_HAS_IOCP)
+
#endif // ASIO_DETAIL_TASK_IO_SERVICE_HPP
diff --git a/ext/asio/asio/detail/task_io_service_fwd.hpp b/ext/asio/asio/detail/task_io_service_fwd.hpp
index 5b18d1d..b66cb07 100644
--- a/ext/asio/asio/detail/task_io_service_fwd.hpp
+++ b/ext/asio/asio/detail/task_io_service_fwd.hpp
@@ -1,8 +1,8 @@
//
-// task_io_service_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~
+// detail/task_io_service_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
namespace asio {
namespace detail {
-template <typename Task>
class task_io_service;
} // namespace detail
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP
diff --git a/ext/asio/asio/detail/task_io_service_operation.hpp b/ext/asio/asio/detail/task_io_service_operation.hpp
index 6776f69..dd4384a 100644
--- a/ext/asio/asio/detail/task_io_service_operation.hpp
+++ b/ext/asio/asio/detail/task_io_service_operation.hpp
@@ -1,8 +1,8 @@
//
-// task_io_service_operation.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/task_io_service_operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,22 +15,21 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
#include "asio/error_code.hpp"
#include "asio/detail/op_queue.hpp"
#include "asio/detail/task_io_service_fwd.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
// Base class for all operations. A function pointer is used instead of virtual
// functions to avoid the associated overhead.
-template <typename Task>
class task_io_service_operation
{
public:
- void complete(task_io_service<Task>& owner)
+ void complete(task_io_service& owner)
{
func_(&owner, this, asio::error_code(), 0);
}
@@ -41,8 +40,9 @@ public:
}
protected:
- typedef void (*func_type)(task_io_service<Task>*,
- task_io_service_operation*, asio::error_code, std::size_t);
+ typedef void (*func_type)(task_io_service*,
+ task_io_service_operation*,
+ asio::error_code, std::size_t);
task_io_service_operation(func_type func)
: next_(0),
diff --git a/ext/asio/asio/detail/thread.hpp b/ext/asio/asio/detail/thread.hpp
index 3c9280b..7c4103b 100644
--- a/ext/asio/asio/detail/thread.hpp
+++ b/ext/asio/asio/detail/thread.hpp
@@ -1,8 +1,8 @@
//
-// thread.hpp
-// ~~~~~~~~~~
+// detail/thread.hpp
+// ~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,7 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
# include "asio/detail/null_thread.hpp"
@@ -53,6 +49,4 @@ typedef posix_thread thread;
} // namespace detail
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_THREAD_HPP
diff --git a/ext/asio/asio/detail/throw_error.hpp b/ext/asio/asio/detail/throw_error.hpp
index 51d6e48..d39aa92 100644
--- a/ext/asio/asio/detail/throw_error.hpp
+++ b/ext/asio/asio/detail/throw_error.hpp
@@ -1,8 +1,8 @@
//
-// throw_error.hpp
-// ~~~~~~~~~~~~~~~
+// detail/throw_error.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,25 +15,30 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include "asio/error_code.hpp"
#include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error_code.hpp"
-#include "asio/system_error.hpp"
namespace asio {
namespace detail {
+ASIO_DECL void do_throw_error(const asio::error_code& err);
+
+ASIO_DECL void do_throw_error(const asio::error_code& err,
+ const char* location);
+
inline void throw_error(const asio::error_code& err)
{
if (err)
- {
- asio::system_error e(err);
- boost::throw_exception(e);
- }
+ do_throw_error(err);
+}
+
+inline void throw_error(const asio::error_code& err,
+ const char* location)
+{
+ if (err)
+ do_throw_error(err, location);
}
} // namespace detail
@@ -41,4 +46,8 @@ inline void throw_error(const asio::error_code& err)
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/throw_error.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
#endif // ASIO_DETAIL_THROW_ERROR_HPP
diff --git a/ext/asio/asio/detail/timer_op.hpp b/ext/asio/asio/detail/timer_op.hpp
index bf3c3ae..62cd292 100644
--- a/ext/asio/asio/detail/timer_op.hpp
+++ b/ext/asio/asio/detail/timer_op.hpp
@@ -1,8 +1,8 @@
//
-// timer_op.hpp
-// ~~~~~~~~~~~~
+// detail/timer_op.hpp
+// ~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,10 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/detail/operation.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
diff --git a/ext/asio/asio/detail/timer_queue.hpp b/ext/asio/asio/detail/timer_queue.hpp
index 2e4d2d5..514c434 100644
--- a/ext/asio/asio/detail/timer_queue.hpp
+++ b/ext/asio/asio/detail/timer_queue.hpp
@@ -1,8 +1,8 @@
//
-// timer_queue.hpp
-// ~~~~~~~~~~~~~~~
+// detail/timer_queue.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,21 +15,22 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <memory>
#include <vector>
#include <boost/config.hpp>
#include <boost/limits.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/detail/hash_map.hpp"
#include "asio/detail/op_queue.hpp"
#include "asio/detail/timer_op.hpp"
#include "asio/detail/timer_queue_base.hpp"
+#include "asio/error.hpp"
+#include "asio/time_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -45,6 +46,26 @@ public:
// The duration type.
typedef typename Time_Traits::duration_type duration_type;
+ // Per-timer data.
+ class per_timer_data
+ {
+ public:
+ per_timer_data() : next_(0), prev_(0) {}
+
+ private:
+ friend class timer_queue;
+
+ // The operations waiting on the timer.
+ op_queue<timer_op> op_queue_;
+
+ // The index of the timer in the heap.
+ std::size_t heap_index_;
+
+ // Pointers to adjacent timers in a linked list.
+ per_timer_data* next_;
+ per_timer_data* prev_;
+ };
+
// Constructor.
timer_queue()
: timers_(),
@@ -55,35 +76,45 @@ public:
// Add a new timer to the queue. Returns true if this is the timer that is
// earliest in the queue, in which case the reactor's event demultiplexing
// function call may need to be interrupted and restarted.
- bool enqueue_timer(const time_type& time, timer_op* op, void* token)
+ bool enqueue_timer(const time_type& time, per_timer_data& timer, timer_op* op)
{
- // Ensure that there is space for the timer in the heap. We reserve here so
- // that the push_back below will not throw due to a reallocation failure.
- heap_.reserve(heap_.size() + 1);
-
- // Insert the new timer into the hash.
- typedef typename hash_map<void*, timer>::iterator iterator;
- typedef typename hash_map<void*, timer>::value_type value_type;
- std::pair<iterator, bool> result =
- timers_.insert(value_type(token, timer()));
- result.first->second.op_queue_.push(op);
- if (result.second)
+ // Enqueue the timer object.
+ if (timer.prev_ == 0 && &timer != timers_)
{
- // Put the new timer at the correct position in the heap.
- result.first->second.time_ = time;
- result.first->second.heap_index_ = heap_.size();
- result.first->second.token_ = token;
- heap_.push_back(&result.first->second);
- up_heap(heap_.size() - 1);
+ if (this->is_positive_infinity(time))
+ {
+ // No heap entry is required for timers that never expire.
+ timer.heap_index_ = (std::numeric_limits<std::size_t>::max)();
+ }
+ else
+ {
+ // Put the new timer at the correct position in the heap. This is done
+ // first since push_back() can throw due to allocation failure.
+ timer.heap_index_ = heap_.size();
+ heap_entry entry = { time, &timer };
+ heap_.push_back(entry);
+ up_heap(heap_.size() - 1);
+ }
+
+ // Insert the new timer into the linked list of active timers.
+ timer.next_ = timers_;
+ timer.prev_ = 0;
+ if (timers_)
+ timers_->prev_ = &timer;
+ timers_ = &timer;
}
- return (heap_[0] == &result.first->second);
+ // Enqueue the individual timer operation.
+ timer.op_queue_.push(op);
+
+ // Interrupt reactor only if newly added timer is first to expire.
+ return timer.heap_index_ == 0 && timer.op_queue_.front() == op;
}
// Whether there are no timers in the queue.
virtual bool empty() const
{
- return heap_.empty();
+ return timers_ == 0;
}
// Get the time for the timer that is earliest in the queue.
@@ -93,12 +124,14 @@ public:
return max_duration;
boost::posix_time::time_duration duration = Time_Traits::to_posix_duration(
- Time_Traits::subtract(heap_[0]->time_, Time_Traits::now()));
+ Time_Traits::subtract(heap_[0].time_, Time_Traits::now()));
if (duration > boost::posix_time::milliseconds(max_duration))
duration = boost::posix_time::milliseconds(max_duration);
- else if (duration < boost::posix_time::milliseconds(0))
+ else if (duration <= boost::posix_time::milliseconds(0))
duration = boost::posix_time::milliseconds(0);
+ else if (duration < boost::posix_time::milliseconds(1))
+ duration = boost::posix_time::milliseconds(1);
return duration.total_milliseconds();
}
@@ -110,12 +143,14 @@ public:
return max_duration;
boost::posix_time::time_duration duration = Time_Traits::to_posix_duration(
- Time_Traits::subtract(heap_[0]->time_, Time_Traits::now()));
+ Time_Traits::subtract(heap_[0].time_, Time_Traits::now()));
if (duration > boost::posix_time::microseconds(max_duration))
duration = boost::posix_time::microseconds(max_duration);
- else if (duration < boost::posix_time::microseconds(0))
+ else if (duration <= boost::posix_time::microseconds(0))
duration = boost::posix_time::microseconds(0);
+ else if (duration < boost::posix_time::microseconds(1))
+ duration = boost::posix_time::microseconds(1);
return duration.total_microseconds();
}
@@ -124,77 +159,54 @@ public:
virtual void get_ready_timers(op_queue<operation>& ops)
{
const time_type now = Time_Traits::now();
- while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_))
+ while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0].time_))
{
- timer* t = heap_[0];
- ops.push(t->op_queue_);
- remove_timer(t);
+ per_timer_data* timer = heap_[0].timer_;
+ ops.push(timer->op_queue_);
+ remove_timer(*timer);
}
}
// Dequeue all timers.
virtual void get_all_timers(op_queue<operation>& ops)
{
- typename hash_map<void*, timer>::iterator i = timers_.begin();
- typename hash_map<void*, timer>::iterator end = timers_.end();
- while (i != end)
+ while (timers_)
{
- ops.push(i->second.op_queue_);
- typename hash_map<void*, timer>::iterator old_i = i++;
- timers_.erase(old_i);
+ per_timer_data* timer = timers_;
+ timers_ = timers_->next_;
+ ops.push(timer->op_queue_);
+ timer->next_ = 0;
+ timer->prev_ = 0;
}
heap_.clear();
- timers_.clear();
}
// Cancel and dequeue the timers with the given token.
- std::size_t cancel_timer(void* timer_token, op_queue<operation>& ops)
+ std::size_t cancel_timer(per_timer_data& timer, op_queue<operation>& ops)
{
std::size_t num_cancelled = 0;
- typedef typename hash_map<void*, timer>::iterator iterator;
- iterator it = timers_.find(timer_token);
- if (it != timers_.end())
+ if (timer.prev_ != 0 || &timer == timers_)
{
- while (timer_op* op = it->second.op_queue_.front())
+ while (timer_op* op = timer.op_queue_.front())
{
op->ec_ = asio::error::operation_aborted;
- it->second.op_queue_.pop();
+ timer.op_queue_.pop();
ops.push(op);
++num_cancelled;
}
- remove_timer(&it->second);
+ remove_timer(timer);
}
return num_cancelled;
}
private:
- // Structure representing a single outstanding timer.
- struct timer
- {
- timer() {}
- timer(const timer&) {}
- void operator=(const timer&) {}
-
- // The time when the timer should fire.
- time_type time_;
-
- // The operations waiting on the timer.
- op_queue<timer_op> op_queue_;
-
- // The index of the timer in the heap.
- size_t heap_index_;
-
- // The token associated with the timer.
- void* token_;
- };
-
// Move the item at the given index up the heap to its correct position.
- void up_heap(size_t index)
+ void up_heap(std::size_t index)
{
- size_t parent = (index - 1) / 2;
+ std::size_t parent = (index - 1) / 2;
while (index > 0
- && Time_Traits::less_than(heap_[index]->time_, heap_[parent]->time_))
+ && Time_Traits::less_than(heap_[index].time_, heap_[parent].time_))
{
swap_heap(index, parent);
index = parent;
@@ -203,16 +215,16 @@ private:
}
// Move the item at the given index down the heap to its correct position.
- void down_heap(size_t index)
+ void down_heap(std::size_t index)
{
- size_t child = index * 2 + 1;
+ std::size_t child = index * 2 + 1;
while (child < heap_.size())
{
- size_t min_child = (child + 1 == heap_.size()
+ std::size_t min_child = (child + 1 == heap_.size()
|| Time_Traits::less_than(
- heap_[child]->time_, heap_[child + 1]->time_))
+ heap_[child].time_, heap_[child + 1].time_))
? child : child + 1;
- if (Time_Traits::less_than(heap_[index]->time_, heap_[min_child]->time_))
+ if (Time_Traits::less_than(heap_[index].time_, heap_[min_child].time_))
break;
swap_heap(index, min_child);
index = min_child;
@@ -221,20 +233,20 @@ private:
}
// Swap two entries in the heap.
- void swap_heap(size_t index1, size_t index2)
+ void swap_heap(std::size_t index1, std::size_t index2)
{
- timer* tmp = heap_[index1];
+ heap_entry tmp = heap_[index1];
heap_[index1] = heap_[index2];
heap_[index2] = tmp;
- heap_[index1]->heap_index_ = index1;
- heap_[index2]->heap_index_ = index2;
+ heap_[index1].timer_->heap_index_ = index1;
+ heap_[index2].timer_->heap_index_ = index2;
}
// Remove a timer from the heap and list of timers.
- void remove_timer(timer* t)
+ void remove_timer(per_timer_data& timer)
{
// Remove the timer from the heap.
- size_t index = t->heap_index_;
+ std::size_t index = timer.heap_index_;
if (!heap_.empty() && index < heap_.size())
{
if (index == heap_.size() - 1)
@@ -245,29 +257,112 @@ private:
{
swap_heap(index, heap_.size() - 1);
heap_.pop_back();
- size_t parent = (index - 1) / 2;
+ std::size_t parent = (index - 1) / 2;
if (index > 0 && Time_Traits::less_than(
- heap_[index]->time_, heap_[parent]->time_))
+ heap_[index].time_, heap_[parent].time_))
up_heap(index);
else
down_heap(index);
}
}
- // Remove the timer from the hash.
- typedef typename hash_map<void*, timer>::iterator iterator;
- iterator it = timers_.find(t->token_);
- if (it != timers_.end())
- timers_.erase(it);
+ // Remove the timer from the linked list of active timers.
+ if (timers_ == &timer)
+ timers_ = timer.next_;
+ if (timer.prev_)
+ timer.prev_->next_ = timer.next_;
+ if (timer.next_)
+ timer.next_->prev_= timer.prev_;
+ timer.next_ = 0;
+ timer.prev_ = 0;
+ }
+
+ // Determine if the specified absolute time is positive infinity.
+ template <typename Time_Type>
+ static bool is_positive_infinity(const Time_Type&)
+ {
+ return false;
+ }
+
+ // Determine if the specified absolute time is positive infinity.
+ static bool is_positive_infinity(const boost::posix_time::ptime& time)
+ {
+ return time == boost::posix_time::pos_infin;
}
- // A hash of timer token to linked lists of timers.
- hash_map<void*, timer> timers_;
+ // The head of a linked list of all active timers.
+ per_timer_data* timers_;
+
+ struct heap_entry
+ {
+ // The time when the timer should fire.
+ time_type time_;
+
+ // The associated timer with enqueued operations.
+ per_timer_data* timer_;
+ };
// The heap of timers, with the earliest timer at the front.
- std::vector<timer*> heap_;
+ std::vector<heap_entry> heap_;
};
+#if !defined(ASIO_HEADER_ONLY)
+
+struct forwarding_posix_time_traits : time_traits<boost::posix_time::ptime> {};
+
+// Template specialisation for the commonly used instantation.
+template <>
+class timer_queue<time_traits<boost::posix_time::ptime> >
+ : public timer_queue_base
+{
+public:
+ // The time type.
+ typedef boost::posix_time::ptime time_type;
+
+ // The duration type.
+ typedef boost::posix_time::time_duration duration_type;
+
+ // Per-timer data.
+ typedef timer_queue<forwarding_posix_time_traits>::per_timer_data
+ per_timer_data;
+
+ // Constructor.
+ ASIO_DECL timer_queue();
+
+ // Destructor.
+ ASIO_DECL virtual ~timer_queue();
+
+ // Add a new timer to the queue. Returns true if this is the timer that is
+ // earliest in the queue, in which case the reactor's event demultiplexing
+ // function call may need to be interrupted and restarted.
+ ASIO_DECL bool enqueue_timer(const time_type& time,
+ per_timer_data& timer, timer_op* op);
+
+ // Whether there are no timers in the queue.
+ ASIO_DECL virtual bool empty() const;
+
+ // Get the time for the timer that is earliest in the queue.
+ ASIO_DECL virtual long wait_duration_msec(long max_duration) const;
+
+ // Get the time for the timer that is earliest in the queue.
+ ASIO_DECL virtual long wait_duration_usec(long max_duration) const;
+
+ // Dequeue all timers not later than the current time.
+ ASIO_DECL virtual void get_ready_timers(op_queue<operation>& ops);
+
+ // Dequeue all timers.
+ ASIO_DECL virtual void get_all_timers(op_queue<operation>& ops);
+
+ // Cancel and dequeue the timers with the given token.
+ ASIO_DECL std::size_t cancel_timer(
+ per_timer_data& timer, op_queue<operation>& ops);
+
+private:
+ timer_queue<forwarding_posix_time_traits> impl_;
+};
+
+#endif // !defined(ASIO_HEADER_ONLY)
+
} // namespace detail
} // namespace asio
diff --git a/ext/asio/asio/detail/timer_queue_base.hpp b/ext/asio/asio/detail/timer_queue_base.hpp
index f978667..0e8d4c7 100644
--- a/ext/asio/asio/detail/timer_queue_base.hpp
+++ b/ext/asio/asio/detail/timer_queue_base.hpp
@@ -1,8 +1,8 @@
//
-// timer_queue_base.hpp
-// ~~~~~~~~~~~~~~~~~~~~
+// detail/timer_queue_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/op_queue.hpp"
#include "asio/detail/operation.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
diff --git a/ext/asio/asio/detail/timer_queue_fwd.hpp b/ext/asio/asio/detail/timer_queue_fwd.hpp
index 5317244..0cca967 100644
--- a/ext/asio/asio/detail/timer_queue_fwd.hpp
+++ b/ext/asio/asio/detail/timer_queue_fwd.hpp
@@ -1,8 +1,8 @@
//
-// timer_queue_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// detail/timer_queue_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,8 +15,6 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
namespace asio {
namespace detail {
@@ -26,6 +24,4 @@ class timer_queue;
} // namespace detail
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_TIMER_QUEUE_FWD_HPP
diff --git a/ext/asio/asio/detail/timer_queue_set.hpp b/ext/asio/asio/detail/timer_queue_set.hpp
index 6860867..9e8d428 100644
--- a/ext/asio/asio/detail/timer_queue_set.hpp
+++ b/ext/asio/asio/detail/timer_queue_set.hpp
@@ -1,8 +1,8 @@
//
-// timer_queue_set.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// detail/timer_queue_set.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,10 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/detail/timer_queue_base.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -26,82 +27,28 @@ class timer_queue_set
{
public:
// Constructor.
- timer_queue_set()
- : first_(0)
- {
- }
+ ASIO_DECL timer_queue_set();
// Add a timer queue to the set.
- void insert(timer_queue_base* q)
- {
- q->next_ = first_;
- first_ = q;
- }
+ ASIO_DECL void insert(timer_queue_base* q);
// Remove a timer queue from the set.
- void erase(timer_queue_base* q)
- {
- if (first_)
- {
- if (q == first_)
- {
- first_ = q->next_;
- q->next_ = 0;
- return;
- }
-
- for (timer_queue_base* p = first_; p->next_; p = p->next_)
- {
- if (p->next_ == q)
- {
- p->next_ = q->next_;
- q->next_ = 0;
- return;
- }
- }
- }
- }
+ ASIO_DECL void erase(timer_queue_base* q);
// Determine whether all queues are empty.
- bool all_empty() const
- {
- for (timer_queue_base* p = first_; p; p = p->next_)
- if (!p->empty())
- return false;
- return true;
- }
+ ASIO_DECL bool all_empty() const;
// Get the wait duration in milliseconds.
- long wait_duration_msec(long max_duration) const
- {
- long min_duration = max_duration;
- for (timer_queue_base* p = first_; p; p = p->next_)
- min_duration = p->wait_duration_msec(min_duration);
- return min_duration;
- }
+ ASIO_DECL long wait_duration_msec(long max_duration) const;
// Get the wait duration in microseconds.
- long wait_duration_usec(long max_duration) const
- {
- long min_duration = max_duration;
- for (timer_queue_base* p = first_; p; p = p->next_)
- min_duration = p->wait_duration_usec(min_duration);
- return min_duration;
- }
+ ASIO_DECL long wait_duration_usec(long max_duration) const;
// Dequeue all ready timers.
- void get_ready_timers(op_queue<operation>& ops)
- {
- for (timer_queue_base* p = first_; p; p = p->next_)
- p->get_ready_timers(ops);
- }
+ ASIO_DECL void get_ready_timers(op_queue<operation>& ops);
// Dequeue all timers.
- void get_all_timers(op_queue<operation>& ops)
- {
- for (timer_queue_base* p = first_; p; p = p->next_)
- p->get_all_timers(ops);
- }
+ ASIO_DECL void get_all_timers(op_queue<operation>& ops);
private:
timer_queue_base* first_;
@@ -112,4 +59,8 @@ private:
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/timer_queue_set.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
#endif // ASIO_DETAIL_TIMER_QUEUE_SET_HPP
diff --git a/ext/asio/asio/detail/timer_scheduler.hpp b/ext/asio/asio/detail/timer_scheduler.hpp
index 6822d3f..1222e63 100644
--- a/ext/asio/asio/detail/timer_scheduler.hpp
+++ b/ext/asio/asio/detail/timer_scheduler.hpp
@@ -1,8 +1,8 @@
//
-// timer_scheduler.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// detail/timer_scheduler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,8 +15,7 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/detail/timer_scheduler_fwd.hpp"
#if defined(ASIO_HAS_IOCP)
@@ -31,6 +30,4 @@
# include "asio/detail/select_reactor.hpp"
#endif
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_TIMER_SCHEDULER_HPP
diff --git a/ext/asio/asio/detail/timer_scheduler_fwd.hpp b/ext/asio/asio/detail/timer_scheduler_fwd.hpp
index d766a87..5fced50 100644
--- a/ext/asio/asio/detail/timer_scheduler_fwd.hpp
+++ b/ext/asio/asio/detail/timer_scheduler_fwd.hpp
@@ -1,8 +1,8 @@
//
-// timer_scheduler_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~
+// detail/timer_scheduler_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,13 +15,19 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/dev_poll_reactor_fwd.hpp"
-#include "asio/detail/epoll_reactor_fwd.hpp"
-#include "asio/detail/kqueue_reactor_fwd.hpp"
-#include "asio/detail/select_reactor_fwd.hpp"
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_service_fwd.hpp"
+#elif defined(ASIO_HAS_EPOLL)
+# include "asio/detail/epoll_reactor_fwd.hpp"
+#elif defined(ASIO_HAS_KQUEUE)
+# include "asio/detail/kqueue_reactor_fwd.hpp"
+#elif defined(ASIO_HAS_DEV_POLL)
+# include "asio/detail/dev_poll_reactor_fwd.hpp"
+#else
+# include "asio/detail/select_reactor_fwd.hpp"
+#endif
namespace asio {
namespace detail {
@@ -35,12 +41,10 @@ typedef kqueue_reactor timer_scheduler;
#elif defined(ASIO_HAS_DEV_POLL)
typedef dev_poll_reactor timer_scheduler;
#else
-typedef select_reactor<false> timer_scheduler;
+typedef select_reactor timer_scheduler;
#endif
} // namespace detail
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP
diff --git a/ext/asio/asio/detail/tss_ptr.hpp b/ext/asio/asio/detail/tss_ptr.hpp
index ac67d9f..0218f5f 100644
--- a/ext/asio/asio/detail/tss_ptr.hpp
+++ b/ext/asio/asio/detail/tss_ptr.hpp
@@ -1,8 +1,8 @@
//
-// tss_ptr.hpp
-// ~~~~~~~~~~~
+// detail/tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,7 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
# include "asio/detail/null_tss_ptr.hpp"
@@ -31,6 +27,8 @@
# error Only Windows and POSIX are supported!
#endif
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
diff --git a/ext/asio/asio/detail/wait_handler.hpp b/ext/asio/asio/detail/wait_handler.hpp
new file mode 100644
index 0000000..0df16cb
--- /dev/null
+++ b/ext/asio/asio/detail/wait_handler.hpp
@@ -0,0 +1,76 @@
+//
+// detail/wait_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WAIT_HANDLER_HPP
+#define ASIO_DETAIL_WAIT_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/timer_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class wait_handler : public timer_op
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(wait_handler);
+
+ wait_handler(Handler h)
+ : timer_op(&wait_handler::do_complete),
+ handler_(h)
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ wait_handler* h(static_cast<wait_handler*>(base));
+ ptr p = { boost::addressof(h->handler_), h, h };
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder1<Handler, asio::error_code>
+ handler(h->handler_, h->ec_);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WAIT_HANDLER_HPP
diff --git a/ext/asio/asio/detail/weak_ptr.hpp b/ext/asio/asio/detail/weak_ptr.hpp
new file mode 100644
index 0000000..35dca19
--- /dev/null
+++ b/ext/asio/asio/detail/weak_ptr.hpp
@@ -0,0 +1,39 @@
+//
+// detail/weak_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WEAK_PTR_HPP
+#define ASIO_DETAIL_WEAK_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/version.hpp>
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1600)
+# include <memory>
+#else
+# include <boost/weak_ptr.hpp>
+#endif
+
+namespace asio {
+namespace detail {
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1600)
+using std::weak_ptr;
+#else
+using boost::weak_ptr;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_WEAK_PTR_HPP
diff --git a/ext/asio/asio/detail/win_event.hpp b/ext/asio/asio/detail/win_event.hpp
index cabb2c3..71ad7e0 100644
--- a/ext/asio/asio/detail/win_event.hpp
+++ b/ext/asio/asio/detail/win_event.hpp
@@ -1,8 +1,8 @@
//
-// win_event.hpp
-// ~~~~~~~~~~~~~
+// detail/win_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,23 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if defined(BOOST_WINDOWS)
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
+#include <boost/assert.hpp>
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/push_options.hpp"
-#include <boost/assert.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
@@ -41,19 +33,7 @@ class win_event
{
public:
// Constructor.
- win_event()
- : event_(::CreateEvent(0, true, false, 0))
- {
- if (!event_)
- {
- DWORD last_error = ::GetLastError();
- asio::system_error e(
- asio::error_code(last_error,
- asio::error::get_system_category()),
- "event");
- boost::throw_exception(e);
- }
- }
+ ASIO_DECL win_event();
// Destructor.
~win_event()
@@ -105,8 +85,12 @@ private:
} // namespace detail
} // namespace asio
-#endif // defined(BOOST_WINDOWS)
-
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_event.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_WINDOWS)
+
#endif // ASIO_DETAIL_WIN_EVENT_HPP
diff --git a/ext/asio/asio/detail/win_fd_set_adapter.hpp b/ext/asio/asio/detail/win_fd_set_adapter.hpp
index 012a10f..0cb9d8c 100644
--- a/ext/asio/asio/detail/win_fd_set_adapter.hpp
+++ b/ext/asio/asio/detail/win_fd_set_adapter.hpp
@@ -1,8 +1,8 @@
//
-// win_fd_set_adapter.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~
+// detail/win_fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/socket_types.hpp"
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -81,8 +83,8 @@ private:
} // namespace detail
} // namespace asio
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-
#include "asio/detail/pop_options.hpp"
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
#endif // ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
diff --git a/ext/asio/asio/detail/win_fenced_block.hpp b/ext/asio/asio/detail/win_fenced_block.hpp
index 6338488..011f44b 100644
--- a/ext/asio/asio/detail/win_fenced_block.hpp
+++ b/ext/asio/asio/detail/win_fenced_block.hpp
@@ -1,8 +1,8 @@
//
-// win_fenced_block.hpp
-// ~~~~~~~~~~~~~~~~~~~~
+// detail/win_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if defined(BOOST_WINDOWS) && !defined(UNDER_CE)
#include "asio/detail/socket_types.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -35,7 +33,10 @@ public:
// Constructor.
win_fenced_block()
{
-#if defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+#if defined(__BORLANDC__)
+ LONG barrier = 0;
+ ::InterlockedExchange(&barrier, 1);
+#elif defined(BOOST_MSVC) && ((BOOST_MSVC < 1400) || !defined(MemoryBarrier))
# if defined(_M_IX86)
# pragma warning(push)
# pragma warning(disable:4793)
@@ -43,15 +44,18 @@ public:
__asm { xchg barrier, eax }
# pragma warning(pop)
# endif // defined(_M_IX86)
-#else // defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+#else
MemoryBarrier();
-#endif // defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+#endif
}
// Destructor.
~win_fenced_block()
{
-#if defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+#if defined(__BORLANDC__)
+ LONG barrier = 0;
+ ::InterlockedExchange(&barrier, 1);
+#elif defined(BOOST_MSVC) && ((BOOST_MSVC < 1400) || !defined(MemoryBarrier))
# if defined(_M_IX86)
# pragma warning(push)
# pragma warning(disable:4793)
@@ -59,17 +63,17 @@ public:
__asm { xchg barrier, eax }
# pragma warning(pop)
# endif // defined(_M_IX86)
-#else // defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+#else
MemoryBarrier();
-#endif // defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+#endif
}
};
} // namespace detail
} // namespace asio
-#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE)
-
#include "asio/detail/pop_options.hpp"
+#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE)
+
#endif // ASIO_DETAIL_WIN_FENCED_BLOCK_HPP
diff --git a/ext/asio/asio/detail/win_iocp_handle_read_op.hpp b/ext/asio/asio/detail/win_iocp_handle_read_op.hpp
new file mode 100644
index 0000000..fb358be
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_handle_read_op.hpp
@@ -0,0 +1,101 @@
+//
+// detail/win_iocp_handle_read_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/error.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Handler>
+class win_iocp_handle_read_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_read_op);
+
+ win_iocp_handle_read_op(const MutableBufferSequence& buffers, Handler handler)
+ : operation(&win_iocp_handle_read_op::do_complete),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code ec, std::size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ win_iocp_handle_read_op* o(static_cast<win_iocp_handle_read_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ if (owner)
+ {
+ // Check whether buffers are still valid.
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::validate(o->buffers_);
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_HANDLE_EOF)
+ ec = asio::error::eof;
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ MutableBufferSequence buffers_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP
diff --git a/ext/asio/asio/detail/win_iocp_handle_service.hpp b/ext/asio/asio/detail/win_iocp_handle_service.hpp
index bfc159c..34f725f 100644
--- a/ext/asio/asio/detail/win_iocp_handle_service.hpp
+++ b/ext/asio/asio/detail/win_iocp_handle_service.hpp
@@ -1,8 +1,8 @@
//
-// win_iocp_handle_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/win_iocp_handle_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,26 +16,23 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_IOCP)
-#include "asio/detail/push_options.hpp"
#include <boost/cstdint.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/error.hpp"
#include "asio/io_service.hpp"
-#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffer_sequence_adapter.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
-#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/operation.hpp"
+#include "asio/detail/win_iocp_handle_read_op.hpp"
+#include "asio/detail/win_iocp_handle_write_op.hpp"
#include "asio/detail/win_iocp_io_service.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -76,75 +73,20 @@ public:
implementation_type* prev_;
};
- win_iocp_handle_service(asio::io_service& io_service)
- : iocp_service_(asio::use_service<win_iocp_io_service>(io_service)),
- mutex_(),
- impl_list_(0)
- {
- }
+ ASIO_DECL win_iocp_handle_service(asio::io_service& io_service);
// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- // Close all implementations, causing all operations to complete.
- asio::detail::mutex::scoped_lock lock(mutex_);
- implementation_type* impl = impl_list_;
- while (impl)
- {
- close_for_destruction(*impl);
- impl = impl->next_;
- }
- }
+ ASIO_DECL void shutdown_service();
// Construct a new handle implementation.
- void construct(implementation_type& impl)
- {
- impl.handle_ = INVALID_HANDLE_VALUE;
- impl.safe_cancellation_thread_id_ = 0;
-
- // Insert implementation into linked list of all implementations.
- asio::detail::mutex::scoped_lock lock(mutex_);
- impl.next_ = impl_list_;
- impl.prev_ = 0;
- if (impl_list_)
- impl_list_->prev_ = &impl;
- impl_list_ = &impl;
- }
+ ASIO_DECL void construct(implementation_type& impl);
// Destroy a handle implementation.
- void destroy(implementation_type& impl)
- {
- close_for_destruction(impl);
-
- // Remove implementation from linked list of all implementations.
- asio::detail::mutex::scoped_lock lock(mutex_);
- if (impl_list_ == &impl)
- impl_list_ = impl.next_;
- if (impl.prev_)
- impl.prev_->next_ = impl.next_;
- if (impl.next_)
- impl.next_->prev_= impl.prev_;
- impl.next_ = 0;
- impl.prev_ = 0;
- }
+ ASIO_DECL void destroy(implementation_type& impl);
// Assign a native handle to a handle implementation.
- asio::error_code assign(implementation_type& impl,
- const native_type& native_handle, asio::error_code& ec)
- {
- if (is_open(impl))
- {
- ec = asio::error::already_open;
- return ec;
- }
-
- if (iocp_service_.register_handle(native_handle, ec))
- return ec;
-
- impl.handle_ = native_handle;
- ec = asio::error_code();
- return ec;
- }
+ ASIO_DECL asio::error_code assign(implementation_type& impl,
+ const native_type& native_handle, asio::error_code& ec);
// Determine whether the handle is open.
bool is_open(const implementation_type& impl) const
@@ -153,26 +95,8 @@ public:
}
// Destroy a handle implementation.
- asio::error_code close(implementation_type& impl,
- asio::error_code& ec)
- {
- if (is_open(impl))
- {
- if (!::CloseHandle(impl.handle_))
- {
- DWORD last_error = ::GetLastError();
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- return ec;
- }
-
- impl.handle_ = INVALID_HANDLE_VALUE;
- impl.safe_cancellation_thread_id_ = 0;
- }
-
- ec = asio::error_code();
- return ec;
- }
+ ASIO_DECL asio::error_code close(implementation_type& impl,
+ asio::error_code& ec);
// Get the native handle representation.
native_type native(const implementation_type& impl) const
@@ -181,106 +105,8 @@ public:
}
// Cancel all operations associated with the handle.
- asio::error_code cancel(implementation_type& impl,
- asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- }
- else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
- ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
- {
- // The version of Windows supports cancellation from any thread.
- typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
- cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
- if (!cancel_io_ex(impl.handle_, 0))
- {
- DWORD last_error = ::GetLastError();
- if (last_error == ERROR_NOT_FOUND)
- {
- // ERROR_NOT_FOUND means that there were no operations to be
- // cancelled. We swallow this error to match the behaviour on other
- // platforms.
- ec = asio::error_code();
- }
- else
- {
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- }
- }
- else
- {
- ec = asio::error_code();
- }
- }
- else if (impl.safe_cancellation_thread_id_ == 0)
- {
- // No operations have been started, so there's nothing to cancel.
- ec = asio::error_code();
- }
- else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
- {
- // Asynchronous operations have been started from the current thread only,
- // so it is safe to try to cancel them using CancelIo.
- if (!::CancelIo(impl.handle_))
- {
- DWORD last_error = ::GetLastError();
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- }
- else
- {
- ec = asio::error_code();
- }
- }
- else
- {
- // Asynchronous operations have been started from more than one thread,
- // so cancellation is not safe.
- ec = asio::error::operation_not_supported;
- }
-
- return ec;
- }
-
- class overlapped_wrapper
- : public OVERLAPPED
- {
- public:
- explicit overlapped_wrapper(asio::error_code& ec)
- {
- Internal = 0;
- InternalHigh = 0;
- Offset = 0;
- OffsetHigh = 0;
-
- // Create a non-signalled manual-reset event, for GetOverlappedResult.
- hEvent = ::CreateEvent(0, TRUE, FALSE, 0);
- if (hEvent)
- {
- // As documented in GetQueuedCompletionStatus, setting the low order
- // bit of this event prevents our synchronous writes from being treated
- // as completion port events.
- *reinterpret_cast<DWORD_PTR*>(&hEvent) |= 1;
- }
- else
- {
- DWORD last_error = ::GetLastError();
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- }
- }
-
- ~overlapped_wrapper()
- {
- if (hEvent)
- {
- ::CloseHandle(hEvent);
- }
- }
- };
+ ASIO_DECL asio::error_code cancel(implementation_type& impl,
+ asio::error_code& ec);
// Write the given data. Returns the number of bytes written.
template <typename ConstBufferSequence>
@@ -296,109 +122,13 @@ public:
size_t write_some_at(implementation_type& impl, boost::uint64_t offset,
const ConstBufferSequence& buffers, asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
asio::const_buffer buffer =
buffer_sequence_adapter<asio::const_buffer,
ConstBufferSequence>::first(buffers);
- // A request to write 0 bytes on a handle is a no-op.
- if (asio::buffer_size(buffer) == 0)
- {
- ec = asio::error_code();
- return 0;
- }
-
- overlapped_wrapper overlapped(ec);
- if (ec)
- {
- return 0;
- }
-
- // Write the data.
- overlapped.Offset = offset & 0xFFFFFFFF;
- overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
- BOOL ok = ::WriteFile(impl.handle_,
- asio::buffer_cast<LPCVOID>(buffer),
- static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped);
- if (!ok)
- {
- DWORD last_error = ::GetLastError();
- if (last_error != ERROR_IO_PENDING)
- {
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- return 0;
- }
- }
-
- // Wait for the operation to complete.
- DWORD bytes_transferred = 0;
- ok = ::GetOverlappedResult(impl.handle_,
- &overlapped, &bytes_transferred, TRUE);
- if (!ok)
- {
- DWORD last_error = ::GetLastError();
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- return 0;
- }
-
- ec = asio::error_code();
- return bytes_transferred;
+ return do_write(impl, offset, buffer, ec);
}
- template <typename ConstBufferSequence, typename Handler>
- class write_op : public operation
- {
- public:
- write_op(const ConstBufferSequence& buffers, Handler handler)
- : operation(&write_op::do_complete),
- buffers_(buffers),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code ec, std::size_t bytes_transferred)
- {
- // Take ownership of the operation object.
- write_op* o(static_cast<write_op*>(base));
- typedef handler_alloc_traits<Handler, write_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
-#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
- // Check whether buffers are still valid.
- buffer_sequence_adapter<asio::const_buffer,
- ConstBufferSequence>::validate(o->buffers_);
-#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder2<Handler, asio::error_code, std::size_t>
- handler(o->handler_, ec, bytes_transferred);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- ConstBufferSequence buffers_;
- Handler handler_;
- };
-
// Start an asynchronous write. The data being written must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
@@ -415,15 +145,16 @@ public:
const ConstBufferSequence& buffers, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef write_op<ConstBufferSequence, Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, buffers, handler);
+ typedef win_iocp_handle_write_op<ConstBufferSequence, Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(buffers, handler);
start_write_op(impl, offset,
buffer_sequence_adapter<asio::const_buffer,
- ConstBufferSequence>::first(buffers), ptr.get());
- ptr.release();
+ ConstBufferSequence>::first(buffers), p.p);
+ p.v = p.p = 0;
}
// Read some data. Returns the number of bytes received.
@@ -439,129 +170,13 @@ public:
size_t read_some_at(implementation_type& impl, boost::uint64_t offset,
const MutableBufferSequence& buffers, asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
asio::mutable_buffer buffer =
buffer_sequence_adapter<asio::mutable_buffer,
MutableBufferSequence>::first(buffers);
- // A request to read 0 bytes on a stream handle is a no-op.
- if (asio::buffer_size(buffer) == 0)
- {
- ec = asio::error_code();
- return 0;
- }
-
- overlapped_wrapper overlapped(ec);
- if (ec)
- {
- return 0;
- }
-
- // Read some data.
- overlapped.Offset = offset & 0xFFFFFFFF;
- overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
- BOOL ok = ::ReadFile(impl.handle_,
- asio::buffer_cast<LPVOID>(buffer),
- static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped);
- if (!ok)
- {
- DWORD last_error = ::GetLastError();
- if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA)
- {
- if (last_error == ERROR_HANDLE_EOF)
- {
- ec = asio::error::eof;
- }
- else
- {
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- }
- return 0;
- }
- }
-
- // Wait for the operation to complete.
- DWORD bytes_transferred = 0;
- ok = ::GetOverlappedResult(impl.handle_,
- &overlapped, &bytes_transferred, TRUE);
- if (!ok)
- {
- DWORD last_error = ::GetLastError();
- if (last_error == ERROR_HANDLE_EOF)
- {
- ec = asio::error::eof;
- }
- else
- {
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- }
- return 0;
- }
-
- ec = asio::error_code();
- return bytes_transferred;
+ return do_read(impl, offset, buffer, ec);
}
- template <typename MutableBufferSequence, typename Handler>
- class read_op : public operation
- {
- public:
- read_op(const MutableBufferSequence& buffers, Handler handler)
- : operation(&read_op::do_complete),
- buffers_(buffers),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code ec, std::size_t bytes_transferred)
- {
- // Take ownership of the operation object.
- read_op* o(static_cast<read_op*>(base));
- typedef handler_alloc_traits<Handler, read_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
-#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
- // Check whether buffers are still valid.
- buffer_sequence_adapter<asio::mutable_buffer,
- MutableBufferSequence>::validate(o->buffers_);
-#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-
- // Map non-portable errors to their portable counterparts.
- if (ec.value() == ERROR_HANDLE_EOF)
- {
- ec = asio::error::eof;
- }
-
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder2<Handler, asio::error_code, std::size_t>
- handler(o->handler_, ec, bytes_transferred);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- MutableBufferSequence buffers_;
- Handler handler_;
- };
-
// Start an asynchronous read. The buffer for the data being received must be
// valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
@@ -579,15 +194,16 @@ public:
const MutableBufferSequence& buffers, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef read_op<MutableBufferSequence, Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, buffers, handler);
+ typedef win_iocp_handle_read_op<MutableBufferSequence, Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(buffers, handler);
start_read_op(impl, offset,
buffer_sequence_adapter<asio::mutable_buffer,
- MutableBufferSequence>::first(buffers), ptr.get());
- ptr.release();
+ MutableBufferSequence>::first(buffers), p.p);
+ p.v = p.p = 0;
}
private:
@@ -613,113 +229,42 @@ private:
void async_read_some_at(implementation_type& impl, boost::uint64_t offset,
const null_buffers& buffers, Handler handler);
+ // Helper class for waiting for synchronous operations to complete.
+ class overlapped_wrapper;
+
+ // Helper function to perform a synchronous write operation.
+ ASIO_DECL size_t do_write(implementation_type& impl,
+ boost::uint64_t offset, const asio::const_buffer& buffer,
+ asio::error_code& ec);
+
// Helper function to start a write operation.
- void start_write_op(implementation_type& impl, boost::uint64_t offset,
- const asio::const_buffer& buffer, operation* op)
- {
- update_cancellation_thread_id(impl);
- iocp_service_.work_started();
+ ASIO_DECL void start_write_op(implementation_type& impl,
+ boost::uint64_t offset, const asio::const_buffer& buffer,
+ operation* op);
- if (!is_open(impl))
- {
- iocp_service_.on_completion(op, asio::error::bad_descriptor);
- }
- else if (asio::buffer_size(buffer) == 0)
- {
- // A request to write 0 bytes on a handle is a no-op.
- iocp_service_.on_completion(op);
- }
- else
- {
- DWORD bytes_transferred = 0;
- op->Offset = offset & 0xFFFFFFFF;
- op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
- BOOL ok = ::WriteFile(impl.handle_,
- asio::buffer_cast<LPCVOID>(buffer),
- static_cast<DWORD>(asio::buffer_size(buffer)),
- &bytes_transferred, op);
- DWORD last_error = ::GetLastError();
- if (!ok && last_error != ERROR_IO_PENDING
- && last_error != ERROR_MORE_DATA)
- {
- iocp_service_.on_completion(op, last_error, bytes_transferred);
- }
- else
- {
- iocp_service_.on_pending(op);
- }
- }
- }
+ // Helper function to perform a synchronous write operation.
+ ASIO_DECL size_t do_read(implementation_type& impl,
+ boost::uint64_t offset, const asio::mutable_buffer& buffer,
+ asio::error_code& ec);
// Helper function to start a read operation.
- void start_read_op(implementation_type& impl, boost::uint64_t offset,
- const asio::mutable_buffer& buffer, operation* op)
- {
- update_cancellation_thread_id(impl);
- iocp_service_.work_started();
-
- if (!is_open(impl))
- {
- iocp_service_.on_completion(op, asio::error::bad_descriptor);
- }
- else if (asio::buffer_size(buffer) == 0)
- {
- // A request to read 0 bytes on a handle is a no-op.
- iocp_service_.on_completion(op);
- }
- else
- {
- DWORD bytes_transferred = 0;
- op->Offset = offset & 0xFFFFFFFF;
- op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
- BOOL ok = ::ReadFile(impl.handle_,
- asio::buffer_cast<LPVOID>(buffer),
- static_cast<DWORD>(asio::buffer_size(buffer)),
- &bytes_transferred, op);
- DWORD last_error = ::GetLastError();
- if (!ok && last_error != ERROR_IO_PENDING
- && last_error != ERROR_MORE_DATA)
- {
- iocp_service_.on_completion(op, last_error, bytes_transferred);
- }
- else
- {
- iocp_service_.on_pending(op);
- }
- }
- }
+ ASIO_DECL void start_read_op(implementation_type& impl,
+ boost::uint64_t offset, const asio::mutable_buffer& buffer,
+ operation* op);
// Update the ID of the thread from which cancellation is safe.
- void update_cancellation_thread_id(implementation_type& impl)
- {
-#if defined(ASIO_ENABLE_CANCELIO)
- if (impl.safe_cancellation_thread_id_ == 0)
- impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
- else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
- impl.safe_cancellation_thread_id_ = ~DWORD(0);
-#else // defined(ASIO_ENABLE_CANCELIO)
- (void)impl;
-#endif // defined(ASIO_ENABLE_CANCELIO)
- }
+ ASIO_DECL void update_cancellation_thread_id(implementation_type& impl);
// Helper function to close a handle when the associated object is being
// destroyed.
- void close_for_destruction(implementation_type& impl)
- {
- if (is_open(impl))
- {
- ::CloseHandle(impl.handle_);
- impl.handle_ = INVALID_HANDLE_VALUE;
- impl.safe_cancellation_thread_id_ = 0;
- }
- }
+ ASIO_DECL void close_for_destruction(implementation_type& impl);
// The IOCP service used for running asynchronous operations and dispatching
// handlers.
win_iocp_io_service& iocp_service_;
// Mutex to protect access to the linked list of implementations.
- asio::detail::mutex mutex_;
+ mutex mutex_;
// The head of a linked list of all implementations.
implementation_type* impl_list_;
@@ -728,8 +273,12 @@ private:
} // namespace detail
} // namespace asio
-#endif // defined(ASIO_HAS_IOCP)
-
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_iocp_handle_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP)
+
#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
diff --git a/ext/asio/asio/detail/win_iocp_handle_write_op.hpp b/ext/asio/asio/detail/win_iocp_handle_write_op.hpp
new file mode 100644
index 0000000..ddfe8fc
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_handle_write_op.hpp
@@ -0,0 +1,97 @@
+//
+// detail/win_iocp_handle_write_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/error.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence, typename Handler>
+class win_iocp_handle_write_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_write_op);
+
+ win_iocp_handle_write_op(const ConstBufferSequence& buffers, Handler handler)
+ : operation(&win_iocp_handle_write_op::do_complete),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code ec, std::size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ win_iocp_handle_write_op* o(static_cast<win_iocp_handle_write_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ if (owner)
+ {
+ // Check whether buffers are still valid.
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence>::validate(o->buffers_);
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ ConstBufferSequence buffers_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP
diff --git a/ext/asio/asio/detail/win_iocp_io_service.hpp b/ext/asio/asio/detail/win_iocp_io_service.hpp
index fd899c1..c8974b6 100644
--- a/ext/asio/asio/detail/win_iocp_io_service.hpp
+++ b/ext/asio/asio/detail/win_iocp_io_service.hpp
@@ -1,8 +1,8 @@
//
-// win_iocp_io_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~
+// detail/win_iocp_io_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,33 +15,24 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_IOCP)
-#include "asio/detail/push_options.hpp"
-#include <boost/limits.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include <boost/scoped_ptr.hpp>
#include "asio/io_service.hpp"
-#include "asio/system_error.hpp"
-#include "asio/detail/call_stack.hpp"
-#include "asio/detail/completion_handler.hpp"
-#include "asio/detail/fenced_block.hpp"
-#include "asio/detail/handler_alloc_helpers.hpp"
-#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/op_queue.hpp"
-#include "asio/detail/service_base.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_op.hpp"
#include "asio/detail/timer_queue_base.hpp"
#include "asio/detail/timer_queue_fwd.hpp"
#include "asio/detail/timer_queue_set.hpp"
+#include "asio/detail/win_iocp_io_service_fwd.hpp"
#include "asio/detail/win_iocp_operation.hpp"
+#include "asio/detail/thread.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -52,69 +43,13 @@ class win_iocp_io_service
: public asio::detail::service_base<win_iocp_io_service>
{
public:
- typedef win_iocp_operation operation;
-
// Constructor.
- win_iocp_io_service(asio::io_service& io_service)
- : asio::detail::service_base<win_iocp_io_service>(io_service),
- iocp_(),
- outstanding_work_(0),
- stopped_(0),
- shutdown_(0),
- timer_thread_(0),
- timer_interrupt_issued_(false)
- {
- }
+ ASIO_DECL win_iocp_io_service(asio::io_service& io_service);
- void init(size_t concurrency_hint)
- {
- iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,
- static_cast<DWORD>((std::min<size_t>)(concurrency_hint, DWORD(~0))));
- if (!iocp_.handle)
- {
- DWORD last_error = ::GetLastError();
- asio::system_error e(
- asio::error_code(last_error,
- asio::error::get_system_category()),
- "iocp");
- boost::throw_exception(e);
- }
- }
+ ASIO_DECL void init(size_t concurrency_hint);
// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- ::InterlockedExchange(&shutdown_, 1);
-
- while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0)
- {
- op_queue<operation> ops;
- timer_queues_.get_all_timers(ops);
- ops.push(completed_ops_);
- if (!ops.empty())
- {
- while (operation* op = ops.front())
- {
- ops.pop();
- ::InterlockedDecrement(&outstanding_work_);
- op->destroy();
- }
- }
- else
- {
- DWORD bytes_transferred = 0;
- dword_ptr_t completion_key = 0;
- LPOVERLAPPED overlapped = 0;
- ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
- &completion_key, &overlapped, max_timeout);
- if (overlapped)
- {
- ::InterlockedDecrement(&outstanding_work_);
- static_cast<operation*>(overlapped)->destroy();
- }
- }
- }
- }
+ ASIO_DECL void shutdown_service();
// Initialise the task. Nothing to do here.
void init_task()
@@ -122,106 +57,23 @@ public:
}
// Register a handle with the IO completion port.
- asio::error_code register_handle(
- HANDLE handle, asio::error_code& ec)
- {
- if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0)
- {
- DWORD last_error = ::GetLastError();
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- }
- else
- {
- ec = asio::error_code();
- }
- return ec;
- }
+ ASIO_DECL asio::error_code register_handle(
+ HANDLE handle, asio::error_code& ec);
// Run the event loop until stopped or no more work.
- size_t run(asio::error_code& ec)
- {
- if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
- {
- stop();
- ec = asio::error_code();
- return 0;
- }
-
- call_stack<win_iocp_io_service>::context ctx(this);
-
- size_t n = 0;
- while (do_one(true, ec))
- if (n != (std::numeric_limits<size_t>::max)())
- ++n;
- return n;
- }
+ ASIO_DECL size_t run(asio::error_code& ec);
// Run until stopped or one operation is performed.
- size_t run_one(asio::error_code& ec)
- {
- if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
- {
- stop();
- ec = asio::error_code();
- return 0;
- }
-
- call_stack<win_iocp_io_service>::context ctx(this);
-
- return do_one(true, ec);
- }
+ ASIO_DECL size_t run_one(asio::error_code& ec);
// Poll for operations without blocking.
- size_t poll(asio::error_code& ec)
- {
- if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
- {
- stop();
- ec = asio::error_code();
- return 0;
- }
-
- call_stack<win_iocp_io_service>::context ctx(this);
-
- size_t n = 0;
- while (do_one(false, ec))
- if (n != (std::numeric_limits<size_t>::max)())
- ++n;
- return n;
- }
+ ASIO_DECL size_t poll(asio::error_code& ec);
// Poll for one operation without blocking.
- size_t poll_one(asio::error_code& ec)
- {
- if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
- {
- stop();
- ec = asio::error_code();
- return 0;
- }
-
- call_stack<win_iocp_io_service>::context ctx(this);
-
- return do_one(false, ec);
- }
+ ASIO_DECL size_t poll_one(asio::error_code& ec);
// Stop the event processing loop.
- void stop()
- {
- if (::InterlockedExchange(&stopped_, 1) == 0)
- {
- if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
- {
- DWORD last_error = ::GetLastError();
- asio::system_error e(
- asio::error_code(last_error,
- asio::error::get_system_category()),
- "pqcs");
- boost::throw_exception(e);
- }
- }
- }
+ ASIO_DECL void stop();
// Reset in preparation for a subsequent run invocation.
void reset()
@@ -244,34 +96,15 @@ public:
// Request invocation of the given handler.
template <typename Handler>
- void dispatch(Handler handler)
- {
- if (call_stack<win_iocp_io_service>::contains(this))
- {
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- else
- post(handler);
- }
+ void dispatch(Handler handler);
// Request invocation of the given handler and return immediately.
template <typename Handler>
- void post(Handler handler)
- {
- // Allocate and construct an operation to wrap the handler.
- typedef completion_handler<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
- post_immediate_completion(ptr.get());
- ptr.release();
- }
+ void post(Handler handler);
// Request invocation of the given operation and return immediately. Assumes
// that work_started() has not yet been called for the operation.
- void post_immediate_completion(operation* op)
+ void post_immediate_completion(win_iocp_operation* op)
{
work_started();
post_deferred_completion(op);
@@ -279,170 +112,50 @@ public:
// Request invocation of the given operation and return immediately. Assumes
// that work_started() was previously called for the operation.
- void post_deferred_completion(operation* op)
- {
- // Flag the operation as ready.
- op->ready_ = 1;
-
- // Enqueue the operation on the I/O completion port.
- if (!::PostQueuedCompletionStatus(iocp_.handle,
- 0, overlapped_contains_result, op))
- {
- // Out of resources. Put on completed queue instead.
- asio::detail::mutex::scoped_lock lock(timer_mutex_);
- completed_ops_.push(op);
- }
- }
+ ASIO_DECL void post_deferred_completion(win_iocp_operation* op);
// Request invocation of the given operation and return immediately. Assumes
// that work_started() was previously called for the operations.
- void post_deferred_completions(op_queue<operation>& ops)
- {
- while (operation* op = ops.front())
- {
- ops.pop();
-
- // Flag the operation as ready.
- op->ready_ = 1;
-
- // Enqueue the operation on the I/O completion port.
- if (!::PostQueuedCompletionStatus(iocp_.handle,
- 0, overlapped_contains_result, op))
- {
- // Out of resources. Put on completed queue instead.
- asio::detail::mutex::scoped_lock lock(timer_mutex_);
- completed_ops_.push(op);
- completed_ops_.push(ops);
- }
- }
- }
+ ASIO_DECL void post_deferred_completions(
+ op_queue<win_iocp_operation>& ops);
// Called after starting an overlapped I/O operation that did not complete
// immediately. The caller must have already called work_started() prior to
// starting the operation.
- void on_pending(operation* op)
- {
- if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
- {
- // Enqueue the operation on the I/O completion port.
- if (!::PostQueuedCompletionStatus(iocp_.handle,
- 0, overlapped_contains_result, op))
- {
- // Out of resources. Put on completed queue instead.
- asio::detail::mutex::scoped_lock lock(timer_mutex_);
- completed_ops_.push(op);
- }
- }
- }
+ ASIO_DECL void on_pending(win_iocp_operation* op);
// Called after starting an overlapped I/O operation that completed
// immediately. The caller must have already called work_started() prior to
// starting the operation.
- void on_completion(operation* op,
- DWORD last_error = 0, DWORD bytes_transferred = 0)
- {
- // Flag that the operation is ready for invocation.
- op->ready_ = 1;
-
- // Store results in the OVERLAPPED structure.
- op->Internal = asio::error::get_system_category();
- op->Offset = last_error;
- op->OffsetHigh = bytes_transferred;
-
- // Enqueue the operation on the I/O completion port.
- if (!::PostQueuedCompletionStatus(iocp_.handle,
- 0, overlapped_contains_result, op))
- {
- // Out of resources. Put on completed queue instead.
- asio::detail::mutex::scoped_lock lock(timer_mutex_);
- completed_ops_.push(op);
- }
- }
+ ASIO_DECL void on_completion(win_iocp_operation* op,
+ DWORD last_error = 0, DWORD bytes_transferred = 0);
// Called after starting an overlapped I/O operation that completed
// immediately. The caller must have already called work_started() prior to
// starting the operation.
- void on_completion(operation* op,
- const asio::error_code& ec, DWORD bytes_transferred = 0)
- {
- // Flag that the operation is ready for invocation.
- op->ready_ = 1;
-
- // Store results in the OVERLAPPED structure.
- op->Internal = ec.category();
- op->Offset = ec.value();
- op->OffsetHigh = bytes_transferred;
-
- // Enqueue the operation on the I/O completion port.
- if (!::PostQueuedCompletionStatus(iocp_.handle,
- 0, overlapped_contains_result, op))
- {
- // Out of resources. Put on completed queue instead.
- asio::detail::mutex::scoped_lock lock(timer_mutex_);
- completed_ops_.push(op);
- }
- }
+ ASIO_DECL void on_completion(win_iocp_operation* op,
+ const asio::error_code& ec, DWORD bytes_transferred = 0);
// Add a new timer queue to the service.
template <typename Time_Traits>
- void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
- {
- asio::detail::mutex::scoped_lock lock(timer_mutex_);
- timer_queues_.insert(&timer_queue);
- }
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue);
// Remove a timer queue from the service.
template <typename Time_Traits>
- void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
- {
- asio::detail::mutex::scoped_lock lock(timer_mutex_);
- timer_queues_.erase(&timer_queue);
- }
+ void remove_timer_queue(timer_queue<Time_Traits>& timer_queue);
// Schedule a new operation in the given timer queue to expire at the
// specified absolute time.
template <typename Time_Traits>
- void schedule_timer(timer_queue<Time_Traits>& timer_queue,
- const typename Time_Traits::time_type& time, timer_op* op, void* token)
- {
- // If the service has been shut down we silently discard the timer.
- if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
- return;
-
- asio::detail::mutex::scoped_lock lock(timer_mutex_);
- bool interrupt = timer_queue.enqueue_timer(time, op, token);
- work_started();
- if (interrupt && !timer_interrupt_issued_)
- {
- timer_interrupt_issued_ = true;
- lock.unlock();
- ::PostQueuedCompletionStatus(iocp_.handle,
- 0, steal_timer_dispatching, 0);
- }
- }
+ void schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op);
// Cancel the timer associated with the given token. Returns the number of
// handlers that have been posted or dispatched.
template <typename Time_Traits>
- std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
- {
- // If the service has been shut down we silently ignore the cancellation.
- if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
- return 0;
-
- asio::detail::mutex::scoped_lock lock(timer_mutex_);
- op_queue<operation> ops;
- std::size_t n = timer_queue.cancel_timer(token, ops);
- post_deferred_completions(ops);
- if (n > 0 && !timer_interrupt_issued_)
- {
- timer_interrupt_issued_ = true;
- lock.unlock();
- ::PostQueuedCompletionStatus(iocp_.handle,
- 0, steal_timer_dispatching, 0);
- }
- return n;
- }
+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer);
private:
#if defined(WINVER) && (WINVER < 0x0500)
@@ -456,181 +169,30 @@ private:
// Dequeues at most one operation from the I/O completion port, and then
// executes it. Returns the number of operations that were dequeued (i.e.
// either 0 or 1).
- size_t do_one(bool block, asio::error_code& ec)
- {
- long this_thread_id = static_cast<long>(::GetCurrentThreadId());
-
- for (;;)
- {
- // Try to acquire responsibility for dispatching timers.
- bool dispatching_timers = (::InterlockedCompareExchange(
- &timer_thread_, this_thread_id, 0) == 0);
-
- // Calculate timeout for GetQueuedCompletionStatus call.
- DWORD timeout = max_timeout;
- if (dispatching_timers)
- {
- asio::detail::mutex::scoped_lock lock(timer_mutex_);
- timer_interrupt_issued_ = false;
- timeout = get_timeout();
- }
-
- // Get the next operation from the queue.
- DWORD bytes_transferred = 0;
- dword_ptr_t completion_key = 0;
- LPOVERLAPPED overlapped = 0;
- ::SetLastError(0);
- BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
- &completion_key, &overlapped, block ? timeout : 0);
- DWORD last_error = ::GetLastError();
-
- // Dispatch any pending timers.
- if (dispatching_timers)
- {
- asio::detail::mutex::scoped_lock lock(timer_mutex_);
- op_queue<operation> ops;
- ops.push(completed_ops_);
- timer_queues_.get_ready_timers(ops);
- post_deferred_completions(ops);
- }
-
- if (!ok && overlapped == 0)
- {
- if (block && last_error == WAIT_TIMEOUT)
- {
- // Relinquish responsibility for dispatching timers.
- if (dispatching_timers)
- {
- ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
- }
-
- continue;
- }
-
- // Transfer responsibility for dispatching timers to another thread.
- if (dispatching_timers && ::InterlockedCompareExchange(
- &timer_thread_, 0, this_thread_id) == this_thread_id)
- {
- ::PostQueuedCompletionStatus(iocp_.handle,
- 0, transfer_timer_dispatching, 0);
- }
-
- ec = asio::error_code();
- return 0;
- }
- else if (overlapped)
- {
- operation* op = static_cast<operation*>(overlapped);
- asio::error_code result_ec(last_error,
- asio::error::get_system_category());
-
- // Transfer responsibility for dispatching timers to another thread.
- if (dispatching_timers && ::InterlockedCompareExchange(
- &timer_thread_, 0, this_thread_id) == this_thread_id)
- {
- ::PostQueuedCompletionStatus(iocp_.handle,
- 0, transfer_timer_dispatching, 0);
- }
-
- // We may have been passed the last_error and bytes_transferred in the
- // OVERLAPPED structure itself.
- if (completion_key == overlapped_contains_result)
- {
- result_ec = asio::error_code(static_cast<int>(op->Offset),
- static_cast<asio::error_category>(op->Internal));
- bytes_transferred = op->OffsetHigh;
- }
-
- // Otherwise ensure any result has been saved into the OVERLAPPED
- // structure.
- else
- {
- op->Internal = result_ec.category();
- op->Offset = result_ec.value();
- op->OffsetHigh = bytes_transferred;
- }
-
- // Dispatch the operation only if ready. The operation may not be ready
- // if the initiating function (e.g. a call to WSARecv) has not yet
- // returned. This is because the initiating function still wants access
- // to the operation's OVERLAPPED structure.
- if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
- {
- // Ensure the count of outstanding work is decremented on block exit.
- work_finished_on_block_exit on_exit = { this };
- (void)on_exit;
-
- op->complete(*this, result_ec, bytes_transferred);
- ec = asio::error_code();
- return 1;
- }
- }
- else if (completion_key == transfer_timer_dispatching)
- {
- // Woken up to try to acquire responsibility for dispatching timers.
- ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
- }
- else if (completion_key == steal_timer_dispatching)
- {
- // Woken up to steal responsibility for dispatching timers.
- ::InterlockedExchange(&timer_thread_, 0);
- }
- else
- {
- // Relinquish responsibility for dispatching timers. If the io_service
- // is not being stopped then the thread will get an opportunity to
- // reacquire timer responsibility on the next loop iteration.
- if (dispatching_timers)
- {
- ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
- }
-
- // The stopped_ flag is always checked to ensure that any leftover
- // interrupts from a previous run invocation are ignored.
- if (::InterlockedExchangeAdd(&stopped_, 0) != 0)
- {
- // Wake up next thread that is blocked on GetQueuedCompletionStatus.
- if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
- {
- last_error = ::GetLastError();
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- return 0;
- }
-
- ec = asio::error_code();
- return 0;
- }
- }
- }
- }
+ ASIO_DECL size_t do_one(bool block, asio::error_code& ec);
- // Get the timeout value for the GetQueuedCompletionStatus call. The timeout
- // value is returned as a number of milliseconds. We will wait no longer than
- // 1000 milliseconds.
- DWORD get_timeout()
- {
- return timer_queues_.wait_duration_msec(max_timeout);
- }
+ // Helper function to add a new timer queue.
+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+ // Helper function to remove a timer queue.
+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
+
+ // Called to recalculate and update the timeout.
+ ASIO_DECL void update_timeout();
// Helper class to call work_finished() on block exit.
- struct work_finished_on_block_exit
- {
- ~work_finished_on_block_exit()
- {
- io_service_->work_finished();
- }
+ struct work_finished_on_block_exit;
- win_iocp_io_service* io_service_;
+ // Helper class for managing a HANDLE.
+ struct auto_handle
+ {
+ HANDLE handle;
+ auto_handle() : handle(0) {}
+ ~auto_handle() { if (handle) ::CloseHandle(handle); }
};
// The IO completion port used for queueing operations.
- struct iocp_holder
- {
- HANDLE handle;
- iocp_holder() : handle(0) {}
- ~iocp_holder() { if (handle) ::CloseHandle(handle); }
- } iocp_;
+ auto_handle iocp_;
// The count of unfinished work.
long outstanding_work_;
@@ -643,44 +205,61 @@ private:
enum
{
- // Maximum GetQueuedCompletionStatus timeout, in milliseconds.
- max_timeout = 500,
+ // Timeout to use with GetQueuedCompletionStatus. Some versions of windows
+ // have a "bug" where a call to GetQueuedCompletionStatus can appear stuck
+ // even though there are events waiting on the queue. Using a timeout helps
+ // to work around the issue.
+ gqcs_timeout = 500,
+
+ // Maximum waitable timer timeout, in milliseconds.
+ max_timeout_msec = 5 * 60 * 1000,
- // Completion key value to indicate that responsibility for dispatching
- // timers is being cooperatively transferred from one thread to another.
- transfer_timer_dispatching = 1,
+ // Maximum waitable timer timeout, in microseconds.
+ max_timeout_usec = max_timeout_msec * 1000,
- // Completion key value to indicate that responsibility for dispatching
- // timers should be stolen from another thread.
- steal_timer_dispatching = 2,
+ // Completion key value used to wake up a thread to dispatch timers or
+ // completed operations.
+ wake_for_dispatch = 1,
// Completion key value to indicate that an operation has posted with the
// original last_error and bytes_transferred values stored in the fields of
// the OVERLAPPED structure.
- overlapped_contains_result = 3
+ overlapped_contains_result = 2
};
- // The thread that's currently in charge of dispatching timers.
- long timer_thread_;
+ // Function object for processing timeouts in a background thread.
+ struct timer_thread_function;
+ friend struct timer_thread_function;
+
+ // Background thread used for processing timeouts.
+ boost::scoped_ptr<thread> timer_thread_;
+
+ // A waitable timer object used for waiting for timeouts.
+ auto_handle waitable_timer_;
- // Mutex for protecting access to the timer queues.
- mutex timer_mutex_;
+ // Non-zero if timers or completed operations need to be dispatched.
+ long dispatch_required_;
- // Whether a thread has been interrupted to process a new timeout.
- bool timer_interrupt_issued_;
+ // Mutex for protecting access to the timer queues and completed operations.
+ mutex dispatch_mutex_;
// The timer queues.
timer_queue_set timer_queues_;
// The operations that are ready to dispatch.
- op_queue<operation> completed_ops_;
+ op_queue<win_iocp_operation> completed_ops_;
};
} // namespace detail
} // namespace asio
-#endif // defined(ASIO_HAS_IOCP)
-
#include "asio/detail/pop_options.hpp"
+#include "asio/detail/impl/win_iocp_io_service.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_iocp_io_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP)
+
#endif // ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP
diff --git a/ext/asio/asio/detail/win_iocp_io_service_fwd.hpp b/ext/asio/asio/detail/win_iocp_io_service_fwd.hpp
index 29d2a05..9f03743 100644
--- a/ext/asio/asio/detail/win_iocp_io_service_fwd.hpp
+++ b/ext/asio/asio/detail/win_iocp_io_service_fwd.hpp
@@ -1,8 +1,8 @@
//
-// win_iocp_io_service_fwd.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/win_iocp_io_service_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,22 +15,9 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/detail/socket_types.hpp"
-
-// This service is only supported on Win32 (NT4 and later).
-#if !defined(ASIO_DISABLE_IOCP)
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
-#if !defined(UNDER_CE)
-
-// Define this to indicate that IOCP is supported on the target platform.
-#define ASIO_HAS_IOCP 1
+#if defined(ASIO_HAS_IOCP)
namespace asio {
namespace detail {
@@ -41,11 +28,6 @@ class win_iocp_overlapped_ptr;
} // namespace detail
} // namespace asio
-#endif // !defined(UNDER_CE)
-#endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-#endif // !defined(ASIO_DISABLE_IOCP)
-
-#include "asio/detail/pop_options.hpp"
+#endif // defined(ASIO_HAS_IOCP)
#endif // ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP
diff --git a/ext/asio/asio/detail/win_iocp_null_buffers_op.hpp b/ext/asio/asio/detail/win_iocp_null_buffers_op.hpp
new file mode 100644
index 0000000..e39fff7
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_null_buffers_op.hpp
@@ -0,0 +1,112 @@
+//
+// detail/win_iocp_null_buffers_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class win_iocp_null_buffers_op : public reactor_op
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_null_buffers_op);
+
+ win_iocp_null_buffers_op(socket_ops::weak_cancel_token_type cancel_token,
+ Handler handler)
+ : reactor_op(&win_iocp_null_buffers_op::do_perform,
+ &win_iocp_null_buffers_op::do_complete),
+ cancel_token_(cancel_token),
+ handler_(handler)
+ {
+ }
+
+ static bool do_perform(reactor_op*)
+ {
+ return true;
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code ec, std::size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ win_iocp_null_buffers_op* o(static_cast<win_iocp_null_buffers_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+ // The reactor may have stored a result in the operation object.
+ if (o->ec_)
+ ec = o->ec_;
+
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (o->cancel_token_.expired())
+ ec = asio::error::operation_aborted;
+ else
+ ec = asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = asio::error::connection_refused;
+ }
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ socket_ops::weak_cancel_token_type cancel_token_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP
diff --git a/ext/asio/asio/detail/win_iocp_operation.hpp b/ext/asio/asio/detail/win_iocp_operation.hpp
index ac81062..649edd1 100644
--- a/ext/asio/asio/detail/win_iocp_operation.hpp
+++ b/ext/asio/asio/detail/win_iocp_operation.hpp
@@ -1,8 +1,8 @@
//
-// win_iocp_operation.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~
+// detail/win_iocp_operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_IOCP)
-#include "asio/error_code.hpp"
#include "asio/detail/op_queue.hpp"
+#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/error_code.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -82,8 +83,8 @@ private:
} // namespace detail
} // namespace asio
-#endif // defined(ASIO_HAS_IOCP)
-
#include "asio/detail/pop_options.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
#endif // ASIO_DETAIL_WIN_IOCP_OPERATION_HPP
diff --git a/ext/asio/asio/detail/win_iocp_overlapped_op.hpp b/ext/asio/asio/detail/win_iocp_overlapped_op.hpp
new file mode 100644
index 0000000..f2b7ddf
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_overlapped_op.hpp
@@ -0,0 +1,84 @@
+//
+// detail/win_iocp_overlapped_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/error.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class win_iocp_overlapped_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_overlapped_op);
+
+ win_iocp_overlapped_op(Handler handler)
+ : operation(&win_iocp_overlapped_op::do_complete),
+ handler_(handler)
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code ec, std::size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ win_iocp_overlapped_op* o(static_cast<win_iocp_overlapped_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP
diff --git a/ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp b/ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp
index 47a3f70..919affe 100644
--- a/ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp
+++ b/ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp
@@ -1,8 +1,8 @@
//
-// win_iocp_overlapped_ptr.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/win_iocp_overlapped_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,18 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_IOCP)
-#include "asio/detail/fenced_block.hpp"
+#include <boost/utility/addressof.hpp>
+#include "asio/io_service.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/win_iocp_overlapped_op.hpp"
#include "asio/detail/win_iocp_io_service.hpp"
-#include "asio/detail/win_iocp_operation.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -74,13 +76,15 @@ public:
template <typename Handler>
void reset(asio::io_service& io_service, Handler handler)
{
- typedef overlapped_op<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+ typedef win_iocp_overlapped_op<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(handler);
io_service.impl_.work_started();
reset();
- ptr_ = ptr.release();
+ ptr_ = p.p;
+ p.v = p.p = 0;
iocp_service_ = &io_service.impl_;
}
@@ -122,44 +126,6 @@ public:
}
private:
- template <typename Handler>
- struct overlapped_op : public win_iocp_operation
- {
- overlapped_op(Handler handler)
- : win_iocp_operation(&overlapped_op::do_complete),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code ec, std::size_t bytes_transferred)
- {
- // Take ownership of the operation object.
- overlapped_op* o(static_cast<overlapped_op*>(base));
- typedef handler_alloc_traits<Handler, overlapped_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder2<Handler, asio::error_code, std::size_t>
- handler(o->handler_, ec, bytes_transferred);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- Handler handler_;
- };
-
win_iocp_operation* ptr_;
win_iocp_io_service* iocp_service_;
};
@@ -167,8 +133,8 @@ private:
} // namespace detail
} // namespace asio
-#endif // defined(ASIO_HAS_IOCP)
-
#include "asio/detail/pop_options.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
#endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP
diff --git a/ext/asio/asio/detail/win_iocp_serial_port_service.hpp b/ext/asio/asio/detail/win_iocp_serial_port_service.hpp
index ed5f75e..bf3a692 100644
--- a/ext/asio/asio/detail/win_iocp_serial_port_service.hpp
+++ b/ext/asio/asio/detail/win_iocp_serial_port_service.hpp
@@ -1,8 +1,8 @@
//
-// win_iocp_serial_port_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/win_iocp_serial_port_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,21 +16,17 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <cstring>
-#include <string>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/detail/config.hpp"
-#if defined(ASIO_HAS_IOCP)
+#if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
+#include <string>
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/win_iocp_handle_service.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -38,133 +34,56 @@ namespace detail {
class win_iocp_serial_port_service
{
public:
- // The native type of a stream handle.
+ // The native type of a serial port.
typedef win_iocp_handle_service::native_type native_type;
- // The implementation type of the stream handle.
+ // The implementation type of the serial port.
typedef win_iocp_handle_service::implementation_type implementation_type;
- win_iocp_serial_port_service(asio::io_service& io_service)
- : handle_service_(io_service)
- {
- }
+ // Constructor.
+ ASIO_DECL win_iocp_serial_port_service(
+ asio::io_service& io_service);
// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- }
+ ASIO_DECL void shutdown_service();
- // Construct a new handle implementation.
+ // Construct a new serial port implementation.
void construct(implementation_type& impl)
{
handle_service_.construct(impl);
}
- // Destroy a handle implementation.
+ // Destroy a serial port implementation.
void destroy(implementation_type& impl)
{
handle_service_.destroy(impl);
}
// Open the serial port using the specified device name.
- asio::error_code open(implementation_type& impl,
- const std::string& device, asio::error_code& ec)
- {
- if (is_open(impl))
- {
- ec = asio::error::already_open;
- return ec;
- }
-
- // For convenience, add a leading \\.\ sequence if not already present.
- std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device;
-
- // Open a handle to the serial port.
- ::HANDLE handle = ::CreateFileA(name.c_str(),
- GENERIC_READ | GENERIC_WRITE, 0, 0,
- OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
- if (handle == INVALID_HANDLE_VALUE)
- {
- DWORD last_error = ::GetLastError();
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- return ec;
- }
-
- // Determine the initial serial port parameters.
- using namespace std; // For memcpy.
- ::DCB dcb;
- memset(&dcb, 0, sizeof(DCB));
- dcb.DCBlength = sizeof(DCB);
- if (!::GetCommState(handle, &dcb))
- {
- DWORD last_error = ::GetLastError();
- ::CloseHandle(handle);
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- return ec;
- }
-
- // Set some default serial port parameters. This implementation does not
- // support changing these, so they might as well be in a known state.
- dcb.fBinary = TRUE; // Win32 only supports binary mode.
- dcb.fDsrSensitivity = FALSE;
- dcb.fNull = FALSE; // Do not ignore NULL characters.
- dcb.fAbortOnError = FALSE; // Ignore serial framing errors.
- if (!::SetCommState(handle, &dcb))
- {
- DWORD last_error = ::GetLastError();
- ::CloseHandle(handle);
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- return ec;
- }
-
- // Set up timeouts so that the serial port will behave similarly to a
- // network socket. Reads wait for at least one byte, then return with
- // whatever they have. Writes return once everything is out the door.
- ::COMMTIMEOUTS timeouts;
- timeouts.ReadIntervalTimeout = 1;
- timeouts.ReadTotalTimeoutMultiplier = 0;
- timeouts.ReadTotalTimeoutConstant = 0;
- timeouts.WriteTotalTimeoutMultiplier = 0;
- timeouts.WriteTotalTimeoutConstant = 0;
- if (!::SetCommTimeouts(handle, &timeouts))
- {
- DWORD last_error = ::GetLastError();
- ::CloseHandle(handle);
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- return ec;
- }
-
- // We're done. Take ownership of the serial port handle.
- if (handle_service_.assign(impl, handle, ec))
- ::CloseHandle(handle);
- return ec;
- }
+ ASIO_DECL asio::error_code open(implementation_type& impl,
+ const std::string& device, asio::error_code& ec);
- // Assign a native handle to a handle implementation.
+ // Assign a native handle to a serial port implementation.
asio::error_code assign(implementation_type& impl,
const native_type& native_handle, asio::error_code& ec)
{
return handle_service_.assign(impl, native_handle, ec);
}
- // Determine whether the handle is open.
+ // Determine whether the serial port is open.
bool is_open(const implementation_type& impl) const
{
return handle_service_.is_open(impl);
}
- // Destroy a handle implementation.
+ // Destroy a serial port implementation.
asio::error_code close(implementation_type& impl,
asio::error_code& ec)
{
return handle_service_.close(impl, ec);
}
- // Get the native handle representation.
+ // Get the native serial port representation.
native_type native(implementation_type& impl)
{
return handle_service_.native(impl);
@@ -182,32 +101,9 @@ public:
asio::error_code set_option(implementation_type& impl,
const SettableSerialPortOption& option, asio::error_code& ec)
{
- using namespace std; // For memcpy.
-
- ::DCB dcb;
- memset(&dcb, 0, sizeof(DCB));
- dcb.DCBlength = sizeof(DCB);
- if (!::GetCommState(handle_service_.native(impl), &dcb))
- {
- DWORD last_error = ::GetLastError();
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- return ec;
- }
-
- if (option.store(dcb, ec))
- return ec;
-
- if (!::SetCommState(handle_service_.native(impl), &dcb))
- {
- DWORD last_error = ::GetLastError();
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- return ec;
- }
-
- ec = asio::error_code();
- return ec;
+ return do_set_option(impl,
+ &win_iocp_serial_port_service::store_option<SettableSerialPortOption>,
+ &option, ec);
}
// Get an option from the serial port.
@@ -215,20 +111,9 @@ public:
asio::error_code get_option(const implementation_type& impl,
GettableSerialPortOption& option, asio::error_code& ec) const
{
- using namespace std; // For memcpy.
-
- ::DCB dcb;
- memset(&dcb, 0, sizeof(DCB));
- dcb.DCBlength = sizeof(DCB);
- if (!::GetCommState(handle_service_.native(impl), &dcb))
- {
- DWORD last_error = ::GetLastError();
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- return ec;
- }
-
- return option.load(dcb, ec);
+ return do_get_option(impl,
+ &win_iocp_serial_port_service::load_option<GettableSerialPortOption>,
+ &option, ec);
}
// Send a break sequence to the serial port.
@@ -274,6 +159,41 @@ public:
}
private:
+ // Function pointer type for storing a serial port option.
+ typedef asio::error_code (*store_function_type)(
+ const void*, ::DCB&, asio::error_code&);
+
+ // Helper function template to store a serial port option.
+ template <typename SettableSerialPortOption>
+ static asio::error_code store_option(const void* option,
+ ::DCB& storage, asio::error_code& ec)
+ {
+ return static_cast<const SettableSerialPortOption*>(option)->store(
+ storage, ec);
+ }
+
+ // Helper function to set a serial port option.
+ ASIO_DECL asio::error_code do_set_option(
+ implementation_type& impl, store_function_type store,
+ const void* option, asio::error_code& ec);
+
+ // Function pointer type for loading a serial port option.
+ typedef asio::error_code (*load_function_type)(
+ void*, const ::DCB&, asio::error_code&);
+
+ // Helper function template to load a serial port option.
+ template <typename GettableSerialPortOption>
+ static asio::error_code load_option(void* option,
+ const ::DCB& storage, asio::error_code& ec)
+ {
+ return static_cast<GettableSerialPortOption*>(option)->load(storage, ec);
+ }
+
+ // Helper function to get a serial port option.
+ ASIO_DECL asio::error_code do_get_option(
+ const implementation_type& impl, load_function_type load,
+ void* option, asio::error_code& ec) const;
+
// The implementation used for initiating asynchronous operations.
win_iocp_handle_service handle_service_;
};
@@ -281,8 +201,12 @@ private:
} // namespace detail
} // namespace asio
-#endif // defined(ASIO_HAS_IOCP)
-
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_iocp_serial_port_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
+
#endif // ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP
diff --git a/ext/asio/asio/detail/win_iocp_socket_accept_op.hpp b/ext/asio/asio/detail/win_iocp_socket_accept_op.hpp
new file mode 100644
index 0000000..a71c7c0
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_socket_accept_op.hpp
@@ -0,0 +1,158 @@
+//
+// detail/win_iocp_socket_accept_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/win_iocp_socket_service_base.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Socket, typename Protocol, typename Handler>
+class win_iocp_socket_accept_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_accept_op);
+
+ win_iocp_socket_accept_op(win_iocp_socket_service_base& socket_service,
+ socket_type socket, Socket& peer, const Protocol& protocol,
+ typename Protocol::endpoint* peer_endpoint,
+ bool enable_connection_aborted, Handler handler)
+ : operation(&win_iocp_socket_accept_op::do_complete),
+ socket_service_(socket_service),
+ socket_(socket),
+ peer_(peer),
+ protocol_(protocol),
+ peer_endpoint_(peer_endpoint),
+ enable_connection_aborted_(enable_connection_aborted),
+ handler_(handler)
+ {
+ }
+
+ socket_holder& new_socket()
+ {
+ return new_socket_;
+ }
+
+ void* output_buffer()
+ {
+ return output_buffer_;
+ }
+
+ DWORD address_length()
+ {
+ return sizeof(sockaddr_storage_type) + 16;
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code ec, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the operation object.
+ win_iocp_socket_accept_op* o(static_cast<win_iocp_socket_accept_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+ if (owner)
+ {
+ typename Protocol::endpoint peer_endpoint;
+ std::size_t addr_len = peer_endpoint.capacity();
+ socket_ops::complete_iocp_accept(o->socket_,
+ o->output_buffer(), o->address_length(),
+ peer_endpoint.data(), &addr_len,
+ o->new_socket_.get(), ec);
+
+ // Restart the accept operation if we got the connection_aborted error
+ // and the enable_connection_aborted socket option is not set.
+ if (ec == asio::error::connection_aborted
+ && !o->enable_connection_aborted_)
+ {
+ o->reset();
+ o->socket_service_.restart_accept_op(o->socket_,
+ o->new_socket_, o->protocol_.family(),
+ o->protocol_.type(), o->protocol_.protocol(),
+ o->output_buffer(), o->address_length(), o);
+ p.v = p.p = 0;
+ return;
+ }
+
+ // If the socket was successfully accepted, transfer ownership of the
+ // socket to the peer object.
+ if (!ec)
+ {
+ o->peer_.assign(o->protocol_,
+ typename Socket::native_type(
+ o->new_socket_.get(), peer_endpoint), ec);
+ if (!ec)
+ o->new_socket_.release();
+ }
+
+ // Pass endpoint back to caller.
+ if (o->peer_endpoint_)
+ *o->peer_endpoint_ = peer_endpoint;
+ }
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder1<Handler, asio::error_code>
+ handler(o->handler_, ec);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ win_iocp_socket_service_base& socket_service_;
+ socket_type socket_;
+ socket_holder new_socket_;
+ Socket& peer_;
+ Protocol protocol_;
+ typename Protocol::endpoint* peer_endpoint_;
+ unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
+ bool enable_connection_aborted_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP
diff --git a/ext/asio/asio/detail/win_iocp_socket_recv_op.hpp b/ext/asio/asio/detail/win_iocp_socket_recv_op.hpp
new file mode 100644
index 0000000..3ab4fcb
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_socket_recv_op.hpp
@@ -0,0 +1,108 @@
+//
+// detail/win_iocp_socket_recv_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Handler>
+class win_iocp_socket_recv_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recv_op);
+
+ win_iocp_socket_recv_op(socket_ops::state_type state,
+ socket_ops::weak_cancel_token_type cancel_token,
+ const MutableBufferSequence& buffers, Handler handler)
+ : operation(&win_iocp_socket_recv_op::do_complete),
+ state_(state),
+ cancel_token_(cancel_token),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code ec, std::size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ win_iocp_socket_recv_op* o(static_cast<win_iocp_socket_recv_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ if (owner)
+ {
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::validate(o->buffers_);
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ socket_ops::complete_iocp_recv(o->state_, o->cancel_token_,
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::all_empty(o->buffers_),
+ ec, bytes_transferred);
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ socket_ops::state_type state_;
+ socket_ops::weak_cancel_token_type cancel_token_;
+ MutableBufferSequence buffers_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP
diff --git a/ext/asio/asio/detail/win_iocp_socket_recvfrom_op.hpp b/ext/asio/asio/detail/win_iocp_socket_recvfrom_op.hpp
new file mode 100644
index 0000000..d1e2ece
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_socket_recvfrom_op.hpp
@@ -0,0 +1,116 @@
+//
+// detail/win_iocp_socket_recvfrom_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Endpoint, typename Handler>
+class win_iocp_socket_recvfrom_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvfrom_op);
+
+ win_iocp_socket_recvfrom_op(Endpoint& endpoint,
+ socket_ops::weak_cancel_token_type cancel_token,
+ const MutableBufferSequence& buffers, Handler handler)
+ : operation(&win_iocp_socket_recvfrom_op::do_complete),
+ endpoint_(endpoint),
+ endpoint_size_(static_cast<int>(endpoint.capacity())),
+ cancel_token_(cancel_token),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ int& endpoint_size()
+ {
+ return endpoint_size_;
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code ec, std::size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ win_iocp_socket_recvfrom_op* o(
+ static_cast<win_iocp_socket_recvfrom_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ if (owner)
+ {
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::validate(o->buffers_);
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ socket_ops::complete_iocp_recvfrom(o->cancel_token_, ec);
+
+ // Record the size of the endpoint returned by the operation.
+ o->endpoint_.resize(o->endpoint_size_);
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ Endpoint& endpoint_;
+ int endpoint_size_;
+ socket_ops::weak_cancel_token_type cancel_token_;
+ MutableBufferSequence buffers_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP
diff --git a/ext/asio/asio/detail/win_iocp_socket_send_op.hpp b/ext/asio/asio/detail/win_iocp_socket_send_op.hpp
new file mode 100644
index 0000000..56f3f2d
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_socket_send_op.hpp
@@ -0,0 +1,102 @@
+//
+// detail/win_iocp_socket_send_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include <boost/utility/addressof.hpp>
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence, typename Handler>
+class win_iocp_socket_send_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_send_op);
+
+ win_iocp_socket_send_op(socket_ops::weak_cancel_token_type cancel_token,
+ const ConstBufferSequence& buffers, Handler handler)
+ : operation(&win_iocp_socket_send_op::do_complete),
+ cancel_token_(cancel_token),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ asio::error_code ec, std::size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ win_iocp_socket_send_op* o(static_cast<win_iocp_socket_send_op*>(base));
+ ptr p = { boost::addressof(o->handler_), o, o };
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ if (owner)
+ {
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence>::validate(o->buffers_);
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ socket_ops::complete_iocp_send(o->cancel_token_, ec);
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ p.h = boost::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ asio::detail::fenced_block b;
+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ }
+ }
+
+private:
+ socket_ops::weak_cancel_token_type cancel_token_;
+ ConstBufferSequence buffers_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP
diff --git a/ext/asio/asio/detail/win_iocp_socket_service.hpp b/ext/asio/asio/detail/win_iocp_socket_service.hpp
index cb1d203..b476f8b 100644
--- a/ext/asio/asio/detail/win_iocp_socket_service.hpp
+++ b/ext/asio/asio/detail/win_iocp_socket_service.hpp
@@ -1,8 +1,8 @@
//
-// win_iocp_socket_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/win_iocp_socket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,19 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_IOCP)
-#include "asio/detail/push_options.hpp"
#include <cstring>
-#include <boost/shared_ptr.hpp>
-#include <boost/type_traits/is_same.hpp>
-#include <boost/weak_ptr.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include <boost/utility/addressof.hpp>
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/socket_base.hpp"
@@ -37,20 +30,27 @@
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/mutex.hpp"
-#include "asio/detail/null_buffers_op.hpp"
#include "asio/detail/operation.hpp"
+#include "asio/detail/reactive_socket_connect_op.hpp"
#include "asio/detail/reactor.hpp"
#include "asio/detail/reactor_op.hpp"
#include "asio/detail/socket_holder.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/win_iocp_io_service.hpp"
+#include "asio/detail/win_iocp_null_buffers_op.hpp"
+#include "asio/detail/win_iocp_socket_accept_op.hpp"
+#include "asio/detail/win_iocp_socket_recvfrom_op.hpp"
+#include "asio/detail/win_iocp_socket_send_op.hpp"
+#include "asio/detail/win_iocp_socket_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Protocol>
-class win_iocp_socket_service
+class win_iocp_socket_service : public win_iocp_socket_service_base
{
public:
// The protocol type.
@@ -59,10 +59,6 @@ public:
// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
- struct noop_deleter { void operator()(void*) {} };
- typedef boost::shared_ptr<void> shared_cancel_token_type;
- typedef boost::weak_ptr<void> weak_cancel_token_type;
-
// The native type of a socket.
class native_type
{
@@ -92,11 +88,6 @@ public:
return socket_;
}
- HANDLE as_handle() const
- {
- return reinterpret_cast<HANDLE>(socket_);
- }
-
bool have_remote_endpoint() const
{
return have_remote_endpoint_;
@@ -114,148 +105,44 @@ public:
};
// The implementation type of the socket.
- class implementation_type
+ struct implementation_type :
+ win_iocp_socket_service_base::base_implementation_type
{
- public:
// Default constructor.
implementation_type()
- : socket_(invalid_socket),
- flags_(0),
- cancel_token_(),
- protocol_(endpoint_type().protocol()),
- next_(0),
- prev_(0)
+ : protocol_(endpoint_type().protocol()),
+ have_remote_endpoint_(false),
+ remote_endpoint_()
{
}
- private:
- // Only this service will have access to the internal values.
- friend class win_iocp_socket_service;
-
- // The native socket representation.
- native_type socket_;
-
- enum
- {
- enable_connection_aborted = 1, // User wants connection_aborted errors.
- close_might_block = 2, // User set linger option for blocking close.
- user_set_non_blocking = 4 // The user wants a non-blocking socket.
- };
-
- // Flags indicating the current state of the socket.
- unsigned char flags_;
-
- // We use a shared pointer as a cancellation token here to work around the
- // broken Windows support for cancellation. MSDN says that when you call
- // closesocket any outstanding WSARecv or WSASend operations will complete
- // with the error ERROR_OPERATION_ABORTED. In practice they complete with
- // ERROR_NETNAME_DELETED, which means you can't tell the difference between
- // a local cancellation and the socket being hard-closed by the peer.
- shared_cancel_token_type cancel_token_;
-
// The protocol associated with the socket.
protocol_type protocol_;
- // Per-descriptor data used by the reactor.
- reactor::per_descriptor_data reactor_data_;
-
-#if defined(ASIO_ENABLE_CANCELIO)
- // The ID of the thread from which it is safe to cancel asynchronous
- // operations. 0 means no asynchronous operations have been started yet.
- // ~0 means asynchronous operations have been started from more than one
- // thread, and cancellation is not supported for the socket.
- DWORD safe_cancellation_thread_id_;
-#endif // defined(ASIO_ENABLE_CANCELIO)
+ // Whether we have a cached remote endpoint.
+ bool have_remote_endpoint_;
- // Pointers to adjacent socket implementations in linked list.
- implementation_type* next_;
- implementation_type* prev_;
+ // A cached remote endpoint.
+ endpoint_type remote_endpoint_;
};
// Constructor.
win_iocp_socket_service(asio::io_service& io_service)
- : io_service_(io_service),
- iocp_service_(use_service<win_iocp_io_service>(io_service)),
- reactor_(0),
- mutex_(),
- impl_list_(0)
- {
- }
-
- // Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
+ : win_iocp_socket_service_base(io_service)
{
- // Close all implementations, causing all operations to complete.
- asio::detail::mutex::scoped_lock lock(mutex_);
- implementation_type* impl = impl_list_;
- while (impl)
- {
- asio::error_code ignored_ec;
- close_for_destruction(*impl);
- impl = impl->next_;
- }
- }
-
- // Construct a new socket implementation.
- void construct(implementation_type& impl)
- {
- impl.socket_ = invalid_socket;
- impl.flags_ = 0;
- impl.cancel_token_.reset();
-#if defined(ASIO_ENABLE_CANCELIO)
- impl.safe_cancellation_thread_id_ = 0;
-#endif // defined(ASIO_ENABLE_CANCELIO)
-
- // Insert implementation into linked list of all implementations.
- asio::detail::mutex::scoped_lock lock(mutex_);
- impl.next_ = impl_list_;
- impl.prev_ = 0;
- if (impl_list_)
- impl_list_->prev_ = &impl;
- impl_list_ = &impl;
- }
-
- // Destroy a socket implementation.
- void destroy(implementation_type& impl)
- {
- close_for_destruction(impl);
-
- // Remove implementation from linked list of all implementations.
- asio::detail::mutex::scoped_lock lock(mutex_);
- if (impl_list_ == &impl)
- impl_list_ = impl.next_;
- if (impl.prev_)
- impl.prev_->next_ = impl.next_;
- if (impl.next_)
- impl.next_->prev_= impl.prev_;
- impl.next_ = 0;
- impl.prev_ = 0;
}
// Open a new socket implementation.
asio::error_code open(implementation_type& impl,
const protocol_type& protocol, asio::error_code& ec)
{
- if (is_open(impl))
+ if (!do_open(impl, protocol.family(),
+ protocol.type(), protocol.protocol(), ec))
{
- ec = asio::error::already_open;
- return ec;
+ impl.protocol_ = protocol;
+ impl.have_remote_endpoint_ = false;
+ impl.remote_endpoint_ = endpoint_type();
}
-
- socket_holder sock(socket_ops::socket(protocol.family(), protocol.type(),
- protocol.protocol(), ec));
- if (sock.get() == invalid_socket)
- return ec;
-
- HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock.get());
- if (iocp_service_.register_handle(sock_as_handle, ec))
- return ec;
-
- impl.socket_ = sock.release();
- impl.flags_ = 0;
- impl.cancel_token_.reset(static_cast<void*>(0), noop_deleter());
- impl.protocol_ = protocol;
- ec = asio::error_code();
return ec;
}
@@ -264,247 +151,40 @@ public:
const protocol_type& protocol, const native_type& native_socket,
asio::error_code& ec)
{
- if (is_open(impl))
- {
- ec = asio::error::already_open;
- return ec;
- }
-
- if (iocp_service_.register_handle(native_socket.as_handle(), ec))
- return ec;
-
- impl.socket_ = native_socket;
- impl.flags_ = 0;
- impl.cancel_token_.reset(static_cast<void*>(0), noop_deleter());
- impl.protocol_ = protocol;
- ec = asio::error_code();
- return ec;
- }
-
- // Determine whether the socket is open.
- bool is_open(const implementation_type& impl) const
- {
- return impl.socket_ != invalid_socket;
- }
-
- // Destroy a socket implementation.
- asio::error_code close(implementation_type& impl,
- asio::error_code& ec)
- {
- if (is_open(impl))
+ if (!do_assign(impl, protocol.type(), native_socket, ec))
{
- // Check if the reactor was created, in which case we need to close the
- // socket on the reactor as well to cancel any operations that might be
- // running there.
- reactor* r = static_cast<reactor*>(
- interlocked_compare_exchange_pointer(
- reinterpret_cast<void**>(&reactor_), 0, 0));
- if (r)
- r->close_descriptor(impl.socket_, impl.reactor_data_);
-
- if (socket_ops::close(impl.socket_, ec) == socket_error_retval)
- return ec;
-
- impl.socket_ = invalid_socket;
- impl.flags_ = 0;
- impl.cancel_token_.reset();
-#if defined(ASIO_ENABLE_CANCELIO)
- impl.safe_cancellation_thread_id_ = 0;
-#endif // defined(ASIO_ENABLE_CANCELIO)
+ impl.protocol_ = protocol;
+ impl.have_remote_endpoint_ = native_socket.have_remote_endpoint();
+ impl.remote_endpoint_ = native_socket.remote_endpoint();
}
-
- ec = asio::error_code();
return ec;
}
// Get the native socket representation.
native_type native(implementation_type& impl)
{
- return impl.socket_;
- }
-
- // Cancel all operations associated with the socket.
- asio::error_code cancel(implementation_type& impl,
- asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
- else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
- ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
- {
- // The version of Windows supports cancellation from any thread.
- typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
- cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
- socket_type sock = impl.socket_;
- HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
- if (!cancel_io_ex(sock_as_handle, 0))
- {
- DWORD last_error = ::GetLastError();
- if (last_error == ERROR_NOT_FOUND)
- {
- // ERROR_NOT_FOUND means that there were no operations to be
- // cancelled. We swallow this error to match the behaviour on other
- // platforms.
- ec = asio::error_code();
- }
- else
- {
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- }
- }
- else
- {
- ec = asio::error_code();
- }
- }
-#if defined(ASIO_ENABLE_CANCELIO)
- else if (impl.safe_cancellation_thread_id_ == 0)
- {
- // No operations have been started, so there's nothing to cancel.
- ec = asio::error_code();
- }
- else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
- {
- // Asynchronous operations have been started from the current thread only,
- // so it is safe to try to cancel them using CancelIo.
- socket_type sock = impl.socket_;
- HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
- if (!::CancelIo(sock_as_handle))
- {
- DWORD last_error = ::GetLastError();
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- }
- else
- {
- ec = asio::error_code();
- }
- }
- else
- {
- // Asynchronous operations have been started from more than one thread,
- // so cancellation is not safe.
- ec = asio::error::operation_not_supported;
- }
-#else // defined(ASIO_ENABLE_CANCELIO)
- else
- {
- // Cancellation is not supported as CancelIo may not be used.
- ec = asio::error::operation_not_supported;
- }
-#endif // defined(ASIO_ENABLE_CANCELIO)
-
- return ec;
- }
-
- // Determine whether the socket is at the out-of-band data mark.
- bool at_mark(const implementation_type& impl,
- asio::error_code& ec) const
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return false;
- }
-
- asio::detail::ioctl_arg_type value = 0;
- socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec);
- return ec ? false : value != 0;
- }
-
- // Determine the number of bytes available for reading.
- std::size_t available(const implementation_type& impl,
- asio::error_code& ec) const
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
- asio::detail::ioctl_arg_type value = 0;
- socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec);
- return ec ? static_cast<std::size_t>(0) : static_cast<std::size_t>(value);
+ if (impl.have_remote_endpoint_)
+ return native_type(impl.socket_, impl.remote_endpoint_);
+ return native_type(impl.socket_);
}
// Bind the socket to the specified local endpoint.
asio::error_code bind(implementation_type& impl,
const endpoint_type& endpoint, asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
return ec;
}
- // Place the socket into the state where it will listen for new connections.
- asio::error_code listen(implementation_type& impl, int backlog,
- asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
- socket_ops::listen(impl.socket_, backlog, ec);
- return ec;
- }
-
// Set a socket option.
template <typename Option>
asio::error_code set_option(implementation_type& impl,
const Option& option, asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
- if (option.level(impl.protocol_) == custom_socket_option_level
- && option.name(impl.protocol_) == enable_connection_aborted_option)
- {
- if (option.size(impl.protocol_) != sizeof(int))
- {
- ec = asio::error::invalid_argument;
- }
- else
- {
- if (*reinterpret_cast<const int*>(option.data(impl.protocol_)))
- impl.flags_ |= implementation_type::enable_connection_aborted;
- else
- impl.flags_ &= ~implementation_type::enable_connection_aborted;
- ec = asio::error_code();
- }
- return ec;
- }
- else
- {
- if (option.level(impl.protocol_) == SOL_SOCKET
- && option.name(impl.protocol_) == SO_LINGER)
- {
- const ::linger* linger_option =
- reinterpret_cast<const ::linger*>(option.data(impl.protocol_));
- if (linger_option->l_onoff != 0 && linger_option->l_linger != 0)
- impl.flags_ |= implementation_type::close_might_block;
- else
- impl.flags_ &= ~implementation_type::close_might_block;
- }
-
- socket_ops::setsockopt(impl.socket_,
- option.level(impl.protocol_), option.name(impl.protocol_),
- option.data(impl.protocol_), option.size(impl.protocol_), ec);
- return ec;
- }
+ socket_ops::setsockopt(impl.socket_, impl.state_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), option.size(impl.protocol_), ec);
+ return ec;
}
// Set a socket option.
@@ -512,65 +192,12 @@ public:
asio::error_code get_option(const implementation_type& impl,
Option& option, asio::error_code& ec) const
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
- if (option.level(impl.protocol_) == custom_socket_option_level
- && option.name(impl.protocol_) == enable_connection_aborted_option)
- {
- if (option.size(impl.protocol_) != sizeof(int))
- {
- ec = asio::error::invalid_argument;
- }
- else
- {
- int* target = reinterpret_cast<int*>(option.data(impl.protocol_));
- if (impl.flags_ & implementation_type::enable_connection_aborted)
- *target = 1;
- else
- *target = 0;
- option.resize(impl.protocol_, sizeof(int));
- ec = asio::error_code();
- }
- return ec;
- }
- else
- {
- size_t size = option.size(impl.protocol_);
- socket_ops::getsockopt(impl.socket_,
- option.level(impl.protocol_), option.name(impl.protocol_),
- option.data(impl.protocol_), &size, ec);
- if (!ec)
- option.resize(impl.protocol_, size);
- return ec;
- }
- }
-
- // Perform an IO control command on the socket.
- template <typename IO_Control_Command>
- asio::error_code io_control(implementation_type& impl,
- IO_Control_Command& command, asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
- socket_ops::ioctl(impl.socket_, command.name(),
- static_cast<ioctl_arg_type*>(command.data()), ec);
-
- if (!ec && command.name() == static_cast<int>(FIONBIO))
- {
- if (*static_cast<ioctl_arg_type*>(command.data()))
- impl.flags_ |= implementation_type::user_set_non_blocking;
- else
- impl.flags_ &= ~implementation_type::user_set_non_blocking;
- }
-
+ std::size_t size = option.size(impl.protocol_);
+ socket_ops::getsockopt(impl.socket_, impl.state_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), &size, ec);
+ if (!ec)
+ option.resize(impl.protocol_, size);
return ec;
}
@@ -578,12 +205,6 @@ public:
endpoint_type local_endpoint(const implementation_type& impl,
asio::error_code& ec) const
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return endpoint_type();
- }
-
endpoint_type endpoint;
std::size_t addr_len = endpoint.capacity();
if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
@@ -596,210 +217,13 @@ public:
endpoint_type remote_endpoint(const implementation_type& impl,
asio::error_code& ec) const
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
+ endpoint_type endpoint = impl.remote_endpoint_;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getpeername(impl.socket_, endpoint.data(),
+ &addr_len, impl.have_remote_endpoint_, ec))
return endpoint_type();
- }
-
- if (impl.socket_.have_remote_endpoint())
- {
- // Check if socket is still connected.
- DWORD connect_time = 0;
- size_t connect_time_len = sizeof(connect_time);
- if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_CONNECT_TIME,
- &connect_time, &connect_time_len, ec) == socket_error_retval)
- {
- return endpoint_type();
- }
- if (connect_time == 0xFFFFFFFF)
- {
- ec = asio::error::not_connected;
- return endpoint_type();
- }
-
- ec = asio::error_code();
- return impl.socket_.remote_endpoint();
- }
- else
- {
- endpoint_type endpoint;
- std::size_t addr_len = endpoint.capacity();
- if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec))
- return endpoint_type();
- endpoint.resize(addr_len);
- return endpoint;
- }
- }
-
- /// Disable sends or receives on the socket.
- asio::error_code shutdown(implementation_type& impl,
- socket_base::shutdown_type what, asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
- socket_ops::shutdown(impl.socket_, what, ec);
- return ec;
- }
-
- // Send the given data to the peer. Returns the number of bytes sent.
- template <typename ConstBufferSequence>
- size_t send(implementation_type& impl, const ConstBufferSequence& buffers,
- socket_base::message_flags flags, asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
- buffer_sequence_adapter<asio::const_buffer,
- ConstBufferSequence> bufs(buffers);
-
- // A request to receive 0 bytes on a stream socket is a no-op.
- if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty())
- {
- ec = asio::error_code();
- return 0;
- }
-
- // Send the data.
- DWORD bytes_transferred = 0;
- int result = ::WSASend(impl.socket_, bufs.buffers(),
- bufs.count(), &bytes_transferred, flags, 0, 0);
- if (result != 0)
- {
- DWORD last_error = ::WSAGetLastError();
- if (last_error == ERROR_NETNAME_DELETED)
- last_error = WSAECONNRESET;
- else if (last_error == ERROR_PORT_UNREACHABLE)
- last_error = WSAECONNREFUSED;
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- return 0;
- }
-
- ec = asio::error_code();
- return bytes_transferred;
- }
-
- // Wait until data can be sent without blocking.
- size_t send(implementation_type& impl, const null_buffers&,
- socket_base::message_flags, asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
- // Wait for socket to become ready.
- socket_ops::poll_write(impl.socket_, ec);
-
- return 0;
- }
-
- template <typename ConstBufferSequence, typename Handler>
- class send_op : public operation
- {
- public:
- send_op(weak_cancel_token_type cancel_token,
- const ConstBufferSequence& buffers, Handler handler)
- : operation(&send_op::do_complete),
- cancel_token_(cancel_token),
- buffers_(buffers),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code ec, std::size_t bytes_transferred)
- {
- // Take ownership of the operation object.
- send_op* o(static_cast<send_op*>(base));
- typedef handler_alloc_traits<Handler, send_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
-#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
- // Check whether buffers are still valid.
- buffer_sequence_adapter<asio::const_buffer,
- ConstBufferSequence>::validate(o->buffers_);
-#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-
- // Map non-portable errors to their portable counterparts.
- if (ec.value() == ERROR_NETNAME_DELETED)
- {
- if (o->cancel_token_.expired())
- ec = asio::error::operation_aborted;
- else
- ec = asio::error::connection_reset;
- }
- else if (ec.value() == ERROR_PORT_UNREACHABLE)
- {
- ec = asio::error::connection_refused;
- }
-
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder2<Handler, asio::error_code, std::size_t>
- handler(o->handler_, ec, bytes_transferred);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- weak_cancel_token_type cancel_token_;
- ConstBufferSequence buffers_;
- Handler handler_;
- };
-
- // Start an asynchronous send. The data being sent must be valid for the
- // lifetime of the asynchronous operation.
- template <typename ConstBufferSequence, typename Handler>
- void async_send(implementation_type& impl, const ConstBufferSequence& buffers,
- socket_base::message_flags flags, Handler handler)
- {
- // Allocate and construct an operation to wrap the handler.
- typedef send_op<ConstBufferSequence, Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr,
- impl.cancel_token_, buffers, handler);
-
- buffer_sequence_adapter<asio::const_buffer,
- ConstBufferSequence> bufs(buffers);
-
- start_send_op(impl, bufs.buffers(), bufs.count(), flags,
- impl.protocol_.type() == SOCK_STREAM && bufs.all_empty(), ptr.get());
- ptr.release();
- }
-
- // Start an asynchronous wait until data can be sent without blocking.
- template <typename Handler>
- void async_send(implementation_type& impl, const null_buffers&,
- socket_base::message_flags, Handler handler)
- {
- // Allocate and construct an operation to wrap the handler.
- typedef null_buffers_op<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
- start_reactor_op(impl, reactor::write_op, ptr.get());
- ptr.release();
+ endpoint.resize(addr_len);
+ return endpoint;
}
// Send a datagram to the specified endpoint. Returns the number of bytes
@@ -809,107 +233,25 @@ public:
const endpoint_type& destination, socket_base::message_flags flags,
asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
buffer_sequence_adapter<asio::const_buffer,
ConstBufferSequence> bufs(buffers);
- // Send the data.
- DWORD bytes_transferred = 0;
- int result = ::WSASendTo(impl.socket_, bufs.buffers(), bufs.count(),
- &bytes_transferred, flags, destination.data(),
- static_cast<int>(destination.size()), 0, 0);
- if (result != 0)
- {
- DWORD last_error = ::WSAGetLastError();
- if (last_error == ERROR_PORT_UNREACHABLE)
- last_error = WSAECONNREFUSED;
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- return 0;
- }
-
- ec = asio::error_code();
- return bytes_transferred;
+ return socket_ops::sync_sendto(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags,
+ destination.data(), destination.size(), ec);
}
// Wait until data can be sent without blocking.
size_t send_to(implementation_type& impl, const null_buffers&,
- socket_base::message_flags, const endpoint_type&,
+ const endpoint_type&, socket_base::message_flags,
asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
// Wait for socket to become ready.
socket_ops::poll_write(impl.socket_, ec);
return 0;
}
- template <typename ConstBufferSequence, typename Handler>
- class send_to_op : public operation
- {
- public:
- send_to_op(weak_cancel_token_type cancel_token,
- const ConstBufferSequence& buffers, Handler handler)
- : operation(&send_to_op::do_complete),
- cancel_token_(cancel_token),
- buffers_(buffers),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code ec, std::size_t bytes_transferred)
- {
- // Take ownership of the operation object.
- send_to_op* o(static_cast<send_to_op*>(base));
- typedef handler_alloc_traits<Handler, send_to_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
-#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
- // Check whether buffers are still valid.
- buffer_sequence_adapter<asio::const_buffer,
- ConstBufferSequence>::validate(o->buffers_);
-#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-
- // Map non-portable errors to their portable counterparts.
- if (ec.value() == ERROR_PORT_UNREACHABLE)
- {
- ec = asio::error::connection_refused;
- }
-
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder2<Handler, asio::error_code, std::size_t>
- handler(o->handler_, ec, bytes_transferred);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- weak_cancel_token_type cancel_token_;
- ConstBufferSequence buffers_;
- Handler handler_;
- };
-
// Start an asynchronous send. The data being sent must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
@@ -918,233 +260,35 @@ public:
socket_base::message_flags flags, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef send_to_op<ConstBufferSequence, Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr,
- impl.cancel_token_, buffers, handler);
+ typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.cancel_token_, buffers, handler);
buffer_sequence_adapter<asio::const_buffer,
ConstBufferSequence> bufs(buffers);
- start_send_to_op(impl, bufs.buffers(),
- bufs.count(), destination, flags, ptr.get());
- ptr.release();
+ start_send_to_op(impl, bufs.buffers(), bufs.count(),
+ destination.data(), static_cast<int>(destination.size()),
+ flags, p.p);
+ p.v = p.p = 0;
}
// Start an asynchronous wait until data can be sent without blocking.
template <typename Handler>
void async_send_to(implementation_type& impl, const null_buffers&,
- socket_base::message_flags, const endpoint_type&, Handler handler)
- {
- // Allocate and construct an operation to wrap the handler.
- typedef null_buffers_op<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
- start_reactor_op(impl, reactor::write_op, ptr.get());
- ptr.release();
- }
-
- // Receive some data from the peer. Returns the number of bytes received.
- template <typename MutableBufferSequence>
- size_t receive(implementation_type& impl,
- const MutableBufferSequence& buffers,
- socket_base::message_flags flags, asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
- buffer_sequence_adapter<asio::mutable_buffer,
- MutableBufferSequence> bufs(buffers);
-
- // A request to receive 0 bytes on a stream socket is a no-op.
- if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty())
- {
- ec = asio::error_code();
- return 0;
- }
-
- // Receive some data.
- DWORD bytes_transferred = 0;
- DWORD recv_flags = flags;
- int result = ::WSARecv(impl.socket_, bufs.buffers(),
- bufs.count(), &bytes_transferred, &recv_flags, 0, 0);
- if (result != 0)
- {
- DWORD last_error = ::WSAGetLastError();
- if (last_error == ERROR_NETNAME_DELETED)
- last_error = WSAECONNRESET;
- else if (last_error == ERROR_PORT_UNREACHABLE)
- last_error = WSAECONNREFUSED;
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- return 0;
- }
- if (bytes_transferred == 0 && impl.protocol_.type() == SOCK_STREAM)
- {
- ec = asio::error::eof;
- return 0;
- }
-
- ec = asio::error_code();
- return bytes_transferred;
- }
-
- // Wait until data can be received without blocking.
- size_t receive(implementation_type& impl, const null_buffers&,
- socket_base::message_flags, asio::error_code& ec)
- {
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
- // Wait for socket to become ready.
- socket_ops::poll_read(impl.socket_, ec);
-
- return 0;
- }
-
- template <typename MutableBufferSequence, typename Handler>
- class receive_op : public operation
- {
- public:
- receive_op(int protocol_type, weak_cancel_token_type cancel_token,
- const MutableBufferSequence& buffers, Handler handler)
- : operation(&receive_op::do_complete),
- protocol_type_(protocol_type),
- cancel_token_(cancel_token),
- buffers_(buffers),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code ec, std::size_t bytes_transferred)
- {
- // Take ownership of the operation object.
- receive_op* o(static_cast<receive_op*>(base));
- typedef handler_alloc_traits<Handler, receive_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
-#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
- // Check whether buffers are still valid.
- buffer_sequence_adapter<asio::mutable_buffer,
- MutableBufferSequence>::validate(o->buffers_);
-#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-
- // Map non-portable errors to their portable counterparts.
- if (ec.value() == ERROR_NETNAME_DELETED)
- {
- if (o->cancel_token_.expired())
- ec = asio::error::operation_aborted;
- else
- ec = asio::error::connection_reset;
- }
- else if (ec.value() == ERROR_PORT_UNREACHABLE)
- {
- ec = asio::error::connection_refused;
- }
-
- // Check for connection closed.
- else if (!ec && bytes_transferred == 0
- && o->protocol_type_ == SOCK_STREAM
- && !buffer_sequence_adapter<asio::mutable_buffer,
- MutableBufferSequence>::all_empty(o->buffers_)
- && !boost::is_same<MutableBufferSequence, null_buffers>::value)
- {
- ec = asio::error::eof;
- }
-
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder2<Handler, asio::error_code, std::size_t>
- handler(o->handler_, ec, bytes_transferred);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- int protocol_type_;
- weak_cancel_token_type cancel_token_;
- MutableBufferSequence buffers_;
- Handler handler_;
- };
-
- // Start an asynchronous receive. The buffer for the data being received
- // must be valid for the lifetime of the asynchronous operation.
- template <typename MutableBufferSequence, typename Handler>
- void async_receive(implementation_type& impl,
- const MutableBufferSequence& buffers,
- socket_base::message_flags flags, Handler handler)
+ const endpoint_type&, socket_base::message_flags, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef receive_op<MutableBufferSequence, Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- int protocol_type = impl.protocol_.type();
- handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type,
- impl.cancel_token_, buffers, handler);
-
- buffer_sequence_adapter<asio::mutable_buffer,
- MutableBufferSequence> bufs(buffers);
+ typedef win_iocp_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.cancel_token_, handler);
- start_receive_op(impl, bufs.buffers(), bufs.count(), flags,
- protocol_type == SOCK_STREAM && bufs.all_empty(), ptr.get());
- ptr.release();
- }
-
- // Wait until data can be received without blocking.
- template <typename Handler>
- void async_receive(implementation_type& impl, const null_buffers& buffers,
- socket_base::message_flags flags, Handler handler)
- {
- if (impl.protocol_.type() == SOCK_STREAM)
- {
- // For stream sockets on Windows, we may issue a 0-byte overlapped
- // WSARecv to wait until there is data available on the socket.
-
- // Allocate and construct an operation to wrap the handler.
- typedef receive_op<null_buffers, Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- int protocol_type = impl.protocol_.type();
- handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type,
- impl.cancel_token_, buffers, handler);
-
- ::WSABUF buf = { 0, 0 };
- start_receive_op(impl, &buf, 1, flags, false, ptr.get());
- ptr.release();
- }
- else
- {
- // Allocate and construct an operation to wrap the handler.
- typedef null_buffers_op<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
- start_reactor_op(impl,
- (flags & socket_base::message_out_of_band)
- ? reactor::except_op : reactor::read_op,
- ptr.get());
- ptr.release();
- }
+ start_reactor_op(impl, reactor::write_op, p.p);
+ p.v = p.p = 0;
}
// Receive a datagram with the endpoint of the sender. Returns the number of
@@ -1155,41 +299,18 @@ public:
endpoint_type& sender_endpoint, socket_base::message_flags flags,
asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
buffer_sequence_adapter<asio::mutable_buffer,
MutableBufferSequence> bufs(buffers);
- // Receive some data.
- DWORD bytes_transferred = 0;
- DWORD recv_flags = flags;
- int endpoint_size = static_cast<int>(sender_endpoint.capacity());
- int result = ::WSARecvFrom(impl.socket_, bufs.buffers(),
- bufs.count(), &bytes_transferred, &recv_flags,
- sender_endpoint.data(), &endpoint_size, 0, 0);
- if (result != 0)
- {
- DWORD last_error = ::WSAGetLastError();
- if (last_error == ERROR_PORT_UNREACHABLE)
- last_error = WSAECONNREFUSED;
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
- return 0;
- }
- if (bytes_transferred == 0 && impl.protocol_.type() == SOCK_STREAM)
- {
- ec = asio::error::eof;
- return 0;
- }
+ std::size_t addr_len = sender_endpoint.capacity();
+ std::size_t bytes_recvd = socket_ops::sync_recvfrom(
+ impl.socket_, impl.state_, bufs.buffers(), bufs.count(),
+ flags, sender_endpoint.data(), &addr_len, ec);
- sender_endpoint.resize(static_cast<std::size_t>(endpoint_size));
+ if (!ec)
+ sender_endpoint.resize(addr_len);
- ec = asio::error_code();
- return bytes_transferred;
+ return bytes_recvd;
}
// Wait until data can be received without blocking.
@@ -1197,12 +318,6 @@ public:
const null_buffers&, endpoint_type& sender_endpoint,
socket_base::message_flags, asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return 0;
- }
-
// Wait for socket to become ready.
socket_ops::poll_read(impl.socket_, ec);
@@ -1212,75 +327,6 @@ public:
return 0;
}
- template <typename MutableBufferSequence, typename Handler>
- class receive_from_op : public operation
- {
- public:
- receive_from_op(int protocol_type, endpoint_type& endpoint,
- const MutableBufferSequence& buffers, Handler handler)
- : operation(&receive_from_op::do_complete),
- protocol_type_(protocol_type),
- endpoint_(endpoint),
- endpoint_size_(static_cast<int>(endpoint.capacity())),
- buffers_(buffers),
- handler_(handler)
- {
- }
-
- int& endpoint_size()
- {
- return endpoint_size_;
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code ec, std::size_t bytes_transferred)
- {
- // Take ownership of the operation object.
- receive_from_op* o(static_cast<receive_from_op*>(base));
- typedef handler_alloc_traits<Handler, receive_from_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
-#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
- // Check whether buffers are still valid.
- buffer_sequence_adapter<asio::mutable_buffer,
- MutableBufferSequence>::validate(o->buffers_);
-#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
-
- // Map non-portable errors to their portable counterparts.
- if (ec.value() == ERROR_PORT_UNREACHABLE)
- {
- ec = asio::error::connection_refused;
- }
-
- // Record the size of the endpoint returned by the operation.
- o->endpoint_.resize(o->endpoint_size_);
-
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder2<Handler, asio::error_code, std::size_t>
- handler(o->handler_, ec, bytes_transferred);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- int protocol_type_;
- endpoint_type& endpoint_;
- int endpoint_size_;
- weak_cancel_token_type cancel_token_;
- MutableBufferSequence buffers_;
- Handler handler_;
- };
-
// Start an asynchronous receive. The buffer for the data being received and
// the sender_endpoint object must both be valid for the lifetime of the
// asynchronous operation.
@@ -1290,19 +336,19 @@ public:
socket_base::message_flags flags, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef receive_from_op<MutableBufferSequence, Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- int protocol_type = impl.protocol_.type();
- handler_ptr<alloc_traits> ptr(raw_ptr,
- protocol_type, sender_endp, buffers, handler);
+ typedef win_iocp_socket_recvfrom_op<
+ MutableBufferSequence, endpoint_type, Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(sender_endp, impl.cancel_token_, buffers, handler);
buffer_sequence_adapter<asio::mutable_buffer,
MutableBufferSequence> bufs(buffers);
start_receive_from_op(impl, bufs.buffers(), bufs.count(),
- sender_endp, flags, &ptr.get()->endpoint_size(), ptr.get());
- ptr.release();
+ sender_endp.data(), flags, &p.p->endpoint_size(), p.p);
+ p.v = p.p = 0;
}
// Wait until data can be received without blocking.
@@ -1312,19 +358,17 @@ public:
socket_base::message_flags flags, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef null_buffers_op<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+ typedef win_iocp_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.cancel_token_, handler);
// Reset endpoint since it can be given no sensible value at this time.
sender_endpoint = endpoint_type();
- start_reactor_op(impl,
- (flags & socket_base::message_out_of_band)
- ? reactor::except_op : reactor::read_op,
- ptr.get());
- ptr.release();
+ start_null_buffers_receive_op(impl, flags, p.p);
+ p.v = p.p = 0;
}
// Accept a new connection.
@@ -1332,12 +376,6 @@ public:
asio::error_code accept(implementation_type& impl, Socket& peer,
endpoint_type* peer_endpoint, asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
// We cannot accept a socket that is already open.
if (peer.is_open())
{
@@ -1345,222 +383,22 @@ public:
return ec;
}
- for (;;)
- {
- socket_holder new_socket;
- std::size_t addr_len = 0;
- if (peer_endpoint)
- {
- addr_len = peer_endpoint->capacity();
- new_socket.reset(socket_ops::accept(impl.socket_,
- peer_endpoint->data(), &addr_len, ec));
- }
- else
- {
- new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec));
- }
-
- if (ec)
- {
- if (ec == asio::error::connection_aborted
- && !(impl.flags_ & implementation_type::enable_connection_aborted))
- {
- // Retry accept operation.
- continue;
- }
- else
- {
- return ec;
- }
- }
+ std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;
+ socket_holder new_socket(socket_ops::sync_accept(impl.socket_,
+ impl.state_, peer_endpoint ? peer_endpoint->data() : 0,
+ peer_endpoint ? &addr_len : 0, ec));
+ // On success, assign new connection to peer socket object.
+ if (new_socket.get() >= 0)
+ {
if (peer_endpoint)
peer_endpoint->resize(addr_len);
-
- peer.assign(impl.protocol_, new_socket.get(), ec);
- if (!ec)
+ if (!peer.assign(impl.protocol_, new_socket.get(), ec))
new_socket.release();
- return ec;
- }
- }
-
- template <typename Socket, typename Handler>
- class accept_op : public operation
- {
- public:
- accept_op(win_iocp_io_service& iocp_service, socket_type socket,
- Socket& peer, const protocol_type& protocol,
- endpoint_type* peer_endpoint, bool enable_connection_aborted,
- Handler handler)
- : operation(&accept_op::do_complete),
- iocp_service_(iocp_service),
- socket_(socket),
- peer_(peer),
- protocol_(protocol),
- peer_endpoint_(peer_endpoint),
- enable_connection_aborted_(enable_connection_aborted),
- handler_(handler)
- {
}
- socket_holder& new_socket()
- {
- return new_socket_;
- }
-
- void* output_buffer()
- {
- return output_buffer_;
- }
-
- DWORD address_length()
- {
- return sizeof(sockaddr_storage_type) + 16;
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code ec, std::size_t /*bytes_transferred*/)
- {
- // Take ownership of the handler object.
- accept_op* o(static_cast<accept_op*>(base));
- typedef handler_alloc_traits<Handler, accept_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
- // Map Windows error ERROR_NETNAME_DELETED to connection_aborted.
- if (ec.value() == ERROR_NETNAME_DELETED)
- {
- ec = asio::error::connection_aborted;
- }
-
- // Restart the accept operation if we got the connection_aborted error
- // and the enable_connection_aborted socket option is not set.
- if (ec == asio::error::connection_aborted
- && !o->enable_connection_aborted_)
- {
- // Reset OVERLAPPED structure.
- o->reset();
-
- // Create a new socket for the next connection, since the AcceptEx
- // call fails with WSAEINVAL if we try to reuse the same socket.
- o->new_socket_.reset();
- o->new_socket_.reset(socket_ops::socket(o->protocol_.family(),
- o->protocol_.type(), o->protocol_.protocol(), ec));
- if (o->new_socket_.get() != invalid_socket)
- {
- // Accept a connection.
- DWORD bytes_read = 0;
- BOOL result = ::AcceptEx(o->socket_, o->new_socket_.get(),
- o->output_buffer(), 0, o->address_length(),
- o->address_length(), &bytes_read, o);
- DWORD last_error = ::WSAGetLastError();
- ec = asio::error_code(last_error,
- asio::error::get_system_category());
-
- // Check if the operation completed immediately.
- if (!result && last_error != WSA_IO_PENDING)
- {
- if (last_error == ERROR_NETNAME_DELETED
- || last_error == WSAECONNABORTED)
- {
- // Post this handler so that operation will be restarted again.
- o->iocp_service_.work_started();
- o->iocp_service_.on_completion(o, ec);
- ptr.release();
- return;
- }
- else
- {
- // Operation already complete. Continue with rest of this
- // handler.
- }
- }
- else
- {
- // Asynchronous operation has been successfully restarted.
- o->iocp_service_.work_started();
- o->iocp_service_.on_pending(o);
- ptr.release();
- return;
- }
- }
- }
-
- // Get the address of the peer.
- endpoint_type peer_endpoint;
- if (!ec)
- {
- LPSOCKADDR local_addr = 0;
- int local_addr_length = 0;
- LPSOCKADDR remote_addr = 0;
- int remote_addr_length = 0;
- GetAcceptExSockaddrs(o->output_buffer(), 0, o->address_length(),
- o->address_length(), &local_addr, &local_addr_length,
- &remote_addr, &remote_addr_length);
- if (static_cast<std::size_t>(remote_addr_length)
- > peer_endpoint.capacity())
- {
- ec = asio::error::invalid_argument;
- }
- else
- {
- using namespace std; // For memcpy.
- memcpy(peer_endpoint.data(), remote_addr, remote_addr_length);
- peer_endpoint.resize(static_cast<std::size_t>(remote_addr_length));
- }
- }
-
- // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
- // and getpeername will work on the accepted socket.
- if (!ec)
- {
- SOCKET update_ctx_param = o->socket_;
- socket_ops::setsockopt(o->new_socket_.get(),
- SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
- &update_ctx_param, sizeof(SOCKET), ec);
- }
-
- // If the socket was successfully accepted, transfer ownership of the
- // socket to the peer object.
- if (!ec)
- {
- o->peer_.assign(o->protocol_,
- native_type(o->new_socket_.get(), peer_endpoint), ec);
- if (!ec)
- o->new_socket_.release();
- }
-
- // Pass endpoint back to caller.
- if (o->peer_endpoint_)
- *o->peer_endpoint_ = peer_endpoint;
-
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder1<Handler, asio::error_code>
- handler(o->handler_, ec);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- win_iocp_io_service& iocp_service_;
- socket_type socket_;
- socket_holder new_socket_;
- Socket& peer_;
- protocol_type protocol_;
- endpoint_type* peer_endpoint_;
- unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
- bool enable_connection_aborted_;
- Handler handler_;
- };
+ return ec;
+ }
// Start an asynchronous accept. The peer and peer_endpoint objects
// must be valid until the accept's handler is invoked.
@@ -1569,442 +407,54 @@ public:
endpoint_type* peer_endpoint, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef accept_op<Socket, Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ typedef win_iocp_socket_accept_op<Socket, protocol_type, Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
bool enable_connection_aborted =
- (impl.flags_ & implementation_type::enable_connection_aborted);
- handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_, impl.socket_, peer,
- impl.protocol_, peer_endpoint, enable_connection_aborted, handler);
+ (impl.state_ & socket_ops::enable_connection_aborted) != 0;
+ p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_,
+ peer_endpoint, enable_connection_aborted, handler);
- start_accept_op(impl, peer.is_open(), ptr.get()->new_socket(),
- ptr.get()->output_buffer(), ptr.get()->address_length(), ptr.get());
- ptr.release();
+ start_accept_op(impl, peer.is_open(), p.p->new_socket(),
+ impl.protocol_.family(), impl.protocol_.type(),
+ impl.protocol_.protocol(), p.p->output_buffer(),
+ p.p->address_length(), p.p);
+ p.v = p.p = 0;
}
// Connect the socket to the specified endpoint.
asio::error_code connect(implementation_type& impl,
const endpoint_type& peer_endpoint, asio::error_code& ec)
{
- if (!is_open(impl))
- {
- ec = asio::error::bad_descriptor;
- return ec;
- }
-
- // Perform the connect operation.
- socket_ops::connect(impl.socket_,
+ socket_ops::sync_connect(impl.socket_,
peer_endpoint.data(), peer_endpoint.size(), ec);
return ec;
}
- class connect_op_base : public reactor_op
- {
- public:
- connect_op_base(socket_type socket, func_type complete_func)
- : reactor_op(&connect_op_base::do_perform, complete_func),
- socket_(socket)
- {
- }
-
- static bool do_perform(reactor_op* base)
- {
- connect_op_base* o(static_cast<connect_op_base*>(base));
-
- // Get the error code from the connect operation.
- int connect_error = 0;
- size_t connect_error_len = sizeof(connect_error);
- if (socket_ops::getsockopt(o->socket_, SOL_SOCKET, SO_ERROR,
- &connect_error, &connect_error_len, o->ec_) == socket_error_retval)
- return true;
-
- // The connection failed so the handler will be posted with an error code.
- if (connect_error)
- {
- o->ec_ = asio::error_code(connect_error,
- asio::error::get_system_category());
- }
-
- return true;
- }
-
- private:
- socket_type socket_;
- };
-
- template <typename Handler>
- class connect_op : public connect_op_base
- {
- public:
- connect_op(socket_type socket, Handler handler)
- : connect_op_base(socket, &connect_op::do_complete),
- handler_(handler)
- {
- }
-
- static void do_complete(io_service_impl* owner, operation* base,
- asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
- {
- // Take ownership of the handler object.
- connect_op* o(static_cast<connect_op*>(base));
- typedef handler_alloc_traits<Handler, connect_op> alloc_traits;
- handler_ptr<alloc_traits> ptr(o->handler_, o);
-
- // Make the upcall if required.
- if (owner)
- {
- // Make a copy of the handler so that the memory can be deallocated
- // before the upcall is made. Even if we're not about to make an
- // upcall, a sub-object of the handler may be the true owner of the
- // memory associated with the handler. Consequently, a local copy of
- // the handler is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- detail::binder1<Handler, asio::error_code>
- handler(o->handler_, o->ec_);
- ptr.reset();
- asio::detail::fenced_block b;
- asio_handler_invoke_helpers::invoke(handler, handler);
- }
- }
-
- private:
- Handler handler_;
- };
-
// Start an asynchronous connect.
template <typename Handler>
void async_connect(implementation_type& impl,
const endpoint_type& peer_endpoint, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef connect_op<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_, handler);
-
- start_connect_op(impl, ptr.get(), peer_endpoint);
- ptr.release();
- }
-
-private:
- // Helper function to start an asynchronous send operation.
- void start_send_op(implementation_type& impl, WSABUF* buffers,
- std::size_t buffer_count, socket_base::message_flags flags,
- bool noop, operation* op)
- {
- update_cancellation_thread_id(impl);
- iocp_service_.work_started();
-
- if (noop)
- iocp_service_.on_completion(op);
- else if (!is_open(impl))
- iocp_service_.on_completion(op, asio::error::bad_descriptor);
- else
- {
- DWORD bytes_transferred = 0;
- int result = ::WSASend(impl.socket_, buffers,
- buffer_count, &bytes_transferred, flags, op, 0);
- DWORD last_error = ::WSAGetLastError();
- if (last_error == ERROR_PORT_UNREACHABLE)
- last_error = WSAECONNREFUSED;
- if (result != 0 && last_error != WSA_IO_PENDING)
- iocp_service_.on_completion(op, last_error, bytes_transferred);
- else
- iocp_service_.on_pending(op);
- }
- }
-
- // Helper function to start an asynchronous send_to operation.
- void start_send_to_op(implementation_type& impl, WSABUF* buffers,
- std::size_t buffer_count, const endpoint_type& destination,
- socket_base::message_flags flags, operation* op)
- {
- update_cancellation_thread_id(impl);
- iocp_service_.work_started();
+ typedef reactive_socket_connect_op<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.socket_, handler);
- if (!is_open(impl))
- iocp_service_.on_completion(op, asio::error::bad_descriptor);
- else
- {
- DWORD bytes_transferred = 0;
- int result = ::WSASendTo(impl.socket_, buffers, buffer_count,
- &bytes_transferred, flags, destination.data(),
- static_cast<int>(destination.size()), op, 0);
- DWORD last_error = ::WSAGetLastError();
- if (last_error == ERROR_PORT_UNREACHABLE)
- last_error = WSAECONNREFUSED;
- if (result != 0 && last_error != WSA_IO_PENDING)
- iocp_service_.on_completion(op, last_error, bytes_transferred);
- else
- iocp_service_.on_pending(op);
- }
+ start_connect_op(impl, p.p, peer_endpoint.data(),
+ static_cast<int>(peer_endpoint.size()));
+ p.v = p.p = 0;
}
-
- // Helper function to start an asynchronous receive operation.
- void start_receive_op(implementation_type& impl, WSABUF* buffers,
- std::size_t buffer_count, socket_base::message_flags flags,
- bool noop, operation* op)
- {
- update_cancellation_thread_id(impl);
- iocp_service_.work_started();
-
- if (noop)
- iocp_service_.on_completion(op);
- else if (!is_open(impl))
- iocp_service_.on_completion(op, asio::error::bad_descriptor);
- else
- {
- DWORD bytes_transferred = 0;
- DWORD recv_flags = flags;
- int result = ::WSARecv(impl.socket_, buffers, buffer_count,
- &bytes_transferred, &recv_flags, op, 0);
- DWORD last_error = ::WSAGetLastError();
- if (last_error == ERROR_NETNAME_DELETED)
- last_error = WSAECONNRESET;
- else if (last_error == ERROR_PORT_UNREACHABLE)
- last_error = WSAECONNREFUSED;
- if (result != 0 && last_error != WSA_IO_PENDING)
- iocp_service_.on_completion(op, last_error, bytes_transferred);
- else
- iocp_service_.on_pending(op);
- }
- }
-
- // Helper function to start an asynchronous receive_from operation.
- void start_receive_from_op(implementation_type& impl, WSABUF* buffers,
- std::size_t buffer_count, endpoint_type& sender_endpoint,
- socket_base::message_flags flags, int* endpoint_size, operation* op)
- {
- update_cancellation_thread_id(impl);
- iocp_service_.work_started();
-
- if (!is_open(impl))
- iocp_service_.on_completion(op, asio::error::bad_descriptor);
- else
- {
- DWORD bytes_transferred = 0;
- DWORD recv_flags = flags;
- int result = ::WSARecvFrom(impl.socket_, buffers,
- buffer_count, &bytes_transferred, &recv_flags,
- sender_endpoint.data(), endpoint_size, op, 0);
- DWORD last_error = ::WSAGetLastError();
- if (last_error == ERROR_PORT_UNREACHABLE)
- last_error = WSAECONNREFUSED;
- if (result != 0 && last_error != WSA_IO_PENDING)
- iocp_service_.on_completion(op, last_error, bytes_transferred);
- else
- iocp_service_.on_pending(op);
- }
- }
-
- // Helper function to start an asynchronous receive_from operation.
- void start_accept_op(implementation_type& impl,
- bool peer_is_open, socket_holder& new_socket,
- void* output_buffer, DWORD address_length, operation* op)
- {
- update_cancellation_thread_id(impl);
- iocp_service_.work_started();
-
- if (!is_open(impl))
- iocp_service_.on_completion(op, asio::error::bad_descriptor);
- else if (peer_is_open)
- iocp_service_.on_completion(op, asio::error::already_open);
- else
- {
- asio::error_code ec;
- new_socket.reset(socket_ops::socket(impl.protocol_.family(),
- impl.protocol_.type(), impl.protocol_.protocol(), ec));
- if (new_socket.get() == invalid_socket)
- iocp_service_.on_completion(op, ec);
- else
- {
- DWORD bytes_read = 0;
- BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer,
- 0, address_length, address_length, &bytes_read, op);
- DWORD last_error = ::WSAGetLastError();
- if (!result && last_error != WSA_IO_PENDING)
- iocp_service_.on_completion(op, last_error);
- else
- iocp_service_.on_pending(op);
- }
- }
- }
-
- // Start an asynchronous read or write operation using the the reactor.
- void start_reactor_op(implementation_type& impl, int op_type, reactor_op* op)
- {
- reactor& r = get_reactor();
- update_cancellation_thread_id(impl);
-
- if (is_open(impl))
- {
- r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false);
- return;
- }
- else
- op->ec_ = asio::error::bad_descriptor;
-
- iocp_service_.post_immediate_completion(op);
- }
-
- // Start the asynchronous connect operation using the reactor.
- void start_connect_op(implementation_type& impl,
- reactor_op* op, const endpoint_type& peer_endpoint)
- {
- reactor& r = get_reactor();
- update_cancellation_thread_id(impl);
-
- if (is_open(impl))
- {
- ioctl_arg_type non_blocking = 1;
- if (!socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, op->ec_))
- {
- if (socket_ops::connect(impl.socket_, peer_endpoint.data(),
- peer_endpoint.size(), op->ec_) != 0)
- {
- if (!op->ec_
- && !(impl.flags_ & implementation_type::user_set_non_blocking))
- {
- non_blocking = 0;
- socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, op->ec_);
- }
-
- if (op->ec_ == asio::error::in_progress
- || op->ec_ == asio::error::would_block)
- {
- op->ec_ = asio::error_code();
- r.start_op(reactor::connect_op, impl.socket_,
- impl.reactor_data_, op, true);
- return;
- }
- }
- }
- }
- else
- op->ec_ = asio::error::bad_descriptor;
-
- iocp_service_.post_immediate_completion(op);
- }
-
- // Helper function to close a socket when the associated object is being
- // destroyed.
- void close_for_destruction(implementation_type& impl)
- {
- if (is_open(impl))
- {
- // Check if the reactor was created, in which case we need to close the
- // socket on the reactor as well to cancel any operations that might be
- // running there.
- reactor* r = static_cast<reactor*>(
- interlocked_compare_exchange_pointer(
- reinterpret_cast<void**>(&reactor_), 0, 0));
- if (r)
- r->close_descriptor(impl.socket_, impl.reactor_data_);
-
- // The socket destructor must not block. If the user has changed the
- // linger option to block in the foreground, we will change it back to the
- // default so that the closure is performed in the background.
- if (impl.flags_ & implementation_type::close_might_block)
- {
- ::linger opt;
- opt.l_onoff = 0;
- opt.l_linger = 0;
- asio::error_code ignored_ec;
- socket_ops::setsockopt(impl.socket_,
- SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec);
- }
-
- asio::error_code ignored_ec;
- socket_ops::close(impl.socket_, ignored_ec);
- impl.socket_ = invalid_socket;
- impl.flags_ = 0;
- impl.cancel_token_.reset();
-#if defined(ASIO_ENABLE_CANCELIO)
- impl.safe_cancellation_thread_id_ = 0;
-#endif // defined(ASIO_ENABLE_CANCELIO)
- }
- }
-
- // Update the ID of the thread from which cancellation is safe.
- void update_cancellation_thread_id(implementation_type& impl)
- {
-#if defined(ASIO_ENABLE_CANCELIO)
- if (impl.safe_cancellation_thread_id_ == 0)
- impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
- else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
- impl.safe_cancellation_thread_id_ = ~DWORD(0);
-#else // defined(ASIO_ENABLE_CANCELIO)
- (void)impl;
-#endif // defined(ASIO_ENABLE_CANCELIO)
- }
-
- // Helper function to get the reactor. If no reactor has been created yet, a
- // new one is obtained from the io_service and a pointer to it is cached in
- // this service.
- reactor& get_reactor()
- {
- reactor* r = static_cast<reactor*>(
- interlocked_compare_exchange_pointer(
- reinterpret_cast<void**>(&reactor_), 0, 0));
- if (!r)
- {
- r = &(use_service<reactor>(io_service_));
- interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r);
- }
- return *r;
- }
-
- // Helper function to emulate InterlockedCompareExchangePointer functionality
- // for:
- // - very old Platform SDKs; and
- // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
- void* interlocked_compare_exchange_pointer(void** dest, void* exch, void* cmp)
- {
-#if defined(_M_IX86)
- return reinterpret_cast<void*>(InterlockedCompareExchange(
- reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch),
- reinterpret_cast<LONG>(cmp)));
-#else
- return InterlockedCompareExchangePointer(dest, exch, cmp);
-#endif
- }
-
- // Helper function to emulate InterlockedExchangePointer functionality for:
- // - very old Platform SDKs; and
- // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
- void* interlocked_exchange_pointer(void** dest, void* val)
- {
-#if defined(_M_IX86)
- return reinterpret_cast<void*>(InterlockedExchange(
- reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val)));
-#else
- return InterlockedExchangePointer(dest, val);
-#endif
- }
-
- // The io_service used to obtain the reactor, if required.
- asio::io_service& io_service_;
-
- // The IOCP service used for running asynchronous operations and dispatching
- // handlers.
- win_iocp_io_service& iocp_service_;
-
- // The reactor used for performing connect operations. This object is created
- // only if needed.
- reactor* reactor_;
-
- // Mutex to protect access to the linked list of implementations.
- asio::detail::mutex mutex_;
-
- // The head of a linked list of all implementations.
- implementation_type* impl_list_;
};
} // namespace detail
} // namespace asio
-#endif // defined(ASIO_HAS_IOCP)
-
#include "asio/detail/pop_options.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
diff --git a/ext/asio/asio/detail/win_iocp_socket_service_base.hpp b/ext/asio/asio/detail/win_iocp_socket_service_base.hpp
new file mode 100644
index 0000000..62010b3
--- /dev/null
+++ b/ext/asio/asio/detail/win_iocp_socket_service_base.hpp
@@ -0,0 +1,385 @@
+//
+// detail/win_iocp_socket_service_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include <boost/type_traits/is_same.hpp>
+#include <boost/utility/addressof.hpp>
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/reactor.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/win_iocp_io_service.hpp"
+#include "asio/detail/win_iocp_null_buffers_op.hpp"
+#include "asio/detail/win_iocp_socket_send_op.hpp"
+#include "asio/detail/win_iocp_socket_recv_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_iocp_socket_service_base
+{
+public:
+ // The implementation type of the socket.
+ struct base_implementation_type
+ {
+ // The native socket representation.
+ socket_type socket_;
+
+ // The current state of the socket.
+ socket_ops::state_type state_;
+
+ // We use a shared pointer as a cancellation token here to work around the
+ // broken Windows support for cancellation. MSDN says that when you call
+ // closesocket any outstanding WSARecv or WSASend operations will complete
+ // with the error ERROR_OPERATION_ABORTED. In practice they complete with
+ // ERROR_NETNAME_DELETED, which means you can't tell the difference between
+ // a local cancellation and the socket being hard-closed by the peer.
+ socket_ops::shared_cancel_token_type cancel_token_;
+
+ // Per-descriptor data used by the reactor.
+ reactor::per_descriptor_data reactor_data_;
+
+#if defined(ASIO_ENABLE_CANCELIO)
+ // The ID of the thread from which it is safe to cancel asynchronous
+ // operations. 0 means no asynchronous operations have been started yet.
+ // ~0 means asynchronous operations have been started from more than one
+ // thread, and cancellation is not supported for the socket.
+ DWORD safe_cancellation_thread_id_;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ // Pointers to adjacent socket implementations in linked list.
+ base_implementation_type* next_;
+ base_implementation_type* prev_;
+ };
+
+ // Constructor.
+ ASIO_DECL win_iocp_socket_service_base(
+ asio::io_service& io_service);
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown_service();
+
+ // Construct a new socket implementation.
+ ASIO_DECL void construct(base_implementation_type& impl);
+
+ // Destroy a socket implementation.
+ ASIO_DECL void destroy(base_implementation_type& impl);
+
+ // Determine whether the socket is open.
+ bool is_open(const base_implementation_type& impl) const
+ {
+ return impl.socket_ != invalid_socket;
+ }
+
+ // Destroy a socket implementation.
+ ASIO_DECL asio::error_code close(
+ base_implementation_type& impl, asio::error_code& ec);
+
+ // Cancel all operations associated with the socket.
+ ASIO_DECL asio::error_code cancel(
+ base_implementation_type& impl, asio::error_code& ec);
+
+ // Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const base_implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ return socket_ops::sockatmark(impl.socket_, ec);
+ }
+
+ // Determine the number of bytes available for reading.
+ std::size_t available(const base_implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ return socket_ops::available(impl.socket_, ec);
+ }
+
+ // Place the socket into the state where it will listen for new connections.
+ asio::error_code listen(base_implementation_type& impl,
+ int backlog, asio::error_code& ec)
+ {
+ socket_ops::listen(impl.socket_, backlog, ec);
+ return ec;
+ }
+
+ // Perform an IO control command on the socket.
+ template <typename IO_Control_Command>
+ asio::error_code io_control(base_implementation_type& impl,
+ IO_Control_Command& command, asio::error_code& ec)
+ {
+ socket_ops::ioctl(impl.socket_, impl.state_, command.name(),
+ static_cast<ioctl_arg_type*>(command.data()), ec);
+ return ec;
+ }
+
+ /// Disable sends or receives on the socket.
+ asio::error_code shutdown(base_implementation_type& impl,
+ socket_base::shutdown_type what, asio::error_code& ec)
+ {
+ socket_ops::shutdown(impl.socket_, what, ec);
+ return ec;
+ }
+
+ // Send the given data to the peer. Returns the number of bytes sent.
+ template <typename ConstBufferSequence>
+ size_t send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_send(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, asio::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous send. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.cancel_token_, buffers, handler);
+
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
+
+ start_send_op(impl, bufs.buffers(), bufs.count(), flags,
+ (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(),
+ p.p);
+ p.v = p.p = 0;
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.cancel_token_, handler);
+
+ start_reactor_op(impl, reactor::write_op, p.p);
+ p.v = p.p = 0;
+ }
+
+ // Receive some data from the peer. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_recv(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, asio::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous receive. The buffer for the data being received
+ // must be valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_receive(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_socket_recv_op<MutableBufferSequence, Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.state_, impl.cancel_token_, buffers, handler);
+
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ start_receive_op(impl, bufs.buffers(), bufs.count(), flags,
+ (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(),
+ p.p);
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags flags, Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_null_buffers_op<Handler> op;
+ typename op::ptr p = { boost::addressof(handler),
+ asio_handler_alloc_helpers::allocate(
+ sizeof(op), handler), 0 };
+ p.p = new (p.v) op(impl.cancel_token_, handler);
+
+ start_null_buffers_receive_op(impl, flags, p.p);
+ p.v = p.p = 0;
+ }
+
+ // Helper function to restart an asynchronous accept operation.
+ ASIO_DECL void restart_accept_op(socket_type s,
+ socket_holder& new_socket, int family, int type, int protocol,
+ void* output_buffer, DWORD address_length, operation* op);
+
+protected:
+ // Open a new socket implementation.
+ ASIO_DECL asio::error_code do_open(
+ base_implementation_type& impl, int family, int type,
+ int protocol, asio::error_code& ec);
+
+ // Assign a native socket to a socket implementation.
+ ASIO_DECL asio::error_code do_assign(
+ base_implementation_type& impl, int type,
+ socket_type native_socket, asio::error_code& ec);
+
+ // Helper function to start an asynchronous send operation.
+ ASIO_DECL void start_send_op(base_implementation_type& impl,
+ WSABUF* buffers, std::size_t buffer_count,
+ socket_base::message_flags flags, bool noop, operation* op);
+
+ // Helper function to start an asynchronous send_to operation.
+ ASIO_DECL void start_send_to_op(base_implementation_type& impl,
+ WSABUF* buffers, std::size_t buffer_count,
+ const socket_addr_type* addr, int addrlen,
+ socket_base::message_flags flags, operation* op);
+
+ // Helper function to start an asynchronous receive operation.
+ ASIO_DECL void start_receive_op(base_implementation_type& impl,
+ WSABUF* buffers, std::size_t buffer_count,
+ socket_base::message_flags flags, bool noop, operation* op);
+
+ // Helper function to start an asynchronous null_buffers receive operation.
+ ASIO_DECL void start_null_buffers_receive_op(
+ base_implementation_type& impl,
+ socket_base::message_flags flags, reactor_op* op);
+
+ // Helper function to start an asynchronous receive_from operation.
+ ASIO_DECL void start_receive_from_op(base_implementation_type& impl,
+ WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr,
+ socket_base::message_flags flags, int* addrlen, operation* op);
+
+ // Helper function to start an asynchronous accept operation.
+ ASIO_DECL void start_accept_op(base_implementation_type& impl,
+ bool peer_is_open, socket_holder& new_socket, int family, int type,
+ int protocol, void* output_buffer, DWORD address_length, operation* op);
+
+ // Start an asynchronous read or write operation using the the reactor.
+ ASIO_DECL void start_reactor_op(base_implementation_type& impl,
+ int op_type, reactor_op* op);
+
+ // Start the asynchronous connect operation using the reactor.
+ ASIO_DECL void start_connect_op(base_implementation_type& impl,
+ reactor_op* op, const socket_addr_type* addr, std::size_t addrlen);
+
+ // Helper function to close a socket when the associated object is being
+ // destroyed.
+ ASIO_DECL void close_for_destruction(base_implementation_type& impl);
+
+ // Update the ID of the thread from which cancellation is safe.
+ ASIO_DECL void update_cancellation_thread_id(
+ base_implementation_type& impl);
+
+ // Helper function to get the reactor. If no reactor has been created yet, a
+ // new one is obtained from the io_service and a pointer to it is cached in
+ // this service.
+ ASIO_DECL reactor& get_reactor();
+
+ // Helper function to emulate InterlockedCompareExchangePointer functionality
+ // for:
+ // - very old Platform SDKs; and
+ // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
+ ASIO_DECL void* interlocked_compare_exchange_pointer(
+ void** dest, void* exch, void* cmp);
+
+ // Helper function to emulate InterlockedExchangePointer functionality for:
+ // - very old Platform SDKs; and
+ // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
+ ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val);
+
+ // The io_service used to obtain the reactor, if required.
+ asio::io_service& io_service_;
+
+ // The IOCP service used for running asynchronous operations and dispatching
+ // handlers.
+ win_iocp_io_service& iocp_service_;
+
+ // The reactor used for performing connect operations. This object is created
+ // only if needed.
+ reactor* reactor_;
+
+ // Mutex to protect access to the linked list of implementations.
+ asio::detail::mutex mutex_;
+
+ // The head of a linked list of all implementations.
+ base_implementation_type* impl_list_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_iocp_socket_service_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP
diff --git a/ext/asio/asio/detail/win_mutex.hpp b/ext/asio/asio/detail/win_mutex.hpp
index 1280a4e..59ad697 100644
--- a/ext/asio/asio/detail/win_mutex.hpp
+++ b/ext/asio/asio/detail/win_mutex.hpp
@@ -1,8 +1,8 @@
//
-// win_mutex.hpp
-// ~~~~~~~~~~~~~
+// detail/win_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,23 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if defined(BOOST_WINDOWS)
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
-#include "asio/detail/socket_types.hpp"
#include "asio/detail/scoped_lock.hpp"
+#include "asio/detail/socket_types.hpp"
#include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
@@ -43,18 +35,7 @@ public:
typedef asio::detail::scoped_lock<win_mutex> scoped_lock;
// Constructor.
- win_mutex()
- {
- int error = do_init();
- if (error != 0)
- {
- asio::system_error e(
- asio::error_code(error,
- asio::error::get_system_category()),
- "mutex");
- boost::throw_exception(e);
- }
- }
+ ASIO_DECL win_mutex();
// Destructor.
~win_mutex()
@@ -78,35 +59,7 @@ private:
// Initialisation must be performed in a separate function to the constructor
// since the compiler does not support the use of structured exceptions and
// C++ exceptions in the same function.
- int do_init()
- {
-#if defined(__MINGW32__)
- // Not sure if MinGW supports structured exception handling, so for now
- // we'll just call the Windows API and hope.
-# if defined(UNDER_CE)
- ::InitializeCriticalSection(&crit_section_);
-# else
- ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000);
-# endif
- return 0;
-#else
- __try
- {
-# if defined(UNDER_CE)
- ::InitializeCriticalSection(&crit_section_);
-# else
- ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000);
-# endif
- }
- __except(GetExceptionCode() == STATUS_NO_MEMORY
- ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
- {
- return ERROR_OUTOFMEMORY;
- }
-
- return 0;
-#endif
- }
+ ASIO_DECL int do_init();
::CRITICAL_SECTION crit_section_;
};
@@ -114,8 +67,12 @@ private:
} // namespace detail
} // namespace asio
-#endif // defined(BOOST_WINDOWS)
-
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_mutex.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_WINDOWS)
+
#endif // ASIO_DETAIL_WIN_MUTEX_HPP
diff --git a/ext/asio/asio/detail/win_thread.hpp b/ext/asio/asio/detail/win_thread.hpp
index 9bf0665..e73d1a4 100644
--- a/ext/asio/asio/detail/win_thread.hpp
+++ b/ext/asio/asio/detail/win_thread.hpp
@@ -1,8 +1,8 @@
//
-// win_thread.hpp
-// ~~~~~~~~~~~~~~
+// detail/win_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,34 +15,24 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if defined(BOOST_WINDOWS) && !defined(UNDER_CE)
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
-#include <memory>
-#include <process.h>
-#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
-unsigned int __stdcall win_thread_function(void* arg);
+ASIO_DECL unsigned int __stdcall win_thread_function(void* arg);
#if defined(WINVER) && (WINVER < 0x0500)
-void __stdcall apc_function(ULONG data);
+ASIO_DECL void __stdcall apc_function(ULONG data);
#else
-void __stdcall apc_function(ULONG_PTR data);
+ASIO_DECL void __stdcall apc_function(ULONG_PTR data);
#endif
template <typename T>
@@ -73,92 +63,26 @@ class win_thread
public:
// Constructor.
template <typename Function>
- win_thread(Function f)
- : exit_event_(0)
+ win_thread(Function f, unsigned int stack_size = 0)
+ : thread_(0),
+ exit_event_(0)
{
- std::auto_ptr<func_base> arg(new func<Function>(f));
-
- ::HANDLE entry_event = 0;
- arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0);
- if (!entry_event)
- {
- DWORD last_error = ::GetLastError();
- asio::system_error e(
- asio::error_code(last_error,
- asio::error::get_system_category()),
- "thread.entry_event");
- boost::throw_exception(e);
- }
-
- arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0);
- if (!exit_event_)
- {
- DWORD last_error = ::GetLastError();
- ::CloseHandle(entry_event);
- asio::system_error e(
- asio::error_code(last_error,
- asio::error::get_system_category()),
- "thread.exit_event");
- boost::throw_exception(e);
- }
-
- unsigned int thread_id = 0;
- thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0, 0,
- win_thread_function, arg.get(), 0, &thread_id));
- if (!thread_)
- {
- DWORD last_error = ::GetLastError();
- if (entry_event)
- ::CloseHandle(entry_event);
- if (exit_event_)
- ::CloseHandle(exit_event_);
- asio::system_error e(
- asio::error_code(last_error,
- asio::error::get_system_category()),
- "thread");
- boost::throw_exception(e);
- }
- arg.release();
-
- if (entry_event)
- {
- ::WaitForSingleObject(entry_event, INFINITE);
- ::CloseHandle(entry_event);
- }
+ start_thread(new func<Function>(f), stack_size);
}
// Destructor.
- ~win_thread()
- {
- ::CloseHandle(thread_);
-
- // The exit_event_ handle is deliberately allowed to leak here since it
- // is an error for the owner of an internal thread not to join() it.
- }
+ ASIO_DECL ~win_thread();
// Wait for the thread to exit.
- void join()
- {
- ::WaitForSingleObject(exit_event_, INFINITE);
- ::CloseHandle(exit_event_);
- if (terminate_threads())
- {
- ::TerminateThread(thread_, 0);
- }
- else
- {
- ::QueueUserAPC(apc_function, thread_, 0);
- ::WaitForSingleObject(thread_, INFINITE);
- }
- }
+ ASIO_DECL void join();
private:
- friend unsigned int __stdcall win_thread_function(void* arg);
+ friend ASIO_DECL unsigned int __stdcall win_thread_function(void* arg);
#if defined(WINVER) && (WINVER < 0x0500)
- friend void __stdcall apc_function(ULONG);
+ friend ASIO_DECL void __stdcall apc_function(ULONG);
#else
- friend void __stdcall apc_function(ULONG_PTR);
+ friend ASIO_DECL void __stdcall apc_function(ULONG_PTR);
#endif
class func_base
@@ -170,6 +94,12 @@ private:
::HANDLE exit_event_;
};
+ struct auto_func_base_ptr
+ {
+ func_base* ptr;
+ ~auto_func_base_ptr() { delete ptr; }
+ };
+
template <typename Function>
class func
: public func_base
@@ -189,44 +119,21 @@ private:
Function f_;
};
+ ASIO_DECL void start_thread(func_base* arg, unsigned int stack_size);
+
::HANDLE thread_;
::HANDLE exit_event_;
};
-inline unsigned int __stdcall win_thread_function(void* arg)
-{
- std::auto_ptr<win_thread::func_base> func(
- static_cast<win_thread::func_base*>(arg));
-
- ::SetEvent(func->entry_event_);
-
- func->run();
-
- // Signal that the thread has finished its work, but rather than returning go
- // to sleep to put the thread into a well known state. If the thread is being
- // joined during global object destruction then it may be killed using
- // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx
- // call will be interrupted using QueueUserAPC and the thread will shut down
- // cleanly.
- HANDLE exit_event = func->exit_event_;
- func.reset();
- ::SetEvent(exit_event);
- ::SleepEx(INFINITE, TRUE);
-
- return 0;
-}
-
-#if defined(WINVER) && (WINVER < 0x0500)
-inline void __stdcall apc_function(ULONG) {}
-#else
-inline void __stdcall apc_function(ULONG_PTR) {}
-#endif
-
} // namespace detail
} // namespace asio
-#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE)
-
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_thread.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE)
+
#endif // ASIO_DETAIL_WIN_THREAD_HPP
diff --git a/ext/asio/asio/detail/win_tss_ptr.hpp b/ext/asio/asio/detail/win_tss_ptr.hpp
index 5a4ed33..fb055f6 100644
--- a/ext/asio/asio/detail/win_tss_ptr.hpp
+++ b/ext/asio/asio/detail/win_tss_ptr.hpp
@@ -1,8 +1,8 @@
//
-// win_tss_ptr.hpp
-// ~~~~~~~~~~~~~~~
+// detail/win_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,50 +15,30 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if defined(BOOST_WINDOWS)
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
+// Helper function to create thread-specific storage.
+ASIO_DECL DWORD win_tss_ptr_create();
+
template <typename T>
class win_tss_ptr
: private noncopyable
{
public:
-#if defined(UNDER_CE)
- enum { out_of_indexes = 0xFFFFFFFF };
-#else
- enum { out_of_indexes = TLS_OUT_OF_INDEXES };
-#endif
-
// Constructor.
win_tss_ptr()
+ : tss_key_(win_tss_ptr_create())
{
- tss_key_ = ::TlsAlloc();
- if (tss_key_ == out_of_indexes)
- {
- DWORD last_error = ::GetLastError();
- asio::system_error e(
- asio::error_code(last_error,
- asio::error::get_system_category()),
- "tss");
- boost::throw_exception(e);
- }
}
// Destructor.
@@ -88,8 +68,12 @@ private:
} // namespace detail
} // namespace asio
-#endif // defined(BOOST_WINDOWS)
-
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_tss_ptr.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_WINDOWS)
+
#endif // ASIO_DETAIL_WIN_TSS_PTR_HPP
diff --git a/ext/asio/asio/detail/wince_thread.hpp b/ext/asio/asio/detail/wince_thread.hpp
index 0b6de48..1dc9990 100644
--- a/ext/asio/asio/detail/wince_thread.hpp
+++ b/ext/asio/asio/detail/wince_thread.hpp
@@ -1,8 +1,8 @@
//
-// wince_thread.hpp
-// ~~~~~~~~~~~~~~~~
+// detail/wince_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,23 +15,17 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
+#include <memory>
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
-#include <memory>
-#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
@@ -53,11 +47,9 @@ public:
if (!thread_)
{
DWORD last_error = ::GetLastError();
- asio::system_error e(
- asio::error_code(last_error,
- asio::error::get_system_category()),
- "thread");
- boost::throw_exception(e);
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "thread");
}
arg.release();
}
@@ -117,8 +109,8 @@ inline DWORD WINAPI wince_thread_function(LPVOID arg)
} // namespace detail
} // namespace asio
-#endif // defined(BOOST_WINDOWS) && defined(UNDER_CE)
-
#include "asio/detail/pop_options.hpp"
+#endif // defined(BOOST_WINDOWS) && defined(UNDER_CE)
+
#endif // ASIO_DETAIL_WINCE_THREAD_HPP
diff --git a/ext/asio/asio/detail/winsock_init.hpp b/ext/asio/asio/detail/winsock_init.hpp
index ae5c4bf..a410859 100644
--- a/ext/asio/asio/detail/winsock_init.hpp
+++ b/ext/asio/asio/detail/winsock_init.hpp
@@ -1,8 +1,8 @@
//
-// winsock_init.hpp
-// ~~~~~~~~~~~~~~~~
+// detail/winsock_init.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,106 +15,76 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/push_options.hpp"
-#include <boost/shared_ptr.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
-#include "asio/detail/noncopyable.hpp"
-#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
-template <int Major = 2, int Minor = 0>
-class winsock_init
- : private noncopyable
+class winsock_init_base
{
-private:
- // Structure to perform the actual initialisation.
- struct do_init
+protected:
+ // Structure to track result of initialisation and number of uses. POD is used
+ // to ensure that the values are zero-initialised prior to any code being run.
+ struct data
{
- do_init()
- {
- WSADATA wsa_data;
- result_ = ::WSAStartup(MAKEWORD(Major, Minor), &wsa_data);
- }
-
- ~do_init()
- {
- ::WSACleanup();
- }
-
- int result() const
- {
- return result_;
- }
-
- // Helper function to manage a do_init singleton. The static instance of the
- // winsock_init object ensures that this function is always called before
- // main, and therefore before any other threads can get started. The do_init
- // instance must be static in this function to ensure that it gets
- // initialised before any other global objects try to use it.
- static boost::shared_ptr<do_init> instance()
- {
- static boost::shared_ptr<do_init> init(new do_init);
- return init;
- }
-
- private:
- int result_;
+ long init_count_;
+ long result_;
};
+ ASIO_DECL static void startup(data& d,
+ unsigned char major, unsigned char minor);
+
+ ASIO_DECL static void cleanup(data& d);
+
+ ASIO_DECL static void throw_on_error(data& d);
+};
+
+template <int Major = 2, int Minor = 0>
+class winsock_init : private winsock_init_base
+{
public:
- // Constructor.
- winsock_init()
- : ref_(do_init::instance())
+ winsock_init(bool allow_throw = true)
+ {
+ startup(data_, Major, Minor);
+ if (allow_throw)
+ throw_on_error(data_);
+ }
+
+ winsock_init(const winsock_init&)
{
- // Check whether winsock was successfully initialised. This check is not
- // performed for the global instance since there will be nobody around to
- // catch the exception.
- if (this != &instance_ && ref_->result() != 0)
- {
- asio::system_error e(
- asio::error_code(ref_->result(),
- asio::error::get_system_category()),
- "winsock");
- boost::throw_exception(e);
- }
+ startup(data_, Major, Minor);
+ throw_on_error(data_);
}
- // Destructor.
~winsock_init()
{
+ cleanup(data_);
}
private:
- // Instance to force initialisation of winsock at global scope.
- static winsock_init instance_;
-
- // Reference to singleton do_init object to ensure that winsock does not get
- // cleaned up until the last user has finished with it.
- boost::shared_ptr<do_init> ref_;
+ static data data_;
};
template <int Major, int Minor>
-winsock_init<Major, Minor> winsock_init<Major, Minor>::instance_;
+winsock_init_base::data winsock_init<Major, Minor>::data_;
+
+// Static variable to ensure that winsock is initialised before main, and
+// therefore before any other threads can get started.
+static const winsock_init<>& winsock_init_instance = winsock_init<>(false);
} // namespace detail
} // namespace asio
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/winsock_init.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
#endif // ASIO_DETAIL_WINSOCK_INIT_HPP
diff --git a/ext/asio/asio/detail/wrapped_handler.hpp b/ext/asio/asio/detail/wrapped_handler.hpp
index e40a7f1..bcebf6e 100644
--- a/ext/asio/asio/detail/wrapped_handler.hpp
+++ b/ext/asio/asio/detail/wrapped_handler.hpp
@@ -1,8 +1,8 @@
//
-// wrapped_handler.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// detail/wrapped_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/type_traits/add_reference.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
@@ -34,9 +30,7 @@ class wrapped_handler
public:
typedef void result_type;
- wrapped_handler(
- typename boost::add_reference<Dispatcher>::type dispatcher,
- Handler handler)
+ wrapped_handler(Dispatcher dispatcher, Handler handler)
: dispatcher_(dispatcher),
handler_(handler)
{
diff --git a/ext/asio/asio/error.hpp b/ext/asio/asio/error.hpp
index 73caac6..138b5d7 100644
--- a/ext/asio/asio/error.hpp
+++ b/ext/asio/asio/error.hpp
@@ -2,7 +2,7 @@
// error.hpp
// ~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <cerrno>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error_code.hpp"
-#include "asio/detail/socket_types.hpp"
+#include "asio/detail/config.hpp"
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# include <winerror.h>
+#else
+# include <cerrno>
+# include <netdb.h>
+#endif
#if defined(GENERATING_DOCUMENTATION)
/// INTERNAL ONLY.
@@ -50,6 +48,8 @@
# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix
#endif
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace error {
@@ -212,7 +212,21 @@ enum ssl_errors
{
};
-// boostify: error category definitions go here.
+// boostify: error category definitions start here.
+
+} // namespace error
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error_code.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace error {
+
+// boostify: error category definitions end here.
inline asio::error_code make_error_code(basic_errors e)
{
@@ -247,14 +261,16 @@ inline asio::error_code make_error_code(ssl_errors e)
} // namespace error
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#undef ASIO_NATIVE_ERROR
#undef ASIO_SOCKET_ERROR
#undef ASIO_NETDB_ERROR
#undef ASIO_GETADDRINFO_ERROR
#undef ASIO_WIN_OR_POSIX
-#include "asio/impl/error_code.ipp"
-
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/error.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
#endif // ASIO_ERROR_HPP
diff --git a/ext/asio/asio/error_code.hpp b/ext/asio/asio/error_code.hpp
index 6657f3f..1af449b 100644
--- a/ext/asio/asio/error_code.hpp
+++ b/ext/asio/asio/error_code.hpp
@@ -2,7 +2,7 @@
// error_code.hpp
// ~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,8 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
+#include "asio/detail/config.hpp"
#include <string>
-#include "asio/detail/pop_options.hpp"
#if defined(GENERATING_DOCUMENTATION)
# define ASIO_WIN_OR_POSIX(e_win, e_posix) implementation_defined
@@ -30,6 +26,8 @@
# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix
#endif
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace error
@@ -106,7 +104,7 @@ public:
}
/// Get the message associated with the error.
- std::string message() const;
+ ASIO_DECL std::string message() const;
struct unspecified_bool_type_t
{
@@ -114,14 +112,12 @@ public:
typedef void (*unspecified_bool_type)(unspecified_bool_type_t);
- static void unspecified_bool_true(unspecified_bool_type_t)
- {
- }
+ static void unspecified_bool_true(unspecified_bool_type_t) {}
/// Operator returns non-null if there is a non-success error code.
operator unspecified_bool_type() const
{
- if (value_ == 0)
+ if (!value_)
return 0;
else
return &error_code::unspecified_bool_true;
@@ -130,7 +126,7 @@ public:
/// Operator to test if the error represents success.
bool operator!() const
{
- return value_ == 0;
+ return !value_;
}
/// Equality operator to compare two error objects.
@@ -155,10 +151,12 @@ private:
} // namespace asio
-#undef ASIO_WIN_OR_POSIX
+#include "asio/detail/pop_options.hpp"
-#include "asio/error.hpp"
+#undef ASIO_WIN_OR_POSIX
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/error_code.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
#endif // ASIO_ERROR_CODE_HPP
diff --git a/ext/asio/asio/handler_alloc_hook.hpp b/ext/asio/asio/handler_alloc_hook.hpp
index 87783cd..dd930b6 100644
--- a/ext/asio/asio/handler_alloc_hook.hpp
+++ b/ext/asio/asio/handler_alloc_hook.hpp
@@ -2,7 +2,7 @@
// handler_alloc_hook.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include <cstddef>
#include "asio/detail/push_options.hpp"
-#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
namespace asio {
diff --git a/ext/asio/asio/handler_invoke_hook.hpp b/ext/asio/asio/handler_invoke_hook.hpp
index b3d7e45..ef22359 100644
--- a/ext/asio/asio/handler_invoke_hook.hpp
+++ b/ext/asio/asio/handler_invoke_hook.hpp
@@ -2,7 +2,7 @@
// handler_invoke_hook.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,6 +15,8 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+#include "asio/detail/config.hpp"
+
#include "asio/detail/push_options.hpp"
namespace asio {
diff --git a/ext/asio/asio/impl/error.ipp b/ext/asio/asio/impl/error.ipp
new file mode 100644
index 0000000..54388b3
--- /dev/null
+++ b/ext/asio/asio/impl/error.ipp
@@ -0,0 +1,33 @@
+//
+// impl/error.ipp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_ERROR_IPP
+#define ASIO_IMPL_ERROR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace error {
+
+// boostify: error category function definitions go here.
+
+} // namespace error
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_ERROR_IPP
diff --git a/ext/asio/asio/impl/error_code.ipp b/ext/asio/asio/impl/error_code.ipp
index 614925d..ed37a17 100644
--- a/ext/asio/asio/impl/error_code.ipp
+++ b/ext/asio/asio/impl/error_code.ipp
@@ -1,50 +1,55 @@
//
-// error_code.ipp
-// ~~~~~~~~~~~~~~
+// impl/error_code.ipp
+// ~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
-#ifndef ASIO_ERROR_CODE_IPP
-#define ASIO_ERROR_CODE_IPP
+#ifndef ASIO_IMPL_ERROR_CODE_IPP
+#define ASIO_IMPL_ERROR_CODE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include <cerrno>
-#include <cstring>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
+#include "asio/detail/config.hpp"
#include "asio/detail/local_free_on_block_exit.hpp"
#include "asio/detail/socket_types.hpp"
+#include "asio/error.hpp"
+#include "asio/error_code.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
-inline std::string error_code::message() const
+std::string error_code::message() const
{
- if (*this == error::already_open)
- return "Already open.";
- if (*this == error::not_found)
- return "Not found.";
- if (*this == error::fd_set_failure)
- return "The descriptor does not fit into the select call's fd_set.";
+ if (category_ == error::get_misc_category())
+ {
+ if (value_ == error::already_open)
+ return "Already open.";
+ if (value_ == error::not_found)
+ return "Not found.";
+ if (value_ == error::fd_set_failure)
+ return "The descriptor does not fit into the select call's fd_set.";
+ if (value_ == error::not_found)
+ return "Element not found.";
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+ if (value_ == error::eof)
+ return "End of file.";
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+ }
if (category_ == error::get_ssl_category())
return "SSL error.";
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
value_type value = value_;
- if (category() != error::get_system_category() && *this != error::eof)
- return "asio error";
- if (*this == error::eof)
+ if (category_ == error::get_misc_category() && value_ == error::eof)
value = ERROR_HANDLE_EOF;
+ else if (category_ != error::get_system_category())
+ return "asio error";
char* msg = 0;
DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
@@ -60,29 +65,31 @@ inline std::string error_code::message() const
else
return "asio error";
#else // defined(BOOST_WINDOWS)
- if (*this == error::eof)
- return "End of file.";
- if (*this == error::host_not_found)
- return "Host not found (authoritative).";
- if (*this == error::host_not_found_try_again)
- return "Host not found (non-authoritative), try again later.";
- if (*this == error::no_recovery)
- return "A non-recoverable error occurred during database lookup.";
- if (*this == error::no_data)
- return "The query is valid, but it does not have associated data.";
- if (*this == error::not_found)
- return "Element not found.";
+ if (category_ == error::get_netdb_category())
+ {
+ if (value_ == error::host_not_found)
+ return "Host not found (authoritative).";
+ if (value_ == error::host_not_found_try_again)
+ return "Host not found (non-authoritative), try again later.";
+ if (value_ == error::no_recovery)
+ return "A non-recoverable error occurred during database lookup.";
+ if (value_ == error::no_data)
+ return "The query is valid, but it does not have associated data.";
+ }
+ if (category_ == error::get_addrinfo_category())
+ {
+ if (value_ == error::service_not_found)
+ return "Service not found.";
+ if (value_ == error::socket_type_not_supported)
+ return "Socket type not supported.";
+ }
+ if (category_ != error::get_system_category())
+ return "asio error";
#if !defined(__sun)
- if (*this == error::operation_aborted)
+ if (value_ == error::operation_aborted)
return "Operation aborted.";
#endif // !defined(__sun)
- if (*this == error::service_not_found)
- return "Service not found.";
- if (*this == error::socket_type_not_supported)
- return "Socket type not supported.";
- if (category() != error::get_system_category())
- return "asio error";
-#if defined(__sun) || defined(__QNX__)
+#if defined(__sun) || defined(__QNX__) || defined(__SYMBIAN32__)
using namespace std;
return strerror(value_);
#elif defined(__MACH__) && defined(__APPLE__) \
@@ -102,4 +109,4 @@ inline std::string error_code::message() const
#include "asio/detail/pop_options.hpp"
-#endif // ASIO_ERROR_CODE_IPP
+#endif // ASIO_IMPL_ERROR_CODE_IPP
diff --git a/ext/asio/asio/impl/io_service.hpp b/ext/asio/asio/impl/io_service.hpp
new file mode 100644
index 0000000..f0c1730
--- /dev/null
+++ b/ext/asio/asio/impl/io_service.hpp
@@ -0,0 +1,132 @@
+//
+// impl/io_service.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_IO_SERVICE_HPP
+#define ASIO_IMPL_IO_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/service_registry.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename Service>
+inline Service& use_service(io_service& ios)
+{
+ // Check that Service meets the necessary type requirements.
+ (void)static_cast<io_service::service*>(static_cast<Service*>(0));
+ (void)static_cast<const io_service::id*>(&Service::id);
+
+ return ios.service_registry_->template use_service<Service>();
+}
+
+template <typename Service>
+inline void add_service(io_service& ios, Service* svc)
+{
+ // Check that Service meets the necessary type requirements.
+ (void)static_cast<io_service::service*>(static_cast<Service*>(0));
+ (void)static_cast<const io_service::id*>(&Service::id);
+
+ ios.service_registry_->template add_service<Service>(svc);
+}
+
+template <typename Service>
+inline bool has_service(io_service& ios)
+{
+ // Check that Service meets the necessary type requirements.
+ (void)static_cast<io_service::service*>(static_cast<Service*>(0));
+ (void)static_cast<const io_service::id*>(&Service::id);
+
+ return ios.service_registry_->template has_service<Service>();
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_service.hpp"
+#else
+# include "asio/detail/task_io_service.hpp"
+#endif
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename Handler>
+inline void io_service::dispatch(Handler handler)
+{
+ impl_.dispatch(handler);
+}
+
+template <typename Handler>
+inline void io_service::post(Handler handler)
+{
+ impl_.post(handler);
+}
+
+template <typename Handler>
+#if defined(GENERATING_DOCUMENTATION)
+unspecified
+#else
+inline detail::wrapped_handler<io_service&, Handler>
+#endif
+io_service::wrap(Handler handler)
+{
+ return detail::wrapped_handler<io_service&, Handler>(*this, handler);
+}
+
+inline io_service::work::work(asio::io_service& io_service)
+ : io_service_(io_service)
+{
+ io_service_.impl_.work_started();
+}
+
+inline io_service::work::work(const work& other)
+ : io_service_(other.io_service_)
+{
+ io_service_.impl_.work_started();
+}
+
+inline io_service::work::~work()
+{
+ io_service_.impl_.work_finished();
+}
+
+inline asio::io_service& io_service::work::io_service()
+{
+ return io_service_;
+}
+
+inline asio::io_service& io_service::work::get_io_service()
+{
+ return io_service_;
+}
+
+inline asio::io_service& io_service::service::io_service()
+{
+ return owner_;
+}
+
+inline asio::io_service& io_service::service::get_io_service()
+{
+ return owner_;
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_IO_SERVICE_HPP
diff --git a/ext/asio/asio/impl/io_service.ipp b/ext/asio/asio/impl/io_service.ipp
index c3fed3b..eb19b8f 100644
--- a/ext/asio/asio/impl/io_service.ipp
+++ b/ext/asio/asio/impl/io_service.ipp
@@ -1,26 +1,23 @@
//
-// io_service.ipp
-// ~~~~~~~~~~~~~~
+// impl/io_service.ipp
+// ~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
-#ifndef ASIO_IO_SERVICE_IPP
-#define ASIO_IO_SERVICE_IPP
+#ifndef ASIO_IMPL_IO_SERVICE_IPP
+#define ASIO_IMPL_IO_SERVICE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <boost/limits.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/io_service.hpp"
#include "asio/detail/service_registry.hpp"
#include "asio/detail/throw_error.hpp"
@@ -28,31 +25,32 @@
# include "asio/detail/win_iocp_io_service.hpp"
#else
# include "asio/detail/task_io_service.hpp"
-# include "asio/detail/reactor.hpp"
#endif
+#include "asio/detail/push_options.hpp"
+
namespace asio {
-inline io_service::io_service()
+io_service::io_service()
: service_registry_(new asio::detail::service_registry(*this)),
impl_(service_registry_->use_service<impl_type>())
{
impl_.init((std::numeric_limits<std::size_t>::max)());
}
-inline io_service::io_service(std::size_t concurrency_hint)
+io_service::io_service(std::size_t concurrency_hint)
: service_registry_(new asio::detail::service_registry(*this)),
impl_(service_registry_->use_service<impl_type>())
{
impl_.init(concurrency_hint);
}
-inline io_service::~io_service()
+io_service::~io_service()
{
delete service_registry_;
}
-inline std::size_t io_service::run()
+std::size_t io_service::run()
{
asio::error_code ec;
std::size_t s = impl_.run(ec);
@@ -60,12 +58,12 @@ inline std::size_t io_service::run()
return s;
}
-inline std::size_t io_service::run(asio::error_code& ec)
+std::size_t io_service::run(asio::error_code& ec)
{
return impl_.run(ec);
}
-inline std::size_t io_service::run_one()
+std::size_t io_service::run_one()
{
asio::error_code ec;
std::size_t s = impl_.run_one(ec);
@@ -73,12 +71,12 @@ inline std::size_t io_service::run_one()
return s;
}
-inline std::size_t io_service::run_one(asio::error_code& ec)
+std::size_t io_service::run_one(asio::error_code& ec)
{
return impl_.run_one(ec);
}
-inline std::size_t io_service::poll()
+std::size_t io_service::poll()
{
asio::error_code ec;
std::size_t s = impl_.poll(ec);
@@ -86,12 +84,12 @@ inline std::size_t io_service::poll()
return s;
}
-inline std::size_t io_service::poll(asio::error_code& ec)
+std::size_t io_service::poll(asio::error_code& ec)
{
return impl_.poll(ec);
}
-inline std::size_t io_service::poll_one()
+std::size_t io_service::poll_one()
{
asio::error_code ec;
std::size_t s = impl_.poll_one(ec);
@@ -99,126 +97,43 @@ inline std::size_t io_service::poll_one()
return s;
}
-inline std::size_t io_service::poll_one(asio::error_code& ec)
+std::size_t io_service::poll_one(asio::error_code& ec)
{
return impl_.poll_one(ec);
}
-inline void io_service::stop()
+void io_service::stop()
{
impl_.stop();
}
-inline void io_service::reset()
+void io_service::reset()
{
impl_.reset();
}
-template <typename Handler>
-inline void io_service::dispatch(Handler handler)
-{
- impl_.dispatch(handler);
-}
-
-template <typename Handler>
-inline void io_service::post(Handler handler)
-{
- impl_.post(handler);
-}
-
-template <typename Handler>
-#if defined(GENERATING_DOCUMENTATION)
-unspecified
-#else
-inline detail::wrapped_handler<io_service&, Handler>
-#endif
-io_service::wrap(Handler handler)
-{
- return detail::wrapped_handler<io_service&, Handler>(*this, handler);
-}
-
-inline io_service::work::work(asio::io_service& io_service)
- : io_service_(io_service)
-{
- io_service_.impl_.work_started();
-}
-
-inline io_service::work::work(const work& other)
- : io_service_(other.io_service_)
-{
- io_service_.impl_.work_started();
-}
-
-inline io_service::work::~work()
-{
- io_service_.impl_.work_finished();
-}
-
-inline asio::io_service& io_service::work::io_service()
-{
- return io_service_;
-}
-
-inline asio::io_service& io_service::work::get_io_service()
-{
- return io_service_;
-}
-
-inline io_service::service::service(asio::io_service& owner)
+io_service::service::service(asio::io_service& owner)
: owner_(owner),
next_(0)
{
}
-inline io_service::service::~service()
-{
-}
-
-inline asio::io_service& io_service::service::io_service()
-{
- return owner_;
-}
-
-inline asio::io_service& io_service::service::get_io_service()
+io_service::service::~service()
{
- return owner_;
}
-template <typename Service>
-inline Service& use_service(io_service& ios)
+service_already_exists::service_already_exists()
+ : std::logic_error("Service already exists.")
{
- // Check that Service meets the necessary type requirements.
- (void)static_cast<io_service::service*>(static_cast<Service*>(0));
- (void)static_cast<const io_service::id*>(&Service::id);
-
- return ios.service_registry_->template use_service<Service>();
}
-template <typename Service>
-void add_service(io_service& ios, Service* svc)
+invalid_service_owner::invalid_service_owner()
+ : std::logic_error("Invalid service owner.")
{
- // Check that Service meets the necessary type requirements.
- (void)static_cast<io_service::service*>(static_cast<Service*>(0));
- (void)static_cast<const io_service::id*>(&Service::id);
-
- if (&ios != &svc->io_service())
- boost::throw_exception(invalid_service_owner());
- if (!ios.service_registry_->template add_service<Service>(svc))
- boost::throw_exception(service_already_exists());
-}
-
-template <typename Service>
-bool has_service(io_service& ios)
-{
- // Check that Service meets the necessary type requirements.
- (void)static_cast<io_service::service*>(static_cast<Service*>(0));
- (void)static_cast<const io_service::id*>(&Service::id);
-
- return ios.service_registry_->template has_service<Service>();
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
-#endif // ASIO_IO_SERVICE_IPP
+#endif // ASIO_IMPL_IO_SERVICE_IPP
diff --git a/ext/asio/asio/impl/read.hpp b/ext/asio/asio/impl/read.hpp
new file mode 100644
index 0000000..bd5d7b5
--- /dev/null
+++ b/ext/asio/asio/impl/read.hpp
@@ -0,0 +1,386 @@
+//
+// impl/read.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_READ_HPP
+#define ASIO_IMPL_READ_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <algorithm>
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/detail/base_from_completion_cond.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/consuming_buffers.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename SyncReadStream, typename MutableBufferSequence,
+ typename CompletionCondition>
+std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
+ CompletionCondition completion_condition, asio::error_code& ec)
+{
+ ec = asio::error_code();
+ asio::detail::consuming_buffers<
+ mutable_buffer, MutableBufferSequence> tmp(buffers);
+ std::size_t total_transferred = 0;
+ tmp.prepare(detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred)));
+ while (tmp.begin() != tmp.end())
+ {
+ std::size_t bytes_transferred = s.read_some(tmp, ec);
+ tmp.consume(bytes_transferred);
+ total_transferred += bytes_transferred;
+ tmp.prepare(detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred)));
+ }
+ return total_transferred;
+}
+
+template <typename SyncReadStream, typename MutableBufferSequence>
+inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename MutableBufferSequence,
+ typename CompletionCondition>
+inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
+ CompletionCondition completion_condition)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read(s, buffers, completion_condition, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+template <typename SyncReadStream, typename Allocator,
+ typename CompletionCondition>
+std::size_t read(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition, asio::error_code& ec)
+{
+ ec = asio::error_code();
+ std::size_t total_transferred = 0;
+ std::size_t max_size = detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred));
+ std::size_t bytes_available = read_size_helper(b, max_size);
+ while (bytes_available > 0)
+ {
+ std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec);
+ b.commit(bytes_transferred);
+ total_transferred += bytes_transferred;
+ max_size = detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred));
+ bytes_available = read_size_helper(b, max_size);
+ }
+ return total_transferred;
+}
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read(s, b, transfer_all(), ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename Allocator,
+ typename CompletionCondition>
+inline std::size_t read(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read(s, b, completion_condition, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+namespace detail
+{
+ template <typename AsyncReadStream, typename MutableBufferSequence,
+ typename CompletionCondition, typename ReadHandler>
+ class read_op
+ : detail::base_from_completion_cond<CompletionCondition>
+ {
+ public:
+ read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers,
+ CompletionCondition completion_condition, ReadHandler handler)
+ : detail::base_from_completion_cond<
+ CompletionCondition>(completion_condition),
+ stream_(stream),
+ buffers_(buffers),
+ total_transferred_(0),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred, int start = 0)
+ {
+ switch (start)
+ {
+ case 1:
+ buffers_.prepare(this->check_for_completion(ec, total_transferred_));
+ for (;;)
+ {
+ stream_.async_read_some(buffers_, *this);
+ return; default:
+ total_transferred_ += bytes_transferred;
+ buffers_.consume(bytes_transferred);
+ buffers_.prepare(this->check_for_completion(ec, total_transferred_));
+ if ((!ec && bytes_transferred == 0)
+ || buffers_.begin() == buffers_.end())
+ break;
+ }
+
+ handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+ }
+ }
+
+ //private:
+ AsyncReadStream& stream_;
+ asio::detail::consuming_buffers<
+ mutable_buffer, MutableBufferSequence> buffers_;
+ std::size_t total_transferred_;
+ ReadHandler handler_;
+ };
+
+ template <typename AsyncReadStream,
+ typename CompletionCondition, typename ReadHandler>
+ class read_op<AsyncReadStream, asio::mutable_buffers_1,
+ CompletionCondition, ReadHandler>
+ : detail::base_from_completion_cond<CompletionCondition>
+ {
+ public:
+ read_op(AsyncReadStream& stream,
+ const asio::mutable_buffers_1& buffers,
+ CompletionCondition completion_condition,
+ ReadHandler handler)
+ : detail::base_from_completion_cond<
+ CompletionCondition>(completion_condition),
+ stream_(stream),
+ buffer_(buffers),
+ total_transferred_(0),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred, int start = 0)
+ {
+ std::size_t n = 0;
+ switch (start)
+ {
+ case 1:
+ n = this->check_for_completion(ec, total_transferred_);
+ for (;;)
+ {
+ stream_.async_read_some(asio::buffer(
+ buffer_ + total_transferred_, n), *this);
+ return; default:
+ total_transferred_ += bytes_transferred;
+ if ((!ec && bytes_transferred == 0)
+ || (n = this->check_for_completion(ec, total_transferred_)) == 0
+ || total_transferred_ == asio::buffer_size(buffer_))
+ break;
+ }
+
+ handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+ }
+ }
+
+ //private:
+ AsyncReadStream& stream_;
+ asio::mutable_buffer buffer_;
+ std::size_t total_transferred_;
+ ReadHandler handler_;
+ };
+
+ template <typename AsyncReadStream, typename MutableBufferSequence,
+ typename CompletionCondition, typename ReadHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ read_op<AsyncReadStream, MutableBufferSequence,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+ }
+
+ template <typename AsyncReadStream, typename MutableBufferSequence,
+ typename CompletionCondition, typename ReadHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ read_op<AsyncReadStream, MutableBufferSequence,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncReadStream,
+ typename MutableBufferSequence, typename CompletionCondition,
+ typename ReadHandler>
+ inline void asio_handler_invoke(const Function& function,
+ read_op<AsyncReadStream, MutableBufferSequence,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncReadStream, typename MutableBufferSequence,
+ typename CompletionCondition, typename ReadHandler>
+inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
+ CompletionCondition completion_condition, ReadHandler handler)
+{
+ detail::read_op<AsyncReadStream, MutableBufferSequence,
+ CompletionCondition, ReadHandler>(
+ s, buffers, completion_condition, handler)(
+ asio::error_code(), 0, 1);
+}
+
+template <typename AsyncReadStream, typename MutableBufferSequence,
+ typename ReadHandler>
+inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
+ ReadHandler handler)
+{
+ async_read(s, buffers, transfer_all(), handler);
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+namespace detail
+{
+ template <typename AsyncReadStream, typename Allocator,
+ typename CompletionCondition, typename ReadHandler>
+ class read_streambuf_op
+ : detail::base_from_completion_cond<CompletionCondition>
+ {
+ public:
+ read_streambuf_op(AsyncReadStream& stream,
+ basic_streambuf<Allocator>& streambuf,
+ CompletionCondition completion_condition, ReadHandler handler)
+ : detail::base_from_completion_cond<
+ CompletionCondition>(completion_condition),
+ stream_(stream),
+ streambuf_(streambuf),
+ total_transferred_(0),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred, int start = 0)
+ {
+ std::size_t max_size, bytes_available;
+ switch (start)
+ {
+ case 1:
+ max_size = this->check_for_completion(ec, total_transferred_);
+ bytes_available = read_size_helper(streambuf_, max_size);
+ for (;;)
+ {
+ stream_.async_read_some(streambuf_.prepare(bytes_available), *this);
+ return; default:
+ total_transferred_ += bytes_transferred;
+ streambuf_.commit(bytes_transferred);
+ max_size = this->check_for_completion(ec, total_transferred_);
+ bytes_available = read_size_helper(streambuf_, max_size);
+ if ((!ec && bytes_transferred == 0) || bytes_available == 0)
+ break;
+ }
+
+ handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+ }
+ }
+
+ //private:
+ AsyncReadStream& stream_;
+ asio::basic_streambuf<Allocator>& streambuf_;
+ std::size_t total_transferred_;
+ ReadHandler handler_;
+ };
+
+ template <typename AsyncReadStream, typename Allocator,
+ typename CompletionCondition, typename ReadHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ read_streambuf_op<AsyncReadStream, Allocator,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+ }
+
+ template <typename AsyncReadStream, typename Allocator,
+ typename CompletionCondition, typename ReadHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ read_streambuf_op<AsyncReadStream, Allocator,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncReadStream,
+ typename Allocator, typename CompletionCondition, typename ReadHandler>
+ inline void asio_handler_invoke(const Function& function,
+ read_streambuf_op<AsyncReadStream, Allocator,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncReadStream, typename Allocator,
+ typename CompletionCondition, typename ReadHandler>
+inline void async_read(AsyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition, ReadHandler handler)
+{
+ detail::read_streambuf_op<AsyncReadStream,
+ Allocator, CompletionCondition, ReadHandler>(
+ s, b, completion_condition, handler)(
+ asio::error_code(), 0, 1);
+}
+
+template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+inline void async_read(AsyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, ReadHandler handler)
+{
+ async_read(s, b, transfer_all(), handler);
+}
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_READ_HPP
diff --git a/ext/asio/asio/impl/read_at.hpp b/ext/asio/asio/impl/read_at.hpp
new file mode 100644
index 0000000..da57fe3
--- /dev/null
+++ b/ext/asio/asio/impl/read_at.hpp
@@ -0,0 +1,410 @@
+//
+// impl/read_at.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_READ_AT_HPP
+#define ASIO_IMPL_READ_AT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <algorithm>
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/detail/base_from_completion_cond.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/consuming_buffers.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
+ typename CompletionCondition>
+std::size_t read_at(SyncRandomAccessReadDevice& d,
+ boost::uint64_t offset, const MutableBufferSequence& buffers,
+ CompletionCondition completion_condition, asio::error_code& ec)
+{
+ ec = asio::error_code();
+ asio::detail::consuming_buffers<
+ mutable_buffer, MutableBufferSequence> tmp(buffers);
+ std::size_t total_transferred = 0;
+ tmp.prepare(detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred)));
+ while (tmp.begin() != tmp.end())
+ {
+ std::size_t bytes_transferred = d.read_some_at(
+ offset + total_transferred, tmp, ec);
+ tmp.consume(bytes_transferred);
+ total_transferred += bytes_transferred;
+ tmp.prepare(detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred)));
+ }
+ return total_transferred;
+}
+
+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
+inline std::size_t read_at(SyncRandomAccessReadDevice& d,
+ boost::uint64_t offset, const MutableBufferSequence& buffers)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read_at(
+ d, offset, buffers, transfer_all(), ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
+ typename CompletionCondition>
+inline std::size_t read_at(SyncRandomAccessReadDevice& d,
+ boost::uint64_t offset, const MutableBufferSequence& buffers,
+ CompletionCondition completion_condition)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read_at(
+ d, offset, buffers, completion_condition, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+template <typename SyncRandomAccessReadDevice, typename Allocator,
+ typename CompletionCondition>
+std::size_t read_at(SyncRandomAccessReadDevice& d,
+ boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition, asio::error_code& ec)
+{
+ ec = asio::error_code();
+ std::size_t total_transferred = 0;
+ std::size_t max_size = detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred));
+ std::size_t bytes_available = read_size_helper(b, max_size);
+ while (bytes_available > 0)
+ {
+ std::size_t bytes_transferred = d.read_some_at(
+ offset + total_transferred, b.prepare(bytes_available), ec);
+ b.commit(bytes_transferred);
+ total_transferred += bytes_transferred;
+ max_size = detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred));
+ bytes_available = read_size_helper(b, max_size);
+ }
+ return total_transferred;
+}
+
+template <typename SyncRandomAccessReadDevice, typename Allocator>
+inline std::size_t read_at(SyncRandomAccessReadDevice& d,
+ boost::uint64_t offset, asio::basic_streambuf<Allocator>& b)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read_at(
+ d, offset, b, transfer_all(), ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncRandomAccessReadDevice, typename Allocator,
+ typename CompletionCondition>
+inline std::size_t read_at(SyncRandomAccessReadDevice& d,
+ boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read_at(
+ d, offset, b, completion_condition, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+namespace detail
+{
+ template <typename AsyncRandomAccessReadDevice,
+ typename MutableBufferSequence, typename CompletionCondition,
+ typename ReadHandler>
+ class read_at_op
+ : detail::base_from_completion_cond<CompletionCondition>
+ {
+ public:
+ read_at_op(AsyncRandomAccessReadDevice& device,
+ boost::uint64_t offset, const MutableBufferSequence& buffers,
+ CompletionCondition completion_condition, ReadHandler handler)
+ : detail::base_from_completion_cond<
+ CompletionCondition>(completion_condition),
+ device_(device),
+ offset_(offset),
+ buffers_(buffers),
+ total_transferred_(0),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred, int start = 0)
+ {
+ switch (start)
+ {
+ case 1:
+ buffers_.prepare(this->check_for_completion(ec, total_transferred_));
+ for (;;)
+ {
+ device_.async_read_some_at(
+ offset_ + total_transferred_, buffers_, *this);
+ return; default:
+ total_transferred_ += bytes_transferred;
+ buffers_.consume(bytes_transferred);
+ buffers_.prepare(this->check_for_completion(ec, total_transferred_));
+ if ((!ec && bytes_transferred == 0)
+ || buffers_.begin() == buffers_.end())
+ break;
+ }
+
+ handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+ }
+ }
+
+ //private:
+ AsyncRandomAccessReadDevice& device_;
+ boost::uint64_t offset_;
+ asio::detail::consuming_buffers<
+ mutable_buffer, MutableBufferSequence> buffers_;
+ std::size_t total_transferred_;
+ ReadHandler handler_;
+ };
+
+ template <typename AsyncRandomAccessReadDevice,
+ typename CompletionCondition, typename ReadHandler>
+ class read_at_op<AsyncRandomAccessReadDevice,
+ asio::mutable_buffers_1, CompletionCondition, ReadHandler>
+ : detail::base_from_completion_cond<CompletionCondition>
+ {
+ public:
+ read_at_op(AsyncRandomAccessReadDevice& device,
+ boost::uint64_t offset, const asio::mutable_buffers_1& buffers,
+ CompletionCondition completion_condition, ReadHandler handler)
+ : detail::base_from_completion_cond<
+ CompletionCondition>(completion_condition),
+ device_(device),
+ offset_(offset),
+ buffer_(buffers),
+ total_transferred_(0),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred, int start = 0)
+ {
+ std::size_t n = 0;
+ switch (start)
+ {
+ case 1:
+ n = this->check_for_completion(ec, total_transferred_);
+ for (;;)
+ {
+ device_.async_read_some_at(offset_ + total_transferred_,
+ asio::buffer(buffer_ + total_transferred_, n), *this);
+ return; default:
+ total_transferred_ += bytes_transferred;
+ if ((!ec && bytes_transferred == 0)
+ || (n = this->check_for_completion(ec, total_transferred_)) == 0
+ || total_transferred_ == asio::buffer_size(buffer_))
+ break;
+ }
+
+ handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+ }
+ }
+
+ //private:
+ AsyncRandomAccessReadDevice& device_;
+ boost::uint64_t offset_;
+ asio::mutable_buffer buffer_;
+ std::size_t total_transferred_;
+ ReadHandler handler_;
+ };
+
+ template <typename AsyncRandomAccessReadDevice,
+ typename MutableBufferSequence, typename CompletionCondition,
+ typename ReadHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+ }
+
+ template <typename AsyncRandomAccessReadDevice,
+ typename MutableBufferSequence, typename CompletionCondition,
+ typename ReadHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncRandomAccessReadDevice,
+ typename MutableBufferSequence, typename CompletionCondition,
+ typename ReadHandler>
+ inline void asio_handler_invoke(const Function& function,
+ read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,
+ typename CompletionCondition, typename ReadHandler>
+inline void async_read_at(AsyncRandomAccessReadDevice& d,
+ boost::uint64_t offset, const MutableBufferSequence& buffers,
+ CompletionCondition completion_condition, ReadHandler handler)
+{
+ detail::read_at_op<AsyncRandomAccessReadDevice,
+ MutableBufferSequence, CompletionCondition, ReadHandler>(
+ d, offset, buffers, completion_condition, handler)(
+ asio::error_code(), 0, 1);
+}
+
+template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,
+ typename ReadHandler>
+inline void async_read_at(AsyncRandomAccessReadDevice& d,
+ boost::uint64_t offset, const MutableBufferSequence& buffers,
+ ReadHandler handler)
+{
+ async_read_at(d, offset, buffers, transfer_all(), handler);
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+namespace detail
+{
+ template <typename AsyncRandomAccessReadDevice, typename Allocator,
+ typename CompletionCondition, typename ReadHandler>
+ class read_at_streambuf_op
+ : detail::base_from_completion_cond<CompletionCondition>
+ {
+ public:
+ read_at_streambuf_op(AsyncRandomAccessReadDevice& device,
+ boost::uint64_t offset, basic_streambuf<Allocator>& streambuf,
+ CompletionCondition completion_condition, ReadHandler handler)
+ : detail::base_from_completion_cond<
+ CompletionCondition>(completion_condition),
+ device_(device),
+ offset_(offset),
+ streambuf_(streambuf),
+ total_transferred_(0),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred, int start = 0)
+ {
+ std::size_t max_size, bytes_available;
+ switch (start)
+ {
+ case 1:
+ max_size = this->check_for_completion(ec, total_transferred_);
+ bytes_available = read_size_helper(streambuf_, max_size);
+ for (;;)
+ {
+ device_.async_read_some_at(offset_ + total_transferred_,
+ streambuf_.prepare(bytes_available), *this);
+ return; default:
+ total_transferred_ += bytes_transferred;
+ streambuf_.commit(bytes_transferred);
+ max_size = this->check_for_completion(ec, total_transferred_);
+ bytes_available = read_size_helper(streambuf_, max_size);
+ if ((!ec && bytes_transferred == 0) || bytes_available == 0)
+ break;
+ }
+
+ handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+ }
+ }
+
+ //private:
+ AsyncRandomAccessReadDevice& device_;
+ boost::uint64_t offset_;
+ asio::basic_streambuf<Allocator>& streambuf_;
+ std::size_t total_transferred_;
+ ReadHandler handler_;
+ };
+
+ template <typename AsyncRandomAccessReadDevice, typename Allocator,
+ typename CompletionCondition, typename ReadHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+ }
+
+ template <typename AsyncRandomAccessReadDevice, typename Allocator,
+ typename CompletionCondition, typename ReadHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncRandomAccessReadDevice,
+ typename Allocator, typename CompletionCondition, typename ReadHandler>
+ inline void asio_handler_invoke(const Function& function,
+ read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncRandomAccessReadDevice, typename Allocator,
+ typename CompletionCondition, typename ReadHandler>
+inline void async_read_at(AsyncRandomAccessReadDevice& d,
+ boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition, ReadHandler handler)
+{
+ detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
+ Allocator, CompletionCondition, ReadHandler>(
+ d, offset, b, completion_condition, handler)(
+ asio::error_code(), 0, 1);
+}
+
+template <typename AsyncRandomAccessReadDevice, typename Allocator,
+ typename ReadHandler>
+inline void async_read_at(AsyncRandomAccessReadDevice& d,
+ boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
+ ReadHandler handler)
+{
+ async_read_at(d, offset, b, transfer_all(), handler);
+}
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_READ_AT_HPP
diff --git a/ext/asio/asio/impl/read_until.hpp b/ext/asio/asio/impl/read_until.hpp
new file mode 100644
index 0000000..ceacca7
--- /dev/null
+++ b/ext/asio/asio/impl/read_until.hpp
@@ -0,0 +1,902 @@
+//
+// impl/read_until.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_READ_UNTIL_HPP
+#define ASIO_IMPL_READ_UNTIL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <algorithm>
+#include <string>
+#include <vector>
+#include <utility>
+#include <boost/limits.hpp>
+#include "asio/buffer.hpp"
+#include "asio/buffers_iterator.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, char delim)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read_until(s, b, delim, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, char delim,
+ asio::error_code& ec)
+{
+ std::size_t search_position = 0;
+ for (;;)
+ {
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::buffers_iterator<const_buffers_type> iterator;
+ const_buffers_type buffers = b.data();
+ iterator begin = iterator::begin(buffers);
+ iterator start = begin + search_position;
+ iterator end = iterator::end(buffers);
+
+ // Look for a match.
+ iterator iter = std::find(start, end, delim);
+ if (iter != end)
+ {
+ // Found a match. We're done.
+ ec = asio::error_code();
+ return iter - begin + 1;
+ }
+ else
+ {
+ // No match. Next search can start with the new data.
+ search_position = end - begin;
+ }
+
+ // Check if buffer is full.
+ if (b.size() == b.max_size())
+ {
+ ec = error::not_found;
+ return 0;
+ }
+
+ // Need more data.
+ std::size_t bytes_to_read = read_size_helper(b, 65536);
+ b.commit(s.read_some(b.prepare(bytes_to_read), ec));
+ if (ec)
+ return 0;
+ }
+}
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const std::string& delim)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read_until(s, b, delim, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+namespace detail
+{
+ // Algorithm that finds a subsequence of equal values in a sequence. Returns
+ // (iterator,true) if a full match was found, in which case the iterator
+ // points to the beginning of the match. Returns (iterator,false) if a
+ // partial match was found at the end of the first sequence, in which case
+ // the iterator points to the beginning of the partial match. Returns
+ // (last1,false) if no full or partial match was found.
+ template <typename Iterator1, typename Iterator2>
+ std::pair<Iterator1, bool> partial_search(
+ Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
+ {
+ for (Iterator1 iter1 = first1; iter1 != last1; ++iter1)
+ {
+ Iterator1 test_iter1 = iter1;
+ Iterator2 test_iter2 = first2;
+ for (;; ++test_iter1, ++test_iter2)
+ {
+ if (test_iter2 == last2)
+ return std::make_pair(iter1, true);
+ if (test_iter1 == last1)
+ {
+ if (test_iter2 != first2)
+ return std::make_pair(iter1, false);
+ else
+ break;
+ }
+ if (*test_iter1 != *test_iter2)
+ break;
+ }
+ }
+ return std::make_pair(last1, false);
+ }
+} // namespace detail
+
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const std::string& delim,
+ asio::error_code& ec)
+{
+ std::size_t search_position = 0;
+ for (;;)
+ {
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::buffers_iterator<const_buffers_type> iterator;
+ const_buffers_type buffers = b.data();
+ iterator begin = iterator::begin(buffers);
+ iterator start = begin + search_position;
+ iterator end = iterator::end(buffers);
+
+ // Look for a match.
+ std::pair<iterator, bool> result = detail::partial_search(
+ start, end, delim.begin(), delim.end());
+ if (result.first != end)
+ {
+ if (result.second)
+ {
+ // Full match. We're done.
+ ec = asio::error_code();
+ return result.first - begin + delim.length();
+ }
+ else
+ {
+ // Partial match. Next search needs to start from beginning of match.
+ search_position = result.first - begin;
+ }
+ }
+ else
+ {
+ // No match. Next search can start with the new data.
+ search_position = end - begin;
+ }
+
+ // Check if buffer is full.
+ if (b.size() == b.max_size())
+ {
+ ec = error::not_found;
+ return 0;
+ }
+
+ // Need more data.
+ std::size_t bytes_to_read = read_size_helper(b, 65536);
+ b.commit(s.read_some(b.prepare(bytes_to_read), ec));
+ if (ec)
+ return 0;
+ }
+}
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const boost::regex& expr)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read_until(s, b, expr, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
+ asio::error_code& ec)
+{
+ std::size_t search_position = 0;
+ for (;;)
+ {
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::buffers_iterator<const_buffers_type> iterator;
+ const_buffers_type buffers = b.data();
+ iterator begin = iterator::begin(buffers);
+ iterator start = begin + search_position;
+ iterator end = iterator::end(buffers);
+
+ // Look for a match.
+ boost::match_results<iterator,
+ typename std::vector<boost::sub_match<iterator> >::allocator_type>
+ match_results;
+ if (regex_search(start, end, match_results, expr,
+ boost::match_default | boost::match_partial))
+ {
+ if (match_results[0].matched)
+ {
+ // Full match. We're done.
+ ec = asio::error_code();
+ return match_results[0].second - begin;
+ }
+ else
+ {
+ // Partial match. Next search needs to start from beginning of match.
+ search_position = match_results[0].first - begin;
+ }
+ }
+ else
+ {
+ // No match. Next search can start with the new data.
+ search_position = end - begin;
+ }
+
+ // Check if buffer is full.
+ if (b.size() == b.max_size())
+ {
+ ec = error::not_found;
+ return 0;
+ }
+
+ // Need more data.
+ std::size_t bytes_to_read = read_size_helper(b, 65536);
+ b.commit(s.read_some(b.prepare(bytes_to_read), ec));
+ if (ec)
+ return 0;
+ }
+}
+
+template <typename SyncReadStream, typename Allocator, typename MatchCondition>
+std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b,
+ MatchCondition match_condition, asio::error_code& ec,
+ typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
+{
+ std::size_t search_position = 0;
+ for (;;)
+ {
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::buffers_iterator<const_buffers_type> iterator;
+ const_buffers_type buffers = b.data();
+ iterator begin = iterator::begin(buffers);
+ iterator start = begin + search_position;
+ iterator end = iterator::end(buffers);
+
+ // Look for a match.
+ std::pair<iterator, bool> result = match_condition(start, end);
+ if (result.second)
+ {
+ // Full match. We're done.
+ ec = asio::error_code();
+ return result.first - begin;
+ }
+ else if (result.first != end)
+ {
+ // Partial match. Next search needs to start from beginning of match.
+ search_position = result.first - begin;
+ }
+ else
+ {
+ // No match. Next search can start with the new data.
+ search_position = end - begin;
+ }
+
+ // Check if buffer is full.
+ if (b.size() == b.max_size())
+ {
+ ec = error::not_found;
+ return 0;
+ }
+
+ // Need more data.
+ std::size_t bytes_to_read = read_size_helper(b, 65536);
+ b.commit(s.read_some(b.prepare(bytes_to_read), ec));
+ if (ec)
+ return 0;
+ }
+}
+
+template <typename SyncReadStream, typename Allocator, typename MatchCondition>
+inline std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
+ typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read_until(s, b, match_condition, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+namespace detail
+{
+ template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+ class read_until_delim_op
+ {
+ public:
+ read_until_delim_op(AsyncReadStream& stream,
+ asio::basic_streambuf<Allocator>& streambuf,
+ char delim, ReadHandler handler)
+ : stream_(stream),
+ streambuf_(streambuf),
+ delim_(delim),
+ search_position_(0),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred, int start = 0)
+ {
+ const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
+ std::size_t bytes_to_read;
+ switch (start)
+ {
+ case 1:
+ for (;;)
+ {
+ {
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::buffers_iterator<const_buffers_type> iterator;
+ const_buffers_type buffers = streambuf_.data();
+ iterator begin = iterator::begin(buffers);
+ iterator start = begin + search_position_;
+ iterator end = iterator::end(buffers);
+
+ // Look for a match.
+ iterator iter = std::find(start, end, delim_);
+ if (iter != end)
+ {
+ // Found a match. We're done.
+ search_position_ = iter - begin + 1;
+ bytes_to_read = 0;
+ }
+
+ // No match yet. Check if buffer is full.
+ else if (streambuf_.size() == streambuf_.max_size())
+ {
+ search_position_ = not_found;
+ bytes_to_read = 0;
+ }
+
+ // Need to read some more data.
+ else
+ {
+ // Next search can start with the new data.
+ search_position_ = end - begin;
+ bytes_to_read = read_size_helper(streambuf_, 65536);
+ }
+ }
+
+ // Check if we're done.
+ if (!start && bytes_to_read == 0)
+ break;
+
+ // Start a new asynchronous read operation to obtain more data.
+ stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this);
+ return; default:
+ streambuf_.commit(bytes_transferred);
+ if (ec || bytes_transferred == 0)
+ break;
+ }
+
+ const asio::error_code result_ec =
+ (search_position_ == not_found)
+ ? error::not_found : ec;
+
+ const std::size_t result_n =
+ (ec || search_position_ == not_found)
+ ? 0 : search_position_;
+
+ handler_(result_ec, result_n);
+ }
+ }
+
+ //private:
+ AsyncReadStream& stream_;
+ asio::basic_streambuf<Allocator>& streambuf_;
+ char delim_;
+ std::size_t search_position_;
+ ReadHandler handler_;
+ };
+
+ template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ read_until_delim_op<AsyncReadStream,
+ Allocator, ReadHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+ }
+
+ template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ read_until_delim_op<AsyncReadStream,
+ Allocator, ReadHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncReadStream, typename Allocator,
+ typename ReadHandler>
+ inline void asio_handler_invoke(const Function& function,
+ read_until_delim_op<AsyncReadStream,
+ Allocator, ReadHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+void async_read_until(AsyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, char delim, ReadHandler handler)
+{
+ detail::read_until_delim_op<
+ AsyncReadStream, Allocator, ReadHandler>(
+ s, b, delim, handler)(
+ asio::error_code(), 0, 1);
+}
+
+namespace detail
+{
+ template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+ class read_until_delim_string_op
+ {
+ public:
+ read_until_delim_string_op(AsyncReadStream& stream,
+ asio::basic_streambuf<Allocator>& streambuf,
+ const std::string& delim, ReadHandler handler)
+ : stream_(stream),
+ streambuf_(streambuf),
+ delim_(delim),
+ search_position_(0),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred, int start = 0)
+ {
+ const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
+ std::size_t bytes_to_read;
+ switch (start)
+ {
+ case 1:
+ for (;;)
+ {
+ {
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::buffers_iterator<const_buffers_type> iterator;
+ const_buffers_type buffers = streambuf_.data();
+ iterator begin = iterator::begin(buffers);
+ iterator start = begin + search_position_;
+ iterator end = iterator::end(buffers);
+
+ // Look for a match.
+ std::pair<iterator, bool> result = detail::partial_search(
+ start, end, delim_.begin(), delim_.end());
+ if (result.first != end && result.second)
+ {
+ // Full match. We're done.
+ search_position_ = result.first - begin + delim_.length();
+ bytes_to_read = 0;
+ }
+
+ // No match yet. Check if buffer is full.
+ else if (streambuf_.size() == streambuf_.max_size())
+ {
+ search_position_ = not_found;
+ bytes_to_read = 0;
+ }
+
+ // Need to read some more data.
+ else
+ {
+ if (result.first != end)
+ {
+ // Partial match. Next search needs to start from beginning of
+ // match.
+ search_position_ = result.first - begin;
+ }
+ else
+ {
+ // Next search can start with the new data.
+ search_position_ = end - begin;
+ }
+
+ bytes_to_read = read_size_helper(streambuf_, 65536);
+ }
+ }
+
+ // Check if we're done.
+ if (!start && bytes_to_read == 0)
+ break;
+
+ // Start a new asynchronous read operation to obtain more data.
+ stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this);
+ return; default:
+ streambuf_.commit(bytes_transferred);
+ if (ec || bytes_transferred == 0)
+ break;
+ }
+
+ const asio::error_code result_ec =
+ (search_position_ == not_found)
+ ? error::not_found : ec;
+
+ const std::size_t result_n =
+ (ec || search_position_ == not_found)
+ ? 0 : search_position_;
+
+ handler_(result_ec, result_n);
+ }
+ }
+
+ //private:
+ AsyncReadStream& stream_;
+ asio::basic_streambuf<Allocator>& streambuf_;
+ std::string delim_;
+ std::size_t search_position_;
+ ReadHandler handler_;
+ };
+
+ template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ read_until_delim_string_op<AsyncReadStream,
+ Allocator, ReadHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+ }
+
+ template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ read_until_delim_string_op<AsyncReadStream,
+ Allocator, ReadHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncReadStream,
+ typename Allocator, typename ReadHandler>
+ inline void asio_handler_invoke(const Function& function,
+ read_until_delim_string_op<AsyncReadStream,
+ Allocator, ReadHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+void async_read_until(AsyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const std::string& delim,
+ ReadHandler handler)
+{
+ detail::read_until_delim_string_op<
+ AsyncReadStream, Allocator, ReadHandler>(
+ s, b, delim, handler)(
+ asio::error_code(), 0, 1);
+}
+
+namespace detail
+{
+ template <typename AsyncReadStream, typename Allocator,
+ typename RegEx, typename ReadHandler>
+ class read_until_expr_op
+ {
+ public:
+ read_until_expr_op(AsyncReadStream& stream,
+ asio::basic_streambuf<Allocator>& streambuf,
+ const boost::regex& expr, ReadHandler handler)
+ : stream_(stream),
+ streambuf_(streambuf),
+ expr_(expr),
+ search_position_(0),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred, int start = 0)
+ {
+ const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
+ std::size_t bytes_to_read;
+ switch (start)
+ {
+ case 1:
+ for (;;)
+ {
+ {
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::buffers_iterator<const_buffers_type> iterator;
+ const_buffers_type buffers = streambuf_.data();
+ iterator begin = iterator::begin(buffers);
+ iterator start = begin + search_position_;
+ iterator end = iterator::end(buffers);
+
+ // Look for a match.
+ boost::match_results<iterator,
+ typename std::vector<boost::sub_match<iterator> >::allocator_type>
+ match_results;
+ bool match = regex_search(start, end, match_results, expr_,
+ boost::match_default | boost::match_partial);
+ if (match && match_results[0].matched)
+ {
+ // Full match. We're done.
+ search_position_ = match_results[0].second - begin;
+ bytes_to_read = 0;
+ }
+
+ // No match yet. Check if buffer is full.
+ else if (streambuf_.size() == streambuf_.max_size())
+ {
+ search_position_ = not_found;
+ bytes_to_read = 0;
+ }
+
+ // Need to read some more data.
+ else
+ {
+ if (match)
+ {
+ // Partial match. Next search needs to start from beginning of
+ // match.
+ search_position_ = match_results[0].first - begin;
+ }
+ else
+ {
+ // Next search can start with the new data.
+ search_position_ = end - begin;
+ }
+
+ bytes_to_read = read_size_helper(streambuf_, 65536);
+ }
+ }
+
+ // Check if we're done.
+ if (!start && bytes_to_read == 0)
+ break;
+
+ // Start a new asynchronous read operation to obtain more data.
+ stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this);
+ return; default:
+ streambuf_.commit(bytes_transferred);
+ if (ec || bytes_transferred == 0)
+ break;
+ }
+
+ const asio::error_code result_ec =
+ (search_position_ == not_found)
+ ? error::not_found : ec;
+
+ const std::size_t result_n =
+ (ec || search_position_ == not_found)
+ ? 0 : search_position_;
+
+ handler_(result_ec, result_n);
+ }
+ }
+
+ //private:
+ AsyncReadStream& stream_;
+ asio::basic_streambuf<Allocator>& streambuf_;
+ RegEx expr_;
+ std::size_t search_position_;
+ ReadHandler handler_;
+ };
+
+ template <typename AsyncReadStream, typename Allocator,
+ typename RegEx, typename ReadHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ read_until_expr_op<AsyncReadStream,
+ Allocator, RegEx, ReadHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+ }
+
+ template <typename AsyncReadStream, typename Allocator,
+ typename RegEx, typename ReadHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ read_until_expr_op<AsyncReadStream,
+ Allocator, RegEx, ReadHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncReadStream, typename Allocator,
+ typename RegEx, typename ReadHandler>
+ inline void asio_handler_invoke(const Function& function,
+ read_until_expr_op<AsyncReadStream,
+ Allocator, RegEx, ReadHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+void async_read_until(AsyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
+ ReadHandler handler)
+{
+ detail::read_until_expr_op<AsyncReadStream,
+ Allocator, boost::regex, ReadHandler>(
+ s, b, expr, handler)(
+ asio::error_code(), 0, 1);
+}
+
+namespace detail
+{
+ template <typename AsyncReadStream, typename Allocator,
+ typename MatchCondition, typename ReadHandler>
+ class read_until_match_op
+ {
+ public:
+ read_until_match_op(AsyncReadStream& stream,
+ asio::basic_streambuf<Allocator>& streambuf,
+ MatchCondition match_condition, ReadHandler handler)
+ : stream_(stream),
+ streambuf_(streambuf),
+ match_condition_(match_condition),
+ search_position_(0),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred, int start = 0)
+ {
+ const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
+ std::size_t bytes_to_read;
+ switch (start)
+ {
+ case 1:
+ for (;;)
+ {
+ {
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::buffers_iterator<const_buffers_type> iterator;
+ const_buffers_type buffers = streambuf_.data();
+ iterator begin = iterator::begin(buffers);
+ iterator start = begin + search_position_;
+ iterator end = iterator::end(buffers);
+
+ // Look for a match.
+ std::pair<iterator, bool> result = match_condition_(start, end);
+ if (result.second)
+ {
+ // Full match. We're done.
+ search_position_ = result.first - begin;
+ bytes_to_read = 0;
+ }
+
+ // No match yet. Check if buffer is full.
+ else if (streambuf_.size() == streambuf_.max_size())
+ {
+ search_position_ = not_found;
+ bytes_to_read = 0;
+ }
+
+ // Need to read some more data.
+ else
+ {
+ if (result.first != end)
+ {
+ // Partial match. Next search needs to start from beginning of
+ // match.
+ search_position_ = result.first - begin;
+ }
+ else
+ {
+ // Next search can start with the new data.
+ search_position_ = end - begin;
+ }
+
+ bytes_to_read = read_size_helper(streambuf_, 65536);
+ }
+ }
+
+ // Check if we're done.
+ if (!start && bytes_to_read == 0)
+ break;
+
+ // Start a new asynchronous read operation to obtain more data.
+ stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this);
+ return; default:
+ streambuf_.commit(bytes_transferred);
+ if (ec || bytes_transferred == 0)
+ break;
+ }
+
+ const asio::error_code result_ec =
+ (search_position_ == not_found)
+ ? error::not_found : ec;
+
+ const std::size_t result_n =
+ (ec || search_position_ == not_found)
+ ? 0 : search_position_;
+
+ handler_(result_ec, result_n);
+ }
+ }
+
+ //private:
+ AsyncReadStream& stream_;
+ asio::basic_streambuf<Allocator>& streambuf_;
+ MatchCondition match_condition_;
+ std::size_t search_position_;
+ ReadHandler handler_;
+ };
+
+ template <typename AsyncReadStream, typename Allocator,
+ typename MatchCondition, typename ReadHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ read_until_match_op<AsyncReadStream,
+ Allocator, MatchCondition, ReadHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+ }
+
+ template <typename AsyncReadStream, typename Allocator,
+ typename MatchCondition, typename ReadHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ read_until_match_op<AsyncReadStream,
+ Allocator, MatchCondition, ReadHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncReadStream, typename Allocator,
+ typename MatchCondition, typename ReadHandler>
+ inline void asio_handler_invoke(const Function& function,
+ read_until_match_op<AsyncReadStream,
+ Allocator, MatchCondition, ReadHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncReadStream, typename Allocator,
+ typename MatchCondition, typename ReadHandler>
+void async_read_until(AsyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b,
+ MatchCondition match_condition, ReadHandler handler,
+ typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
+{
+ detail::read_until_match_op<
+ AsyncReadStream, Allocator, MatchCondition, ReadHandler>(
+ s, b, match_condition, handler)(
+ asio::error_code(), 0, 1);
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_READ_UNTIL_HPP
diff --git a/ext/asio/asio/impl/serial_port_base.hpp b/ext/asio/asio/impl/serial_port_base.hpp
new file mode 100644
index 0000000..758e652
--- /dev/null
+++ b/ext/asio/asio/impl/serial_port_base.hpp
@@ -0,0 +1,59 @@
+//
+// impl/serial_port_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_SERIAL_PORT_BASE_HPP
+#define ASIO_IMPL_SERIAL_PORT_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+inline serial_port_base::baud_rate::baud_rate(unsigned int rate)
+ : value_(rate)
+{
+}
+
+inline unsigned int serial_port_base::baud_rate::value() const
+{
+ return value_;
+}
+
+inline serial_port_base::flow_control::type
+serial_port_base::flow_control::value() const
+{
+ return value_;
+}
+
+inline serial_port_base::parity::type serial_port_base::parity::value() const
+{
+ return value_;
+}
+
+inline serial_port_base::stop_bits::type
+serial_port_base::stop_bits::value() const
+{
+ return value_;
+}
+
+inline unsigned int serial_port_base::character_size::value() const
+{
+ return value_;
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_SERIAL_PORT_BASE_HPP
diff --git a/ext/asio/asio/impl/serial_port_base.ipp b/ext/asio/asio/impl/serial_port_base.ipp
index 64ab6a4..4d3204d 100644
--- a/ext/asio/asio/impl/serial_port_base.ipp
+++ b/ext/asio/asio/impl/serial_port_base.ipp
@@ -1,40 +1,43 @@
//
-// serial_port_base.ipp
-// ~~~~~~~~~~~~~~~~~~~~
+// impl/serial_port_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
-#ifndef ASIO_SERIAL_PORT_BASE_IPP
-#define ASIO_SERIAL_PORT_BASE_IPP
+#ifndef ASIO_IMPL_SERIAL_PORT_BASE_IPP
+#define ASIO_IMPL_SERIAL_PORT_BASE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
+#if defined(ASIO_HAS_SERIAL_PORT)
+
+#include <stdexcept>
#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/error.hpp"
+#include "asio/serial_port_base.hpp"
-namespace asio {
+#if defined(GENERATING_DOCUMENTATION)
+# define ASIO_OPTION_STORAGE implementation_defined
+#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# define ASIO_OPTION_STORAGE DCB
+#else
+# define ASIO_OPTION_STORAGE termios
+#endif
-inline serial_port_base::baud_rate::baud_rate(unsigned int rate)
- : value_(rate)
-{
-}
+#include "asio/detail/push_options.hpp"
-inline unsigned int serial_port_base::baud_rate::value() const
-{
- return value_;
-}
+namespace asio {
-inline asio::error_code serial_port_base::baud_rate::store(
+asio::error_code serial_port_base::baud_rate::store(
ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -122,7 +125,7 @@ inline asio::error_code serial_port_base::baud_rate::store(
return ec;
}
-inline asio::error_code serial_port_base::baud_rate::load(
+asio::error_code serial_port_base::baud_rate::load(
const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -204,7 +207,7 @@ inline asio::error_code serial_port_base::baud_rate::load(
return ec;
}
-inline serial_port_base::flow_control::flow_control(
+serial_port_base::flow_control::flow_control(
serial_port_base::flow_control::type t)
: value_(t)
{
@@ -215,13 +218,7 @@ inline serial_port_base::flow_control::flow_control(
}
}
-inline serial_port_base::flow_control::type
-serial_port_base::flow_control::value() const
-{
- return value_;
-}
-
-inline asio::error_code serial_port_base::flow_control::store(
+asio::error_code serial_port_base::flow_control::store(
ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -255,12 +252,16 @@ inline asio::error_code serial_port_base::flow_control::store(
storage.c_iflag &= ~(IXOFF | IXON);
# if defined(_BSD_SOURCE)
storage.c_cflag &= ~CRTSCTS;
+# elif defined(__QNXNTO__)
+ storage.c_cflag &= ~(IHFLOW | OHFLOW);
# endif
break;
case software:
storage.c_iflag |= IXOFF | IXON;
# if defined(_BSD_SOURCE)
storage.c_cflag &= ~CRTSCTS;
+# elif defined(__QNXNTO__)
+ storage.c_cflag &= ~(IHFLOW | OHFLOW);
# endif
break;
case hardware:
@@ -268,6 +269,10 @@ inline asio::error_code serial_port_base::flow_control::store(
storage.c_iflag &= ~(IXOFF | IXON);
storage.c_cflag |= CRTSCTS;
break;
+# elif defined(__QNXNTO__)
+ storage.c_iflag &= ~(IXOFF | IXON);
+ storage.c_cflag |= (IHFLOW | OHFLOW);
+ break;
# else
ec = asio::error::operation_not_supported;
return ec;
@@ -280,7 +285,7 @@ inline asio::error_code serial_port_base::flow_control::store(
return ec;
}
-inline asio::error_code serial_port_base::flow_control::load(
+asio::error_code serial_port_base::flow_control::load(
const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -306,6 +311,11 @@ inline asio::error_code serial_port_base::flow_control::load(
{
value_ = hardware;
}
+# elif defined(__QNXNTO__)
+ else if (storage.c_cflag & IHFLOW && storage.c_cflag & OHFLOW)
+ {
+ value_ = hardware;
+ }
# endif
else
{
@@ -316,7 +326,7 @@ inline asio::error_code serial_port_base::flow_control::load(
return ec;
}
-inline serial_port_base::parity::parity(serial_port_base::parity::type t)
+serial_port_base::parity::parity(serial_port_base::parity::type t)
: value_(t)
{
if (t != none && t != odd && t != even)
@@ -326,12 +336,7 @@ inline serial_port_base::parity::parity(serial_port_base::parity::type t)
}
}
-inline serial_port_base::parity::type serial_port_base::parity::value() const
-{
- return value_;
-}
-
-inline asio::error_code serial_port_base::parity::store(
+asio::error_code serial_port_base::parity::store(
ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -378,7 +383,7 @@ inline asio::error_code serial_port_base::parity::store(
return ec;
}
-inline asio::error_code serial_port_base::parity::load(
+asio::error_code serial_port_base::parity::load(
const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -415,7 +420,7 @@ inline asio::error_code serial_port_base::parity::load(
return ec;
}
-inline serial_port_base::stop_bits::stop_bits(
+serial_port_base::stop_bits::stop_bits(
serial_port_base::stop_bits::type t)
: value_(t)
{
@@ -426,13 +431,7 @@ inline serial_port_base::stop_bits::stop_bits(
}
}
-inline serial_port_base::stop_bits::type
-serial_port_base::stop_bits::value() const
-{
- return value_;
-}
-
-inline asio::error_code serial_port_base::stop_bits::store(
+asio::error_code serial_port_base::stop_bits::store(
ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -468,7 +467,7 @@ inline asio::error_code serial_port_base::stop_bits::store(
return ec;
}
-inline asio::error_code serial_port_base::stop_bits::load(
+asio::error_code serial_port_base::stop_bits::load(
const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -495,7 +494,7 @@ inline asio::error_code serial_port_base::stop_bits::load(
return ec;
}
-inline serial_port_base::character_size::character_size(unsigned int t)
+serial_port_base::character_size::character_size(unsigned int t)
: value_(t)
{
if (t < 5 || t > 8)
@@ -505,12 +504,7 @@ inline serial_port_base::character_size::character_size(unsigned int t)
}
}
-inline unsigned int serial_port_base::character_size::value() const
-{
- return value_;
-}
-
-inline asio::error_code serial_port_base::character_size::store(
+asio::error_code serial_port_base::character_size::store(
ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -530,7 +524,7 @@ inline asio::error_code serial_port_base::character_size::store(
return ec;
}
-inline asio::error_code serial_port_base::character_size::load(
+asio::error_code serial_port_base::character_size::load(
const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -554,4 +548,8 @@ inline asio::error_code serial_port_base::character_size::load(
#include "asio/detail/pop_options.hpp"
-#endif // ASIO_SERIAL_PORT_BASE_IPP
+#undef ASIO_OPTION_STORAGE
+
+#endif // defined(ASIO_HAS_SERIAL_PORT)
+
+#endif // ASIO_IMPL_SERIAL_PORT_BASE_IPP
diff --git a/ext/asio/asio/impl/src.cpp b/ext/asio/asio/impl/src.cpp
new file mode 100644
index 0000000..1dac400
--- /dev/null
+++ b/ext/asio/asio/impl/src.cpp
@@ -0,0 +1,25 @@
+//
+// impl/src.cpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#if defined(_MSC_VER) \
+ || defined(__BORLANDC__) \
+ || defined(__DMC__)
+# pragma message ( \
+ "This file is deprecated. " \
+ "Please #include <asio/impl/src.hpp> instead.")
+#elif defined(__GNUC__) \
+ || defined(__HP_aCC) \
+ || defined(__SUNPRO_CC) \
+ || defined(__IBMCPP__)
+# warning "This file is deprecated."
+# warning "Please #include <asio/impl/src.hpp> instead."
+#endif
+
+#include "asio/impl/src.hpp"
diff --git a/ext/asio/asio/impl/src.hpp b/ext/asio/asio/impl/src.hpp
new file mode 100644
index 0000000..b37eabd
--- /dev/null
+++ b/ext/asio/asio/impl/src.hpp
@@ -0,0 +1,65 @@
+//
+// impl/src.hpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_SRC_HPP
+#define ASIO_IMPL_SRC_HPP
+
+#define ASIO_SOURCE
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# error Do not compile Asio library source with ASIO_HEADER_ONLY defined
+#endif
+
+#include "asio/impl/error.ipp"
+#include "asio/impl/error_code.ipp"
+#include "asio/impl/io_service.ipp"
+#include "asio/impl/serial_port_base.ipp"
+#include "asio/detail/impl/descriptor_ops.ipp"
+#include "asio/detail/impl/dev_poll_reactor.ipp"
+#include "asio/detail/impl/epoll_reactor.ipp"
+#include "asio/detail/impl/eventfd_select_interrupter.ipp"
+#include "asio/detail/impl/kqueue_reactor.ipp"
+#include "asio/detail/impl/pipe_select_interrupter.ipp"
+#include "asio/detail/impl/posix_event.ipp"
+#include "asio/detail/impl/posix_mutex.ipp"
+#include "asio/detail/impl/posix_thread.ipp"
+#include "asio/detail/impl/posix_tss_ptr.ipp"
+#include "asio/detail/impl/reactive_descriptor_service.ipp"
+#include "asio/detail/impl/reactive_serial_port_service.ipp"
+#include "asio/detail/impl/reactive_socket_service_base.ipp"
+#include "asio/detail/impl/resolver_service_base.ipp"
+#include "asio/detail/impl/select_reactor.ipp"
+#include "asio/detail/impl/service_registry.ipp"
+#include "asio/detail/impl/socket_ops.ipp"
+#include "asio/detail/impl/socket_select_interrupter.ipp"
+#include "asio/detail/impl/strand_service.ipp"
+#include "asio/detail/impl/task_io_service.ipp"
+#include "asio/detail/impl/throw_error.ipp"
+#include "asio/detail/impl/timer_queue.ipp"
+#include "asio/detail/impl/timer_queue_set.ipp"
+#include "asio/detail/impl/win_iocp_handle_service.ipp"
+#include "asio/detail/impl/win_iocp_io_service.ipp"
+#include "asio/detail/impl/win_iocp_serial_port_service.ipp"
+#include "asio/detail/impl/win_iocp_socket_service_base.ipp"
+#include "asio/detail/impl/win_event.ipp"
+#include "asio/detail/impl/win_mutex.ipp"
+#include "asio/detail/impl/win_thread.ipp"
+#include "asio/detail/impl/win_tss_ptr.ipp"
+#include "asio/detail/impl/winsock_init.ipp"
+#include "asio/ip/impl/address.ipp"
+#include "asio/ip/impl/address_v4.ipp"
+#include "asio/ip/impl/address_v6.ipp"
+#include "asio/ip/impl/host_name.ipp"
+#include "asio/ip/detail/impl/endpoint.ipp"
+#include "asio/local/detail/impl/endpoint.ipp"
+
+#endif // ASIO_IMPL_SRC_HPP
diff --git a/ext/asio/asio/impl/write.hpp b/ext/asio/asio/impl/write.hpp
new file mode 100644
index 0000000..91cb65e
--- /dev/null
+++ b/ext/asio/asio/impl/write.hpp
@@ -0,0 +1,396 @@
+//
+// impl/write.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_WRITE_HPP
+#define ASIO_IMPL_WRITE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/detail/base_from_completion_cond.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/consuming_buffers.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename SyncWriteStream, typename ConstBufferSequence,
+ typename CompletionCondition>
+std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
+ CompletionCondition completion_condition, asio::error_code& ec)
+{
+ ec = asio::error_code();
+ asio::detail::consuming_buffers<
+ const_buffer, ConstBufferSequence> tmp(buffers);
+ std::size_t total_transferred = 0;
+ tmp.prepare(detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred)));
+ while (tmp.begin() != tmp.end())
+ {
+ std::size_t bytes_transferred = s.write_some(tmp, ec);
+ tmp.consume(bytes_transferred);
+ total_transferred += bytes_transferred;
+ tmp.prepare(detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred)));
+ }
+ return total_transferred;
+}
+
+template <typename SyncWriteStream, typename ConstBufferSequence>
+inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncWriteStream, typename ConstBufferSequence,
+ typename CompletionCondition>
+inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
+ CompletionCondition completion_condition)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = write(s, buffers, completion_condition, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+template <typename SyncWriteStream, typename Allocator,
+ typename CompletionCondition>
+std::size_t write(SyncWriteStream& s,
+ asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition, asio::error_code& ec)
+{
+ std::size_t bytes_transferred = write(s, b.data(), completion_condition, ec);
+ b.consume(bytes_transferred);
+ return bytes_transferred;
+}
+
+template <typename SyncWriteStream, typename Allocator>
+inline std::size_t write(SyncWriteStream& s,
+ asio::basic_streambuf<Allocator>& b)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = write(s, b, transfer_all(), ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncWriteStream, typename Allocator,
+ typename CompletionCondition>
+inline std::size_t write(SyncWriteStream& s,
+ asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = write(s, b, completion_condition, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+namespace detail
+{
+ template <typename AsyncWriteStream, typename ConstBufferSequence,
+ typename CompletionCondition, typename WriteHandler>
+ class write_op
+ : detail::base_from_completion_cond<CompletionCondition>
+ {
+ public:
+ write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers,
+ CompletionCondition completion_condition, WriteHandler handler)
+ : detail::base_from_completion_cond<
+ CompletionCondition>(completion_condition),
+ stream_(stream),
+ buffers_(buffers),
+ total_transferred_(0),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred, int start = 0)
+ {
+ switch (start)
+ {
+ case 1:
+ buffers_.prepare(this->check_for_completion(ec, total_transferred_));
+ for (;;)
+ {
+ stream_.async_write_some(buffers_, *this);
+ return; default:
+ total_transferred_ += bytes_transferred;
+ buffers_.consume(bytes_transferred);
+ buffers_.prepare(this->check_for_completion(ec, total_transferred_));
+ if ((!ec && bytes_transferred == 0)
+ || buffers_.begin() == buffers_.end())
+ break;
+ }
+
+ handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+ }
+ }
+
+ //private:
+ AsyncWriteStream& stream_;
+ asio::detail::consuming_buffers<
+ const_buffer, ConstBufferSequence> buffers_;
+ std::size_t total_transferred_;
+ WriteHandler handler_;
+ };
+
+ template <typename AsyncWriteStream,
+ typename CompletionCondition, typename WriteHandler>
+ class write_op<AsyncWriteStream, asio::mutable_buffers_1,
+ CompletionCondition, WriteHandler>
+ : detail::base_from_completion_cond<CompletionCondition>
+ {
+ public:
+ write_op(AsyncWriteStream& stream,
+ const asio::mutable_buffers_1& buffers,
+ CompletionCondition completion_condition,
+ WriteHandler handler)
+ : detail::base_from_completion_cond<
+ CompletionCondition>(completion_condition),
+ stream_(stream),
+ buffer_(buffers),
+ total_transferred_(0),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred, int start = 0)
+ {
+ std::size_t n = 0;
+ switch (start)
+ {
+ case 1:
+ n = this->check_for_completion(ec, total_transferred_);
+ for (;;)
+ {
+ stream_.async_write_some(asio::buffer(
+ buffer_ + total_transferred_, n), *this);
+ return; default:
+ total_transferred_ += bytes_transferred;
+ if ((!ec && bytes_transferred == 0)
+ || (n = this->check_for_completion(ec, total_transferred_)) == 0
+ || total_transferred_ == asio::buffer_size(buffer_))
+ break;
+ }
+
+ handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+ }
+ }
+
+ //private:
+ AsyncWriteStream& stream_;
+ asio::mutable_buffer buffer_;
+ std::size_t total_transferred_;
+ WriteHandler handler_;
+ };
+
+ template <typename AsyncWriteStream,
+ typename CompletionCondition, typename WriteHandler>
+ class write_op<AsyncWriteStream, asio::const_buffers_1,
+ CompletionCondition, WriteHandler>
+ : detail::base_from_completion_cond<CompletionCondition>
+ {
+ public:
+ write_op(AsyncWriteStream& stream,
+ const asio::const_buffers_1& buffers,
+ CompletionCondition completion_condition,
+ WriteHandler handler)
+ : detail::base_from_completion_cond<
+ CompletionCondition>(completion_condition),
+ stream_(stream),
+ buffer_(buffers),
+ total_transferred_(0),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred, int start = 0)
+ {
+ std::size_t n = 0;
+ switch (start)
+ {
+ case 1:
+ n = this->check_for_completion(ec, total_transferred_);
+ for (;;)
+ {
+ stream_.async_write_some(asio::buffer(
+ buffer_ + total_transferred_, n), *this);
+ return; default:
+ total_transferred_ += bytes_transferred;
+ if ((!ec && bytes_transferred == 0)
+ || (n = this->check_for_completion(ec, total_transferred_)) == 0
+ || total_transferred_ == asio::buffer_size(buffer_))
+ break;
+ }
+
+ handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+ }
+ }
+
+ //private:
+ AsyncWriteStream& stream_;
+ asio::const_buffer buffer_;
+ std::size_t total_transferred_;
+ WriteHandler handler_;
+ };
+
+ template <typename AsyncWriteStream, typename ConstBufferSequence,
+ typename CompletionCondition, typename WriteHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ write_op<AsyncWriteStream, ConstBufferSequence,
+ CompletionCondition, WriteHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+ }
+
+ template <typename AsyncWriteStream, typename ConstBufferSequence,
+ typename CompletionCondition, typename WriteHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ write_op<AsyncWriteStream, ConstBufferSequence,
+ CompletionCondition, WriteHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncWriteStream,
+ typename ConstBufferSequence, typename CompletionCondition,
+ typename WriteHandler>
+ inline void asio_handler_invoke(const Function& function,
+ write_op<AsyncWriteStream, ConstBufferSequence,
+ CompletionCondition, WriteHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncWriteStream, typename ConstBufferSequence,
+ typename CompletionCondition, typename WriteHandler>
+inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
+ CompletionCondition completion_condition, WriteHandler handler)
+{
+ detail::write_op<AsyncWriteStream, ConstBufferSequence,
+ CompletionCondition, WriteHandler>(
+ s, buffers, completion_condition, handler)(
+ asio::error_code(), 0, 1);
+}
+
+template <typename AsyncWriteStream, typename ConstBufferSequence,
+ typename WriteHandler>
+inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
+ WriteHandler handler)
+{
+ async_write(s, buffers, transfer_all(), handler);
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+namespace detail
+{
+ template <typename AsyncWriteStream, typename Allocator,
+ typename WriteHandler>
+ class write_streambuf_handler
+ {
+ public:
+ write_streambuf_handler(asio::basic_streambuf<Allocator>& streambuf,
+ WriteHandler handler)
+ : streambuf_(streambuf),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ const std::size_t bytes_transferred)
+ {
+ streambuf_.consume(bytes_transferred);
+ handler_(ec, bytes_transferred);
+ }
+
+ //private:
+ asio::basic_streambuf<Allocator>& streambuf_;
+ WriteHandler handler_;
+ };
+
+ template <typename AsyncWriteStream, typename Allocator,
+ typename WriteHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ write_streambuf_handler<AsyncWriteStream,
+ Allocator, WriteHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+ }
+
+ template <typename AsyncWriteStream, typename Allocator,
+ typename WriteHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ write_streambuf_handler<AsyncWriteStream,
+ Allocator, WriteHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncWriteStream, typename Allocator,
+ typename WriteHandler>
+ inline void asio_handler_invoke(const Function& function,
+ write_streambuf_handler<AsyncWriteStream,
+ Allocator, WriteHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncWriteStream, typename Allocator,
+ typename CompletionCondition, typename WriteHandler>
+inline void async_write(AsyncWriteStream& s,
+ asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition, WriteHandler handler)
+{
+ async_write(s, b.data(), completion_condition,
+ detail::write_streambuf_handler<
+ AsyncWriteStream, Allocator, WriteHandler>(b, handler));
+}
+
+template <typename AsyncWriteStream, typename Allocator, typename WriteHandler>
+inline void async_write(AsyncWriteStream& s,
+ asio::basic_streambuf<Allocator>& b, WriteHandler handler)
+{
+ async_write(s, b, transfer_all(), handler);
+}
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_WRITE_HPP
diff --git a/ext/asio/asio/impl/write_at.hpp b/ext/asio/asio/impl/write_at.hpp
new file mode 100644
index 0000000..1de6800
--- /dev/null
+++ b/ext/asio/asio/impl/write_at.hpp
@@ -0,0 +1,417 @@
+//
+// impl/write_at.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_WRITE_AT_HPP
+#define ASIO_IMPL_WRITE_AT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/detail/base_from_completion_cond.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/consuming_buffers.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
+ typename CompletionCondition>
+std::size_t write_at(SyncRandomAccessWriteDevice& d,
+ boost::uint64_t offset, const ConstBufferSequence& buffers,
+ CompletionCondition completion_condition, asio::error_code& ec)
+{
+ ec = asio::error_code();
+ asio::detail::consuming_buffers<
+ const_buffer, ConstBufferSequence> tmp(buffers);
+ std::size_t total_transferred = 0;
+ tmp.prepare(detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred)));
+ while (tmp.begin() != tmp.end())
+ {
+ std::size_t bytes_transferred = d.write_some_at(
+ offset + total_transferred, tmp, ec);
+ tmp.consume(bytes_transferred);
+ total_transferred += bytes_transferred;
+ tmp.prepare(detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred)));
+ }
+ return total_transferred;
+}
+
+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>
+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
+ boost::uint64_t offset, const ConstBufferSequence& buffers)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = write_at(
+ d, offset, buffers, transfer_all(), ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
+ typename CompletionCondition>
+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
+ boost::uint64_t offset, const ConstBufferSequence& buffers,
+ CompletionCondition completion_condition)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = write_at(
+ d, offset, buffers, completion_condition, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+template <typename SyncRandomAccessWriteDevice, typename Allocator,
+ typename CompletionCondition>
+std::size_t write_at(SyncRandomAccessWriteDevice& d,
+ boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition, asio::error_code& ec)
+{
+ std::size_t bytes_transferred = write_at(
+ d, offset, b.data(), completion_condition, ec);
+ b.consume(bytes_transferred);
+ return bytes_transferred;
+}
+
+template <typename SyncRandomAccessWriteDevice, typename Allocator>
+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
+ boost::uint64_t offset, asio::basic_streambuf<Allocator>& b)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = write_at(d, offset, b, transfer_all(), ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncRandomAccessWriteDevice, typename Allocator,
+ typename CompletionCondition>
+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
+ boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = write_at(
+ d, offset, b, completion_condition, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+namespace detail
+{
+ template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
+ typename CompletionCondition, typename WriteHandler>
+ class write_at_op
+ : detail::base_from_completion_cond<CompletionCondition>
+ {
+ public:
+ write_at_op(AsyncRandomAccessWriteDevice& device,
+ boost::uint64_t offset, const ConstBufferSequence& buffers,
+ CompletionCondition completion_condition, WriteHandler handler)
+ : detail::base_from_completion_cond<
+ CompletionCondition>(completion_condition),
+ device_(device),
+ offset_(offset),
+ buffers_(buffers),
+ total_transferred_(0),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred, int start = 0)
+ {
+ switch (start)
+ {
+ case 1:
+ buffers_.prepare(this->check_for_completion(ec, total_transferred_));
+ for (;;)
+ {
+ device_.async_write_some_at(
+ offset_ + total_transferred_, buffers_, *this);
+ return; default:
+ total_transferred_ += bytes_transferred;
+ buffers_.consume(bytes_transferred);
+ buffers_.prepare(this->check_for_completion(ec, total_transferred_));
+ if ((!ec && bytes_transferred == 0)
+ || buffers_.begin() == buffers_.end())
+ break;
+ }
+
+ handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+ }
+ }
+
+ //private:
+ AsyncRandomAccessWriteDevice& device_;
+ boost::uint64_t offset_;
+ asio::detail::consuming_buffers<
+ const_buffer, ConstBufferSequence> buffers_;
+ std::size_t total_transferred_;
+ WriteHandler handler_;
+ };
+
+ template <typename AsyncRandomAccessWriteDevice,
+ typename CompletionCondition, typename WriteHandler>
+ class write_at_op<AsyncRandomAccessWriteDevice,
+ asio::mutable_buffers_1, CompletionCondition, WriteHandler>
+ : detail::base_from_completion_cond<CompletionCondition>
+ {
+ public:
+ write_at_op(AsyncRandomAccessWriteDevice& device,
+ boost::uint64_t offset, const asio::mutable_buffers_1& buffers,
+ CompletionCondition completion_condition,
+ WriteHandler handler)
+ : detail::base_from_completion_cond<
+ CompletionCondition>(completion_condition),
+ device_(device),
+ offset_(offset),
+ buffer_(buffers),
+ total_transferred_(0),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred, int start = 0)
+ {
+ std::size_t n = 0;
+ switch (start)
+ {
+ case 1:
+ n = this->check_for_completion(ec, total_transferred_);
+ for (;;)
+ {
+ device_.async_write_some_at(offset_ + total_transferred_,
+ asio::buffer(buffer_ + total_transferred_, n), *this);
+ return; default:
+ total_transferred_ += bytes_transferred;
+ if ((!ec && bytes_transferred == 0)
+ || (n = this->check_for_completion(ec, total_transferred_)) == 0
+ || total_transferred_ == asio::buffer_size(buffer_))
+ break;
+ }
+
+ handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+ }
+ }
+
+ //private:
+ AsyncRandomAccessWriteDevice& device_;
+ boost::uint64_t offset_;
+ asio::mutable_buffer buffer_;
+ std::size_t total_transferred_;
+ WriteHandler handler_;
+ };
+
+ template <typename AsyncRandomAccessWriteDevice,
+ typename CompletionCondition, typename WriteHandler>
+ class write_at_op<AsyncRandomAccessWriteDevice, asio::const_buffers_1,
+ CompletionCondition, WriteHandler>
+ : detail::base_from_completion_cond<CompletionCondition>
+ {
+ public:
+ write_at_op(AsyncRandomAccessWriteDevice& device,
+ boost::uint64_t offset, const asio::const_buffers_1& buffers,
+ CompletionCondition completion_condition,
+ WriteHandler handler)
+ : detail::base_from_completion_cond<
+ CompletionCondition>(completion_condition),
+ device_(device),
+ offset_(offset),
+ buffer_(buffers),
+ total_transferred_(0),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred, int start = 0)
+ {
+ std::size_t n = 0;
+ switch (start)
+ {
+ case 1:
+ n = this->check_for_completion(ec, total_transferred_);
+ for (;;)
+ {
+ device_.async_write_some_at(offset_ + total_transferred_,
+ asio::buffer(buffer_ + total_transferred_, n), *this);
+ return; default:
+ total_transferred_ += bytes_transferred;
+ if ((!ec && bytes_transferred == 0)
+ || (n = this->check_for_completion(ec, total_transferred_)) == 0
+ || total_transferred_ == asio::buffer_size(buffer_))
+ break;
+ }
+
+ handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+ }
+ }
+
+ //private:
+ AsyncRandomAccessWriteDevice& device_;
+ boost::uint64_t offset_;
+ asio::const_buffer buffer_;
+ std::size_t total_transferred_;
+ WriteHandler handler_;
+ };
+
+ template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
+ typename CompletionCondition, typename WriteHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
+ CompletionCondition, WriteHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+ }
+
+ template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
+ typename CompletionCondition, typename WriteHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
+ CompletionCondition, WriteHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncRandomAccessWriteDevice,
+ typename ConstBufferSequence, typename CompletionCondition,
+ typename WriteHandler>
+ inline void asio_handler_invoke(const Function& function,
+ write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
+ CompletionCondition, WriteHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
+ typename CompletionCondition, typename WriteHandler>
+inline void async_write_at(AsyncRandomAccessWriteDevice& d,
+ boost::uint64_t offset, const ConstBufferSequence& buffers,
+ CompletionCondition completion_condition, WriteHandler handler)
+{
+ detail::write_at_op<AsyncRandomAccessWriteDevice,
+ ConstBufferSequence, CompletionCondition, WriteHandler>(
+ d, offset, buffers, completion_condition, handler)(
+ asio::error_code(), 0, 1);
+}
+
+template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
+ typename WriteHandler>
+inline void async_write_at(AsyncRandomAccessWriteDevice& d,
+ boost::uint64_t offset, const ConstBufferSequence& buffers,
+ WriteHandler handler)
+{
+ async_write_at(d, offset, buffers, transfer_all(), handler);
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+namespace detail
+{
+ template <typename AsyncRandomAccessWriteDevice,
+ typename Allocator, typename WriteHandler>
+ class write_at_streambuf_op
+ {
+ public:
+ write_at_streambuf_op(
+ asio::basic_streambuf<Allocator>& streambuf,
+ WriteHandler handler)
+ : streambuf_(streambuf),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ const std::size_t bytes_transferred)
+ {
+ streambuf_.consume(bytes_transferred);
+ handler_(ec, bytes_transferred);
+ }
+
+ //private:
+ asio::basic_streambuf<Allocator>& streambuf_;
+ WriteHandler handler_;
+ };
+
+ template <typename AsyncRandomAccessWriteDevice, typename Allocator,
+ typename WriteHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ write_at_streambuf_op<AsyncRandomAccessWriteDevice,
+ Allocator, WriteHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+ }
+
+ template <typename AsyncRandomAccessWriteDevice, typename Allocator,
+ typename WriteHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ write_at_streambuf_op<AsyncRandomAccessWriteDevice,
+ Allocator, WriteHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncRandomAccessWriteDevice,
+ typename Allocator, typename WriteHandler>
+ inline void asio_handler_invoke(const Function& function,
+ write_at_streambuf_op<AsyncRandomAccessWriteDevice,
+ Allocator, WriteHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncRandomAccessWriteDevice, typename Allocator,
+ typename CompletionCondition, typename WriteHandler>
+inline void async_write_at(AsyncRandomAccessWriteDevice& d,
+ boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition, WriteHandler handler)
+{
+ async_write_at(d, offset, b.data(), completion_condition,
+ detail::write_at_streambuf_op<
+ AsyncRandomAccessWriteDevice, Allocator, WriteHandler>(b, handler));
+}
+
+template <typename AsyncRandomAccessWriteDevice, typename Allocator,
+ typename WriteHandler>
+inline void async_write_at(AsyncRandomAccessWriteDevice& d,
+ boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
+ WriteHandler handler)
+{
+ async_write_at(d, offset, b, transfer_all(), handler);
+}
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_WRITE_AT_HPP
diff --git a/ext/asio/asio/io_service.hpp b/ext/asio/asio/io_service.hpp
index 62d9e54..4fc3e05 100644
--- a/ext/asio/asio/io_service.hpp
+++ b/ext/asio/asio/io_service.hpp
@@ -2,7 +2,7 @@
// io_service.hpp
// ~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,25 +15,29 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
#include <stdexcept>
#include <typeinfo>
-#include <boost/config.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error_code.hpp"
#include "asio/detail/noncopyable.hpp"
-#include "asio/detail/reactor_fwd.hpp"
#include "asio/detail/service_registry_fwd.hpp"
-#include "asio/detail/signal_init.hpp"
-#include "asio/detail/task_io_service_fwd.hpp"
-#include "asio/detail/win_iocp_io_service_fwd.hpp"
-#include "asio/detail/winsock_init.hpp"
#include "asio/detail/wrapped_handler.hpp"
+#include "asio/error_code.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_service_fwd.hpp"
+#else
+# include "asio/detail/task_io_service_fwd.hpp"
+#endif
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# include "asio/detail/winsock_init.hpp"
+#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \
+ || defined(__osf__)
+# include "asio/detail/signal_init.hpp"
+#endif
+
+#include "asio/detail/push_options.hpp"
namespace asio {
@@ -45,7 +49,7 @@ template <typename Service> bool has_service(io_service& ios);
#if defined(ASIO_HAS_IOCP)
namespace detail { typedef win_iocp_io_service io_service_impl; }
#else
-namespace detail { typedef task_io_service<reactor> io_service_impl; }
+namespace detail { typedef task_io_service io_service_impl; }
#endif
/// Provides core I/O functionality.
@@ -196,7 +200,7 @@ public:
class strand;
/// Constructor.
- io_service();
+ ASIO_DECL io_service();
/// Constructor.
/**
@@ -205,7 +209,7 @@ public:
* @param concurrency_hint A suggestion to the implementation on how many
* threads it should allow to run simultaneously.
*/
- explicit io_service(std::size_t concurrency_hint);
+ ASIO_DECL explicit io_service(std::size_t concurrency_hint);
/// Destructor.
/**
@@ -239,7 +243,7 @@ public:
* destructor defined above destroys all handlers, causing all @c shared_ptr
* references to all connection objects to be destroyed.
*/
- ~io_service();
+ ASIO_DECL ~io_service();
/// Run the io_service object's event processing loop.
/**
@@ -265,7 +269,7 @@ public:
* The poll() function may also be used to dispatch ready handlers, but
* without blocking.
*/
- std::size_t run();
+ ASIO_DECL std::size_t run();
/// Run the io_service object's event processing loop.
/**
@@ -291,7 +295,7 @@ public:
* The poll() function may also be used to dispatch ready handlers, but
* without blocking.
*/
- std::size_t run(asio::error_code& ec);
+ ASIO_DECL std::size_t run(asio::error_code& ec);
/// Run the io_service object's event processing loop to execute at most one
/// handler.
@@ -303,7 +307,7 @@ public:
*
* @throws asio::system_error Thrown on failure.
*/
- std::size_t run_one();
+ ASIO_DECL std::size_t run_one();
/// Run the io_service object's event processing loop to execute at most one
/// handler.
@@ -315,7 +319,7 @@ public:
*
* @return The number of handlers that were executed.
*/
- std::size_t run_one(asio::error_code& ec);
+ ASIO_DECL std::size_t run_one(asio::error_code& ec);
/// Run the io_service object's event processing loop to execute ready
/// handlers.
@@ -327,7 +331,7 @@ public:
*
* @throws asio::system_error Thrown on failure.
*/
- std::size_t poll();
+ ASIO_DECL std::size_t poll();
/// Run the io_service object's event processing loop to execute ready
/// handlers.
@@ -339,7 +343,7 @@ public:
*
* @return The number of handlers that were executed.
*/
- std::size_t poll(asio::error_code& ec);
+ ASIO_DECL std::size_t poll(asio::error_code& ec);
/// Run the io_service object's event processing loop to execute one ready
/// handler.
@@ -351,7 +355,7 @@ public:
*
* @throws asio::system_error Thrown on failure.
*/
- std::size_t poll_one();
+ ASIO_DECL std::size_t poll_one();
/// Run the io_service object's event processing loop to execute one ready
/// handler.
@@ -363,7 +367,7 @@ public:
*
* @return The number of handlers that were executed.
*/
- std::size_t poll_one(asio::error_code& ec);
+ ASIO_DECL std::size_t poll_one(asio::error_code& ec);
/// Stop the io_service object's event processing loop.
/**
@@ -372,7 +376,7 @@ public:
* return as soon as possible. Subsequent calls to run(), run_one(), poll()
* or poll_one() will return immediately until reset() is called.
*/
- void stop();
+ ASIO_DECL void stop();
/// Reset the io_service in preparation for a subsequent run() invocation.
/**
@@ -385,7 +389,7 @@ public:
* This function must not be called while there are any unfinished calls to
* the run(), run_one(), poll() or poll_one() functions.
*/
- void reset();
+ ASIO_DECL void reset();
/// Request the io_service to invoke the given handler.
/**
@@ -605,10 +609,10 @@ protected:
/**
* @param owner The io_service object that owns the service.
*/
- service(asio::io_service& owner);
+ ASIO_DECL service(asio::io_service& owner);
/// Destructor.
- virtual ~service();
+ ASIO_DECL virtual ~service();
private:
/// Destroy all user-defined handler objects owned by the service.
@@ -631,10 +635,7 @@ class service_already_exists
: public std::logic_error
{
public:
- service_already_exists()
- : std::logic_error("Service already exists.")
- {
- }
+ ASIO_DECL service_already_exists();
};
/// Exception thrown when trying to add a service object to an io_service where
@@ -643,16 +644,44 @@ class invalid_service_owner
: public std::logic_error
{
public:
- invalid_service_owner()
- : std::logic_error("Invalid service owner.")
+ ASIO_DECL invalid_service_owner();
+};
+
+namespace detail {
+
+// Special derived service id type to keep classes header-file only.
+template <typename Type>
+class service_id
+ : public asio::io_service::id
+{
+};
+
+// Special service base class to keep classes header-file only.
+template <typename Type>
+class service_base
+ : public asio::io_service::service
+{
+public:
+ static asio::detail::service_id<Type> id;
+
+ // Constructor.
+ service_base(asio::io_service& io_service)
+ : asio::io_service::service(io_service)
{
}
};
-} // namespace asio
+template <typename Type>
+asio::detail::service_id<Type> service_base<Type>::id;
-#include "asio/impl/io_service.ipp"
+} // namespace detail
+} // namespace asio
#include "asio/detail/pop_options.hpp"
+#include "asio/impl/io_service.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/io_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
#endif // ASIO_IO_SERVICE_HPP
diff --git a/ext/asio/asio/ip/address.hpp b/ext/asio/asio/ip/address.hpp
index 92ee4ae..47683db 100644
--- a/ext/asio/asio/ip/address.hpp
+++ b/ext/asio/asio/ip/address.hpp
@@ -1,8 +1,8 @@
//
-// address.hpp
-// ~~~~~~~~~~~
+// ip/address.hpp
+// ~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,21 +15,17 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include <string>
+#include "asio/error_code.hpp"
+#include "asio/ip/address_v4.hpp"
+#include "asio/ip/address_v6.hpp"
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
#if !defined(BOOST_NO_IOSTREAM)
# include <iosfwd>
#endif // !defined(BOOST_NO_IOSTREAM)
-#include <string>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-#include "asio/error.hpp"
-#include "asio/ip/address_v4.hpp"
-#include "asio/ip/address_v6.hpp"
-#include "asio/detail/throw_error.hpp"
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace ip {
@@ -47,63 +43,27 @@ class address
{
public:
/// Default constructor.
- address()
- : type_(ipv4),
- ipv4_address_(),
- ipv6_address_()
- {
- }
+ ASIO_DECL address();
/// Construct an address from an IPv4 address.
- address(const asio::ip::address_v4& ipv4_address)
- : type_(ipv4),
- ipv4_address_(ipv4_address),
- ipv6_address_()
- {
- }
+ ASIO_DECL address(const asio::ip::address_v4& ipv4_address);
/// Construct an address from an IPv6 address.
- address(const asio::ip::address_v6& ipv6_address)
- : type_(ipv6),
- ipv4_address_(),
- ipv6_address_(ipv6_address)
- {
- }
+ ASIO_DECL address(const asio::ip::address_v6& ipv6_address);
/// Copy constructor.
- address(const address& other)
- : type_(other.type_),
- ipv4_address_(other.ipv4_address_),
- ipv6_address_(other.ipv6_address_)
- {
- }
+ ASIO_DECL address(const address& other);
/// Assign from another address.
- address& operator=(const address& other)
- {
- type_ = other.type_;
- ipv4_address_ = other.ipv4_address_;
- ipv6_address_ = other.ipv6_address_;
- return *this;
- }
+ ASIO_DECL address& operator=(const address& other);
/// Assign from an IPv4 address.
- address& operator=(const asio::ip::address_v4& ipv4_address)
- {
- type_ = ipv4;
- ipv4_address_ = ipv4_address;
- ipv6_address_ = asio::ip::address_v6();
- return *this;
- }
+ ASIO_DECL address& operator=(
+ const asio::ip::address_v4& ipv4_address);
/// Assign from an IPv6 address.
- address& operator=(const asio::ip::address_v6& ipv6_address)
- {
- type_ = ipv6;
- ipv4_address_ = asio::ip::address_v4();
- ipv6_address_ = ipv6_address;
- return *this;
- }
+ ASIO_DECL address& operator=(
+ const asio::ip::address_v6& ipv6_address);
/// Get whether the address is an IP version 4 address.
bool is_v4() const
@@ -118,127 +78,63 @@ public:
}
/// Get the address as an IP version 4 address.
- asio::ip::address_v4 to_v4() const
- {
- if (type_ != ipv4)
- {
- asio::system_error e(
- asio::error::address_family_not_supported);
- boost::throw_exception(e);
- }
- return ipv4_address_;
- }
+ ASIO_DECL asio::ip::address_v4 to_v4() const;
/// Get the address as an IP version 6 address.
- asio::ip::address_v6 to_v6() const
- {
- if (type_ != ipv6)
- {
- asio::system_error e(
- asio::error::address_family_not_supported);
- boost::throw_exception(e);
- }
- return ipv6_address_;
- }
+ ASIO_DECL asio::ip::address_v6 to_v6() const;
/// Get the address as a string in dotted decimal format.
- std::string to_string() const
- {
- if (type_ == ipv6)
- return ipv6_address_.to_string();
- return ipv4_address_.to_string();
- }
+ ASIO_DECL std::string to_string() const;
/// Get the address as a string in dotted decimal format.
- std::string to_string(asio::error_code& ec) const
- {
- if (type_ == ipv6)
- return ipv6_address_.to_string(ec);
- return ipv4_address_.to_string(ec);
- }
+ ASIO_DECL std::string to_string(asio::error_code& ec) const;
/// Create an address from an IPv4 address string in dotted decimal form,
/// or from an IPv6 address in hexadecimal notation.
- static address from_string(const char* str)
- {
- asio::error_code ec;
- address addr = from_string(str, ec);
- asio::detail::throw_error(ec);
- return addr;
- }
+ ASIO_DECL static address from_string(const char* str);
/// Create an address from an IPv4 address string in dotted decimal form,
/// or from an IPv6 address in hexadecimal notation.
- static address from_string(const char* str, asio::error_code& ec)
- {
- asio::ip::address_v6 ipv6_address =
- asio::ip::address_v6::from_string(str, ec);
- if (!ec)
- {
- address tmp;
- tmp.type_ = ipv6;
- tmp.ipv6_address_ = ipv6_address;
- return tmp;
- }
-
- asio::ip::address_v4 ipv4_address =
- asio::ip::address_v4::from_string(str, ec);
- if (!ec)
- {
- address tmp;
- tmp.type_ = ipv4;
- tmp.ipv4_address_ = ipv4_address;
- return tmp;
- }
-
- return address();
- }
+ ASIO_DECL static address from_string(
+ const char* str, asio::error_code& ec);
/// Create an address from an IPv4 address string in dotted decimal form,
/// or from an IPv6 address in hexadecimal notation.
- static address from_string(const std::string& str)
- {
- return from_string(str.c_str());
- }
+ ASIO_DECL static address from_string(const std::string& str);
/// Create an address from an IPv4 address string in dotted decimal form,
/// or from an IPv6 address in hexadecimal notation.
- static address from_string(const std::string& str,
- asio::error_code& ec)
+ ASIO_DECL static address from_string(
+ const std::string& str, asio::error_code& ec);
+
+ /// Compare two addresses for equality.
+ ASIO_DECL friend bool operator==(const address& a1, const address& a2);
+
+ /// Compare two addresses for inequality.
+ friend bool operator!=(const address& a1, const address& a2)
{
- return from_string(str.c_str(), ec);
+ return !(a1 == a2);
}
- /// Compare two addresses for equality.
- friend bool operator==(const address& a1, const address& a2)
+ /// Compare addresses for ordering.
+ ASIO_DECL friend bool operator<(const address& a1, const address& a2);
+
+ /// Compare addresses for ordering.
+ friend bool operator>(const address& a1, const address& a2)
{
- if (a1.type_ != a2.type_)
- return false;
- if (a1.type_ == ipv6)
- return a1.ipv6_address_ == a2.ipv6_address_;
- return a1.ipv4_address_ == a2.ipv4_address_;
+ return a2 < a1;
}
- /// Compare two addresses for inequality.
- friend bool operator!=(const address& a1, const address& a2)
+ /// Compare addresses for ordering.
+ friend bool operator<=(const address& a1, const address& a2)
{
- if (a1.type_ != a2.type_)
- return true;
- if (a1.type_ == ipv6)
- return a1.ipv6_address_ != a2.ipv6_address_;
- return a1.ipv4_address_ != a2.ipv4_address_;
+ return !(a2 < a1);
}
/// Compare addresses for ordering.
- friend bool operator<(const address& a1, const address& a2)
+ friend bool operator>=(const address& a1, const address& a2)
{
- if (a1.type_ < a2.type_)
- return true;
- if (a1.type_ > a2.type_)
- return false;
- if (a1.type_ == ipv6)
- return a1.ipv6_address_ < a2.ipv6_address_;
- return a1.ipv4_address_ < a2.ipv4_address_;
+ return !(a1 < a2);
}
private:
@@ -268,11 +164,7 @@ private:
*/
template <typename Elem, typename Traits>
std::basic_ostream<Elem, Traits>& operator<<(
- std::basic_ostream<Elem, Traits>& os, const address& addr)
-{
- os << addr.to_string();
- return os;
-}
+ std::basic_ostream<Elem, Traits>& os, const address& addr);
#endif // !defined(BOOST_NO_IOSTREAM)
@@ -281,4 +173,9 @@ std::basic_ostream<Elem, Traits>& operator<<(
#include "asio/detail/pop_options.hpp"
+#include "asio/ip/impl/address.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/impl/address.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
#endif // ASIO_IP_ADDRESS_HPP
diff --git a/ext/asio/asio/ip/address_v4.hpp b/ext/asio/asio/ip/address_v4.hpp
index 1b49556..7567ef9 100644
--- a/ext/asio/asio/ip/address_v4.hpp
+++ b/ext/asio/asio/ip/address_v4.hpp
@@ -1,8 +1,8 @@
//
-// address_v4.hpp
-// ~~~~~~~~~~~~~~
+// ip/address_v4.hpp
+// ~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,24 +15,18 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include <string>
+#include <boost/array.hpp>
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/error_code.hpp"
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
#if !defined(BOOST_NO_IOSTREAM)
# include <iosfwd>
#endif // !defined(BOOST_NO_IOSTREAM)
-#include <climits>
-#include <string>
-#include <stdexcept>
-#include <boost/array.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-#include "asio/error.hpp"
-#include "asio/detail/socket_ops.hpp"
-#include "asio/detail/socket_types.hpp"
-#include "asio/detail/throw_error.hpp"
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace ip {
@@ -59,34 +53,10 @@ public:
}
/// Construct an address from raw bytes.
- explicit address_v4(const bytes_type& bytes)
- {
-#if UCHAR_MAX > 0xFF
- if (bytes[0] > 0xFF || bytes[1] > 0xFF
- || bytes[2] > 0xFF || bytes[3] > 0xFF)
- {
- std::out_of_range ex("address_v4 from bytes_type");
- boost::throw_exception(ex);
- }
-#endif // UCHAR_MAX > 0xFF
-
- using namespace std; // For memcpy.
- memcpy(&addr_.s_addr, bytes.elems, 4);
- }
+ ASIO_DECL explicit address_v4(const bytes_type& bytes);
/// Construct an address from a unsigned long in host byte order.
- explicit address_v4(unsigned long addr)
- {
-#if ULONG_MAX > 0xFFFFFFFF
- if (addr > 0xFFFFFFFF)
- {
- std::out_of_range ex("address_v4 from unsigned long");
- boost::throw_exception(ex);
- }
-#endif // ULONG_MAX > 0xFFFFFFFF
-
- addr_.s_addr = asio::detail::socket_ops::host_to_network_long(addr);
- }
+ ASIO_DECL explicit address_v4(unsigned long addr);
/// Copy constructor.
address_v4(const address_v4& other)
@@ -102,96 +72,42 @@ public:
}
/// Get the address in bytes, in network byte order.
- bytes_type to_bytes() const
- {
- using namespace std; // For memcpy.
- bytes_type bytes;
- memcpy(bytes.elems, &addr_.s_addr, 4);
- return bytes;
- }
+ ASIO_DECL bytes_type to_bytes() const;
/// Get the address as an unsigned long in host byte order
- unsigned long to_ulong() const
- {
- return asio::detail::socket_ops::network_to_host_long(addr_.s_addr);
- }
+ ASIO_DECL unsigned long to_ulong() const;
/// Get the address as a string in dotted decimal format.
- std::string to_string() const
- {
- asio::error_code ec;
- std::string addr = to_string(ec);
- asio::detail::throw_error(ec);
- return addr;
- }
+ ASIO_DECL std::string to_string() const;
/// Get the address as a string in dotted decimal format.
- std::string to_string(asio::error_code& ec) const
- {
- char addr_str[asio::detail::max_addr_v4_str_len];
- const char* addr =
- asio::detail::socket_ops::inet_ntop(AF_INET, &addr_, addr_str,
- asio::detail::max_addr_v4_str_len, 0, ec);
- if (addr == 0)
- return std::string();
- return addr;
- }
+ ASIO_DECL std::string to_string(asio::error_code& ec) const;
/// Create an address from an IP address string in dotted decimal form.
- static address_v4 from_string(const char* str)
- {
- asio::error_code ec;
- address_v4 addr = from_string(str, ec);
- asio::detail::throw_error(ec);
- return addr;
- }
+ ASIO_DECL static address_v4 from_string(const char* str);
/// Create an address from an IP address string in dotted decimal form.
- static address_v4 from_string(const char* str, asio::error_code& ec)
- {
- address_v4 tmp;
- if (asio::detail::socket_ops::inet_pton(
- AF_INET, str, &tmp.addr_, 0, ec) <= 0)
- return address_v4();
- return tmp;
- }
+ ASIO_DECL static address_v4 from_string(
+ const char* str, asio::error_code& ec);
/// Create an address from an IP address string in dotted decimal form.
- static address_v4 from_string(const std::string& str)
- {
- return from_string(str.c_str());
- }
+ ASIO_DECL static address_v4 from_string(const std::string& str);
/// Create an address from an IP address string in dotted decimal form.
- static address_v4 from_string(const std::string& str,
- asio::error_code& ec)
- {
- return from_string(str.c_str(), ec);
- }
+ ASIO_DECL static address_v4 from_string(
+ const std::string& str, asio::error_code& ec);
/// Determine whether the address is a class A address.
- bool is_class_a() const
- {
- return IN_CLASSA(to_ulong());
- }
+ ASIO_DECL bool is_class_a() const;
/// Determine whether the address is a class B address.
- bool is_class_b() const
- {
- return IN_CLASSB(to_ulong());
- }
+ ASIO_DECL bool is_class_b() const;
/// Determine whether the address is a class C address.
- bool is_class_c() const
- {
- return IN_CLASSC(to_ulong());
- }
+ ASIO_DECL bool is_class_c() const;
/// Determine whether the address is a multicast address.
- bool is_multicast() const
- {
- return IN_MULTICAST(to_ulong());
- }
+ ASIO_DECL bool is_multicast() const;
/// Compare two addresses for equality.
friend bool operator==(const address_v4& a1, const address_v4& a2)
@@ -249,23 +165,12 @@ public:
/// Obtain an address object that represents the broadcast address that
/// corresponds to the specified address and netmask.
- static address_v4 broadcast(const address_v4& addr, const address_v4& mask)
- {
- return address_v4(addr.to_ulong() | ~mask.to_ulong());
- }
+ ASIO_DECL static address_v4 broadcast(
+ const address_v4& addr, const address_v4& mask);
/// Obtain the netmask that corresponds to the address, based on its address
/// class.
- static address_v4 netmask(const address_v4& addr)
- {
- if (addr.is_class_a())
- return address_v4(0xFF000000);
- if (addr.is_class_b())
- return address_v4(0xFFFF0000);
- if (addr.is_class_c())
- return address_v4(0xFFFFFF00);
- return address_v4(0xFFFFFFFF);
- }
+ ASIO_DECL static address_v4 netmask(const address_v4& addr);
private:
// The underlying IPv4 address.
@@ -288,22 +193,7 @@ private:
*/
template <typename Elem, typename Traits>
std::basic_ostream<Elem, Traits>& operator<<(
- std::basic_ostream<Elem, Traits>& os, const address_v4& addr)
-{
- asio::error_code ec;
- std::string s = addr.to_string(ec);
- if (ec)
- {
- if (os.exceptions() & std::ios::failbit)
- asio::detail::throw_error(ec);
- else
- os.setstate(std::ios_base::failbit);
- }
- else
- for (std::string::iterator i = s.begin(); i != s.end(); ++i)
- os << os.widen(*i);
- return os;
-}
+ std::basic_ostream<Elem, Traits>& os, const address_v4& addr);
#endif // !defined(BOOST_NO_IOSTREAM)
@@ -312,4 +202,9 @@ std::basic_ostream<Elem, Traits>& operator<<(
#include "asio/detail/pop_options.hpp"
+#include "asio/ip/impl/address_v4.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/impl/address_v4.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
#endif // ASIO_IP_ADDRESS_V4_HPP
diff --git a/ext/asio/asio/ip/address_v6.hpp b/ext/asio/asio/ip/address_v6.hpp
index 8d2c083..261c651 100644
--- a/ext/asio/asio/ip/address_v6.hpp
+++ b/ext/asio/asio/ip/address_v6.hpp
@@ -1,8 +1,8 @@
//
-// address_v6.hpp
-// ~~~~~~~~~~~~~~
+// ip/address_v6.hpp
+// ~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,26 +15,19 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include <string>
+#include <boost/array.hpp>
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/error_code.hpp"
+#include "asio/ip/address_v4.hpp"
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
#if !defined(BOOST_NO_IOSTREAM)
# include <iosfwd>
#endif // !defined(BOOST_NO_IOSTREAM)
-#include <cstring>
-#include <string>
-#include <stdexcept>
-#include <typeinfo>
-#include <boost/array.hpp>
-#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-#include "asio/error.hpp"
-#include "asio/detail/socket_ops.hpp"
-#include "asio/detail/socket_types.hpp"
-#include "asio/detail/throw_error.hpp"
-#include "asio/ip/address_v4.hpp"
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace ip {
@@ -55,46 +48,17 @@ public:
typedef boost::array<unsigned char, 16> bytes_type;
/// Default constructor.
- address_v6()
- : scope_id_(0)
- {
- asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
- addr_ = tmp_addr;
- }
+ ASIO_DECL address_v6();
/// Construct an address from raw bytes and scope ID.
- explicit address_v6(const bytes_type& bytes, unsigned long scope_id = 0)
- : scope_id_(scope_id)
- {
-#if UCHAR_MAX > 0xFF
- for (std::size_t i = 0; i < bytes.size(); ++i)
- {
- if (bytes[i] > 0xFF)
- {
- std::out_of_range ex("address_v6 from bytes_type");
- boost::throw_exception(ex);
- }
- }
-#endif // UCHAR_MAX > 0xFF
-
- using namespace std; // For memcpy.
- memcpy(addr_.s6_addr, bytes.elems, 16);
- }
+ ASIO_DECL explicit address_v6(const bytes_type& bytes,
+ unsigned long scope_id = 0);
/// Copy constructor.
- address_v6(const address_v6& other)
- : addr_(other.addr_),
- scope_id_(other.scope_id_)
- {
- }
+ ASIO_DECL address_v6(const address_v6& other);
/// Assign from another address.
- address_v6& operator=(const address_v6& other)
- {
- addr_ = other.addr_;
- scope_id_ = other.scope_id_;
- return *this;
- }
+ ASIO_DECL address_v6& operator=(const address_v6& other);
/// The scope ID of the address.
/**
@@ -115,217 +79,80 @@ public:
}
/// Get the address in bytes, in network byte order.
- bytes_type to_bytes() const
- {
- using namespace std; // For memcpy.
- bytes_type bytes;
- memcpy(bytes.elems, addr_.s6_addr, 16);
- return bytes;
- }
+ ASIO_DECL bytes_type to_bytes() const;
/// Get the address as a string.
- std::string to_string() const
- {
- asio::error_code ec;
- std::string addr = to_string(ec);
- asio::detail::throw_error(ec);
- return addr;
- }
+ ASIO_DECL std::string to_string() const;
/// Get the address as a string.
- std::string to_string(asio::error_code& ec) const
- {
- char addr_str[asio::detail::max_addr_v6_str_len];
- const char* addr =
- asio::detail::socket_ops::inet_ntop(AF_INET6, &addr_, addr_str,
- asio::detail::max_addr_v6_str_len, scope_id_, ec);
- if (addr == 0)
- return std::string();
- return addr;
- }
+ ASIO_DECL std::string to_string(asio::error_code& ec) const;
/// Create an address from an IP address string.
- static address_v6 from_string(const char* str)
- {
- asio::error_code ec;
- address_v6 addr = from_string(str, ec);
- asio::detail::throw_error(ec);
- return addr;
- }
+ ASIO_DECL static address_v6 from_string(const char* str);
/// Create an address from an IP address string.
- static address_v6 from_string(const char* str, asio::error_code& ec)
- {
- address_v6 tmp;
- if (asio::detail::socket_ops::inet_pton(
- AF_INET6, str, &tmp.addr_, &tmp.scope_id_, ec) <= 0)
- return address_v6();
- return tmp;
- }
+ ASIO_DECL static address_v6 from_string(
+ const char* str, asio::error_code& ec);
/// Create an address from an IP address string.
- static address_v6 from_string(const std::string& str)
- {
- return from_string(str.c_str());
- }
+ ASIO_DECL static address_v6 from_string(const std::string& str);
/// Create an address from an IP address string.
- static address_v6 from_string(const std::string& str,
- asio::error_code& ec)
- {
- return from_string(str.c_str(), ec);
- }
+ ASIO_DECL static address_v6 from_string(
+ const std::string& str, asio::error_code& ec);
/// Converts an IPv4-mapped or IPv4-compatible address to an IPv4 address.
- address_v4 to_v4() const
- {
- if (!is_v4_mapped() && !is_v4_compatible())
- {
- std::bad_cast ex;
- boost::throw_exception(ex);
- }
-
- address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12],
- addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } };
- return address_v4(v4_bytes);
- }
+ ASIO_DECL address_v4 to_v4() const;
/// Determine whether the address is a loopback address.
- bool is_loopback() const
- {
-#if defined(__BORLANDC__)
- return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)
- && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)
- && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)
- && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)
- && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)
- && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)
- && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0)
- && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1));
-#else
- using namespace asio::detail;
- return IN6_IS_ADDR_LOOPBACK(&addr_) != 0;
-#endif
- }
+ ASIO_DECL bool is_loopback() const;
/// Determine whether the address is unspecified.
- bool is_unspecified() const
- {
-#if defined(__BORLANDC__)
- return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)
- && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)
- && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)
- && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)
- && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)
- && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)
- && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0)
- && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0));
-#else
- using namespace asio::detail;
- return IN6_IS_ADDR_UNSPECIFIED(&addr_) != 0;
-#endif
- }
+ ASIO_DECL bool is_unspecified() const;
/// Determine whether the address is link local.
- bool is_link_local() const
- {
- using namespace asio::detail;
- return IN6_IS_ADDR_LINKLOCAL(&addr_) != 0;
- }
+ ASIO_DECL bool is_link_local() const;
/// Determine whether the address is site local.
- bool is_site_local() const
- {
- using namespace asio::detail;
- return IN6_IS_ADDR_SITELOCAL(&addr_) != 0;
- }
+ ASIO_DECL bool is_site_local() const;
/// Determine whether the address is a mapped IPv4 address.
- bool is_v4_mapped() const
- {
- using namespace asio::detail;
- return IN6_IS_ADDR_V4MAPPED(&addr_) != 0;
- }
+ ASIO_DECL bool is_v4_mapped() const;
/// Determine whether the address is an IPv4-compatible address.
- bool is_v4_compatible() const
- {
- using namespace asio::detail;
- return IN6_IS_ADDR_V4COMPAT(&addr_) != 0;
- }
+ ASIO_DECL bool is_v4_compatible() const;
/// Determine whether the address is a multicast address.
- bool is_multicast() const
- {
- using namespace asio::detail;
- return IN6_IS_ADDR_MULTICAST(&addr_) != 0;
- }
+ ASIO_DECL bool is_multicast() const;
/// Determine whether the address is a global multicast address.
- bool is_multicast_global() const
- {
- using namespace asio::detail;
- return IN6_IS_ADDR_MC_GLOBAL(&addr_) != 0;
- }
+ ASIO_DECL bool is_multicast_global() const;
/// Determine whether the address is a link-local multicast address.
- bool is_multicast_link_local() const
- {
- using namespace asio::detail;
- return IN6_IS_ADDR_MC_LINKLOCAL(&addr_) != 0;
- }
+ ASIO_DECL bool is_multicast_link_local() const;
/// Determine whether the address is a node-local multicast address.
- bool is_multicast_node_local() const
- {
- using namespace asio::detail;
- return IN6_IS_ADDR_MC_NODELOCAL(&addr_) != 0;
- }
+ ASIO_DECL bool is_multicast_node_local() const;
/// Determine whether the address is a org-local multicast address.
- bool is_multicast_org_local() const
- {
- using namespace asio::detail;
- return IN6_IS_ADDR_MC_ORGLOCAL(&addr_) != 0;
- }
+ ASIO_DECL bool is_multicast_org_local() const;
/// Determine whether the address is a site-local multicast address.
- bool is_multicast_site_local() const
- {
- using namespace asio::detail;
- return IN6_IS_ADDR_MC_SITELOCAL(&addr_) != 0;
- }
+ ASIO_DECL bool is_multicast_site_local() const;
/// Compare two addresses for equality.
- friend bool operator==(const address_v6& a1, const address_v6& a2)
- {
- using namespace std; // For memcmp.
- return memcmp(&a1.addr_, &a2.addr_,
- sizeof(asio::detail::in6_addr_type)) == 0
- && a1.scope_id_ == a2.scope_id_;
- }
+ ASIO_DECL friend bool operator==(
+ const address_v6& a1, const address_v6& a2);
/// Compare two addresses for inequality.
friend bool operator!=(const address_v6& a1, const address_v6& a2)
{
- using namespace std; // For memcmp.
- return memcmp(&a1.addr_, &a2.addr_,
- sizeof(asio::detail::in6_addr_type)) != 0
- || a1.scope_id_ != a2.scope_id_;
+ return !(a1 == a2);
}
/// Compare addresses for ordering.
- friend bool operator<(const address_v6& a1, const address_v6& a2)
- {
- using namespace std; // For memcmp.
- int memcmp_result = memcmp(&a1.addr_, &a2.addr_,
- sizeof(asio::detail::in6_addr_type));
- if (memcmp_result < 0)
- return true;
- if (memcmp_result > 0)
- return false;
- return a1.scope_id_ < a2.scope_id_;
- }
+ ASIO_DECL friend bool operator<(
+ const address_v6& a1, const address_v6& a2);
/// Compare addresses for ordering.
friend bool operator>(const address_v6& a1, const address_v6& a2)
@@ -352,31 +179,13 @@ public:
}
/// Obtain an address object that represents the loopback address.
- static address_v6 loopback()
- {
- address_v6 tmp;
- asio::detail::in6_addr_type tmp_addr = IN6ADDR_LOOPBACK_INIT;
- tmp.addr_ = tmp_addr;
- return tmp;
- }
+ ASIO_DECL static address_v6 loopback();
/// Create an IPv4-mapped IPv6 address.
- static address_v6 v4_mapped(const address_v4& addr)
- {
- address_v4::bytes_type v4_bytes = addr.to_bytes();
- bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF,
- v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } };
- return address_v6(v6_bytes);
- }
+ ASIO_DECL static address_v6 v4_mapped(const address_v4& addr);
/// Create an IPv4-compatible IPv6 address.
- static address_v6 v4_compatible(const address_v4& addr)
- {
- address_v4::bytes_type v4_bytes = addr.to_bytes();
- bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } };
- return address_v6(v6_bytes);
- }
+ ASIO_DECL static address_v6 v4_compatible(const address_v4& addr);
private:
// The underlying IPv6 address.
@@ -402,22 +211,7 @@ private:
*/
template <typename Elem, typename Traits>
std::basic_ostream<Elem, Traits>& operator<<(
- std::basic_ostream<Elem, Traits>& os, const address_v6& addr)
-{
- asio::error_code ec;
- std::string s = addr.to_string(ec);
- if (ec)
- {
- if (os.exceptions() & std::ios::failbit)
- asio::detail::throw_error(ec);
- else
- os.setstate(std::ios_base::failbit);
- }
- else
- for (std::string::iterator i = s.begin(); i != s.end(); ++i)
- os << os.widen(*i);
- return os;
-}
+ std::basic_ostream<Elem, Traits>& os, const address_v6& addr);
#endif // !defined(BOOST_NO_IOSTREAM)
@@ -426,4 +220,9 @@ std::basic_ostream<Elem, Traits>& operator<<(
#include "asio/detail/pop_options.hpp"
+#include "asio/ip/impl/address_v6.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/impl/address_v6.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
#endif // ASIO_IP_ADDRESS_V6_HPP
diff --git a/ext/asio/asio/ip/basic_endpoint.hpp b/ext/asio/asio/ip/basic_endpoint.hpp
index 4ad3f68..5e5ef0b 100644
--- a/ext/asio/asio/ip/basic_endpoint.hpp
+++ b/ext/asio/asio/ip/basic_endpoint.hpp
@@ -1,8 +1,8 @@
//
-// basic_endpoint.hpp
-// ~~~~~~~~~~~~~~~~~~
+// ip/basic_endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,25 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include "asio/ip/address.hpp"
+#include "asio/ip/detail/endpoint.hpp"
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include <boost/throw_exception.hpp>
-#include <boost/detail/workaround.hpp>
-#include <cstring>
#if !defined(BOOST_NO_IOSTREAM)
-# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
-# include <ostream>
-# endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
-# include <sstream>
+# include <iosfwd>
#endif // !defined(BOOST_NO_IOSTREAM)
-#include "asio/detail/pop_options.hpp"
-#include "asio/error.hpp"
-#include "asio/ip/address.hpp"
-#include "asio/detail/socket_ops.hpp"
-#include "asio/detail/socket_types.hpp"
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace ip {
@@ -67,11 +57,8 @@ public:
/// Default constructor.
basic_endpoint()
- : data_()
+ : impl_()
{
- data_.v4.sin_family = AF_INET;
- data_.v4.sin_port = 0;
- data_.v4.sin_addr.s_addr = INADDR_ANY;
}
/// Construct an endpoint using a port number, specified in the host's byte
@@ -91,74 +78,35 @@ public:
* @endcode
*/
basic_endpoint(const InternetProtocol& protocol, unsigned short port_num)
- : data_()
+ : impl_(protocol.family(), port_num)
{
- using namespace std; // For memcpy.
- if (protocol.family() == PF_INET)
- {
- data_.v4.sin_family = AF_INET;
- data_.v4.sin_port =
- asio::detail::socket_ops::host_to_network_short(port_num);
- data_.v4.sin_addr.s_addr = INADDR_ANY;
- }
- else
- {
- data_.v6.sin6_family = AF_INET6;
- data_.v6.sin6_port =
- asio::detail::socket_ops::host_to_network_short(port_num);
- data_.v6.sin6_flowinfo = 0;
- asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
- data_.v6.sin6_addr = tmp_addr;
- data_.v6.sin6_scope_id = 0;
- }
}
/// Construct an endpoint using a port number and an IP address. This
/// constructor may be used for accepting connections on a specific interface
/// or for making a connection to a remote endpoint.
basic_endpoint(const asio::ip::address& addr, unsigned short port_num)
- : data_()
+ : impl_(addr, port_num)
{
- using namespace std; // For memcpy.
- if (addr.is_v4())
- {
- data_.v4.sin_family = AF_INET;
- data_.v4.sin_port =
- asio::detail::socket_ops::host_to_network_short(port_num);
- data_.v4.sin_addr.s_addr =
- asio::detail::socket_ops::host_to_network_long(
- addr.to_v4().to_ulong());
- }
- else
- {
- data_.v6.sin6_family = AF_INET6;
- data_.v6.sin6_port =
- asio::detail::socket_ops::host_to_network_short(port_num);
- data_.v6.sin6_flowinfo = 0;
- asio::ip::address_v6 v6_addr = addr.to_v6();
- asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes();
- memcpy(data_.v6.sin6_addr.s6_addr, bytes.elems, 16);
- data_.v6.sin6_scope_id = v6_addr.scope_id();
- }
}
/// Copy constructor.
basic_endpoint(const basic_endpoint& other)
- : data_(other.data_)
+ : impl_(other.impl_)
{
}
/// Assign from another endpoint.
basic_endpoint& operator=(const basic_endpoint& other)
{
- data_ = other.data_;
+ impl_ = other.impl_;
return *this;
}
/// The protocol associated with the endpoint.
protocol_type protocol() const
{
- if (is_v4())
+ if (impl_.is_v4())
return InternetProtocol::v4();
return InternetProtocol::v6();
}
@@ -166,137 +114,104 @@ public:
/// Get the underlying endpoint in the native type.
data_type* data()
{
- return &data_.base;
+ return impl_.data();
}
/// Get the underlying endpoint in the native type.
const data_type* data() const
{
- return &data_.base;
+ return impl_.data();
}
/// Get the underlying size of the endpoint in the native type.
std::size_t size() const
{
- if (is_v4())
- return sizeof(asio::detail::sockaddr_in4_type);
- else
- return sizeof(asio::detail::sockaddr_in6_type);
+ return impl_.size();
}
/// Set the underlying size of the endpoint in the native type.
void resize(std::size_t size)
{
- if (size > sizeof(asio::detail::sockaddr_storage_type))
- {
- asio::system_error e(asio::error::invalid_argument);
- boost::throw_exception(e);
- }
+ impl_.resize(size);
}
/// Get the capacity of the endpoint in the native type.
std::size_t capacity() const
{
- return sizeof(asio::detail::sockaddr_storage_type);
+ return impl_.capacity();
}
/// Get the port associated with the endpoint. The port number is always in
/// the host's byte order.
unsigned short port() const
{
- if (is_v4())
- {
- return asio::detail::socket_ops::network_to_host_short(
- data_.v4.sin_port);
- }
- else
- {
- return asio::detail::socket_ops::network_to_host_short(
- data_.v6.sin6_port);
- }
+ return impl_.port();
}
/// Set the port associated with the endpoint. The port number is always in
/// the host's byte order.
void port(unsigned short port_num)
{
- if (is_v4())
- {
- data_.v4.sin_port
- = asio::detail::socket_ops::host_to_network_short(port_num);
- }
- else
- {
- data_.v6.sin6_port
- = asio::detail::socket_ops::host_to_network_short(port_num);
- }
+ impl_.port(port_num);
}
/// Get the IP address associated with the endpoint.
asio::ip::address address() const
{
- using namespace std; // For memcpy.
- if (is_v4())
- {
- return asio::ip::address_v4(
- asio::detail::socket_ops::network_to_host_long(
- data_.v4.sin_addr.s_addr));
- }
- else
- {
- asio::ip::address_v6::bytes_type bytes;
- memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16);
- return asio::ip::address_v6(bytes, data_.v6.sin6_scope_id);
- }
+ return impl_.address();
}
/// Set the IP address associated with the endpoint.
void address(const asio::ip::address& addr)
{
- basic_endpoint<InternetProtocol> tmp_endpoint(addr, port());
- data_ = tmp_endpoint.data_;
+ impl_.address(addr);
}
/// Compare two endpoints for equality.
friend bool operator==(const basic_endpoint<InternetProtocol>& e1,
const basic_endpoint<InternetProtocol>& e2)
{
- return e1.address() == e2.address() && e1.port() == e2.port();
+ return e1.impl_ == e2.impl_;
}
/// Compare two endpoints for inequality.
friend bool operator!=(const basic_endpoint<InternetProtocol>& e1,
const basic_endpoint<InternetProtocol>& e2)
{
- return e1.address() != e2.address() || e1.port() != e2.port();
+ return !(e1 == e2);
}
/// Compare endpoints for ordering.
friend bool operator<(const basic_endpoint<InternetProtocol>& e1,
const basic_endpoint<InternetProtocol>& e2)
{
- if (e1.address() < e2.address())
- return true;
- if (e1.address() != e2.address())
- return false;
- return e1.port() < e2.port();
+ return e1.impl_ < e2.impl_;
}
-private:
- // Helper function to determine whether the endpoint is IPv4.
- bool is_v4() const
+ /// Compare endpoints for ordering.
+ friend bool operator>(const basic_endpoint<InternetProtocol>& e1,
+ const basic_endpoint<InternetProtocol>& e2)
+ {
+ return e2.impl_ < e1.impl_;
+ }
+
+ /// Compare endpoints for ordering.
+ friend bool operator<=(const basic_endpoint<InternetProtocol>& e1,
+ const basic_endpoint<InternetProtocol>& e2)
{
- return data_.base.sa_family == AF_INET;
+ return !(e2 < e1);
}
- // The underlying IP socket address.
- union data_union
+ /// Compare endpoints for ordering.
+ friend bool operator>=(const basic_endpoint<InternetProtocol>& e1,
+ const basic_endpoint<InternetProtocol>& e2)
{
- asio::detail::socket_addr_type base;
- asio::detail::sockaddr_storage_type storage;
- asio::detail::sockaddr_in4_type v4;
- asio::detail::sockaddr_in6_type v6;
- } data_;
+ return !(e1 < e2);
+ }
+
+private:
+ // The underlying IP endpoint.
+ asio::ip::detail::endpoint impl_;
};
#if !defined(BOOST_NO_IOSTREAM)
@@ -313,64 +228,10 @@ private:
*
* @relates asio::ip::basic_endpoint
*/
-#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
-template <typename InternetProtocol>
-std::ostream& operator<<(std::ostream& os,
- const basic_endpoint<InternetProtocol>& endpoint)
-{
- const address& addr = endpoint.address();
- asio::error_code ec;
- std::string a = addr.to_string(ec);
- if (ec)
- {
- if (os.exceptions() & std::ios::failbit)
- asio::detail::throw_error(ec);
- else
- os.setstate(std::ios_base::failbit);
- }
- else
- {
- std::ostringstream tmp_os;
- tmp_os.imbue(std::locale::classic());
- if (addr.is_v4())
- tmp_os << a;
- else
- tmp_os << '[' << a << ']';
- tmp_os << ':' << endpoint.port();
- os << tmp_os.str();
- }
- return os;
-}
-#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
template <typename Elem, typename Traits, typename InternetProtocol>
std::basic_ostream<Elem, Traits>& operator<<(
std::basic_ostream<Elem, Traits>& os,
- const basic_endpoint<InternetProtocol>& endpoint)
-{
- const address& addr = endpoint.address();
- asio::error_code ec;
- std::string a = addr.to_string(ec);
- if (ec)
- {
- if (os.exceptions() & std::ios::failbit)
- asio::detail::throw_error(ec);
- else
- os.setstate(std::ios_base::failbit);
- }
- else
- {
- std::ostringstream tmp_os;
- tmp_os.imbue(std::locale::classic());
- if (addr.is_v4())
- tmp_os << a;
- else
- tmp_os << '[' << a << ']';
- tmp_os << ':' << endpoint.port();
- os << tmp_os.str();
- }
- return os;
-}
-#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+ const basic_endpoint<InternetProtocol>& endpoint);
#endif // !defined(BOOST_NO_IOSTREAM)
@@ -379,4 +240,6 @@ std::basic_ostream<Elem, Traits>& operator<<(
#include "asio/detail/pop_options.hpp"
+#include "asio/ip/impl/basic_endpoint.hpp"
+
#endif // ASIO_IP_BASIC_ENDPOINT_HPP
diff --git a/ext/asio/asio/ip/basic_resolver.hpp b/ext/asio/asio/ip/basic_resolver.hpp
index 43a37af..c8847e1 100644
--- a/ext/asio/asio/ip/basic_resolver.hpp
+++ b/ext/asio/asio/ip/basic_resolver.hpp
@@ -1,8 +1,8 @@
//
-// basic_resolver.hpp
-// ~~~~~~~~~~~~~~~~~~
+// ip/basic_resolver.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/basic_io_object.hpp"
+#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/ip/basic_resolver_iterator.hpp"
#include "asio/ip/basic_resolver_query.hpp"
#include "asio/ip/resolver_service.hpp"
-#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace ip {
diff --git a/ext/asio/asio/ip/basic_resolver_entry.hpp b/ext/asio/asio/ip/basic_resolver_entry.hpp
index 09b144b..4117b7b 100644
--- a/ext/asio/asio/ip/basic_resolver_entry.hpp
+++ b/ext/asio/asio/ip/basic_resolver_entry.hpp
@@ -1,8 +1,8 @@
//
-// basic_resolver_entry.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// ip/basic_resolver_entry.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include <string>
#include "asio/detail/push_options.hpp"
-#include <string>
-#include "asio/detail/pop_options.hpp"
namespace asio {
namespace ip {
diff --git a/ext/asio/asio/ip/basic_resolver_iterator.hpp b/ext/asio/asio/ip/basic_resolver_iterator.hpp
index 1982d62..033b7e0 100644
--- a/ext/asio/asio/ip/basic_resolver_iterator.hpp
+++ b/ext/asio/asio/ip/basic_resolver_iterator.hpp
@@ -1,8 +1,8 @@
//
-// basic_resolver_iterator.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// ip/basic_resolver_iterator.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,20 +15,18 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <boost/iterator.hpp>
-#include <boost/shared_ptr.hpp>
#include <cstring>
#include <string>
#include <vector>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/shared_ptr.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/ip/basic_resolver_entry.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace ip {
@@ -176,7 +174,7 @@ private:
}
typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type;
- boost::shared_ptr<values_type> values_;
+ asio::detail::shared_ptr<values_type> values_;
std::size_t index_;
};
diff --git a/ext/asio/asio/ip/basic_resolver_query.hpp b/ext/asio/asio/ip/basic_resolver_query.hpp
index 3cbb335..22ab643 100644
--- a/ext/asio/asio/ip/basic_resolver_query.hpp
+++ b/ext/asio/asio/ip/basic_resolver_query.hpp
@@ -1,8 +1,8 @@
//
-// basic_resolver_query.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// ip/basic_resolver_query.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
+#include "asio/detail/config.hpp"
#include <string>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/detail/socket_ops.hpp"
#include "asio/ip/resolver_query_base.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace ip {
diff --git a/ext/asio/asio/ip/detail/endpoint.hpp b/ext/asio/asio/ip/detail/endpoint.hpp
new file mode 100644
index 0000000..fbea71e
--- /dev/null
+++ b/ext/asio/asio/ip/detail/endpoint.hpp
@@ -0,0 +1,140 @@
+//
+// ip/detail/endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_DETAIL_ENDPOINT_HPP
+#define ASIO_IP_DETAIL_ENDPOINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <string>
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/error_code.hpp"
+#include "asio/ip/address.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+namespace detail {
+
+// Helper class for implementating an IP endpoint.
+class endpoint
+{
+public:
+ // Default constructor.
+ ASIO_DECL endpoint();
+
+ // Construct an endpoint using a family and port number.
+ ASIO_DECL endpoint(int family, unsigned short port_num);
+
+ // Construct an endpoint using an address and port number.
+ ASIO_DECL endpoint(const asio::ip::address& addr,
+ unsigned short port_num);
+
+ // Copy constructor.
+ endpoint(const endpoint& other)
+ : data_(other.data_)
+ {
+ }
+
+ // Assign from another endpoint.
+ endpoint& operator=(const endpoint& other)
+ {
+ data_ = other.data_;
+ return *this;
+ }
+
+ // Get the underlying endpoint in the native type.
+ asio::detail::socket_addr_type* data()
+ {
+ return &data_.base;
+ }
+
+ // Get the underlying endpoint in the native type.
+ const asio::detail::socket_addr_type* data() const
+ {
+ return &data_.base;
+ }
+
+ // Get the underlying size of the endpoint in the native type.
+ std::size_t size() const
+ {
+ if (is_v4())
+ return sizeof(asio::detail::sockaddr_in4_type);
+ else
+ return sizeof(asio::detail::sockaddr_in6_type);
+ }
+
+ // Set the underlying size of the endpoint in the native type.
+ ASIO_DECL void resize(std::size_t size);
+
+ // Get the capacity of the endpoint in the native type.
+ std::size_t capacity() const
+ {
+ return sizeof(asio::detail::sockaddr_storage_type);
+ }
+
+ // Get the port associated with the endpoint.
+ ASIO_DECL unsigned short port() const;
+
+ // Set the port associated with the endpoint.
+ ASIO_DECL void port(unsigned short port_num);
+
+ // Get the IP address associated with the endpoint.
+ ASIO_DECL asio::ip::address address() const;
+
+ // Set the IP address associated with the endpoint.
+ ASIO_DECL void address(const asio::ip::address& addr);
+
+ // Compare two endpoints for equality.
+ ASIO_DECL friend bool operator==(
+ const endpoint& e1, const endpoint& e2);
+
+ // Compare endpoints for ordering.
+ ASIO_DECL friend bool operator<(
+ const endpoint& e1, const endpoint& e2);
+
+ // Determine whether the endpoint is IPv4.
+ bool is_v4() const
+ {
+ return data_.base.sa_family == AF_INET;
+ }
+
+#if !defined(BOOST_NO_IOSTREAM)
+ // Convert to a string.
+ ASIO_DECL std::string to_string(asio::error_code& ec) const;
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+private:
+ // The underlying IP socket address.
+ union data_union
+ {
+ asio::detail::socket_addr_type base;
+ asio::detail::sockaddr_storage_type storage;
+ asio::detail::sockaddr_in4_type v4;
+ asio::detail::sockaddr_in6_type v6;
+ } data_;
+};
+
+} // namespace detail
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/detail/impl/endpoint.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_IP_DETAIL_ENDPOINT_HPP
diff --git a/ext/asio/asio/ip/detail/impl/endpoint.ipp b/ext/asio/asio/ip/detail/impl/endpoint.ipp
new file mode 100644
index 0000000..b1469c8
--- /dev/null
+++ b/ext/asio/asio/ip/detail/impl/endpoint.ipp
@@ -0,0 +1,202 @@
+//
+// ip/detail/impl/endpoint.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP
+#define ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstring>
+#if !defined(BOOST_NO_IOSTREAM)
+# include <sstream>
+#endif // !defined(BOOST_NO_IOSTREAM)
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/ip/detail/endpoint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+namespace detail {
+
+ASIO_DECL
+endpoint::endpoint()
+ : data_()
+{
+ data_.v4.sin_family = AF_INET;
+ data_.v4.sin_port = 0;
+ data_.v4.sin_addr.s_addr = INADDR_ANY;
+}
+
+ASIO_DECL
+endpoint::endpoint(int family, unsigned short port_num)
+ : data_()
+{
+ using namespace std; // For memcpy.
+ if (family == PF_INET)
+ {
+ data_.v4.sin_family = AF_INET;
+ data_.v4.sin_port =
+ asio::detail::socket_ops::host_to_network_short(port_num);
+ data_.v4.sin_addr.s_addr = INADDR_ANY;
+ }
+ else
+ {
+ data_.v6.sin6_family = AF_INET6;
+ data_.v6.sin6_port =
+ asio::detail::socket_ops::host_to_network_short(port_num);
+ data_.v6.sin6_flowinfo = 0;
+ asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
+ data_.v6.sin6_addr = tmp_addr;
+ data_.v6.sin6_scope_id = 0;
+ }
+}
+
+ASIO_DECL
+endpoint::endpoint(const asio::ip::address& addr,
+ unsigned short port_num)
+ : data_()
+{
+ using namespace std; // For memcpy.
+ if (addr.is_v4())
+ {
+ data_.v4.sin_family = AF_INET;
+ data_.v4.sin_port =
+ asio::detail::socket_ops::host_to_network_short(port_num);
+ data_.v4.sin_addr.s_addr =
+ asio::detail::socket_ops::host_to_network_long(
+ addr.to_v4().to_ulong());
+ }
+ else
+ {
+ data_.v6.sin6_family = AF_INET6;
+ data_.v6.sin6_port =
+ asio::detail::socket_ops::host_to_network_short(port_num);
+ data_.v6.sin6_flowinfo = 0;
+ asio::ip::address_v6 v6_addr = addr.to_v6();
+ asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes();
+ memcpy(data_.v6.sin6_addr.s6_addr, bytes.elems, 16);
+ data_.v6.sin6_scope_id = v6_addr.scope_id();
+ }
+}
+
+ASIO_DECL
+void endpoint::resize(std::size_t size)
+{
+ if (size > sizeof(asio::detail::sockaddr_storage_type))
+ {
+ asio::error_code ec(asio::error::invalid_argument);
+ asio::detail::throw_error(ec);
+ }
+}
+
+ASIO_DECL
+unsigned short endpoint::port() const
+{
+ if (is_v4())
+ {
+ return asio::detail::socket_ops::network_to_host_short(
+ data_.v4.sin_port);
+ }
+ else
+ {
+ return asio::detail::socket_ops::network_to_host_short(
+ data_.v6.sin6_port);
+ }
+}
+
+ASIO_DECL
+void endpoint::port(unsigned short port_num)
+{
+ if (is_v4())
+ {
+ data_.v4.sin_port
+ = asio::detail::socket_ops::host_to_network_short(port_num);
+ }
+ else
+ {
+ data_.v6.sin6_port
+ = asio::detail::socket_ops::host_to_network_short(port_num);
+ }
+}
+
+ASIO_DECL
+asio::ip::address endpoint::address() const
+{
+ using namespace std; // For memcpy.
+ if (is_v4())
+ {
+ return asio::ip::address_v4(
+ asio::detail::socket_ops::network_to_host_long(
+ data_.v4.sin_addr.s_addr));
+ }
+ else
+ {
+ asio::ip::address_v6::bytes_type bytes;
+ memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16);
+ return asio::ip::address_v6(bytes, data_.v6.sin6_scope_id);
+ }
+}
+
+ASIO_DECL
+void endpoint::address(const asio::ip::address& addr)
+{
+ endpoint tmp_endpoint(addr, port());
+ data_ = tmp_endpoint.data_;
+}
+
+ASIO_DECL
+bool operator==(const endpoint& e1, const endpoint& e2)
+{
+ return e1.address() == e2.address() && e1.port() == e2.port();
+}
+
+ASIO_DECL
+bool operator<(const endpoint& e1, const endpoint& e2)
+{
+ if (e1.address() < e2.address())
+ return true;
+ if (e1.address() != e2.address())
+ return false;
+ return e1.port() < e2.port();
+}
+
+#if !defined(BOOST_NO_IOSTREAM)
+ASIO_DECL
+std::string endpoint::to_string(asio::error_code& ec) const
+{
+ std::string a = address().to_string(ec);
+ if (ec)
+ return std::string();
+
+ std::ostringstream tmp_os;
+ tmp_os.imbue(std::locale::classic());
+ if (is_v4())
+ tmp_os << a;
+ else
+ tmp_os << '[' << a << ']';
+ tmp_os << ':' << port();
+
+ return tmp_os.str();
+}
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+} // namespace detail
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP
diff --git a/ext/asio/asio/ip/detail/socket_option.hpp b/ext/asio/asio/ip/detail/socket_option.hpp
index 00045f8..e370b11 100644
--- a/ext/asio/asio/ip/detail/socket_option.hpp
+++ b/ext/asio/asio/ip/detail/socket_option.hpp
@@ -1,8 +1,8 @@
//
-// socket_option.hpp
-// ~~~~~~~~~~~~~~~~~
+// detail/socket_option.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,18 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
#include <cstring>
-#include <boost/config.hpp>
#include <boost/throw_exception.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/ip/address.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_types.hpp"
+#include "asio/ip/address.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace ip {
diff --git a/ext/asio/asio/ip/host_name.hpp b/ext/asio/asio/ip/host_name.hpp
index f24ce1a..8bfaae9 100644
--- a/ext/asio/asio/ip/host_name.hpp
+++ b/ext/asio/asio/ip/host_name.hpp
@@ -1,8 +1,8 @@
//
-// host_name.hpp
-// ~~~~~~~~~~~~~
+// ip/host_name.hpp
+// ~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,48 +15,28 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <string>
-#include "asio/detail/pop_options.hpp"
+#include "asio/error_code.hpp"
-#include "asio/error.hpp"
-#include "asio/detail/socket_ops.hpp"
-#include "asio/detail/throw_error.hpp"
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace ip {
/// Get the current host name.
-std::string host_name();
+ASIO_DECL std::string host_name();
/// Get the current host name.
-std::string host_name(asio::error_code& ec);
-
-inline std::string host_name()
-{
- char name[1024];
- asio::error_code ec;
- if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0)
- {
- asio::detail::throw_error(ec);
- return std::string();
- }
- return std::string(name);
-}
-
-inline std::string host_name(asio::error_code& ec)
-{
- char name[1024];
- if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0)
- return std::string();
- return std::string(name);
-}
+ASIO_DECL std::string host_name(asio::error_code& ec);
} // namespace ip
} // namespace asio
#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/impl/host_name.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
#endif // ASIO_IP_HOST_NAME_HPP
diff --git a/ext/asio/asio/ip/icmp.hpp b/ext/asio/asio/ip/icmp.hpp
index d76b4d1..59df5b0 100644
--- a/ext/asio/asio/ip/icmp.hpp
+++ b/ext/asio/asio/ip/icmp.hpp
@@ -1,8 +1,8 @@
//
-// icmp.hpp
-// ~~~~~~~~
+// ip/icmp.hpp
+// ~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
+#include "asio/detail/socket_types.hpp"
#include "asio/basic_raw_socket.hpp"
#include "asio/ip/basic_endpoint.hpp"
#include "asio/ip/basic_resolver.hpp"
#include "asio/ip/basic_resolver_iterator.hpp"
#include "asio/ip/basic_resolver_query.hpp"
-#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace ip {
diff --git a/ext/asio/asio/ip/impl/address.hpp b/ext/asio/asio/ip/impl/address.hpp
new file mode 100644
index 0000000..0983d24
--- /dev/null
+++ b/ext/asio/asio/ip/impl/address.hpp
@@ -0,0 +1,53 @@
+//
+// ip/impl/address.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_ADDRESS_HPP
+#define ASIO_IP_IMPL_ADDRESS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+ std::basic_ostream<Elem, Traits>& os, const address& addr)
+{
+ asio::error_code ec;
+ std::string s = addr.to_string(ec);
+ if (ec)
+ {
+ if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit)
+ asio::detail::throw_error(ec);
+ else
+ os.setstate(std::basic_ostream<Elem, Traits>::failbit);
+ }
+ else
+ for (std::string::iterator i = s.begin(); i != s.end(); ++i)
+ os << os.widen(*i);
+ return os;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+#endif // ASIO_IP_IMPL_ADDRESS_HPP
diff --git a/ext/asio/asio/ip/impl/address.ipp b/ext/asio/asio/ip/impl/address.ipp
new file mode 100644
index 0000000..24916ab
--- /dev/null
+++ b/ext/asio/asio/ip/impl/address.ipp
@@ -0,0 +1,203 @@
+//
+// ip/impl/address.ipp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_ADDRESS_IPP
+#define ASIO_IP_IMPL_ADDRESS_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <typeinfo>
+#include <boost/throw_exception.hpp>
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/ip/address.hpp"
+#include "asio/system_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+ASIO_DECL
+address::address()
+ : type_(ipv4),
+ ipv4_address_(),
+ ipv6_address_()
+{
+}
+
+ASIO_DECL
+address::address(const asio::ip::address_v4& ipv4_address)
+ : type_(ipv4),
+ ipv4_address_(ipv4_address),
+ ipv6_address_()
+{
+}
+
+ASIO_DECL
+address::address(const asio::ip::address_v6& ipv6_address)
+ : type_(ipv6),
+ ipv4_address_(),
+ ipv6_address_(ipv6_address)
+{
+}
+
+ASIO_DECL
+address::address(const address& other)
+ : type_(other.type_),
+ ipv4_address_(other.ipv4_address_),
+ ipv6_address_(other.ipv6_address_)
+{
+}
+
+ASIO_DECL
+address& address::operator=(const address& other)
+{
+ type_ = other.type_;
+ ipv4_address_ = other.ipv4_address_;
+ ipv6_address_ = other.ipv6_address_;
+ return *this;
+}
+
+ASIO_DECL
+address& address::operator=(const asio::ip::address_v4& ipv4_address)
+{
+ type_ = ipv4;
+ ipv4_address_ = ipv4_address;
+ ipv6_address_ = asio::ip::address_v6();
+ return *this;
+}
+
+ASIO_DECL
+address& address::operator=(const asio::ip::address_v6& ipv6_address)
+{
+ type_ = ipv6;
+ ipv4_address_ = asio::ip::address_v4();
+ ipv6_address_ = ipv6_address;
+ return *this;
+}
+
+ASIO_DECL
+asio::ip::address_v4 address::to_v4() const
+{
+ if (type_ != ipv4)
+ {
+ std::bad_cast ex;
+ boost::throw_exception(ex);
+ }
+ return ipv4_address_;
+}
+
+ASIO_DECL
+asio::ip::address_v6 address::to_v6() const
+{
+ if (type_ != ipv6)
+ {
+ std::bad_cast ex;
+ boost::throw_exception(ex);
+ }
+ return ipv6_address_;
+}
+
+ASIO_DECL
+std::string address::to_string() const
+{
+ if (type_ == ipv6)
+ return ipv6_address_.to_string();
+ return ipv4_address_.to_string();
+}
+
+ASIO_DECL
+std::string address::to_string(asio::error_code& ec) const
+{
+ if (type_ == ipv6)
+ return ipv6_address_.to_string(ec);
+ return ipv4_address_.to_string(ec);
+}
+
+ASIO_DECL
+address address::from_string(const char* str)
+{
+ asio::error_code ec;
+ address addr = from_string(str, ec);
+ asio::detail::throw_error(ec);
+ return addr;
+}
+
+ASIO_DECL
+address address::from_string(const char* str, asio::error_code& ec)
+{
+ asio::ip::address_v6 ipv6_address =
+ asio::ip::address_v6::from_string(str, ec);
+ if (!ec)
+ {
+ address tmp;
+ tmp.type_ = ipv6;
+ tmp.ipv6_address_ = ipv6_address;
+ return tmp;
+ }
+
+ asio::ip::address_v4 ipv4_address =
+ asio::ip::address_v4::from_string(str, ec);
+ if (!ec)
+ {
+ address tmp;
+ tmp.type_ = ipv4;
+ tmp.ipv4_address_ = ipv4_address;
+ return tmp;
+ }
+
+ return address();
+}
+
+ASIO_DECL
+address address::from_string(const std::string& str)
+{
+ return from_string(str.c_str());
+}
+
+ASIO_DECL
+address address::from_string(const std::string& str,
+ asio::error_code& ec)
+{
+ return from_string(str.c_str(), ec);
+}
+
+ASIO_DECL
+bool operator==(const address& a1, const address& a2)
+{
+ if (a1.type_ != a2.type_)
+ return false;
+ if (a1.type_ == address::ipv6)
+ return a1.ipv6_address_ == a2.ipv6_address_;
+ return a1.ipv4_address_ == a2.ipv4_address_;
+}
+
+ASIO_DECL
+bool operator<(const address& a1, const address& a2)
+{
+ if (a1.type_ < a2.type_)
+ return true;
+ if (a1.type_ > a2.type_)
+ return false;
+ if (a1.type_ == address::ipv6)
+ return a1.ipv6_address_ < a2.ipv6_address_;
+ return a1.ipv4_address_ < a2.ipv4_address_;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_IMPL_ADDRESS_IPP
diff --git a/ext/asio/asio/ip/impl/address_v4.hpp b/ext/asio/asio/ip/impl/address_v4.hpp
new file mode 100644
index 0000000..bbe0882
--- /dev/null
+++ b/ext/asio/asio/ip/impl/address_v4.hpp
@@ -0,0 +1,53 @@
+//
+// ip/impl/address_v4.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_ADDRESS_V4_HPP
+#define ASIO_IP_IMPL_ADDRESS_V4_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+ std::basic_ostream<Elem, Traits>& os, const address_v4& addr)
+{
+ asio::error_code ec;
+ std::string s = addr.to_string(ec);
+ if (ec)
+ {
+ if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit)
+ asio::detail::throw_error(ec);
+ else
+ os.setstate(std::basic_ostream<Elem, Traits>::failbit);
+ }
+ else
+ for (std::string::iterator i = s.begin(); i != s.end(); ++i)
+ os << os.widen(*i);
+ return os;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+#endif // ASIO_IP_IMPL_ADDRESS_V4_HPP
diff --git a/ext/asio/asio/ip/impl/address_v4.ipp b/ext/asio/asio/ip/impl/address_v4.ipp
new file mode 100644
index 0000000..2c8e9aa
--- /dev/null
+++ b/ext/asio/asio/ip/impl/address_v4.ipp
@@ -0,0 +1,178 @@
+//
+// ip/impl/address_v4.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_ADDRESS_V4_IPP
+#define ASIO_IP_IMPL_ADDRESS_V4_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <climits>
+#include <stdexcept>
+#include <boost/throw_exception.hpp>
+#include "asio/error.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/ip/address_v4.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+ASIO_DECL
+address_v4::address_v4(const address_v4::bytes_type& bytes)
+{
+#if UCHAR_MAX > 0xFF
+ if (bytes[0] > 0xFF || bytes[1] > 0xFF
+ || bytes[2] > 0xFF || bytes[3] > 0xFF)
+ {
+ std::out_of_range ex("address_v4 from bytes_type");
+ boost::throw_exception(ex);
+ }
+#endif // UCHAR_MAX > 0xFF
+
+ using namespace std; // For memcpy.
+ memcpy(&addr_.s_addr, bytes.elems, 4);
+}
+
+ASIO_DECL
+address_v4::address_v4(unsigned long addr)
+{
+#if ULONG_MAX > 0xFFFFFFFF
+ if (addr > 0xFFFFFFFF)
+ {
+ std::out_of_range ex("address_v4 from unsigned long");
+ boost::throw_exception(ex);
+ }
+#endif // ULONG_MAX > 0xFFFFFFFF
+
+ addr_.s_addr = asio::detail::socket_ops::host_to_network_long(addr);
+}
+
+ASIO_DECL
+address_v4::bytes_type address_v4::to_bytes() const
+{
+ using namespace std; // For memcpy.
+ bytes_type bytes;
+ memcpy(bytes.elems, &addr_.s_addr, 4);
+ return bytes;
+}
+
+ASIO_DECL
+unsigned long address_v4::to_ulong() const
+{
+ return asio::detail::socket_ops::network_to_host_long(addr_.s_addr);
+}
+
+ASIO_DECL
+std::string address_v4::to_string() const
+{
+ asio::error_code ec;
+ std::string addr = to_string(ec);
+ asio::detail::throw_error(ec);
+ return addr;
+}
+
+ASIO_DECL
+std::string address_v4::to_string(asio::error_code& ec) const
+{
+ char addr_str[asio::detail::max_addr_v4_str_len];
+ const char* addr =
+ asio::detail::socket_ops::inet_ntop(AF_INET, &addr_, addr_str,
+ asio::detail::max_addr_v4_str_len, 0, ec);
+ if (addr == 0)
+ return std::string();
+ return addr;
+}
+
+ASIO_DECL
+address_v4 address_v4::from_string(const char* str)
+{
+ asio::error_code ec;
+ address_v4 addr = from_string(str, ec);
+ asio::detail::throw_error(ec);
+ return addr;
+}
+
+ASIO_DECL
+address_v4 address_v4::from_string(
+ const char* str, asio::error_code& ec)
+{
+ address_v4 tmp;
+ if (asio::detail::socket_ops::inet_pton(
+ AF_INET, str, &tmp.addr_, 0, ec) <= 0)
+ return address_v4();
+ return tmp;
+}
+
+ASIO_DECL
+address_v4 address_v4::from_string(const std::string& str)
+{
+ return from_string(str.c_str());
+}
+
+ASIO_DECL
+address_v4 address_v4::from_string(
+ const std::string& str, asio::error_code& ec)
+{
+ return from_string(str.c_str(), ec);
+}
+
+ASIO_DECL
+bool address_v4::is_class_a() const
+{
+ return IN_CLASSA(to_ulong());
+}
+
+ASIO_DECL
+bool address_v4::is_class_b() const
+{
+ return IN_CLASSB(to_ulong());
+}
+
+ASIO_DECL
+bool address_v4::is_class_c() const
+{
+ return IN_CLASSC(to_ulong());
+}
+
+ASIO_DECL
+bool address_v4::is_multicast() const
+{
+ return IN_MULTICAST(to_ulong());
+}
+
+ASIO_DECL
+address_v4 address_v4::broadcast(const address_v4& addr, const address_v4& mask)
+{
+ return address_v4(addr.to_ulong() | (mask.to_ulong() ^ 0xFFFFFFFF));
+}
+
+ASIO_DECL
+address_v4 address_v4::netmask(const address_v4& addr)
+{
+ if (addr.is_class_a())
+ return address_v4(0xFF000000);
+ if (addr.is_class_b())
+ return address_v4(0xFFFF0000);
+ if (addr.is_class_c())
+ return address_v4(0xFFFFFF00);
+ return address_v4(0xFFFFFFFF);
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_IMPL_ADDRESS_V4_IPP
diff --git a/ext/asio/asio/ip/impl/address_v6.hpp b/ext/asio/asio/ip/impl/address_v6.hpp
new file mode 100644
index 0000000..796a505
--- /dev/null
+++ b/ext/asio/asio/ip/impl/address_v6.hpp
@@ -0,0 +1,53 @@
+//
+// ip/impl/address_v6.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_ADDRESS_V6_HPP
+#define ASIO_IP_IMPL_ADDRESS_V6_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+ std::basic_ostream<Elem, Traits>& os, const address_v6& addr)
+{
+ asio::error_code ec;
+ std::string s = addr.to_string(ec);
+ if (ec)
+ {
+ if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit)
+ asio::detail::throw_error(ec);
+ else
+ os.setstate(std::basic_ostream<Elem, Traits>::failbit);
+ }
+ else
+ for (std::string::iterator i = s.begin(); i != s.end(); ++i)
+ os << os.widen(*i);
+ return os;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+#endif // ASIO_IP_IMPL_ADDRESS_V6_HPP
diff --git a/ext/asio/asio/ip/impl/address_v6.ipp b/ext/asio/asio/ip/impl/address_v6.ipp
new file mode 100644
index 0000000..17b6382
--- /dev/null
+++ b/ext/asio/asio/ip/impl/address_v6.ipp
@@ -0,0 +1,313 @@
+//
+// ip/impl/address_v6.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_ADDRESS_V6_IPP
+#define ASIO_IP_IMPL_ADDRESS_V6_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstring>
+#include <stdexcept>
+#include <typeinfo>
+#include <boost/throw_exception.hpp>
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/ip/address_v6.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+ASIO_DECL
+address_v6::address_v6()
+ : scope_id_(0)
+{
+ asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
+ addr_ = tmp_addr;
+}
+
+ASIO_DECL
+address_v6::address_v6(const address_v6::bytes_type& bytes,
+ unsigned long scope_id)
+ : scope_id_(scope_id)
+{
+#if UCHAR_MAX > 0xFF
+ for (std::size_t i = 0; i < bytes.size(); ++i)
+ {
+ if (bytes[i] > 0xFF)
+ {
+ std::out_of_range ex("address_v6 from bytes_type");
+ boost::throw_exception(ex);
+ }
+ }
+#endif // UCHAR_MAX > 0xFF
+
+ using namespace std; // For memcpy.
+ memcpy(addr_.s6_addr, bytes.elems, 16);
+}
+
+ASIO_DECL
+address_v6::address_v6(const address_v6& other)
+ : addr_(other.addr_),
+ scope_id_(other.scope_id_)
+{
+}
+
+ASIO_DECL
+address_v6& address_v6::operator=(const address_v6& other)
+{
+ addr_ = other.addr_;
+ scope_id_ = other.scope_id_;
+ return *this;
+}
+
+ASIO_DECL
+address_v6::bytes_type address_v6::to_bytes() const
+{
+ using namespace std; // For memcpy.
+ bytes_type bytes;
+ memcpy(bytes.elems, addr_.s6_addr, 16);
+ return bytes;
+}
+
+ASIO_DECL
+std::string address_v6::to_string() const
+{
+ asio::error_code ec;
+ std::string addr = to_string(ec);
+ asio::detail::throw_error(ec);
+ return addr;
+}
+
+ASIO_DECL
+std::string address_v6::to_string(asio::error_code& ec) const
+{
+ char addr_str[asio::detail::max_addr_v6_str_len];
+ const char* addr =
+ asio::detail::socket_ops::inet_ntop(AF_INET6, &addr_, addr_str,
+ asio::detail::max_addr_v6_str_len, scope_id_, ec);
+ if (addr == 0)
+ return std::string();
+ return addr;
+}
+
+ASIO_DECL
+address_v6 address_v6::from_string(const char* str)
+{
+ asio::error_code ec;
+ address_v6 addr = from_string(str, ec);
+ asio::detail::throw_error(ec);
+ return addr;
+}
+
+ASIO_DECL
+address_v6 address_v6::from_string(
+ const char* str, asio::error_code& ec)
+{
+ address_v6 tmp;
+ if (asio::detail::socket_ops::inet_pton(
+ AF_INET6, str, &tmp.addr_, &tmp.scope_id_, ec) <= 0)
+ return address_v6();
+ return tmp;
+}
+
+ASIO_DECL
+address_v6 address_v6::from_string(const std::string& str)
+{
+ return from_string(str.c_str());
+}
+
+ASIO_DECL
+address_v6 address_v6::from_string(
+ const std::string& str, asio::error_code& ec)
+{
+ return from_string(str.c_str(), ec);
+}
+
+ASIO_DECL
+address_v4 address_v6::to_v4() const
+{
+ if (!is_v4_mapped() && !is_v4_compatible())
+ {
+ std::bad_cast ex;
+ boost::throw_exception(ex);
+ }
+
+ address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12],
+ addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } };
+ return address_v4(v4_bytes);
+}
+
+ASIO_DECL
+bool address_v6::is_loopback() const
+{
+#if defined(__BORLANDC__)
+ return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)
+ && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)
+ && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)
+ && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)
+ && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)
+ && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)
+ && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0)
+ && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1));
+#else
+ using namespace asio::detail;
+ return IN6_IS_ADDR_LOOPBACK(&addr_) != 0;
+#endif
+}
+
+ASIO_DECL
+bool address_v6::is_unspecified() const
+{
+#if defined(__BORLANDC__)
+ return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)
+ && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)
+ && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)
+ && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)
+ && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)
+ && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)
+ && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0)
+ && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0));
+#else
+ using namespace asio::detail;
+ return IN6_IS_ADDR_UNSPECIFIED(&addr_) != 0;
+#endif
+}
+
+ASIO_DECL
+bool address_v6::is_link_local() const
+{
+ using namespace asio::detail;
+ return IN6_IS_ADDR_LINKLOCAL(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_site_local() const
+{
+ using namespace asio::detail;
+ return IN6_IS_ADDR_SITELOCAL(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_v4_mapped() const
+{
+ using namespace asio::detail;
+ return IN6_IS_ADDR_V4MAPPED(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_v4_compatible() const
+{
+ using namespace asio::detail;
+ return IN6_IS_ADDR_V4COMPAT(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_multicast() const
+{
+ using namespace asio::detail;
+ return IN6_IS_ADDR_MULTICAST(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_multicast_global() const
+{
+ using namespace asio::detail;
+ return IN6_IS_ADDR_MC_GLOBAL(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_multicast_link_local() const
+{
+ using namespace asio::detail;
+ return IN6_IS_ADDR_MC_LINKLOCAL(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_multicast_node_local() const
+{
+ using namespace asio::detail;
+ return IN6_IS_ADDR_MC_NODELOCAL(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_multicast_org_local() const
+{
+ using namespace asio::detail;
+ return IN6_IS_ADDR_MC_ORGLOCAL(&addr_) != 0;
+}
+
+ASIO_DECL
+bool address_v6::is_multicast_site_local() const
+{
+ using namespace asio::detail;
+ return IN6_IS_ADDR_MC_SITELOCAL(&addr_) != 0;
+}
+
+ASIO_DECL
+bool operator==(const address_v6& a1, const address_v6& a2)
+{
+ using namespace std; // For memcmp.
+ return memcmp(&a1.addr_, &a2.addr_,
+ sizeof(asio::detail::in6_addr_type)) == 0
+ && a1.scope_id_ == a2.scope_id_;
+}
+
+ASIO_DECL
+bool operator<(const address_v6& a1, const address_v6& a2)
+{
+ using namespace std; // For memcmp.
+ int memcmp_result = memcmp(&a1.addr_, &a2.addr_,
+ sizeof(asio::detail::in6_addr_type));
+ if (memcmp_result < 0)
+ return true;
+ if (memcmp_result > 0)
+ return false;
+ return a1.scope_id_ < a2.scope_id_;
+}
+
+ASIO_DECL
+address_v6 address_v6::loopback()
+{
+ address_v6 tmp;
+ asio::detail::in6_addr_type tmp_addr = IN6ADDR_LOOPBACK_INIT;
+ tmp.addr_ = tmp_addr;
+ return tmp;
+}
+
+ASIO_DECL
+address_v6 address_v6::v4_mapped(const address_v4& addr)
+{
+ address_v4::bytes_type v4_bytes = addr.to_bytes();
+ bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF,
+ v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } };
+ return address_v6(v6_bytes);
+}
+
+ASIO_DECL
+address_v6 address_v6::v4_compatible(const address_v4& addr)
+{
+ address_v4::bytes_type v4_bytes = addr.to_bytes();
+ bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } };
+ return address_v6(v6_bytes);
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_IMPL_ADDRESS_V6_IPP
diff --git a/ext/asio/asio/ip/impl/basic_endpoint.hpp b/ext/asio/asio/ip/impl/basic_endpoint.hpp
new file mode 100644
index 0000000..db7d5fb
--- /dev/null
+++ b/ext/asio/asio/ip/impl/basic_endpoint.hpp
@@ -0,0 +1,55 @@
+//
+// ip/impl/basic_endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_BASIC_ENDPOINT_HPP
+#define ASIO_IP_IMPL_BASIC_ENDPOINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if !defined(BOOST_NO_IOSTREAM)
+
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename Elem, typename Traits, typename InternetProtocol>
+std::basic_ostream<Elem, Traits>& operator<<(
+ std::basic_ostream<Elem, Traits>& os,
+ const basic_endpoint<InternetProtocol>& endpoint)
+{
+ asio::ip::detail::endpoint tmp_ep(endpoint.address(), endpoint.port());
+ asio::error_code ec;
+ std::string s = tmp_ep.to_string(ec);
+ if (ec)
+ {
+ if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit)
+ asio::detail::throw_error(ec);
+ else
+ os.setstate(std::basic_ostream<Elem, Traits>::failbit);
+ }
+ else
+ for (std::string::iterator i = s.begin(); i != s.end(); ++i)
+ os << os.widen(*i);
+ return os;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+#endif // ASIO_IP_IMPL_BASIC_ENDPOINT_HPP
diff --git a/ext/asio/asio/ip/impl/host_name.ipp b/ext/asio/asio/ip/impl/host_name.ipp
new file mode 100644
index 0000000..5bf5cca
--- /dev/null
+++ b/ext/asio/asio/ip/impl/host_name.ipp
@@ -0,0 +1,56 @@
+//
+// ip/impl/host_name.ipp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_HOST_NAME_IPP
+#define ASIO_IP_IMPL_HOST_NAME_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/ip/host_name.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+ASIO_DECL
+std::string host_name()
+{
+ char name[1024];
+ asio::error_code ec;
+ if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0)
+ {
+ asio::detail::throw_error(ec);
+ return std::string();
+ }
+ return std::string(name);
+}
+
+ASIO_DECL
+std::string host_name(asio::error_code& ec)
+{
+ char name[1024];
+ if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0)
+ return std::string();
+ return std::string(name);
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_IMPL_HOST_NAME_IPP
diff --git a/ext/asio/asio/ip/multicast.hpp b/ext/asio/asio/ip/multicast.hpp
index eeedc6c..f2193c0 100644
--- a/ext/asio/asio/ip/multicast.hpp
+++ b/ext/asio/asio/ip/multicast.hpp
@@ -1,8 +1,8 @@
//
-// multicast.hpp
-// ~~~~~~~~~~~~~
+// ip/multicast.hpp
+// ~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/ip/detail/socket_option.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace ip {
namespace multicast {
diff --git a/ext/asio/asio/ip/resolver_query_base.hpp b/ext/asio/asio/ip/resolver_query_base.hpp
index 5a0acea..8963f41 100644
--- a/ext/asio/asio/ip/resolver_query_base.hpp
+++ b/ext/asio/asio/ip/resolver_query_base.hpp
@@ -1,8 +1,8 @@
//
-// resolver_query_base.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~
+// ip/resolver_query_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
+#include "asio/detail/config.hpp"
#include <boost/detail/workaround.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/detail/socket_types.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace ip {
diff --git a/ext/asio/asio/ip/resolver_service.hpp b/ext/asio/asio/ip/resolver_service.hpp
index 75f6b2c..0d866d6 100644
--- a/ext/asio/asio/ip/resolver_service.hpp
+++ b/ext/asio/asio/ip/resolver_service.hpp
@@ -1,8 +1,8 @@
//
-// resolver_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~
+// ip/resolver_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/error.hpp"
+#include "asio/detail/config.hpp"
+#include "asio/error_code.hpp"
+#include "asio/detail/resolver_service.hpp"
#include "asio/io_service.hpp"
#include "asio/ip/basic_resolver_iterator.hpp"
#include "asio/ip/basic_resolver_query.hpp"
-#include "asio/detail/resolver_service.hpp"
-#include "asio/detail/service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace ip {
@@ -72,13 +72,14 @@ public:
explicit resolver_service(asio::io_service& io_service)
: asio::detail::service_base<
resolver_service<InternetProtocol> >(io_service),
- service_impl_(asio::use_service<service_impl_type>(io_service))
+ service_impl_(io_service)
{
}
/// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
+ service_impl_.shutdown_service();
}
/// Construct a new resolver implementation.
@@ -130,8 +131,8 @@ public:
}
private:
- // The service that provides the platform-specific implementation.
- service_impl_type& service_impl_;
+ // The platform-specific implementation.
+ service_impl_type service_impl_;
};
} // namespace ip
diff --git a/ext/asio/asio/ip/tcp.hpp b/ext/asio/asio/ip/tcp.hpp
index a2e9ac9..67fb09f 100644
--- a/ext/asio/asio/ip/tcp.hpp
+++ b/ext/asio/asio/ip/tcp.hpp
@@ -1,8 +1,8 @@
//
-// tcp.hpp
-// ~~~~~~~
+// ip/tcp.hpp
+// ~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,18 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/basic_socket_acceptor.hpp"
#include "asio/basic_socket_iostream.hpp"
#include "asio/basic_stream_socket.hpp"
+#include "asio/detail/socket_option.hpp"
+#include "asio/detail/socket_types.hpp"
#include "asio/ip/basic_endpoint.hpp"
#include "asio/ip/basic_resolver.hpp"
#include "asio/ip/basic_resolver_iterator.hpp"
#include "asio/ip/basic_resolver_query.hpp"
-#include "asio/detail/socket_option.hpp"
-#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace ip {
diff --git a/ext/asio/asio/ip/udp.hpp b/ext/asio/asio/ip/udp.hpp
index fb26118..ca3ac78 100644
--- a/ext/asio/asio/ip/udp.hpp
+++ b/ext/asio/asio/ip/udp.hpp
@@ -1,8 +1,8 @@
//
-// udp.hpp
-// ~~~~~~~
+// ip/udp.hpp
+// ~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/basic_datagram_socket.hpp"
+#include "asio/detail/socket_types.hpp"
#include "asio/ip/basic_endpoint.hpp"
#include "asio/ip/basic_resolver.hpp"
#include "asio/ip/basic_resolver_iterator.hpp"
#include "asio/ip/basic_resolver_query.hpp"
-#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace ip {
diff --git a/ext/asio/asio/ip/unicast.hpp b/ext/asio/asio/ip/unicast.hpp
index 46d7239..e3d04e5 100644
--- a/ext/asio/asio/ip/unicast.hpp
+++ b/ext/asio/asio/ip/unicast.hpp
@@ -1,8 +1,8 @@
//
-// unicast.hpp
-// ~~~~~~~~~~~
+// ip/unicast.hpp
+// ~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/ip/detail/socket_option.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace ip {
namespace unicast {
diff --git a/ext/asio/asio/ip/v6_only.hpp b/ext/asio/asio/ip/v6_only.hpp
index 928caff..5ac6a37 100644
--- a/ext/asio/asio/ip/v6_only.hpp
+++ b/ext/asio/asio/ip/v6_only.hpp
@@ -1,8 +1,8 @@
//
-// v6_only.hpp
-// ~~~~~~~~~~~
+// ip/v6_only.hpp
+// ~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,10 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/detail/socket_option.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace ip {
diff --git a/ext/asio/asio/is_read_buffered.hpp b/ext/asio/asio/is_read_buffered.hpp
index 8d97174..e48de55 100644
--- a/ext/asio/asio/is_read_buffered.hpp
+++ b/ext/asio/asio/is_read_buffered.hpp
@@ -2,7 +2,7 @@
// is_read_buffered.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/buffered_read_stream_fwd.hpp"
#include "asio/buffered_stream_fwd.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
diff --git a/ext/asio/asio/is_write_buffered.hpp b/ext/asio/asio/is_write_buffered.hpp
index 5d16b1c..c681a2b 100644
--- a/ext/asio/asio/is_write_buffered.hpp
+++ b/ext/asio/asio/is_write_buffered.hpp
@@ -2,7 +2,7 @@
// is_write_buffered.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/buffered_stream_fwd.hpp"
#include "asio/buffered_write_stream_fwd.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail {
diff --git a/ext/asio/asio/local/basic_endpoint.hpp b/ext/asio/asio/local/basic_endpoint.hpp
index 81e6a7e..d2d0a02 100644
--- a/ext/asio/asio/local/basic_endpoint.hpp
+++ b/ext/asio/asio/local/basic_endpoint.hpp
@@ -1,8 +1,8 @@
//
-// basic_endpoint.hpp
-// ~~~~~~~~~~~~~~~~~~
+// local/basic_endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Derived from a public domain implementation written by Daniel Casimiro.
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,30 +16,18 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/throw_exception.hpp>
-#include <cstddef>
-#include <cstring>
-#include <ostream>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/system_error.hpp"
-#include "asio/detail/socket_ops.hpp"
-#include "asio/detail/socket_types.hpp"
-#include "asio/detail/throw_error.hpp"
-
-#if !defined(ASIO_DISABLE_LOCAL_SOCKETS)
-# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-# define ASIO_HAS_LOCAL_SOCKETS 1
-# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-#endif // !defined(ASIO_DISABLE_LOCAL_SOCKETS)
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_LOCAL_SOCKETS) \
|| defined(GENERATING_DOCUMENTATION)
+#include "asio/local/detail/endpoint.hpp"
+
+#if !defined(BOOST_NO_IOSTREAM)
+# include <iosfwd>
+#endif // !defined(BOOST_NO_IOSTREAM)
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace local {
@@ -74,34 +62,30 @@ public:
/// Default constructor.
basic_endpoint()
{
- init("", 0);
}
/// Construct an endpoint using the specified path name.
basic_endpoint(const char* path)
+ : impl_(path)
{
- using namespace std; // For strlen.
- init(path, strlen(path));
}
/// Construct an endpoint using the specified path name.
basic_endpoint(const std::string& path)
+ : impl_(path)
{
- init(path.data(), path.length());
}
/// Copy constructor.
basic_endpoint(const basic_endpoint& other)
- : data_(other.data_),
- path_length_(other.path_length_)
+ : impl_(other.impl_)
{
}
/// Assign from another endpoint.
basic_endpoint& operator=(const basic_endpoint& other)
{
- data_ = other.data_;
- path_length_ = other.path_length_;
+ impl_ = other.impl_;
return *this;
}
@@ -114,123 +98,96 @@ public:
/// Get the underlying endpoint in the native type.
data_type* data()
{
- return &data_.base;
+ return impl_.data();
}
/// Get the underlying endpoint in the native type.
const data_type* data() const
{
- return &data_.base;
+ return impl_.data();
}
/// Get the underlying size of the endpoint in the native type.
std::size_t size() const
{
- return path_length_
- + offsetof(asio::detail::sockaddr_un_type, sun_path);
+ return impl_.size();
}
/// Set the underlying size of the endpoint in the native type.
void resize(std::size_t size)
{
- if (size > sizeof(asio::detail::sockaddr_un_type))
- {
- asio::system_error e(asio::error::invalid_argument);
- boost::throw_exception(e);
- }
- else if (size == 0)
- {
- path_length_ = 0;
- }
- else
- {
- path_length_ = size
- - offsetof(asio::detail::sockaddr_un_type, sun_path);
-
- // The path returned by the operating system may be NUL-terminated.
- if (path_length_ > 0 && data_.local.sun_path[path_length_ - 1] == 0)
- --path_length_;
- }
+ impl_.resize(size);
}
/// Get the capacity of the endpoint in the native type.
std::size_t capacity() const
{
- return sizeof(asio::detail::sockaddr_un_type);
+ return impl_.capacity();
}
/// Get the path associated with the endpoint.
std::string path() const
{
- return std::string(data_.local.sun_path, path_length_);
+ return impl_.path();
}
/// Set the path associated with the endpoint.
void path(const char* p)
{
- using namespace std; // For strlen.
- init(p, strlen(p));
+ impl_.path(p);
}
/// Set the path associated with the endpoint.
void path(const std::string& p)
{
- init(p.data(), p.length());
+ impl_.path(p);
}
/// Compare two endpoints for equality.
friend bool operator==(const basic_endpoint<Protocol>& e1,
const basic_endpoint<Protocol>& e2)
{
- return e1.path() == e2.path();
+ return e1.impl_ == e2.impl_;
}
/// Compare two endpoints for inequality.
friend bool operator!=(const basic_endpoint<Protocol>& e1,
const basic_endpoint<Protocol>& e2)
{
- return e1.path() != e2.path();
+ return !(e1.impl_ == e2.impl_);
}
/// Compare endpoints for ordering.
friend bool operator<(const basic_endpoint<Protocol>& e1,
const basic_endpoint<Protocol>& e2)
{
- return e1.path() < e2.path();
+ return e1.impl_ < e2.impl_;
}
-private:
- // The underlying UNIX socket address.
- union data_union
+ /// Compare endpoints for ordering.
+ friend bool operator>(const basic_endpoint<Protocol>& e1,
+ const basic_endpoint<Protocol>& e2)
{
- asio::detail::socket_addr_type base;
- asio::detail::sockaddr_un_type local;
- } data_;
+ return e2.impl_ < e1.impl_;
+ }
- // The length of the path associated with the endpoint.
- std::size_t path_length_;
+ /// Compare endpoints for ordering.
+ friend bool operator<=(const basic_endpoint<Protocol>& e1,
+ const basic_endpoint<Protocol>& e2)
+ {
+ return !(e2 < e1);
+ }
- // Initialise with a specified path.
- void init(const char* path, std::size_t path_length)
+ /// Compare endpoints for ordering.
+ friend bool operator>=(const basic_endpoint<Protocol>& e1,
+ const basic_endpoint<Protocol>& e2)
{
- if (path_length > sizeof(data_.local.sun_path) - 1)
- {
- // The buffer is not large enough to store this address.
- asio::error_code ec(asio::error::name_too_long);
- asio::detail::throw_error(ec);
- }
-
- using namespace std; // For memcpy.
- data_.local = asio::detail::sockaddr_un_type();
- data_.local.sun_family = AF_UNIX;
- memcpy(data_.local.sun_path, path, path_length);
- path_length_ = path_length;
-
- // NUL-terminate normal path names. Names that start with a NUL are in the
- // UNIX domain protocol's "abstract namespace" and are not NUL-terminated.
- if (path_length > 0 && data_.local.sun_path[0] == 0)
- data_.local.sun_path[path_length] = 0;
+ return !(e1 < e2);
}
+
+private:
+ // The underlying UNIX domain endpoint.
+ asio::local::detail::endpoint impl_;
};
/// Output an endpoint as a string.
@@ -257,9 +214,9 @@ std::basic_ostream<Elem, Traits>& operator<<(
} // namespace local
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_LOCAL_BASIC_ENDPOINT_HPP
diff --git a/ext/asio/asio/local/connect_pair.hpp b/ext/asio/asio/local/connect_pair.hpp
index da1d4fc..4a58247 100644
--- a/ext/asio/asio/local/connect_pair.hpp
+++ b/ext/asio/asio/local/connect_pair.hpp
@@ -1,8 +1,8 @@
//
-// connect_pair.hpp
-// ~~~~~~~~~~~~~~~~
+// local/connect_pair.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,18 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_LOCAL_SOCKETS) \
+ || defined(GENERATING_DOCUMENTATION)
#include "asio/basic_socket.hpp"
-#include "asio/error.hpp"
-#include "asio/local/basic_endpoint.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/local/basic_endpoint.hpp"
-#if defined(ASIO_HAS_LOCAL_SOCKETS) \
- || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace local {
@@ -73,8 +75,9 @@ inline asio::error_code connect_pair(
if (socket1.assign(protocol, sv[0], ec))
{
asio::error_code temp_ec;
- asio::detail::socket_ops::close(sv[0], temp_ec);
- asio::detail::socket_ops::close(sv[1], temp_ec);
+ asio::detail::socket_ops::state_type state[2] = { 0, 0 };
+ asio::detail::socket_ops::close(sv[0], state[0], true, temp_ec);
+ asio::detail::socket_ops::close(sv[1], state[1], true, temp_ec);
return ec;
}
@@ -82,7 +85,8 @@ inline asio::error_code connect_pair(
{
asio::error_code temp_ec;
socket1.close(temp_ec);
- asio::detail::socket_ops::close(sv[1], temp_ec);
+ asio::detail::socket_ops::state_type state = 0;
+ asio::detail::socket_ops::close(sv[1], state, true, temp_ec);
return ec;
}
@@ -92,9 +96,9 @@ inline asio::error_code connect_pair(
} // namespace local
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_LOCAL_CONNECT_PAIR_HPP
diff --git a/ext/asio/asio/local/datagram_protocol.hpp b/ext/asio/asio/local/datagram_protocol.hpp
index 0340180..39f47ce 100644
--- a/ext/asio/asio/local/datagram_protocol.hpp
+++ b/ext/asio/asio/local/datagram_protocol.hpp
@@ -1,8 +1,8 @@
//
-// datagram_protocol.hpp
-// ~~~~~~~~~~~~~~~~~~~~~
+// local/datagram_protocol.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,16 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_LOCAL_SOCKETS) \
+ || defined(GENERATING_DOCUMENTATION)
#include "asio/basic_datagram_socket.hpp"
-#include "asio/local/basic_endpoint.hpp"
#include "asio/detail/socket_types.hpp"
+#include "asio/local/basic_endpoint.hpp"
-#if defined(ASIO_HAS_LOCAL_SOCKETS) \
- || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace local {
@@ -70,9 +72,9 @@ public:
} // namespace local
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP
diff --git a/ext/asio/asio/local/detail/endpoint.hpp b/ext/asio/asio/local/detail/endpoint.hpp
new file mode 100644
index 0000000..05fc992
--- /dev/null
+++ b/ext/asio/asio/local/detail/endpoint.hpp
@@ -0,0 +1,133 @@
+//
+// local/detail/endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Derived from a public domain implementation written by Daniel Casimiro.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_LOCAL_DETAIL_ENDPOINT_HPP
+#define ASIO_LOCAL_DETAIL_ENDPOINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_LOCAL_SOCKETS)
+
+#include <cstddef>
+#include <string>
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace local {
+namespace detail {
+
+// Helper class for implementing a UNIX domain endpoint.
+class endpoint
+{
+public:
+ // Default constructor.
+ ASIO_DECL endpoint();
+
+ // Construct an endpoint using the specified path name.
+ ASIO_DECL endpoint(const char* path);
+
+ // Construct an endpoint using the specified path name.
+ ASIO_DECL endpoint(const std::string& path);
+
+ // Copy constructor.
+ endpoint(const endpoint& other)
+ : data_(other.data_),
+ path_length_(other.path_length_)
+ {
+ }
+
+ // Assign from another endpoint.
+ endpoint& operator=(const endpoint& other)
+ {
+ data_ = other.data_;
+ path_length_ = other.path_length_;
+ return *this;
+ }
+
+ // Get the underlying endpoint in the native type.
+ asio::detail::socket_addr_type* data()
+ {
+ return &data_.base;
+ }
+
+ // Get the underlying endpoint in the native type.
+ const asio::detail::socket_addr_type* data() const
+ {
+ return &data_.base;
+ }
+
+ // Get the underlying size of the endpoint in the native type.
+ std::size_t size() const
+ {
+ return path_length_
+ + offsetof(asio::detail::sockaddr_un_type, sun_path);
+ }
+
+ // Set the underlying size of the endpoint in the native type.
+ ASIO_DECL void resize(std::size_t size);
+
+ // Get the capacity of the endpoint in the native type.
+ std::size_t capacity() const
+ {
+ return sizeof(asio::detail::sockaddr_un_type);
+ }
+
+ // Get the path associated with the endpoint.
+ ASIO_DECL std::string path() const;
+
+ // Set the path associated with the endpoint.
+ ASIO_DECL void path(const char* p);
+
+ // Set the path associated with the endpoint.
+ ASIO_DECL void path(const std::string& p);
+
+ // Compare two endpoints for equality.
+ ASIO_DECL friend bool operator==(
+ const endpoint& e1, const endpoint& e2);
+
+ // Compare endpoints for ordering.
+ ASIO_DECL friend bool operator<(
+ const endpoint& e1, const endpoint& e2);
+
+private:
+ // The underlying UNIX socket address.
+ union data_union
+ {
+ asio::detail::socket_addr_type base;
+ asio::detail::sockaddr_un_type local;
+ } data_;
+
+ // The length of the path associated with the endpoint.
+ std::size_t path_length_;
+
+ // Initialise with a specified path.
+ ASIO_DECL void init(const char* path, std::size_t path_length);
+};
+
+} // namespace detail
+} // namespace local
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/local/detail/impl/endpoint.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
+
+#endif // ASIO_LOCAL_DETAIL_ENDPOINT_HPP
diff --git a/ext/asio/asio/local/detail/impl/endpoint.ipp b/ext/asio/asio/local/detail/impl/endpoint.ipp
new file mode 100644
index 0000000..1bc2c94
--- /dev/null
+++ b/ext/asio/asio/local/detail/impl/endpoint.ipp
@@ -0,0 +1,138 @@
+//
+// local/detail/impl/endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Derived from a public domain implementation written by Daniel Casimiro.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP
+#define ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_LOCAL_SOCKETS)
+
+#include <cstring>
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/local/detail/endpoint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace local {
+namespace detail {
+
+ASIO_DECL
+endpoint::endpoint()
+{
+ init("", 0);
+}
+
+ASIO_DECL
+endpoint::endpoint(const char* path)
+{
+ using namespace std; // For strlen.
+ init(path, strlen(path));
+}
+
+ASIO_DECL
+endpoint::endpoint(const std::string& path)
+{
+ init(path.data(), path.length());
+}
+
+ASIO_DECL
+void endpoint::resize(std::size_t size)
+{
+ if (size > sizeof(asio::detail::sockaddr_un_type))
+ {
+ asio::error_code ec(asio::error::invalid_argument);
+ asio::detail::throw_error(ec);
+ }
+ else if (size == 0)
+ {
+ path_length_ = 0;
+ }
+ else
+ {
+ path_length_ = size
+ - offsetof(asio::detail::sockaddr_un_type, sun_path);
+
+ // The path returned by the operating system may be NUL-terminated.
+ if (path_length_ > 0 && data_.local.sun_path[path_length_ - 1] == 0)
+ --path_length_;
+ }
+}
+
+ASIO_DECL
+std::string endpoint::path() const
+{
+ return std::string(data_.local.sun_path, path_length_);
+}
+
+ASIO_DECL
+void endpoint::path(const char* p)
+{
+ using namespace std; // For strlen.
+ init(p, strlen(p));
+}
+
+ASIO_DECL
+void endpoint::path(const std::string& p)
+{
+ init(p.data(), p.length());
+}
+
+ASIO_DECL
+bool operator==(const endpoint& e1, const endpoint& e2)
+{
+ return e1.path() == e2.path();
+}
+
+ASIO_DECL
+bool operator<(const endpoint& e1, const endpoint& e2)
+{
+ return e1.path() < e2.path();
+}
+
+ASIO_DECL
+void endpoint::init(const char* path, std::size_t path_length)
+{
+ if (path_length > sizeof(data_.local.sun_path) - 1)
+ {
+ // The buffer is not large enough to store this address.
+ asio::error_code ec(asio::error::name_too_long);
+ asio::detail::throw_error(ec);
+ }
+
+ using namespace std; // For memcpy.
+ data_.local = asio::detail::sockaddr_un_type();
+ data_.local.sun_family = AF_UNIX;
+ memcpy(data_.local.sun_path, path, path_length);
+ path_length_ = path_length;
+
+ // NUL-terminate normal path names. Names that start with a NUL are in the
+ // UNIX domain protocol's "abstract namespace" and are not NUL-terminated.
+ if (path_length > 0 && data_.local.sun_path[0] == 0)
+ data_.local.sun_path[path_length] = 0;
+}
+
+} // namespace detail
+} // namespace local
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
+
+#endif // ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP
diff --git a/ext/asio/asio/local/stream_protocol.hpp b/ext/asio/asio/local/stream_protocol.hpp
index 47fe42f..e65a2f6 100644
--- a/ext/asio/asio/local/stream_protocol.hpp
+++ b/ext/asio/asio/local/stream_protocol.hpp
@@ -1,8 +1,8 @@
//
-// stream_protocol.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// local/stream_protocol.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,18 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_LOCAL_SOCKETS) \
+ || defined(GENERATING_DOCUMENTATION)
#include "asio/basic_socket_acceptor.hpp"
#include "asio/basic_socket_iostream.hpp"
#include "asio/basic_stream_socket.hpp"
-#include "asio/local/basic_endpoint.hpp"
#include "asio/detail/socket_types.hpp"
+#include "asio/local/basic_endpoint.hpp"
-#if defined(ASIO_HAS_LOCAL_SOCKETS) \
- || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace local {
@@ -80,9 +82,9 @@ public:
} // namespace local
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_LOCAL_STREAM_PROTOCOL_HPP
diff --git a/ext/asio/asio/placeholders.hpp b/ext/asio/asio/placeholders.hpp
index 70e69fc..6fda487 100644
--- a/ext/asio/asio/placeholders.hpp
+++ b/ext/asio/asio/placeholders.hpp
@@ -2,7 +2,7 @@
// placeholders.hpp
// ~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <boost/bind/arg.hpp>
#include <boost/detail/workaround.hpp>
-#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace placeholders {
diff --git a/ext/asio/asio/posix/basic_descriptor.hpp b/ext/asio/asio/posix/basic_descriptor.hpp
index 37bcc94..591e65a 100644
--- a/ext/asio/asio/posix/basic_descriptor.hpp
+++ b/ext/asio/asio/posix/basic_descriptor.hpp
@@ -1,8 +1,8 @@
//
-// basic_descriptor.hpp
-// ~~~~~~~~~~~~~~~~~~~~
+// posix/basic_descriptor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,17 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
+ || defined(GENERATING_DOCUMENTATION)
#include "asio/basic_io_object.hpp"
+#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/posix/descriptor_base.hpp"
-#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace posix {
@@ -291,4 +292,7 @@ protected:
#include "asio/detail/pop_options.hpp"
+#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+ // || defined(GENERATING_DOCUMENTATION)
+
#endif // ASIO_POSIX_BASIC_DESCRIPTOR_HPP
diff --git a/ext/asio/asio/posix/basic_stream_descriptor.hpp b/ext/asio/asio/posix/basic_stream_descriptor.hpp
index 21e2287..8211c58 100644
--- a/ext/asio/asio/posix/basic_stream_descriptor.hpp
+++ b/ext/asio/asio/posix/basic_stream_descriptor.hpp
@@ -1,8 +1,8 @@
//
-// basic_stream_descriptor.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// posix/basic_stream_descriptor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,20 +15,18 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
-#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
+ || defined(GENERATING_DOCUMENTATION)
+#include <cstddef>
+#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/posix/basic_descriptor.hpp"
#include "asio/posix/stream_descriptor_service.hpp"
-#include "asio/detail/throw_error.hpp"
-#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
- || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace posix {
@@ -296,9 +294,9 @@ public:
} // namespace posix
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP
diff --git a/ext/asio/asio/posix/descriptor_base.hpp b/ext/asio/asio/posix/descriptor_base.hpp
index 29e1746..2222915 100644
--- a/ext/asio/asio/posix/descriptor_base.hpp
+++ b/ext/asio/asio/posix/descriptor_base.hpp
@@ -1,8 +1,8 @@
//
-// descriptor_base.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// posix/descriptor_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,16 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include <boost/detail/workaround.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
+ || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/io_control.hpp"
#include "asio/detail/socket_option.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace posix {
@@ -90,4 +90,7 @@ protected:
#include "asio/detail/pop_options.hpp"
+#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+ // || defined(GENERATING_DOCUMENTATION)
+
#endif // ASIO_POSIX_DESCRIPTOR_BASE_HPP
diff --git a/ext/asio/asio/posix/stream_descriptor.hpp b/ext/asio/asio/posix/stream_descriptor.hpp
index 72fbbed..48c20a3 100644
--- a/ext/asio/asio/posix/stream_descriptor.hpp
+++ b/ext/asio/asio/posix/stream_descriptor.hpp
@@ -1,8 +1,8 @@
//
-// stream_descriptor.hpp
-// ~~~~~~~~~~~~~~~~~~~~~
+// posix/stream_descriptor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,13 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/posix/basic_stream_descriptor.hpp"
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
|| defined(GENERATING_DOCUMENTATION)
+#include "asio/posix/basic_stream_descriptor.hpp"
+
namespace asio {
namespace posix {
@@ -34,6 +34,4 @@ typedef basic_stream_descriptor<> stream_descriptor;
#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_POSIX_STREAM_DESCRIPTOR_HPP
diff --git a/ext/asio/asio/posix/stream_descriptor_service.hpp b/ext/asio/asio/posix/stream_descriptor_service.hpp
index 61cee1b..4660e79 100644
--- a/ext/asio/asio/posix/stream_descriptor_service.hpp
+++ b/ext/asio/asio/posix/stream_descriptor_service.hpp
@@ -1,8 +1,8 @@
//
-// stream_descriptor_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// posix/stream_descriptor_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,28 +15,18 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/error.hpp"
-#include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
-
-#if !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
-# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-# define ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1
-# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-#endif // !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
|| defined(GENERATING_DOCUMENTATION)
+#include <cstddef>
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
#include "asio/detail/reactive_descriptor_service.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace posix {
@@ -179,9 +169,9 @@ private:
} // namespace posix
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP
diff --git a/ext/asio/asio/raw_socket_service.hpp b/ext/asio/asio/raw_socket_service.hpp
index a8973d3..3d0016d 100644
--- a/ext/asio/asio/raw_socket_service.hpp
+++ b/ext/asio/asio/raw_socket_service.hpp
@@ -2,7 +2,7 @@
// raw_socket_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/error.hpp"
#include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_socket_service.hpp"
@@ -32,6 +26,8 @@
# include "asio/detail/reactive_socket_service.hpp"
#endif
+#include "asio/detail/push_options.hpp"
+
namespace asio {
/// Default service implementation for a raw socket.
diff --git a/ext/asio/asio/read.hpp b/ext/asio/asio/read.hpp
index 859c05a..7f04b07 100644
--- a/ext/asio/asio/read.hpp
+++ b/ext/asio/asio/read.hpp
@@ -2,7 +2,7 @@
// read.hpp
// ~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/basic_streambuf.hpp"
+#include "asio/basic_streambuf_fwd.hpp"
#include "asio/error.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
/**
@@ -536,8 +533,8 @@ void async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b,
} // namespace asio
-#include "asio/impl/read.ipp"
-
#include "asio/detail/pop_options.hpp"
+#include "asio/impl/read.hpp"
+
#endif // ASIO_READ_HPP
diff --git a/ext/asio/asio/read_at.hpp b/ext/asio/asio/read_at.hpp
index 6bb3fe1..4be1f96 100644
--- a/ext/asio/asio/read_at.hpp
+++ b/ext/asio/asio/read_at.hpp
@@ -2,7 +2,7 @@
// read_at.hpp
// ~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
#include <boost/cstdint.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/basic_streambuf.hpp"
+#include "asio/basic_streambuf_fwd.hpp"
#include "asio/error.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
/**
@@ -569,8 +566,8 @@ void async_read_at(AsyncRandomAccessReadDevice& d,
} // namespace asio
-#include "asio/impl/read_at.ipp"
-
#include "asio/detail/pop_options.hpp"
+#include "asio/impl/read_at.hpp"
+
#endif // ASIO_READ_AT_HPP
diff --git a/ext/asio/asio/read_until.hpp b/ext/asio/asio/read_until.hpp
index 5df71ce..67fa066 100644
--- a/ext/asio/asio/read_until.hpp
+++ b/ext/asio/asio/read_until.hpp
@@ -2,7 +2,7 @@
// read_until.hpp
// ~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,27 +15,22 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/config.hpp"
#if !defined(BOOST_NO_IOSTREAM)
-#include "asio/detail/push_options.hpp"
#include <cstddef>
-#include <boost/regex.hpp>
#include <boost/type_traits/is_function.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/detail/workaround.hpp>
#include <string>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/basic_streambuf.hpp"
+#include "asio/detail/regex_fwd.hpp"
#include "asio/error.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace detail
@@ -914,10 +909,10 @@ void async_read_until(AsyncReadStream& s,
} // namespace asio
-#include "asio/impl/read_until.ipp"
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/read_until.hpp"
#endif // !defined(BOOST_NO_IOSTREAM)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_READ_UNTIL_HPP
diff --git a/ext/asio/asio/serial_port.hpp b/ext/asio/asio/serial_port.hpp
index a55a03a..4cc6fd4 100644
--- a/ext/asio/asio/serial_port.hpp
+++ b/ext/asio/asio/serial_port.hpp
@@ -2,7 +2,7 @@
// serial_port.hpp
// ~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,13 +16,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/basic_serial_port.hpp"
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_SERIAL_PORT) \
|| defined(GENERATING_DOCUMENTATION)
+#include "asio/basic_serial_port.hpp"
+
namespace asio {
/// Typedef for the typical usage of a serial port.
@@ -33,6 +33,4 @@ typedef basic_serial_port<> serial_port;
#endif // defined(ASIO_HAS_SERIAL_PORT)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_SERIAL_PORT_HPP
diff --git a/ext/asio/asio/serial_port_base.hpp b/ext/asio/asio/serial_port_base.hpp
index 28e51a0..9c7a773 100644
--- a/ext/asio/asio/serial_port_base.hpp
+++ b/ext/asio/asio/serial_port_base.hpp
@@ -2,7 +2,7 @@
// serial_port_base.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info at repinvariant.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,32 +16,18 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <stdexcept>
-#include <boost/config.hpp>
-#include <boost/detail/workaround.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#if !defined(ASIO_DISABLE_SERIAL_PORT)
-# if defined(ASIO_HAS_IOCP) \
- || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-# define ASIO_HAS_SERIAL_PORT 1
-# endif // defined(ASIO_HAS_IOCP)
-#endif // !defined(ASIO_DISABLE_STREAM_HANDLE)
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_SERIAL_PORT) \
|| defined(GENERATING_DOCUMENTATION)
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-# include "asio/detail/push_options.hpp"
# include <termios.h>
-# include "asio/detail/pop_options.hpp"
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-#include "asio/error_code.hpp"
+#include <boost/detail/workaround.hpp>
#include "asio/detail/socket_types.hpp"
+#include "asio/error_code.hpp"
#if defined(GENERATING_DOCUMENTATION)
# define ASIO_OPTION_STORAGE implementation_defined
@@ -51,6 +37,8 @@
# define ASIO_OPTION_STORAGE termios
#endif
+#include "asio/detail/push_options.hpp"
+
namespace asio {
/// The serial_port_base class is used as a base for the basic_serial_port class
@@ -67,9 +55,11 @@ public:
public:
explicit baud_rate(unsigned int rate = 0);
unsigned int value() const;
- asio::error_code store(ASIO_OPTION_STORAGE& storage,
+ ASIO_DECL asio::error_code store(
+ ASIO_OPTION_STORAGE& storage,
asio::error_code& ec) const;
- asio::error_code load(const ASIO_OPTION_STORAGE& storage,
+ ASIO_DECL asio::error_code load(
+ const ASIO_OPTION_STORAGE& storage,
asio::error_code& ec);
private:
unsigned int value_;
@@ -83,11 +73,13 @@ public:
{
public:
enum type { none, software, hardware };
- explicit flow_control(type t = none);
+ ASIO_DECL explicit flow_control(type t = none);
type value() const;
- asio::error_code store(ASIO_OPTION_STORAGE& storage,
+ ASIO_DECL asio::error_code store(
+ ASIO_OPTION_STORAGE& storage,
asio::error_code& ec) const;
- asio::error_code load(const ASIO_OPTION_STORAGE& storage,
+ ASIO_DECL asio::error_code load(
+ const ASIO_OPTION_STORAGE& storage,
asio::error_code& ec);
private:
type value_;
@@ -101,11 +93,13 @@ public:
{
public:
enum type { none, odd, even };
- explicit parity(type t = none);
+ ASIO_DECL explicit parity(type t = none);
type value() const;
- asio::error_code store(ASIO_OPTION_STORAGE& storage,
+ ASIO_DECL asio::error_code store(
+ ASIO_OPTION_STORAGE& storage,
asio::error_code& ec) const;
- asio::error_code load(const ASIO_OPTION_STORAGE& storage,
+ ASIO_DECL asio::error_code load(
+ const ASIO_OPTION_STORAGE& storage,
asio::error_code& ec);
private:
type value_;
@@ -119,11 +113,13 @@ public:
{
public:
enum type { one, onepointfive, two };
- explicit stop_bits(type t = one);
+ ASIO_DECL explicit stop_bits(type t = one);
type value() const;
- asio::error_code store(ASIO_OPTION_STORAGE& storage,
+ ASIO_DECL asio::error_code store(
+ ASIO_OPTION_STORAGE& storage,
asio::error_code& ec) const;
- asio::error_code load(const ASIO_OPTION_STORAGE& storage,
+ ASIO_DECL asio::error_code load(
+ const ASIO_OPTION_STORAGE& storage,
asio::error_code& ec);
private:
type value_;
@@ -136,11 +132,13 @@ public:
class character_size
{
public:
- explicit character_size(unsigned int t = 8);
+ ASIO_DECL explicit character_size(unsigned int t = 8);
unsigned int value() const;
- asio::error_code store(ASIO_OPTION_STORAGE& storage,
+ ASIO_DECL asio::error_code store(
+ ASIO_OPTION_STORAGE& storage,
asio::error_code& ec) const;
- asio::error_code load(const ASIO_OPTION_STORAGE& storage,
+ ASIO_DECL asio::error_code load(
+ const ASIO_OPTION_STORAGE& storage,
asio::error_code& ec);
private:
unsigned int value_;
@@ -161,13 +159,16 @@ private:
} // namespace asio
-#include "asio/impl/serial_port_base.ipp"
+#include "asio/detail/pop_options.hpp"
#undef ASIO_OPTION_STORAGE
+#include "asio/impl/serial_port_base.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/serial_port_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
#endif // defined(ASIO_HAS_SERIAL_PORT)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_SERIAL_PORT_BASE_HPP
diff --git a/ext/asio/asio/serial_port_service.hpp b/ext/asio/asio/serial_port_service.hpp
index 5847c29..37142d5 100644
--- a/ext/asio/asio/serial_port_service.hpp
+++ b/ext/asio/asio/serial_port_service.hpp
@@ -2,7 +2,7 @@
// serial_port_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,23 +15,20 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_SERIAL_PORT) \
+ || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/push_options.hpp"
#include <cstddef>
-#include <boost/config.hpp>
#include <string>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/reactive_serial_port_service.hpp"
+#include "asio/detail/win_iocp_serial_port_service.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/serial_port_base.hpp"
-#include "asio/detail/service_base.hpp"
-#include "asio/detail/reactive_serial_port_service.hpp"
-#include "asio/detail/win_iocp_serial_port_service.hpp"
-#if defined(ASIO_HAS_SERIAL_PORT) \
- || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
namespace asio {
@@ -199,9 +196,9 @@ private:
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#endif // defined(ASIO_HAS_SERIAL_PORT)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_SERIAL_PORT_SERVICE_HPP
diff --git a/ext/asio/asio/socket_acceptor_service.hpp b/ext/asio/asio/socket_acceptor_service.hpp
index b2e2c6d..a1e4874 100644
--- a/ext/asio/asio/socket_acceptor_service.hpp
+++ b/ext/asio/asio/socket_acceptor_service.hpp
@@ -2,7 +2,7 @@
// socket_acceptor_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/basic_socket.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_socket_service.hpp"
@@ -28,6 +26,8 @@
# include "asio/detail/reactive_socket_service.hpp"
#endif
+#include "asio/detail/push_options.hpp"
+
namespace asio {
/// Default service implementation for a socket acceptor.
diff --git a/ext/asio/asio/socket_base.hpp b/ext/asio/asio/socket_base.hpp
index d82cd22..56585e1 100644
--- a/ext/asio/asio/socket_base.hpp
+++ b/ext/asio/asio/socket_base.hpp
@@ -2,7 +2,7 @@
// socket_base.hpp
// ~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
+#include "asio/detail/config.hpp"
#include <boost/detail/workaround.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/detail/io_control.hpp"
#include "asio/detail/socket_option.hpp"
#include "asio/detail/socket_types.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
/// The socket_base class is used as a base for the basic_stream_socket and
diff --git a/ext/asio/asio/ssl.hpp b/ext/asio/asio/ssl.hpp
index a9fff5e..48aff5a 100644
--- a/ext/asio/asio/ssl.hpp
+++ b/ext/asio/asio/ssl.hpp
@@ -2,7 +2,7 @@
// ssl.hpp
// ~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
diff --git a/ext/asio/asio/ssl/basic_context.hpp b/ext/asio/asio/ssl/basic_context.hpp
index ea3893e..20ed57d 100755
--- a/ext/asio/asio/ssl/basic_context.hpp
+++ b/ext/asio/asio/ssl/basic_context.hpp
@@ -1,9 +1,9 @@
//
-// basic_context.hpp
-// ~~~~~~~~~~~~~~~~~
+// ssl/basic_context.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,17 +16,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <string>
#include <boost/noncopyable.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/ssl/context_base.hpp"
-#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace ssl {
diff --git a/ext/asio/asio/ssl/context.hpp b/ext/asio/asio/ssl/context.hpp
index d53882a..7aedc4d 100644
--- a/ext/asio/asio/ssl/context.hpp
+++ b/ext/asio/asio/ssl/context.hpp
@@ -1,9 +1,9 @@
//
-// context.hpp
-// ~~~~~~~~~~~
+// ssl/context.hpp
+// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,8 +16,7 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/ssl/basic_context.hpp"
#include "asio/ssl/context_service.hpp"
@@ -30,6 +29,4 @@ typedef basic_context<context_service> context;
} // namespace ssl
} // namespace asio
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_SSL_CONTEXT_HPP
diff --git a/ext/asio/asio/ssl/context_base.hpp b/ext/asio/asio/ssl/context_base.hpp
index a0700ca..7636bed 100755
--- a/ext/asio/asio/ssl/context_base.hpp
+++ b/ext/asio/asio/ssl/context_base.hpp
@@ -1,8 +1,8 @@
//
-// context_base.hpp
-// ~~~~~~~~~~~~~~~~
+// ssl/context_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
+#include "asio/detail/config.hpp"
#include <boost/detail/workaround.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/ssl/detail/openssl_types.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace ssl {
diff --git a/ext/asio/asio/ssl/context_service.hpp b/ext/asio/asio/ssl/context_service.hpp
index e9cfef7..766bbde 100755
--- a/ext/asio/asio/ssl/context_service.hpp
+++ b/ext/asio/asio/ssl/context_service.hpp
@@ -1,9 +1,9 @@
//
-// context_service.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// ssl/context_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,19 +16,16 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <string>
#include <boost/noncopyable.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/error.hpp"
#include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
#include "asio/ssl/context_base.hpp"
#include "asio/ssl/detail/openssl_context_service.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace ssl {
diff --git a/ext/asio/asio/ssl/detail/openssl_context_service.hpp b/ext/asio/asio/ssl/detail/openssl_context_service.hpp
index a3d4fdb..7019542 100755
--- a/ext/asio/asio/ssl/detail/openssl_context_service.hpp
+++ b/ext/asio/asio/ssl/detail/openssl_context_service.hpp
@@ -1,9 +1,9 @@
//
-// openssl_context_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// ssl/detail/openssl_context_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,21 +16,18 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstring>
#include <string>
#include <boost/function.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/error.hpp"
#include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
#include "asio/ssl/context_base.hpp"
#include "asio/ssl/detail/openssl_init.hpp"
#include "asio/ssl/detail/openssl_types.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace ssl {
namespace detail {
diff --git a/ext/asio/asio/ssl/detail/openssl_init.hpp b/ext/asio/asio/ssl/detail/openssl_init.hpp
index 9ecbb78..dcda50f 100755
--- a/ext/asio/asio/ssl/detail/openssl_init.hpp
+++ b/ext/asio/asio/ssl/detail/openssl_init.hpp
@@ -1,9 +1,9 @@
//
-// openssl_init.hpp
-// ~~~~~~~~~~~~~~~~
+// ssl/detail/openssl_init.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,20 +16,17 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstring>
#include <vector>
#include <boost/assert.hpp>
-#include <boost/config.hpp>
#include <boost/shared_ptr.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/detail/mutex.hpp"
#include "asio/detail/tss_ptr.hpp"
#include "asio/ssl/detail/openssl_types.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
namespace ssl {
namespace detail {
diff --git a/ext/asio/asio/ssl/detail/openssl_operation.hpp b/ext/asio/asio/ssl/detail/openssl_operation.hpp
index 8d237e3..c5119a5 100755
--- a/ext/asio/asio/ssl/detail/openssl_operation.hpp
+++ b/ext/asio/asio/ssl/detail/openssl_operation.hpp
@@ -1,6 +1,6 @@
//
-// openssl_operation.hpp
-// ~~~~~~~~~~~~~~~~~~~~~
+// ssl/detail/openssl_operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
//
@@ -15,19 +15,19 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <boost/function.hpp>
#include <boost/assert.hpp>
#include <boost/bind.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/buffer.hpp"
-#include "asio/placeholders.hpp"
-#include "asio/write.hpp"
#include "asio/detail/socket_ops.hpp"
+#include "asio/placeholders.hpp"
#include "asio/ssl/detail/openssl_types.hpp"
+#include "asio/strand.hpp"
+#include "asio/system_error.hpp"
+#include "asio/write.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace ssl {
@@ -160,7 +160,7 @@ public:
if (error_code == SSL_ERROR_SSL)
return handler_(asio::error_code(
- error_code, asio::error::get_ssl_category()), rc);
+ sys_error_code, asio::error::get_ssl_category()), rc);
bool is_read_needed = (error_code == SSL_ERROR_WANT_READ);
bool is_write_needed = (error_code == SSL_ERROR_WANT_WRITE ||
@@ -195,7 +195,7 @@ public:
else
{
return handler_(asio::error_code(
- error_code, asio::error::get_ssl_category()), rc);
+ sys_error_code, asio::error::get_ssl_category()), rc);
}
}
diff --git a/ext/asio/asio/ssl/detail/openssl_stream_service.hpp b/ext/asio/asio/ssl/detail/openssl_stream_service.hpp
index d7bb457..aef9e7e 100644
--- a/ext/asio/asio/ssl/detail/openssl_stream_service.hpp
+++ b/ext/asio/asio/ssl/detail/openssl_stream_service.hpp
@@ -1,9 +1,9 @@
//
-// stream_service.hpp
-// ~~~~~~~~~~~~~~~~~~
+// ssl/detail/stream_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,9 +16,7 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
#include <climits>
#include <memory>
@@ -26,17 +24,17 @@
#include <boost/noncopyable.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/buffer_sequence_adapter.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
-#include "asio/strand.hpp"
-#include "asio/detail/buffer_sequence_adapter.hpp"
-#include "asio/detail/service_base.hpp"
#include "asio/ssl/basic_context.hpp"
#include "asio/ssl/stream_base.hpp"
#include "asio/ssl/detail/openssl_operation.hpp"
#include "asio/ssl/detail/openssl_types.hpp"
+#include "asio/strand.hpp"
+#include "asio/system_error.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace ssl {
@@ -92,7 +90,7 @@ private:
: base_handler<Stream>(io_service)
, handler_(handler)
{
- set_func(boost::bind(
+ this->set_func(boost::bind(
&io_handler<Stream, Handler>::handler_impl,
this, boost::arg<1>(), boost::arg<2>() ));
}
@@ -116,7 +114,7 @@ private:
: base_handler<Stream>(io_service)
, handler_(handler)
{
- set_func(boost::bind(
+ this->set_func(boost::bind(
&handshake_handler<Stream, Handler>::handler_impl,
this, boost::arg<1>(), boost::arg<2>() ));
}
@@ -141,7 +139,7 @@ private:
: base_handler<Stream>(io_service),
handler_(handler)
{
- set_func(boost::bind(
+ this->set_func(boost::bind(
&shutdown_handler<Stream, Handler>::handler_impl,
this, boost::arg<1>(), boost::arg<2>() ));
}
diff --git a/ext/asio/asio/ssl/detail/openssl_types.hpp b/ext/asio/asio/ssl/detail/openssl_types.hpp
index c697d74..fbe1b74 100755
--- a/ext/asio/asio/ssl/detail/openssl_types.hpp
+++ b/ext/asio/asio/ssl/detail/openssl_types.hpp
@@ -1,8 +1,8 @@
//
-// openssl_types.hpp
-// ~~~~~~~~~~~~~~~~~
+// ssl/detail/openssl_types.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/socket_types.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <openssl/conf.h>
#include <openssl/ssl.h>
#include <openssl/engine.h>
#include <openssl/err.h>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/detail/pop_options.hpp"
+#include "asio/detail/socket_types.hpp"
#endif // ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP
diff --git a/ext/asio/asio/ssl/stream.hpp b/ext/asio/asio/ssl/stream.hpp
index e800e62..e16cd9a 100644
--- a/ext/asio/asio/ssl/stream.hpp
+++ b/ext/asio/asio/ssl/stream.hpp
@@ -1,9 +1,9 @@
//
-// stream.hpp
-// ~~~~~~~~~~
+// ssl/stream.hpp
+// ~~~~~~~~~~~~~~
//
// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,20 +16,17 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
#include <boost/noncopyable.hpp>
#include <boost/type_traits/remove_reference.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/ssl/basic_context.hpp"
#include "asio/ssl/stream_base.hpp"
#include "asio/ssl/stream_service.hpp"
-#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace ssl {
diff --git a/ext/asio/asio/ssl/stream_base.hpp b/ext/asio/asio/ssl/stream_base.hpp
index d62d386..e1cc0d7 100755
--- a/ext/asio/asio/ssl/stream_base.hpp
+++ b/ext/asio/asio/ssl/stream_base.hpp
@@ -1,8 +1,8 @@
//
-// stream_base.hpp
-// ~~~~~~~~~~~~~~~
+// ssl/stream_base.hpp
+// ~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+#include <boost/detail/workaround.hpp>
#include "asio/detail/push_options.hpp"
-#include <boost/detail/workaround.hpp>
-#include "asio/detail/pop_options.hpp"
namespace asio {
namespace ssl {
diff --git a/ext/asio/asio/ssl/stream_service.hpp b/ext/asio/asio/ssl/stream_service.hpp
index 1f1e6ad..d99548e 100644
--- a/ext/asio/asio/ssl/stream_service.hpp
+++ b/ext/asio/asio/ssl/stream_service.hpp
@@ -1,9 +1,9 @@
//
-// stream_service.hpp
-// ~~~~~~~~~~~~~~~~~~
+// ssl/stream_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
-// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,19 +16,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
#include <boost/noncopyable.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
#include "asio/ssl/basic_context.hpp"
-#include "asio/ssl/stream_base.hpp"
#include "asio/ssl/detail/openssl_stream_service.hpp"
+#include "asio/ssl/stream_base.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace ssl {
diff --git a/ext/asio/asio/strand.hpp b/ext/asio/asio/strand.hpp
index 6b32151..5a526f2 100644
--- a/ext/asio/asio/strand.hpp
+++ b/ext/asio/asio/strand.hpp
@@ -2,7 +2,7 @@
// strand.hpp
// ~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/io_service.hpp"
+#include "asio/detail/config.hpp"
#include "asio/detail/strand_service.hpp"
#include "asio/detail/wrapped_handler.hpp"
+#include "asio/io_service.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
diff --git a/ext/asio/asio/stream_socket_service.hpp b/ext/asio/asio/stream_socket_service.hpp
index 1c4935c..553719e 100644
--- a/ext/asio/asio/stream_socket_service.hpp
+++ b/ext/asio/asio/stream_socket_service.hpp
@@ -2,7 +2,7 @@
// stream_socket_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/error.hpp"
#include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_socket_service.hpp"
@@ -32,6 +26,8 @@
# include "asio/detail/reactive_socket_service.hpp"
#endif
+#include "asio/detail/push_options.hpp"
+
namespace asio {
/// Default service implementation for a stream socket.
diff --git a/ext/asio/asio/streambuf.hpp b/ext/asio/asio/streambuf.hpp
index 665155b..553da3e 100644
--- a/ext/asio/asio/streambuf.hpp
+++ b/ext/asio/asio/streambuf.hpp
@@ -2,7 +2,7 @@
// streambuf.hpp
// ~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,12 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/basic_streambuf.hpp"
+#include "asio/detail/config.hpp"
#if !defined(BOOST_NO_IOSTREAM)
+#include "asio/basic_streambuf.hpp"
+
namespace asio {
/// Typedef for the typical usage of basic_streambuf.
@@ -30,6 +30,4 @@ typedef basic_streambuf<> streambuf;
#endif // !defined(BOOST_NO_IOSTREAM)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_STREAMBUF_HPP
diff --git a/ext/asio/asio/system_error.hpp b/ext/asio/asio/system_error.hpp
index e704b3f..60580a1 100644
--- a/ext/asio/asio/system_error.hpp
+++ b/ext/asio/asio/system_error.hpp
@@ -2,7 +2,7 @@
// system_error.hpp
// ~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,18 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
+#include "asio/detail/config.hpp"
#include <boost/scoped_ptr.hpp>
#include <cerrno>
#include <exception>
#include <string>
-#include "asio/detail/pop_options.hpp"
-
#include "asio/error_code.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
/// The system_error class is used to represent system conditions that
diff --git a/ext/asio/asio/thread.hpp b/ext/asio/asio/thread.hpp
index 9e578bc..070483e 100644
--- a/ext/asio/asio/thread.hpp
+++ b/ext/asio/asio/thread.hpp
@@ -2,7 +2,7 @@
// thread.hpp
// ~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
+#include "asio/detail/config.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/thread.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
/// A simple abstraction for starting threads.
diff --git a/ext/asio/asio/time_traits.hpp b/ext/asio/asio/time_traits.hpp
index 0371373..3b2899b 100644
--- a/ext/asio/asio/time_traits.hpp
+++ b/ext/asio/asio/time_traits.hpp
@@ -2,7 +2,7 @@
// time_traits.hpp
// ~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,14 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
#include "asio/detail/socket_types.hpp" // Must come before posix_time.
#include "asio/detail/push_options.hpp"
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "asio/detail/pop_options.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
/// Time traits suitable for use with the deadline timer.
diff --git a/ext/asio/asio/version.hpp b/ext/asio/asio/version.hpp
index 198f508..0402d0e 100644
--- a/ext/asio/asio/version.hpp
+++ b/ext/asio/asio/version.hpp
@@ -2,7 +2,7 @@
// version.hpp
// ~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -18,6 +18,6 @@
// ASIO_VERSION % 100 is the sub-minor version
// ASIO_VERSION / 100 % 1000 is the minor version
// ASIO_VERSION / 100000 is the major version
-#define ASIO_VERSION 100405 // 1.4.5
+#define ASIO_VERSION 100408 // 1.4.8
#endif // ASIO_VERSION_HPP
diff --git a/ext/asio/asio/windows/basic_handle.hpp b/ext/asio/asio/windows/basic_handle.hpp
index 8c2ee60..f87b3db 100644
--- a/ext/asio/asio/windows/basic_handle.hpp
+++ b/ext/asio/asio/windows/basic_handle.hpp
@@ -1,8 +1,8 @@
//
-// basic_handle.hpp
-// ~~~~~~~~~~~~~~~~
+// windows/basic_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,15 +15,17 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
+ || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
+ || defined(GENERATING_DOCUMENTATION)
#include "asio/basic_io_object.hpp"
-#include "asio/error.hpp"
#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace windows {
@@ -222,4 +224,8 @@ protected:
#include "asio/detail/pop_options.hpp"
+#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
+ // || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
+ // || defined(GENERATING_DOCUMENTATION)
+
#endif // ASIO_WINDOWS_BASIC_HANDLE_HPP
diff --git a/ext/asio/asio/windows/basic_random_access_handle.hpp b/ext/asio/asio/windows/basic_random_access_handle.hpp
index 2e6b994..056b175 100644
--- a/ext/asio/asio/windows/basic_random_access_handle.hpp
+++ b/ext/asio/asio/windows/basic_random_access_handle.hpp
@@ -1,8 +1,8 @@
//
-// basic_random_access_handle.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// windows/basic_random_access_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,20 +15,18 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
-#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
+ || defined(GENERATING_DOCUMENTATION)
+#include <cstddef>
+#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/windows/basic_handle.hpp"
#include "asio/windows/random_access_handle_service.hpp"
-#include "asio/detail/throw_error.hpp"
-#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
- || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace windows {
@@ -312,9 +310,9 @@ public:
} // namespace windows
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP
diff --git a/ext/asio/asio/windows/basic_stream_handle.hpp b/ext/asio/asio/windows/basic_stream_handle.hpp
index 48e7153..28149f4 100644
--- a/ext/asio/asio/windows/basic_stream_handle.hpp
+++ b/ext/asio/asio/windows/basic_stream_handle.hpp
@@ -1,8 +1,8 @@
//
-// basic_stream_handle.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~
+// windows/basic_stream_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,20 +15,18 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
-#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
+ || defined(GENERATING_DOCUMENTATION)
+#include <cstddef>
#include "asio/error.hpp"
#include "asio/windows/basic_handle.hpp"
#include "asio/windows/stream_handle_service.hpp"
#include "asio/detail/throw_error.hpp"
-#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
- || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace windows {
@@ -294,9 +292,9 @@ public:
} // namespace windows
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP
diff --git a/ext/asio/asio/windows/overlapped_ptr.hpp b/ext/asio/asio/windows/overlapped_ptr.hpp
index 087170b..8f4d628 100644
--- a/ext/asio/asio/windows/overlapped_ptr.hpp
+++ b/ext/asio/asio/windows/overlapped_ptr.hpp
@@ -1,8 +1,8 @@
//
-// overlapped_ptr.hpp
-// ~~~~~~~~~~~~~~~~~~
+// windows/overlapped_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,20 +15,16 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR) \
+ || defined(GENERATING_DOCUMENTATION)
-#include "asio/io_service.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/win_iocp_overlapped_ptr.hpp"
+#include "asio/io_service.hpp"
-#if !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR)
-# if defined(ASIO_HAS_IOCP)
-# define ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1
-# endif // defined(ASIO_HAS_IOCP)
-#endif // !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR)
-
-#if defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR) \
- || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace windows {
@@ -110,9 +106,9 @@ private:
} // namespace windows
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#endif // defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_WINDOWS_OVERLAPPED_PTR_HPP
diff --git a/ext/asio/asio/windows/random_access_handle.hpp b/ext/asio/asio/windows/random_access_handle.hpp
index 6e5dd7b..727b084 100644
--- a/ext/asio/asio/windows/random_access_handle.hpp
+++ b/ext/asio/asio/windows/random_access_handle.hpp
@@ -1,8 +1,8 @@
//
-// random_access_handle.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~
+// windows/random_access_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,13 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/windows/basic_random_access_handle.hpp"
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
|| defined(GENERATING_DOCUMENTATION)
+#include "asio/windows/basic_random_access_handle.hpp"
+
namespace asio {
namespace windows {
@@ -34,6 +34,4 @@ typedef basic_random_access_handle<> random_access_handle;
#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_HPP
diff --git a/ext/asio/asio/windows/random_access_handle_service.hpp b/ext/asio/asio/windows/random_access_handle_service.hpp
index 2e579f8..b2c05ef 100644
--- a/ext/asio/asio/windows/random_access_handle_service.hpp
+++ b/ext/asio/asio/windows/random_access_handle_service.hpp
@@ -1,8 +1,8 @@
//
-// random_access_handle_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// windows/random_access_handle_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,27 +15,19 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
+ || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include <boost/cstdint.hpp>
-#include "asio/detail/pop_options.hpp"
-
+#include "asio/detail/win_iocp_handle_service.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
-#include "asio/detail/win_iocp_handle_service.hpp"
-#if !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)
-# if defined(ASIO_HAS_IOCP)
-# define ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1
-# endif // defined(ASIO_HAS_IOCP)
-#endif // !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)
-
-#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
- || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace windows {
@@ -172,9 +164,9 @@ private:
} // namespace windows
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_SERVICE_HPP
diff --git a/ext/asio/asio/windows/stream_handle.hpp b/ext/asio/asio/windows/stream_handle.hpp
index d55dc31..802d157 100644
--- a/ext/asio/asio/windows/stream_handle.hpp
+++ b/ext/asio/asio/windows/stream_handle.hpp
@@ -1,8 +1,8 @@
//
-// stream_handle.hpp
-// ~~~~~~~~~~~~~~~~~~
+// windows/stream_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,13 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/windows/basic_stream_handle.hpp"
+#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
|| defined(GENERATING_DOCUMENTATION)
+#include "asio/windows/basic_stream_handle.hpp"
+
namespace asio {
namespace windows {
@@ -34,6 +34,4 @@ typedef basic_stream_handle<> stream_handle;
#endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_WINDOWS_STREAM_HANDLE_HPP
diff --git a/ext/asio/asio/windows/stream_handle_service.hpp b/ext/asio/asio/windows/stream_handle_service.hpp
index 75eff60..816cfe5 100644
--- a/ext/asio/asio/windows/stream_handle_service.hpp
+++ b/ext/asio/asio/windows/stream_handle_service.hpp
@@ -1,8 +1,8 @@
//
-// stream_handle_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~
+// windows/stream_handle_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,26 +15,17 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
-#include "asio/detail/push_options.hpp"
-#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
+#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
+ || defined(GENERATING_DOCUMENTATION)
+#include <cstddef>
+#include "asio/detail/win_iocp_handle_service.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
-#include "asio/detail/service_base.hpp"
-#include "asio/detail/win_iocp_handle_service.hpp"
-#if !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)
-# if defined(ASIO_HAS_IOCP)
-# define ASIO_HAS_WINDOWS_STREAM_HANDLE 1
-# endif // defined(ASIO_HAS_IOCP)
-#endif // !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)
-
-#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
- || defined(GENERATING_DOCUMENTATION)
+#include "asio/detail/push_options.hpp"
namespace asio {
namespace windows {
@@ -170,9 +161,9 @@ private:
} // namespace windows
} // namespace asio
+#include "asio/detail/pop_options.hpp"
+
#endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
// || defined(GENERATING_DOCUMENTATION)
-#include "asio/detail/pop_options.hpp"
-
#endif // ASIO_WINDOWS_STREAM_HANDLE_SERVICE_HPP
diff --git a/ext/asio/asio/write.hpp b/ext/asio/asio/write.hpp
index 2b188cd..bd90ecb 100644
--- a/ext/asio/asio/write.hpp
+++ b/ext/asio/asio/write.hpp
@@ -2,7 +2,7 @@
// write.hpp
// ~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,16 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/basic_streambuf.hpp"
+#include "asio/basic_streambuf_fwd.hpp"
#include "asio/error.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
/**
@@ -533,8 +530,8 @@ void async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b,
} // namespace asio
-#include "asio/impl/write.ipp"
-
#include "asio/detail/pop_options.hpp"
+#include "asio/impl/write.hpp"
+
#endif // ASIO_WRITE_HPP
diff --git a/ext/asio/asio/write_at.hpp b/ext/asio/asio/write_at.hpp
index 5690bcf..37d0cbb 100644
--- a/ext/asio/asio/write_at.hpp
+++ b/ext/asio/asio/write_at.hpp
@@ -2,7 +2,7 @@
// write_at.hpp
// ~~~~~~~~~~~~
//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,17 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include "asio/detail/push_options.hpp"
-
-#include "asio/detail/push_options.hpp"
+#include "asio/detail/config.hpp"
#include <cstddef>
-#include <boost/config.hpp>
#include <boost/cstdint.hpp>
-#include "asio/detail/pop_options.hpp"
-
-#include "asio/basic_streambuf.hpp"
+#include "asio/basic_streambuf_fwd.hpp"
#include "asio/error.hpp"
+#include "asio/detail/push_options.hpp"
+
namespace asio {
/**
@@ -556,8 +553,8 @@ void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset,
} // namespace asio
-#include "asio/impl/write_at.ipp"
-
#include "asio/detail/pop_options.hpp"
+#include "asio/impl/write_at.hpp"
+
#endif // ASIO_WRITE_AT_HPP
diff --git a/src/bin/auth/main.cc b/src/bin/auth/main.cc
index a6db762..480c2f7 100644
--- a/src/bin/auth/main.cc
+++ b/src/bin/auth/main.cc
@@ -176,9 +176,15 @@ main(int argc, char* argv[]) {
// all initial configurations, but as a short term workaround we
// handle the traditional "database_file" setup by directly calling
// updateConfig().
+ // if server load configure failed, we won't exit, give user second chance
+ // to correct the configure.
auth_server->setConfigSession(config_session);
- configureAuthServer(*auth_server, config_session->getFullConfig());
- auth_server->updateConfig(ElementPtr());
+ try {
+ configureAuthServer(*auth_server, config_session->getFullConfig());
+ auth_server->updateConfig(ElementPtr());
+ } catch (const AuthConfigError& ex) {
+ cout << "[bin10-auth] Server load config failed:" << ex.what() << endl;
+ }
if (uid != NULL) {
changeUser(uid);
diff --git a/src/bin/auth/statistics.cc b/src/bin/auth/statistics.cc
index e68793c..415aa14 100644
--- a/src/bin/auth/statistics.cc
+++ b/src/bin/auth/statistics.cc
@@ -91,10 +91,6 @@ AuthCountersImpl::submitStatistics() const {
const int seq =
statistics_session_->group_sendmsg(statistics_element, "Stats");
isc::data::ConstElementPtr env, answer;
- if (verbose_mode_) {
- std::cerr << "[b10-auth] "
- << "send statistics data" << std::endl;
- }
// TODO: parse and check response from statistics module
// currently it just returns empty message
statistics_session_->group_recvmsg(env, answer, false, seq);
diff --git a/src/bin/auth/tests/Makefile.am b/src/bin/auth/tests/Makefile.am
index 026dde3..050373a 100644
--- a/src/bin/auth/tests/Makefile.am
+++ b/src/bin/auth/tests/Makefile.am
@@ -18,7 +18,6 @@ CLEANFILES = *.gcno *.gcda
TESTS =
if HAVE_GTEST
-BUILT_SOURCES = ../spec_config.h
TESTS += run_unittests
run_unittests_SOURCES = $(top_srcdir)/src/lib/dns/tests/unittest_util.h
run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
@@ -28,7 +27,6 @@ run_unittests_SOURCES += ../change_user.h ../change_user.cc
run_unittests_SOURCES += ../auth_config.h ../auth_config.cc
run_unittests_SOURCES += ../command.h ../command.cc
run_unittests_SOURCES += ../common.h ../common.cc
-run_unittests_SOURCES += ../spec_config.h
run_unittests_SOURCES += ../statistics.h ../statistics.cc
run_unittests_SOURCES += auth_srv_unittest.cc
run_unittests_SOURCES += config_unittest.cc
diff --git a/src/bin/bind10/bind10.py.in b/src/bin/bind10/bind10.py.in
index e6504e1..648d085 100755
--- a/src/bin/bind10/bind10.py.in
+++ b/src/bin/bind10/bind10.py.in
@@ -546,6 +546,9 @@ class BoB:
def start_stats(self, c_channel_env):
self.start_simple("b10-stats", c_channel_env)
+ def start_stats_httpd(self, c_channel_env):
+ self.start_simple("b10-stats-httpd", c_channel_env)
+
def start_cmdctl(self, c_channel_env):
"""
Starts the command control process
@@ -595,6 +598,7 @@ class BoB:
# ... and finally start the remaining processes
self.start_stats(c_channel_env)
+ self.start_stats_httpd(c_channel_env)
self.start_cmdctl(c_channel_env)
def startup(self):
@@ -644,6 +648,7 @@ class BoB:
self.cc_session.group_sendmsg(cmd, "Xfrin", "Xfrin")
self.cc_session.group_sendmsg(cmd, "Zonemgr", "Zonemgr")
self.cc_session.group_sendmsg(cmd, "Stats", "Stats")
+ self.cc_session.group_sendmsg(cmd, "StatsHttpd", "StatsHttpd")
def stop_process(self, process, recipient):
"""
diff --git a/src/bin/bind10/run_bind10.sh.in b/src/bin/bind10/run_bind10.sh.in
old mode 100644
new mode 100755
index edc01fe..89301bd
--- a/src/bin/bind10/run_bind10.sh.in
+++ b/src/bin/bind10/run_bind10.sh.in
@@ -23,14 +23,14 @@ BIND10_PATH=@abs_top_builddir@/src/bin/bind10
PATH=@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/resolver:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/stats:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:@abs_top_builddir@/src/bin/zonemgr:$PATH
export PATH
-PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/xfr/.libs:@abs_top_builddir@/src/lib/log/.libs
+PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/xfr/.libs:@abs_top_builddir@/src/lib/log/.libs:@abs_top_builddir@/src/lib/util/io/.libs
export PYTHONPATH
# If necessary (rare cases), explicitly specify paths to dynamic libraries
# required by loadable python modules.
SET_ENV_LIBRARY_PATH=@SET_ENV_LIBRARY_PATH@
if test $SET_ENV_LIBRARY_PATH = yes; then
- @ENV_LIBRARY_PATH@=@abs_top_builddir@/src/lib/dns/.libs:@abs_top_builddir@/src/lib/exceptions/.libs:$@ENV_LIBRARY_PATH@
+ @ENV_LIBRARY_PATH@=@abs_top_builddir@/src/lib/dns/.libs:@abs_top_builddir@/src/lib/cryptolink/.libs:@abs_top_builddir@/src/lib/util/.libs:@abs_top_builddir@/src/lib/util/io/.libs:@abs_top_builddir@/src/lib/exceptions/.libs:$@ENV_LIBRARY_PATH@
export @ENV_LIBRARY_PATH@
fi
diff --git a/src/bin/bind10/tests/bind10_test.py.in b/src/bin/bind10/tests/bind10_test.py.in
index 8432c89..2ffe2b4 100644
--- a/src/bin/bind10/tests/bind10_test.py.in
+++ b/src/bin/bind10/tests/bind10_test.py.in
@@ -183,6 +183,7 @@ class MockBob(BoB):
self.xfrin = False
self.zonemgr = False
self.stats = False
+ self.stats_httpd = False
self.cmdctl = False
self.c_channel_env = {}
self.processes = { }
@@ -236,10 +237,15 @@ class MockBob(BoB):
self.processes[10] = ProcessInfo('b10-stats', ['/bin/false'])
self.processes[10].pid = 10
+ def start_stats_httpd(self, c_channel_env):
+ self.stats_httpd = True
+ self.processes[11] = ProcessInfo('b10-stats-httpd', ['/bin/false'])
+ self.processes[11].pid = 11
+
def start_cmdctl(self, c_channel_env):
self.cmdctl = True
- self.processes[11] = ProcessInfo('b10-cmdctl', ['/bin/false'])
- self.processes[11].pid = 11
+ self.processes[12] = ProcessInfo('b10-cmdctl', ['/bin/false'])
+ self.processes[12].pid = 12
# We don't really use all of these stop_ methods. But it might turn out
# someone would add some stop_ method to BoB and we want that one overriden
@@ -289,9 +295,14 @@ class MockBob(BoB):
del self.processes[10]
self.stats = False
+ def stop_stats_httpd(self):
+ if self.stats_httpd:
+ del self.processes[11]
+ self.stats_httpd = False
+
def stop_cmdctl(self):
if self.cmdctl:
- del self.processes[11]
+ del self.processes[12]
self.cmdctl = False
class TestStartStopProcessesBob(unittest.TestCase):
@@ -316,6 +327,7 @@ class TestStartStopProcessesBob(unittest.TestCase):
self.assertEqual(bob.xfrin, auth)
self.assertEqual(bob.zonemgr, auth)
self.assertEqual(bob.stats, core)
+ self.assertEqual(bob.stats_httpd, core)
self.assertEqual(bob.cmdctl, core)
def check_preconditions(self, bob):
@@ -544,7 +556,8 @@ class TestBossCmd(unittest.TestCase):
[8, 'b10-xfrin'],
[9, 'b10-zonemgr'],
[10, 'b10-stats'],
- [11, 'b10-cmdctl']]
+ [11, 'b10-stats-httpd'],
+ [12, 'b10-cmdctl']]
self.assertEqual(answer, {'result': [0, processes]})
class TestParseArgs(unittest.TestCase):
diff --git a/src/bin/cfgmgr/b10-cfgmgr.py.in b/src/bin/cfgmgr/b10-cfgmgr.py.in
index 607a6dc..d91dfca 100755
--- a/src/bin/cfgmgr/b10-cfgmgr.py.in
+++ b/src/bin/cfgmgr/b10-cfgmgr.py.in
@@ -18,6 +18,7 @@
import sys; sys.path.append ('@@PYTHONPATH@@')
from isc.config.cfgmgr import ConfigManager, ConfigManagerDataReadError
+import bind10_config
from isc.cc import SessionError
import isc.util.process
import signal
@@ -28,24 +29,10 @@ import os.path
isc.util.process.rename()
-# If B10_FROM_SOURCE is set in the environment, we use data files
-# from a directory relative to the value of that variable, or, if defined,
-# relative to the value of B10_FROM_SOURCE_LOCALSTATEDIR. Otherwise
-# we use the ones installed on the system.
-# B10_FROM_SOURCE_LOCALSTATEDIR is specifically intended to be used for
-# tests where we want to use variuos types of configuration within the test
-# environment. (We may want to make it even more generic so that the path is
-# passed from the boss process)
-if "B10_FROM_SOURCE" in os.environ:
- if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
- DATA_PATH = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"]
- else:
- DATA_PATH = os.environ["B10_FROM_SOURCE"]
- PLUGIN_PATH = [DATA_PATH + '/src/bin/cfgmgr/plugins']
-else:
- PREFIX = "@prefix@"
- DATA_PATH = "@localstatedir@/@PACKAGE@".replace("${prefix}", PREFIX)
- PLUGIN_PATHS = ["@prefix@/share/@PACKAGE@/config_plugins"]
+# Import some paths from our configuration
+DATA_PATH = bind10_config.DATA_PATH
+PLUGIN_PATHS = bind10_config.PLUGIN_PATHS
+PREFIX = bind10_config.PREFIX
DEFAULT_CONFIG_FILE = "b10-config.db"
cm = None
diff --git a/src/bin/cfgmgr/plugins/Makefile.am b/src/bin/cfgmgr/plugins/Makefile.am
index 952fde6..d83c2bb 100644
--- a/src/bin/cfgmgr/plugins/Makefile.am
+++ b/src/bin/cfgmgr/plugins/Makefile.am
@@ -1 +1,5 @@
-EXTRA_DIST = README
+SUBDIRS = tests
+EXTRA_DIST = README tsig_keys.py tsig_keys.spec
+
+config_plugindir = @prefix@/share/@PACKAGE@/config_plugins
+config_plugin_DATA = tsig_keys.py tsig_keys.spec
diff --git a/src/bin/cfgmgr/plugins/tests/Makefile.am b/src/bin/cfgmgr/plugins/tests/Makefile.am
new file mode 100644
index 0000000..896dab7
--- /dev/null
+++ b/src/bin/cfgmgr/plugins/tests/Makefile.am
@@ -0,0 +1,27 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
+PYTESTS = tsig_keys_test.py
+
+EXTRA_DIST = $(PYTESTS)
+
+# If necessary (rare cases), explicitly specify paths to dynamic libraries
+# required by loadable python modules.
+LIBRARY_PATH_PLACEHOLDER =
+if SET_ENV_LIBRARY_PATH
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs
+endif
+
+# test using command-line arguments, so use check-local target instead of TESTS
+check-local:
+if ENABLE_PYTHON_COVERAGE
+ touch $(abs_top_srcdir)/.coverage
+ rm -f .coverage
+ ${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
+ for pytest in $(PYTESTS) ; do \
+ echo Running test: $$pytest ; \
+ env B10_TEST_PLUGIN_DIR=$(abs_srcdir)/..:$(abs_builddir)/.. \
+ env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/cfgmgr:$(abs_top_builddir)/src/lib/dns/python/.libs \
+ $(LIBRARY_PATH_PLACEHOLDER) \
+ $(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
+ done
+
diff --git a/src/bin/cfgmgr/plugins/tests/tsig_keys_test.py b/src/bin/cfgmgr/plugins/tests/tsig_keys_test.py
new file mode 100644
index 0000000..be2921c
--- /dev/null
+++ b/src/bin/cfgmgr/plugins/tests/tsig_keys_test.py
@@ -0,0 +1,103 @@
+# Copyright (C) 2011 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+# Make sure we can load the module, put it into path
+import sys
+import os
+sys.path.extend(os.environ["B10_TEST_PLUGIN_DIR"].split(':'))
+
+import tsig_keys
+import unittest
+import isc.config.module_spec
+
+class TSigKeysTest(unittest.TestCase):
+ def test_load(self):
+ """
+ Checks the entry point returns the correct values.
+ """
+ (spec, check) = tsig_keys.load()
+ # It returns the checking function
+ self.assertEqual(check, tsig_keys.check)
+ # The plugin stores it's spec
+ self.assertEqual(spec, tsig_keys.spec)
+
+ def test_spec(self):
+ """
+ Checks the spec is looking sane (doesn't do really deep check here).
+ """
+ spec = tsig_keys.spec
+ # In python, we don't generally check the type of something, because
+ # of the duck typing.
+ # But this is unittest, so we check it does what we intend and
+ # supplying that's behaving the same but is different is not our
+ # intention
+ self.assertTrue(isinstance(spec, isc.config.module_spec.ModuleSpec))
+ # Correct name
+ self.assertEqual("tsig_keys", spec.get_module_name())
+ # There are no commands, nobody would handle them anyway
+ self.assertEqual([], spec.get_commands_spec())
+ # There's some nonempty configuration
+ self.assertNotEqual({}, spec.get_config_spec())
+
+ def test_missing_keys(self):
+ """
+ Test that missing keys doesn't kill us. There are just no keys there.
+ """
+ self.assertEqual(None, tsig_keys.check({}))
+
+ def test_data_empty(self):
+ """Check we accept valid config with empty set of tsig keys."""
+ self.assertEqual(None, tsig_keys.check({'keys': []}))
+
+ def test_keys_valid(self):
+ """
+ Check we accept some valid keys (we don't check all the algorithms,
+ that's the job of isc.dns.TSIGKey).
+ """
+ self.assertEqual(None, tsig_keys.check({'keys':
+ ['testkey:QklORCAxMCBpcyBjb29sCg==',
+ 'test.key:QklORCAxMCBpcyBjb29sCg==:hmac-sha1']}))
+
+ def test_keys_same_name(self):
+ """
+ Test we reject when we have multiple keys with the same name.
+ """
+ self.assertEqual("Multiple TSIG keys with name 'test.key.'",
+ tsig_keys.check({'keys':
+ ['test.key:QklORCAxMCBpcyBjb29sCg==',
+ 'test.key:b3RoZXIK']}))
+
+ def test_invalid_key(self):
+ """
+ Test we reject invalid key.
+ """
+ self.assertEqual("TSIG: Invalid TSIG key string: invalid.key",
+ tsig_keys.check({'keys': ['invalid.key']}))
+ self.assertEqual(
+ "TSIG: attempt to decode a value not in base64 char set",
+ tsig_keys.check({'keys': ['invalid.key:123']}))
+
+ def test_bad_format(self):
+ """
+ Test we fail on bad format. We don't really care much how here, though,
+ as this should not get in trough config manager anyway.
+ """
+ self.assertNotEqual(None, tsig_keys.check({'bad_name': {}}))
+ self.assertNotEqual(None, tsig_keys.check({'keys': 'not_list'}))
+ self.assertNotEqual(None, tsig_keys.check({'keys': 42}))
+ self.assertNotEqual(None, tsig_keys.check({'keys': {}}))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/src/bin/cfgmgr/plugins/tsig_keys.py b/src/bin/cfgmgr/plugins/tsig_keys.py
new file mode 100644
index 0000000..d57e645
--- /dev/null
+++ b/src/bin/cfgmgr/plugins/tsig_keys.py
@@ -0,0 +1,50 @@
+# Copyright (C) 2011 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+# This is the plugin for tsig_keys configuration section. The TSIG keyring
+# lives there (eg. all the shared secrets, with some exceptions where there
+# are some TSIG keys elsewhere, but these should be removed soon). We do
+# sanity checking of user configuration here, simply by trying to construct
+# all the keys here.
+
+from isc.config.module_spec import module_spec_from_file
+from isc.util.file import path_search
+from pydnspp import TSIGKey, InvalidParameter
+from bind10_config import PLUGIN_PATHS
+spec = module_spec_from_file(path_search('tsig_keys.spec', PLUGIN_PATHS))
+
+def check(config):
+ # Check the data layout first
+ errors=[]
+ if not spec.validate_config(False, config, errors):
+ return ' '.join(errors)
+ # Get the list of keys, if any
+ keys = config.get('keys', [])
+ # Run through them, check they can be constructed and there are no
+ # duplicates
+ keyNames = set()
+ for key in keys:
+ try:
+ name = str(TSIGKey(key).get_key_name())
+ except InvalidParameter as e:
+ return "TSIG: " + str(e)
+ if name in keyNames:
+ return "Multiple TSIG keys with name '" + name + "'"
+ keyNames.add(name)
+ # No error found, so let's assume it's OK
+ return None
+
+def load():
+ return (spec, check)
diff --git a/src/bin/cfgmgr/plugins/tsig_keys.spec b/src/bin/cfgmgr/plugins/tsig_keys.spec
new file mode 100644
index 0000000..e558dd2
--- /dev/null
+++ b/src/bin/cfgmgr/plugins/tsig_keys.spec
@@ -0,0 +1,21 @@
+{
+ "module_spec": {
+ "module_name": "tsig_keys",
+ "module_description": "The TSIG keyring is stored here",
+ "config_data": [
+ {
+ "item_name": "keys",
+ "item_type": "list",
+ "item_optional": false,
+ "item_default": [],
+ "list_item_spec": {
+ "item_name": "key",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": ""
+ }
+ }
+ ],
+ "commands": []
+ }
+}
diff --git a/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in b/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in
index 37cd0f5..ea5fc8b 100644
--- a/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in
+++ b/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in
@@ -20,6 +20,7 @@
import unittest
import os
import sys
+import bind10_config
from isc.testutils.parse_args import OptsError, TestOptParser
class MyConfigManager:
@@ -110,6 +111,7 @@ class TestConfigManagerStartup(unittest.TestCase):
env_var = os.environ["B10_FROM_SOURCE"]
os.environ["B10_FROM_SOURCE"] = tmp_env_var
+ bind10_config.reload()
b = __import__("b10-cfgmgr", globals(), locals())
b.PLUGIN_PATH = [] # It's enough to test plugins in one test
b.ConfigManager = MyConfigManager
@@ -117,6 +119,7 @@ class TestConfigManagerStartup(unittest.TestCase):
if env_var != None:
os.environ["B10_FROM_SOURCE"] = env_var
+ bind10_config.reload()
sys.modules.pop("b10-cfgmgr")
diff --git a/src/bin/host/Makefile.am b/src/bin/host/Makefile.am
index 0758cb9..ec34ce7 100644
--- a/src/bin/host/Makefile.am
+++ b/src/bin/host/Makefile.am
@@ -10,17 +10,20 @@ endif
CLEANFILES = *.gcno *.gcda
-bin_PROGRAMS = host
-host_SOURCES = host.cc
-host_LDADD = $(top_builddir)/src/lib/dns/libdns++.la
-host_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-
-#man_MANS = host.1
-#EXTRA_DIST = $(man_MANS) host.xml
-#
-#if ENABLE_MAN
-#
-#host.1: host.xml
-# xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/host.xml
-#
-#endif
+bin_PROGRAMS = b10-host
+b10_host_SOURCES = host.cc
+b10_host_LDADD = $(top_builddir)/src/lib/dns/libdns++.la
+b10_host_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+
+man_MANS = b10-host.1
+EXTRA_DIST = $(man_MANS) b10-host.xml
+
+.PHONY: man
+if ENABLE_MAN
+
+man: b10-host.1
+
+b10-host.1: b10-host.xml
+ xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-host.xml
+
+endif
diff --git a/src/bin/host/README b/src/bin/host/README
index d493a95..5cc4068 100644
--- a/src/bin/host/README
+++ b/src/bin/host/README
@@ -1,14 +1,4 @@
-Rewriting host(1) in C++ from scratch using BIND 10's libdns.
+Rewriting host(1) in C++ from scratch using BIND 10's libdns++.
-Initial functionality:
-
- host _hostname_ [server]
-
-By default, it looks up the A, AAAA, and MX record sets.
-
-Note it doesn't use /etc/resolv.conf at this time.
-The default name server used is 127.0.0.1.
-
- -r disable recursive processing
- -t _type_ specific query type
- -v enable verbose output mode, including elapsed time
+The bugs and incompatibilities are listed in the manual page
+and in the source code.
diff --git a/src/bin/host/b10-host.1 b/src/bin/host/b10-host.1
new file mode 100644
index 0000000..ed0068b
--- /dev/null
+++ b/src/bin/host/b10-host.1
@@ -0,0 +1,122 @@
+'\" t
+.\" Title: b10-host
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
+.\" Date: May 4, 2011
+.\" Manual: BIND10
+.\" Source: BIND10
+.\" Language: English
+.\"
+.TH "B10\-HOST" "1" "May 4, 2011" "BIND10" "BIND10"
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+b10-host \- DNS lookup utility
+.SH "SYNOPSIS"
+.HP \w'\fBb10\-host\fR\ 'u
+\fBb10\-host\fR [\fB\-a\fR] [\fB\-c\ \fR\fB\fIclass\fR\fR] [\fB\-d\fR] [\fB\-p\ \fR\fB\fIport\fR\fR] [\fB\-r\fR] [\fB\-t\ \fR\fB\fItype\fR\fR] [\fB\-v\fR] [\fIname\fR] [\fB\fIserver\fR\fR]
+.SH "DESCRIPTION"
+.PP
+The
+\fBb10\-host\fR
+utility does DNS lookups\&. Its initial goal is to be a
+\fBhost\fR(1)
+clone, but also add a few features useful for BIND 10 development testing\&.
+.PP
+By default, it looks up the A, AAAA, and MX record sets for the
+\fIname\fR\&. Optionally, you may select a name server to query against by adding the
+\fIserver\fR
+argument\&.
+.SH "OPTIONS"
+.PP
+The arguments are as follows:
+.PP
+\fB\-a\fR
+.RS 4
+Enable verbose mode and do a query for type ANY\&. (If the
+\fB\-t\fR
+option is also set, then the ANY query is not done, but it still uses verbose mode\&.)
+.RE
+.PP
+\fB\-c \fR\fB\fIclass\fR\fR
+.RS 4
+Define the class for the query\&. The default is IN (Internet)\&.
+.RE
+.PP
+\fB\-d\fR
+.RS 4
+Enable verbose output mode, including elapsed time in milliseconds\&. Verbose mode shows the header, question, answer, authority, and additional sections (if provided)\&. (Same as
+\fB\-v\fR\&.)
+.RE
+.PP
+\fB\-p \fR\fB\fIport\fR\fR
+.RS 4
+Select an alternative port for the query\&. This may be a number or a service name\&. The default is 53 (domain)\&. This is not a standard feature of
+\fBhost\fR(1)\&.
+.RE
+.PP
+\fB\-r\fR
+.RS 4
+Disable recursive processing by not setting the Recursion Desired flag in the query\&.
+.RE
+.PP
+\fB\-t \fR\fB\fItype\fR\fR
+.RS 4
+Select a specific resource record type for the query\&. By default, it looks up the A, AAAA, and MX record sets\&.
+(This overrides the
+\fB\-a\fR
+option\&.)
+.RE
+.PP
+\fB\-v\fR
+.RS 4
+Same as
+\fB\-d\fR
+option\&.
+.RE
+.SH "COMPATIBILITY / BUGS"
+.PP
+
+\fBb10\-host\fR
+does not do reverse lookups by default yet (by detecting if name is a IPv4 or IPv6 address)\&.
+.PP
+Unknown
+\fB\-c\fR
+class or
+\fB\-t\fR
+type causes
+\fBb10\-host\fR
+to Abort\&.
+.PP
+Not all types are supported yet for formatting\&. Not all switches are supported yet\&.
+.PP
+It doesn\'t use
+/etc/resolv\&.conf
+at this time\&. The default name server used is 127\&.0\&.0\&.1\&.
+.PP
+
+\fBb10\-host\fR
+does not do reverse lookups by default yet (by detecting if name is a IPv4 or IPv6 address)\&.
+.PP
+
+\fB\-p\fR
+is not a standard feature\&.
+.SH "HISTORY"
+.PP
+The C++ version of
+\fBb10\-host\fR
+was started in October 2009 by Jeremy C\&. Reed of ISC\&. Its usage and output were based on the standard
+\fBhost\fR
+command\&.
+.SH "COPYRIGHT"
+.br
+Copyright \(co 2011 Internet Systems Consortium, Inc. ("ISC")
+.br
diff --git a/src/bin/host/b10-host.xml b/src/bin/host/b10-host.xml
new file mode 100644
index 0000000..7da07dd
--- /dev/null
+++ b/src/bin/host/b10-host.xml
@@ -0,0 +1,201 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "—">]>
+<!--
+ - Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id$ -->
+<refentry>
+
+ <refentryinfo>
+ <date>May 4, 2011</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>b10-host</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo>BIND10</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>b10-host</refname>
+ <refpurpose>DNS lookup utility</refpurpose>
+ </refnamediv>
+
+ <docinfo>
+ <copyright>
+ <year>2011</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ </docinfo>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>b10-host</command>
+ <arg><option>-a</option></arg>
+ <arg><option>-c <replaceable>class</replaceable></option></arg>
+ <arg><option>-d</option></arg>
+ <arg><option>-p <replaceable>port</replaceable></option></arg>
+ <arg><option>-r</option></arg>
+ <arg><option>-t <replaceable>type</replaceable></option></arg>
+ <arg><option>-v</option></arg>
+ <arg><replaceable>name</replaceable></arg>
+ <arg><option><replaceable>server</replaceable></option></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>DESCRIPTION</title>
+ <para>
+ The <command>b10-host</command> utility does DNS lookups.
+ Its initial goal is to be a
+ <citerefentry><refentrytitle>host</refentrytitle>
+ <manvolnum>1</manvolnum></citerefentry>
+ clone, but also add a few features useful for BIND 10 development
+ testing.
+ </para>
+
+ <para>
+ By default, it looks up the A, AAAA, and MX record sets for the
+ <replaceable>name</replaceable>.
+ Optionally, you may select a name server to query against by adding
+ the <replaceable>server</replaceable> argument.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>OPTIONS</title>
+
+ <para>The arguments are as follows:</para>
+
+ <variablelist>
+
+ <varlistentry>
+ <term><option>-a</option></term>
+ <listitem><para>
+ Enable verbose mode and do a query for type ANY.
+ (If the <option>-t</option> option is also set, then the
+ ANY query is not done, but it still uses verbose mode.)
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-c <replaceable>class</replaceable></option></term>
+ <listitem><para>
+ Define the class for the query.
+ The default is IN (Internet).
+<!-- TODO: bug if class is unknown causes seg fault and possible core dump -->
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-d</option></term>
+ <listitem><para>
+ Enable verbose output mode, including elapsed time in
+ milliseconds.
+ Verbose mode shows the header, question, answer, authority,
+ and additional sections (if provided).
+ (Same as <option>-v</option>.)
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-p <replaceable>port</replaceable></option></term>
+ <listitem><para>
+ Select an alternative port for the query.
+ This may be a number or a service name.
+ The default is 53 (domain).
+ This is not a standard feature of
+ <citerefentry><refentrytitle>host</refentrytitle>
+ <manvolnum>1</manvolnum></citerefentry>.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-r</option></term>
+ <listitem><para>
+ Disable recursive processing by not setting the
+ Recursion Desired flag in the query.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-t <replaceable>type</replaceable></option></term>
+ <listitem><para>
+ Select a specific resource record type for the query.
+ By default, it looks up the A, AAAA, and MX record sets.
+<!-- TODO: bug if class is unknown causes seg fault and possible core dump -->
+ (This overrides the <option>-a</option> option.)
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-v</option></term>
+ <listitem><para>
+ Same as <option>-d</option> option.
+ </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+
+ </refsect1>
+
+ <refsect1>
+ <title>COMPATIBILITY / BUGS</title>
+ <para>
+ <command>b10-host</command> does not do reverse lookups by
+ default yet (by detecting if name is a IPv4 or IPv6 address).
+ </para>
+
+ <para>
+ Unknown <option>-c</option> class or <option>-t</option> type
+ causes <command>b10-host</command> to Abort.
+ </para>
+
+ <para>
+ Not all types are supported yet for formatting.
+ Not all switches are supported yet.
+ </para>
+
+ <para>
+ It doesn't use <filename>/etc/resolv.conf</filename> at this time.
+ The default name server used is 127.0.0.1.
+ </para>
+
+ <para>
+ <command>b10-host</command> does not do reverse lookups by
+ default yet (by detecting if name is a IPv4 or IPv6 address).
+ </para>
+
+ <para>
+ <option>-p</option> is not a standard feature.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>HISTORY</title>
+ <para>
+ The C++ version of <command>b10-host</command> was started in
+ October 2009 by Jeremy C. Reed of ISC.
+ Its usage and output were based on the standard <command>host</command>
+ command.
+ </para>
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/src/bin/host/host.cc b/src/bin/host/host.cc
index 973509e..f0df0c8 100644
--- a/src/bin/host/host.cc
+++ b/src/bin/host/host.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2011 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
@@ -44,13 +44,16 @@ namespace {
char* dns_type = NULL; // not set, so A, AAAA, MX
const char* server = "127.0.0.1";
const char* server_port = "53";
-int verbose = 0;
-int first_time = 1;
-bool recursive_bit = true;
+const char* dns_class = "IN";
+bool verbose = false;
+bool dns_any = false;
+int first_time = 1;
+bool recursive_bit = true;
struct timeval before_time, after_time;
int
-host_lookup(const char* const name, const char* const type) {
+host_lookup(const char* const name, const char* const dns_class,
+ const char* const type, bool any) {
Message msg(Message::RENDER);
@@ -64,8 +67,8 @@ host_lookup(const char* const name, const char* const type) {
}
msg.addQuestion(Question(Name(name),
- RRClass::IN(), // IN class only for now
- RRType(type))); // if NULL then:
+ RRClass(dns_class),
+ any ? RRType::ANY() : RRType(type))); // if NULL then:
OutputBuffer obuffer(512);
MessageRenderer renderer(obuffer);
@@ -127,18 +130,29 @@ host_lookup(const char* const name, const char* const type) {
rmsg.fromWire(ibuffer);
if (!verbose) {
+ string description = "";
for (RRsetIterator it =
rmsg.beginSection(Message::SECTION_ANSWER);
it != rmsg.endSection(Message::SECTION_ANSWER);
++it) {
- if ((*it)->getType() != RRType::A()) {
- continue;
+
+ if ((*it)->getType() == RRType::A()) {
+ description = "has address";
+ }
+ else if ((*it)->getType() == RRType::AAAA()) {
+ description = "has IPv6 address";
+ }
+ else if ((*it)->getType() == RRType::MX()) {
+ description = "mail is handled by";
+ }
+ else if ((*it)->getType() == RRType::TXT()) {
+ description = "descriptive text";
}
RdataIteratorPtr rit = (*it)->getRdataIterator();
for (; !rit->isLast(); rit->next()) {
// instead of using my name, maybe use returned label?
- cout << name << " has address " <<
+ cout << name << " " << description << " " <<
(*rit).getCurrent().toText() << endl;
}
}
@@ -159,13 +173,19 @@ host_lookup(const char* const name, const char* const type) {
// TODO: if NXDOMAIN, host(1) doesn't show HEADER
// Host hsdjkfhksjhdfkj not found: 3(NXDOMAIN)
- // TODO: figure out the new libdns way to test if NXDOMAIN
+ // TODO: test if NXDOMAIN
std::cout << "Received " << cc <<
" bytes in " << elapsed_time << " ms\n";
// TODO: " bytes from 127.0.0.1#53 in 0 ms
} //verbose
+/*
+TODO: handle InvalidRRClass
+TODO: handle invalid type exception
+ } catch (InvalidType ivt) {
+ std::cerr << "invalid type:" << ivt.what();
+*/
} catch (const exception& ex) {
std::cerr << "parse failed for " <<
string(name) << "/" << type << ": " << ex.what() << std::endl;
@@ -184,26 +204,36 @@ int
main(int argc, char* argv[]) {
int c;
- while ((c = getopt(argc, argv, "p:rt:v")) != -1)
+ while ((c = getopt(argc, argv, "ac:dp:rt:v")) != -1)
switch (c) {
+ case 'a':
+ dns_any = true;
+ verbose = true;
+ break;
+ case 'c':
+ dns_class = optarg;
+ break;
+ // p for port is a non-standard switch
+ case 'p':
+ server_port = optarg;
+ break;
case 'r':
recursive_bit = false;
break;
case 't':
dns_type = optarg;
break;
- case 'p':
- server_port = optarg;
- break;
+ case 'd':
+ // drop through to v, because debug and verbose are equivalent
case 'v':
- verbose = 1;
+ verbose = true;
break;
}
argc -= optind;
argv += optind;
if (argc < 1) {
- cout << "Usage: host [-vr] [-t type] hostname [server]\n";
+ cout << "Usage: host [-adprv] [-c class] [-t type] hostname [server]\n";
exit(1);
}
@@ -212,12 +242,13 @@ main(int argc, char* argv[]) {
}
if (dns_type == NULL) {
- host_lookup(argv[0], "A");
+ host_lookup(argv[0], dns_class, "A", dns_any);
// TODO: don't do next if A doesn't exist
- host_lookup(argv[0], "AAAA");
- host_lookup(argv[0], "MX");
+ host_lookup(argv[0], dns_class, "AAAA", dns_any);
+ host_lookup(argv[0], dns_class, "MX", dns_any);
} else {
- host_lookup(argv[0], dns_type);
+ // -t overrides -a, regardless of order
+ host_lookup(argv[0], dns_class, dns_type, false);
}
return (0);
}
diff --git a/src/bin/msgq/tests/msgq_test.py b/src/bin/msgq/tests/msgq_test.py
index f926845..26878f7 100644
--- a/src/bin/msgq/tests/msgq_test.py
+++ b/src/bin/msgq/tests/msgq_test.py
@@ -132,7 +132,7 @@ class SendNonblock(unittest.TestCase):
task()
# If we got here, then everything worked well and in time
# In that case, we terminate successfully
- sys.exit(0) # needs exit code
+ os._exit(0) # needs exit code
else:
(pid, status) = os.waitpid(task_pid, 0)
self.assertEqual(0, status,
diff --git a/src/bin/resolver/resolver.cc b/src/bin/resolver/resolver.cc
index 591e214..e43b48e 100644
--- a/src/bin/resolver/resolver.cc
+++ b/src/bin/resolver/resolver.cc
@@ -144,7 +144,7 @@ public:
void resolve(const isc::dns::QuestionPtr& question,
const isc::resolve::ResolverInterface::CallbackPtr& callback);
- void processNormalQuery(const Question& question,
+ void processNormalQuery(ConstMessagePtr query_message,
MessagePtr answer_message,
OutputBufferPtr buffer,
DNSServer* server);
@@ -468,7 +468,7 @@ Resolver::processMessage(const IOMessage& io_message,
// The RecursiveQuery object will post the "resume" event to the
// DNSServer when an answer arrives, so we don't have to do it now.
sendAnswer = false;
- impl_->processNormalQuery(*question, answer_message,
+ impl_->processNormalQuery(query_message, answer_message,
buffer, server);
}
}
@@ -486,13 +486,19 @@ ResolverImpl::resolve(const QuestionPtr& question,
}
void
-ResolverImpl::processNormalQuery(const Question& question,
+ResolverImpl::processNormalQuery(ConstMessagePtr query_message,
MessagePtr answer_message,
OutputBufferPtr buffer,
DNSServer* server)
{
- dlog("Processing normal query");
- rec_query_->resolve(question, answer_message, buffer, server);
+ if (upstream_.empty()) {
+ dlog("Processing normal query");
+ ConstQuestionPtr question = *query_message->beginQuestion();
+ rec_query_->resolve(*question, answer_message, buffer, server);
+ } else {
+ dlog("Processing forward query");
+ rec_query_->forward(query_message, answer_message, buffer, server);
+ }
}
ConstElementPtr
diff --git a/src/bin/resolver/response_scrubber.cc b/src/bin/resolver/response_scrubber.cc
index 93bd808..d35a96f 100644
--- a/src/bin/resolver/response_scrubber.cc
+++ b/src/bin/resolver/response_scrubber.cc
@@ -1,4 +1,3 @@
-
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
@@ -50,7 +49,7 @@ ResponseScrubber::Category ResponseScrubber::addressCheck(
unsigned int
ResponseScrubber::scrubSection(Message& message,
const vector<const Name*>& names,
- const NameComparisonResult::NameRelation connection,
+ const NameComparisonResult::NameRelation connection,
const Message::Section section)
{
unsigned int count = 0; // Count of RRsets removed
@@ -74,30 +73,32 @@ ResponseScrubber::scrubSection(Message& message,
// Start looking at the remaining entries in the section.
removed = false;
- for (; (i != message.endSection(section)) && (!removed); ++i) {
+ for (; i != message.endSection(section); ++i) {
// Loop through the list of names given and see if any are in the
// given relationship with the QNAME of this RRset
- bool nomatch = true;
+ bool match = false;
for (vector<const Name*>::const_iterator n = names.begin();
- ((n != names.end()) && nomatch); ++n) {
+ n != names.end(); ++n) {
NameComparisonResult result = (*i)->getName().compare(**n);
NameComparisonResult::NameRelation relationship =
result.getRelation();
if ((relationship == NameComparisonResult::EQUAL) ||
(relationship == connection)) {
-
+
// RRset in the specified relationship, so a match has
// been found
- nomatch = false;
+ match = true;
+ break;
}
}
// Remove the RRset if there was no match to one of the given names.
- if (nomatch) {
+ if (!match) {
message.removeRRset(section, i);
++count; // One more RRset removed
removed = true; // Something was removed
+ break; // It invalidated the iterators, start again
} else {
// There was a match so this is one more entry we can skip next
@@ -107,7 +108,7 @@ ResponseScrubber::scrubSection(Message& message,
}
}
- return count;
+ return (count);
}
// Perform the scrubbing of all sections of the message.
@@ -126,7 +127,7 @@ ResponseScrubber::scrubAllSections(Message& message, const Name& bailiwick) {
count += scrubSection(message, bailiwick_names,
NameComparisonResult::SUBDOMAIN, Message::SECTION_ADDITIONAL);
- return count;
+ return (count);
}
// Scrub across sections.
@@ -171,7 +172,6 @@ ResponseScrubber::scrubCrossSections(isc::dns::Message& message) {
// superdomain of the names in the question/answer section.
return (scrubSection(message, source,
NameComparisonResult::SUPERDOMAIN, Message::SECTION_AUTHORITY));
-
}
// Scrub a message
@@ -183,7 +183,7 @@ ResponseScrubber::scrub(const isc::dns::MessagePtr& message,
unsigned int sections_removed = scrubAllSections(*message, bailiwick);
sections_removed += scrubCrossSections(*message);
- return sections_removed;
+ return (sections_removed);
}
diff --git a/src/bin/stats/Makefile.am b/src/bin/stats/Makefile.am
index b173813..e4a4f92 100644
--- a/src/bin/stats/Makefile.am
+++ b/src/bin/stats/Makefile.am
@@ -2,35 +2,35 @@ SUBDIRS = tests
pkglibexecdir = $(libexecdir)/@PACKAGE@
-pkglibexec_SCRIPTS = b10-stats
-noinst_SCRIPTS = b10-stats_stub
+pkglibexec_SCRIPTS = b10-stats b10-stats-httpd
b10_statsdir = $(pkgdatadir)
-b10_stats_DATA = stats.spec
+b10_stats_DATA = stats.spec stats-httpd.spec stats-schema.spec
+b10_stats_DATA += stats-httpd-xml.tpl stats-httpd-xsd.tpl stats-httpd-xsl.tpl
-CLEANFILES = stats.spec b10-stats stats.pyc stats.pyo b10-stats_stub stats_stub.pyc stats_stub.pyo
+CLEANFILES = b10-stats stats.pyc
+CLEANFILES += b10-stats-httpd stats_httpd.pyc
-man_MANS = b10-stats.8
-EXTRA_DIST = $(man_MANS) b10-stats.xml
+man_MANS = b10-stats.8 b10-stats-httpd.8
+EXTRA_DIST = $(man_MANS) b10-stats.xml b10-stats-httpd.xml
+EXTRA_DIST += stats.spec stats-httpd.spec stats-schema.spec
+EXTRA_DIST += stats-httpd-xml.tpl stats-httpd-xsd.tpl stats-httpd-xsl.tpl
if ENABLE_MAN
b10-stats.8: b10-stats.xml
xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-stats.xml
-endif
+b10-stats-httpd.8: b10-stats-httpd.xml
+ xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-stats-httpd.xml
-stats.spec: stats.spec.pre
- $(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" stats.spec.pre >$@
+endif
# this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
b10-stats: stats.py
- $(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \
- -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" \
- -e "s|.*#@@REMOVED@@$$||" stats.py >$@
+ $(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" stats.py >$@
chmod a+x $@
-b10-stats_stub: stats_stub.py stats.py
- $(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \
- -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" stats_stub.py >$@
+b10-stats-httpd: stats_httpd.py
+ $(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" stats_httpd.py >$@
chmod a+x $@
diff --git a/src/bin/stats/b10-stats-httpd.8 b/src/bin/stats/b10-stats-httpd.8
new file mode 100644
index 0000000..ed4aafa
--- /dev/null
+++ b/src/bin/stats/b10-stats-httpd.8
@@ -0,0 +1,136 @@
+'\" t
+.\" Title: b10-stats-httpd
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
+.\" Date: Mar 8, 2011
+.\" Manual: BIND10
+.\" Source: BIND10
+.\" Language: English
+.\"
+.TH "B10\-STATS\-HTTPD" "8" "Mar 8, 2011" "BIND10" "BIND10"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+b10-stats-httpd \- BIND 10 HTTP server for HTTP/XML interface of statistics
+.SH "SYNOPSIS"
+.HP \w'\fBb10\-stats\-httpd\fR\ 'u
+\fBb10\-stats\-httpd\fR [\fB\-v\fR]| [\fB\-\-verbose\fR]
+.SH "DESCRIPTION"
+.PP
+
+\fBb10\-stats\-httpd\fR
+is a standalone HTTP server\&. It is intended for HTTP/XML interface for statistics module\&. This server process runs as a process separated from the process of the BIND 10 Stats daemon (\fBb10\-stats\fR)\&. The server is initially executed by the BIND 10 boss process (\fBbind10\fR) and eventually exited by it\&. The server is intended to be server requests by HTTP clients like web browsers and third\-party modules\&. When the server is asked, it requests BIND 10 statistics data from
+\fBb10\-stats\fR, and it sends the data back in Python dictionary format and the server converts it into XML format\&. The server sends it to the HTTP client\&. The server can send three types of document, which are XML (Extensible Markup Language), XSD (XML Schema definition) and XSL (Extensible Stylesheet Language)\&. The XML document is the statistics data of BIND 10, The XSD document is the data schema of it, and The XSL document is the style sheet to be showed for the web browsers\&. There is different URL for each document\&. But please note that you would be redirected to the URL of XML document if you request the URL of the root document\&. For example, you would be redirected to http://127\&.0\&.0\&.1:8000/bind10/statistics/xml if you request http://127\&.0\&.0\&.1:8000/\&. Please see the manual and the spec file of
+\fBb10\-stats\fR
+for more details about the items of BIND 10 statistics\&. The server uses CC session in communication with
+\fBb10\-stats\fR\&. CC session is provided by
+\fBb10\-msgq\fR
+which is started by
+\fBbind10\fR
+in advance\&. The server is implemented by HTTP\-server libraries included in Python 3\&. The server obtains the configuration from the config manager (\fBb10\-cfgmgr\fR) in runtime\&. Please see below for more details about this spec file and configuration of the server\&.
+.SH "OPTIONS"
+.PP
+The argument is as follow:
+.PP
+\fB\-v\fR, \fB\-\-verbose\fR
+.RS 4
+
+\fBb10\-stats\-httpd\fR
+switches to verbose mode and sends verbose messages to STDOUT\&.
+.RE
+.SH "FILES"
+.PP
+
+/usr/local/share/bind10\-devel/stats\-httpd\&.spec
+\(em the spec file of
+\fBb10\-stats\-httpd\fR\&. This file contains configurable settings of
+\fBb10\-stats\-httpd\fR\&. This setting can be configured in runtime via
+bindctl(1)\&. Please see the manual of
+bindctl(1)
+about how to configure the settings\&.
+.PP
+/usr/local/share/bind10\-devel/stats\-schema\&.spec
+\(em This is a spec file for data schema of of BIND 10 statistics\&. This schema cannot be configured via
+bindctl(1)\&.
+.PP
+
+/usr/local/share/bind10\-devel/stats\-httpd\-xml\&.tpl
+\(em the template file of XML document\&.
+.PP
+
+/usr/local/share/bind10\-devel/stats\-httpd\-xsd\&.tpl
+\(em the template file of XSD document\&.
+.PP
+
+/usr/local/share/bind10\-devel/stats\-httpd\-xsl\&.tpl
+\(em the template file of XSL document\&.
+.SH "CONFIGURATION AND COMMANDS"
+.PP
+The configurable setting in
+stats\-httpd\&.spec
+is:
+.PP
+\fIlisten_on\fR
+.RS 4
+a list of pairs of address and port for
+\fBb10\-stats\-httpd\fR
+to listen HTTP requests on\&. The pair consists of the
+\fIaddress\fR
+string and
+\fIport\fR
+number\&. The default setting is the list of address 127\&.0\&.0\&.1 port 8000\&. If the server is started by the default setting being left, for example, the URL for XML document is http://127\&.0\&.0\&.1:8000/bind10/statistics/xml\&. And also IPv6 addresses can be configured and they works in the runtime environment for dual stack\&. You can change the settings through
+bindctl(8)\&.
+.RE
+.PP
+The commands in
+stats\-httpd\&.spec
+are:
+.PP
+\fBstatus\fR
+.RS 4
+shows the status of
+\fBb10\-stats\-httpd\fR
+with its PID\&.
+.RE
+.PP
+\fBshutdown\fR
+.RS 4
+exits the
+\fBb10\-stats\-httpd\fR
+process\&. (Note that the BIND 10 boss process will restart this service\&.)
+.RE
+.SH "SEE ALSO"
+.PP
+
+\fBb10-stats\fR(8),
+\fBb10-msgq\fR(8),
+\fBb10-cfgmgr\fR(8),
+\fBbind10\fR(8),
+\fBbindctl\fR(1),
+BIND 10 Guide\&.
+.SH "HISTORY"
+.PP
+
+\fBb10\-stats\-httpd\fR
+was designed and implemented by Naoki Kambe of JPRS in Mar 2011\&.
+.SH "COPYRIGHT"
+.br
+Copyright \(co 2011 Internet Systems Consortium, Inc. ("ISC")
+.br
diff --git a/src/bin/stats/b10-stats-httpd.xml b/src/bin/stats/b10-stats-httpd.xml
new file mode 100644
index 0000000..34c704f
--- /dev/null
+++ b/src/bin/stats/b10-stats-httpd.xml
@@ -0,0 +1,221 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "—">]>
+<!--
+ - Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<refentry>
+
+ <refentryinfo>
+ <date>Mar 8, 2011</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>b10-stats-httpd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ <refmiscinfo>BIND10</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>b10-stats-httpd</refname>
+ <refpurpose>BIND 10 HTTP server for HTTP/XML interface of statistics</refpurpose>
+ </refnamediv>
+
+ <docinfo>
+ <copyright>
+ <year>2011</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ </docinfo>
+
+ <refsynopsisdiv>
+ <cmdsynopsis> <command>b10-stats-httpd</command>
+ <arg><option>-v</option></arg>|<arg><option>--verbose</option></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>DESCRIPTION</title>
+ <para>
+ <command>b10-stats-httpd</command> is a standalone HTTP server. It is
+ intended for HTTP/XML interface for statistics module. This server
+ process runs as a process separated from the process of the BIND 10 Stats
+ daemon (<command>b10-stats</command>). The server is initially executed
+ by the BIND 10 boss process (<command>bind10</command>) and eventually
+ exited by it. The server is intended to be server requests by HTTP
+ clients like web browsers and third-party modules. When the server is
+ asked, it requests BIND 10 statistics data from
+ <command>b10-stats</command>, and it sends the data back in Python
+ dictionary format and the server converts it into XML format. The server
+ sends it to the HTTP client. The server can send three types of document,
+ which are XML (Extensible Markup Language), XSD (XML Schema definition)
+ and XSL (Extensible Stylesheet Language). The XML document is the
+ statistics data of BIND 10, The XSD document is the data schema of it,
+ and The XSL document is the style sheet to be showed for the web
+ browsers. There is different URL for each document. But please note that
+ you would be redirected to the URL of XML document if you request the URL
+ of the root document. For example, you would be redirected to
+ http://127.0.0.1:8000/bind10/statistics/xml if you request
+ http://127.0.0.1:8000/. Please see the manual and the spec file
+ of <command>b10-stats</command> for more details about the items of BIND
+ 10 statistics. The server uses CC session in communication
+ with <command>b10-stats</command>. CC session is provided
+ by <command>b10-msgq</command> which is started
+ by <command>bind10</command> in advance. The server is implemented by
+ HTTP-server libraries included in Python 3. The server obtains the
+ configuration from the config manager (<command>b10-cfgmgr</command>) in
+ runtime. Please see below for more details about this spec file and
+ configuration of the server.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>OPTIONS</title>
+ <para>The argument is as follow:</para>
+ <variablelist>
+ <varlistentry>
+ <term><option>-v</option>, <option>--verbose</option></term>
+ <listitem>
+ <para>
+ <command>b10-stats-httpd</command> switches to verbose mode and sends
+ verbose messages to STDOUT.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>FILES</title>
+ <para>
+ <filename>/usr/local/share/bind10-devel/stats-httpd.spec</filename>
+ <!--TODO: The filename should be computed from prefix-->
+ — the spec file of <command>b10-stats-httpd</command>. This file
+ contains configurable settings
+ of <command>b10-stats-httpd</command>. This setting can be configured in
+ runtime via
+ <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>. Please
+ see the manual
+ of <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum> about
+ how to configure the settings.
+ </para>
+ <para><filename>/usr/local/share/bind10-devel/stats-schema.spec</filename>
+ <!--TODO: The filename should be computed from prefix-->
+ — This is a spec file for data schema of
+ of BIND 10 statistics. This schema cannot be configured
+ via <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>.
+ </para>
+ <para>
+ <filename>/usr/local/share/bind10-devel/stats-httpd-xml.tpl</filename>
+ <!--TODO: The filename should be computed from prefix-->
+ — the template file of XML document.
+ </para>
+ <para>
+ <filename>/usr/local/share/bind10-devel/stats-httpd-xsd.tpl</filename>
+ <!--TODO: The filename should be computed from prefix-->
+ — the template file of XSD document.
+ </para>
+ <para>
+ <filename>/usr/local/share/bind10-devel/stats-httpd-xsl.tpl</filename>
+ <!--TODO: The filename should be computed from prefix-->
+ — the template file of XSL document.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>CONFIGURATION AND COMMANDS</title>
+ <para>
+ The configurable setting in
+ <filename>stats-httpd.spec</filename> is:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><varname>listen_on</varname></term>
+ <listitem>
+ <para>
+ a list of pairs of address and port for
+ <command>b10-stats-httpd</command> to listen HTTP requests on. The
+ pair consists of the <varname>address</varname> string
+ and <varname>port</varname> number. The default setting is the list
+ of address 127.0.0.1 port 8000. If the server is started by the
+ default setting being left, for example, the URL for XML document
+ is http://127.0.0.1:8000/bind10/statistics/xml. And also IPv6
+ addresses can be configured and they works in the runtime
+ environment for dual stack. You can change the settings
+ through <refentrytitle>bindctl</refentrytitle><manvolnum>8</manvolnum>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ The commands in <filename>stats-httpd.spec</filename> are:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><command>status</command></term>
+ <listitem>
+ <para>
+ shows the status of <command>b10-stats-httpd</command> with its
+ PID.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><command>shutdown</command></term>
+ <listitem>
+ <para>
+ exits the <command>b10-stats-httpd</command> process. (Note that
+ the BIND 10 boss process will restart this service.)
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>b10-stats</refentrytitle><manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>
+ </citerefentry>,
+ <citetitle>BIND 10 Guide</citetitle>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>HISTORY</title>
+ <para>
+ <command>b10-stats-httpd</command> was designed and implemented by Naoki
+ Kambe of JPRS in Mar 2011.
+ </para>
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/src/bin/stats/b10-stats.8 b/src/bin/stats/b10-stats.8
index 5714234..f69e4d3 100644
--- a/src/bin/stats/b10-stats.8
+++ b/src/bin/stats/b10-stats.8
@@ -63,11 +63,17 @@ switches to verbose mode\&. It sends verbose messages to STDOUT\&.
.PP
/usr/local/share/bind10\-devel/stats\&.spec
\(em This is a spec file for
-\fBb10\-stats\fR\&. It contains definitions of statistics items of BIND 10 and commands received via
+\fBb10\-stats\fR\&. It contains commands for
+\fBb10\-stats\fR\&. They can be invoked via
+bindctl(1)\&.
+.PP
+/usr/local/share/bind10\-devel/stats\-schema\&.spec
+\(em This is a spec file for data schema of of BIND 10 statistics\&. This schema cannot be configured via
bindctl(1)\&.
.SH "SEE ALSO"
.PP
+\fBb10-stats-httpd\fR(8),
\fBbind10\fR(8),
\fBbindctl\fR(1),
\fBb10-auth\fR(8),
diff --git a/src/bin/stats/b10-stats.xml b/src/bin/stats/b10-stats.xml
index 7ec58dd..f0c472d 100644
--- a/src/bin/stats/b10-stats.xml
+++ b/src/bin/stats/b10-stats.xml
@@ -89,10 +89,17 @@
<refsect1>
<title>FILES</title>
<para><filename>/usr/local/share/bind10-devel/stats.spec</filename>
+ <!--TODO: The filename should be computed from prefix-->
— This is a spec file for <command>b10-stats</command>. It
- contains definitions of statistics items of BIND 10 and commands
- received via
- <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>.
+ contains commands for <command>b10-stats</command>. They can be
+ invoked
+ via <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>.
+ </para>
+ <para><filename>/usr/local/share/bind10-devel/stats-schema.spec</filename>
+ <!--TODO: The filename should be computed from prefix-->
+ — This is a spec file for data schema of
+ of BIND 10 statistics. This schema cannot be configured
+ via <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>.
</para>
</refsect1>
@@ -100,6 +107,9 @@
<title>SEE ALSO</title>
<para>
<citerefentry>
+ <refentrytitle>b10-stats-httpd</refentrytitle><manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
<refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
</citerefentry>,
<citerefentry>
diff --git a/src/bin/stats/run_b10-stats.sh.in b/src/bin/stats/run_b10-stats.sh.in
deleted file mode 100644
index 65b9737..0000000
--- a/src/bin/stats/run_b10-stats.sh.in
+++ /dev/null
@@ -1,33 +0,0 @@
-#! /bin/sh
-
-# Copyright (C) 2010 Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-PYTHON_EXEC=${PYTHON_EXEC:- at PYTHON@}
-export PYTHON_EXEC
-
-PYTHONPATH=@abs_top_builddir@/src/lib/python
-export PYTHONPATH
-
-BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
-export BIND10_MSGQ_SOCKET_FILE
-
-B10_FROM_BUILD=@abs_top_builddir@
-export B10_FROM_BUILD
-
-STATS_PATH=@abs_top_builddir@/src/bin/stats
-
-cd ${STATS_PATH}
-exec ${PYTHON_EXEC} -O b10-stats "$@"
diff --git a/src/bin/stats/run_b10-stats_stub.sh.in b/src/bin/stats/run_b10-stats_stub.sh.in
deleted file mode 100644
index 19ade5c..0000000
--- a/src/bin/stats/run_b10-stats_stub.sh.in
+++ /dev/null
@@ -1,33 +0,0 @@
-#! /bin/sh
-
-# Copyright (C) 2010 Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-PYTHON_EXEC=${PYTHON_EXEC:- at PYTHON@}
-export PYTHON_EXEC
-
-PYTHONPATH=@abs_top_builddir@/src/lib/python
-export PYTHONPATH
-
-B10_FROM_BUILD=@abs_top_srcdir@
-export B10_FROM_BUILD
-
-BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
-export BIND10_MSGQ_SOCKET_FILE
-
-STATS_PATH=@abs_top_builddir@/src/bin/stats
-
-cd ${STATS_PATH}
-exec ${PYTHON_EXEC} -O b10-stats_stub "$@"
diff --git a/src/bin/stats/stats-httpd-xml.tpl.in b/src/bin/stats/stats-httpd-xml.tpl.in
new file mode 100644
index 0000000..d5846ad
--- /dev/null
+++ b/src/bin/stats/stats-httpd-xml.tpl.in
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="$xsl_url_path"?>
+<!--
+ - Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<stats:stats_data version="1.0"
+ xmlns:stats="$xsd_namespace"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="$xsd_namespace $xsd_url_path">
+ $xml_string
+</stats:stats_data>
diff --git a/src/bin/stats/stats-httpd-xsd.tpl.in b/src/bin/stats/stats-httpd-xsd.tpl.in
new file mode 100644
index 0000000..6ad1280
--- /dev/null
+++ b/src/bin/stats/stats-httpd-xsd.tpl.in
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ - Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<schema targetNamespace="$xsd_namespace"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:stats="$xsd_namespace">
+ <annotation>
+ <documentation xml:lang="en">XML schema of the statistics
+ data in BIND 10</documentation>
+ </annotation>
+ <element name="stats_data">
+ <annotation>
+ <documentation>A set of statistics data</documentation>
+ </annotation>
+ <complexType>
+ $xsd_string
+ <attribute name="version" type="token" use="optional" default="1.0">
+ <annotation>
+ <documentation>Version number of syntax</documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+</schema>
diff --git a/src/bin/stats/stats-httpd-xsl.tpl.in b/src/bin/stats/stats-httpd-xsl.tpl.in
new file mode 100644
index 0000000..01ffdc6
--- /dev/null
+++ b/src/bin/stats/stats-httpd-xsl.tpl.in
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ - Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:stats="$xsd_namespace">
+ <xsl:output method="html" encoding="UTF-8"
+ doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"
+ doctype-system=" http://www.w3.org/TR/html4/loose.dtd " />
+ <xsl:template match="/">
+ <html lang="en">
+ <head>
+ <title>BIND 10 Statistics</title>
+ <style type="text/css"><![CDATA[
+table {
+ border: 1px #000000 solid;
+ border-collapse: collapse;
+}
+td, th {
+ padding: 3px 20px;
+ border: 1px #000000 solid;
+}
+td.title {
+ text-decoration:underline;
+}
+]]>
+ </style>
+ </head>
+ <body>
+ <h1>BIND 10 Statistics</h1>
+ <table>
+ <tr>
+ <th>Title</th>
+ <th>Value</th>
+ </tr>
+ <xsl:apply-templates />
+ </table>
+ </body>
+ </html>
+ </xsl:template>
+ $xsl_string
+</xsl:stylesheet>
diff --git a/src/bin/stats/stats-httpd.spec.in b/src/bin/stats/stats-httpd.spec.in
new file mode 100644
index 0000000..6307135
--- /dev/null
+++ b/src/bin/stats/stats-httpd.spec.in
@@ -0,0 +1,54 @@
+{
+ "module_spec": {
+ "module_name": "StatsHttpd",
+ "module_description": "Stats HTTP daemon",
+ "config_data": [
+ {
+ "item_name": "listen_on",
+ "item_type": "list",
+ "item_optional": false,
+ "item_default": [
+ {
+ "address": "127.0.0.1",
+ "port": 8000
+ }
+ ],
+ "list_item_spec": {
+ "item_name": "address",
+ "item_type": "map",
+ "item_optional": false,
+ "item_default": {},
+ "map_item_spec": [
+ {
+ "item_name": "address",
+ "item_type": "string",
+ "item_optional": true,
+ "item_default": "127.0.0.1",
+ "item_description": "listen-on address for HTTP"
+ },
+ {
+ "item_name": "port",
+ "item_type": "integer",
+ "item_optional": true,
+ "item_default": 8000,
+ "item_description": "listen-on port for HTTP"
+ }
+ ]
+ },
+ "item_description": "http listen-on address and port"
+ }
+ ],
+ "commands": [
+ {
+ "command_name": "status",
+ "command_description": "Status of the stats httpd",
+ "command_args": []
+ },
+ {
+ "command_name": "shutdown",
+ "command_description": "Shut down the stats httpd",
+ "command_args": []
+ }
+ ]
+ }
+}
diff --git a/src/bin/stats/stats-schema.spec.in b/src/bin/stats/stats-schema.spec.in
new file mode 100644
index 0000000..37e9c1a
--- /dev/null
+++ b/src/bin/stats/stats-schema.spec.in
@@ -0,0 +1,87 @@
+{
+ "module_spec": {
+ "module_name": "Stats",
+ "module_description": "Statistics data schema",
+ "config_data": [
+ {
+ "item_name": "report_time",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": "1970-01-01T00:00:00Z",
+ "item_title": "Report time",
+ "item_description": "A date time when stats module reports",
+ "item_format": "date-time"
+ },
+ {
+ "item_name": "bind10.boot_time",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": "1970-01-01T00:00:00Z",
+ "item_title": "bind10.BootTime",
+ "item_description": "A date time when bind10 process starts initially",
+ "item_format": "date-time"
+ },
+ {
+ "item_name": "stats.boot_time",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": "1970-01-01T00:00:00Z",
+ "item_title": "stats.BootTime",
+ "item_description": "A date time when the stats module starts initially or when the stats module restarts",
+ "item_format": "date-time"
+ },
+ {
+ "item_name": "stats.start_time",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": "1970-01-01T00:00:00Z",
+ "item_title": "stats.StartTime",
+ "item_description": "A date time when the stats module starts collecting data or resetting values last time",
+ "item_format": "date-time"
+ },
+ {
+ "item_name": "stats.last_update_time",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": "1970-01-01T00:00:00Z",
+ "item_title": "stats.LastUpdateTime",
+ "item_description": "The latest date time when the stats module receives from other modules like auth server or boss process and so on",
+ "item_format": "date-time"
+ },
+ {
+ "item_name": "stats.timestamp",
+ "item_type": "real",
+ "item_optional": false,
+ "item_default": 0.0,
+ "item_title": "stats.Timestamp",
+ "item_description": "A current time stamp since epoch time (1970-01-01T00:00:00Z)",
+ "item_format": "second"
+ },
+ {
+ "item_name": "stats.lname",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": "",
+ "item_title": "stats.LocalName",
+ "item_description": "A localname of stats module given via CC protocol"
+ },
+ {
+ "item_name": "auth.queries.tcp",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 0,
+ "item_title": "auth.queries.tcp",
+ "item_description": "A number of total query counts which all auth servers receive over TCP since they started initially"
+ },
+ {
+ "item_name": "auth.queries.udp",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 0,
+ "item_title": "auth.queries.udp",
+ "item_description": "A number of total query counts which all auth servers receive over UDP since they started initially"
+ }
+ ],
+ "commands": []
+ }
+}
diff --git a/src/bin/stats/stats.py.in b/src/bin/stats/stats.py.in
old mode 100755
new mode 100644
index eeddd92..969676e
--- a/src/bin/stats/stats.py.in
+++ b/src/bin/stats/stats.py.in
@@ -24,26 +24,24 @@ from optparse import OptionParser, OptionValueError
from collections import defaultdict
from isc.config.ccsession import ModuleCCSession, create_answer
from isc.cc import Session, SessionError
-# Note: Following lines are removed in b10-stats #@@REMOVED@@
-if __name__ == 'stats': #@@REMOVED@@
- try: #@@REMOVED@@
- from fake_time import time, strftime, gmtime #@@REMOVED@@
- except ImportError: #@@REMOVED@@
- pass #@@REMOVED@@
# for setproctitle
import isc.util.process
isc.util.process.rename()
-# If B10_FROM_BUILD is set in the environment, we use data files
+# If B10_FROM_SOURCE is set in the environment, we use data files
# from a directory relative to that, otherwise we use the ones
# installed on the system
-if "B10_FROM_BUILD" in os.environ:
- SPECFILE_LOCATION = os.environ["B10_FROM_BUILD"] + "/src/bin/stats/stats.spec"
+if "B10_FROM_SOURCE" in os.environ:
+ BASE_LOCATION = os.environ["B10_FROM_SOURCE"] + os.sep + \
+ "src" + os.sep + "bin" + os.sep + "stats"
else:
PREFIX = "@prefix@"
DATAROOTDIR = "@datarootdir@"
- SPECFILE_LOCATION = "@datadir@/@PACKAGE@/stats.spec".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
+ BASE_LOCATION = "@datadir@" + os.sep + "@PACKAGE@"
+ BASE_LOCATION = BASE_LOCATION.replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
+SPECFILE_LOCATION = BASE_LOCATION + os.sep + "stats.spec"
+SCHEMA_SPECFILE_LOCATION = BASE_LOCATION + os.sep + "stats-schema.spec"
class Singleton(type):
"""
@@ -182,8 +180,7 @@ class CCSessionListener(Listener):
self.session = self.subject.session = self.cc_session._session
# initialize internal data
- self.config_spec = self.cc_session.get_module_spec().get_config_spec()
- self.stats_spec = self.config_spec
+ self.stats_spec = isc.config.module_spec_from_file(SCHEMA_SPECFILE_LOCATION).get_config_spec()
self.stats_data = self.initialize_data(self.stats_spec)
# add event handler invoked via SessionSubject object
@@ -274,9 +271,6 @@ class CCSessionListener(Listener):
"""
handle set command
"""
- if self.verbose:
- sys.stdout.write("[b10-stats] 'set' command received, args: "+str(args)+"\n")
-
# 'args' must be dictionary type
self.stats_data.update(args['stats_data'])
diff --git a/src/bin/stats/stats.spec.in b/src/bin/stats/stats.spec.in
new file mode 100644
index 0000000..25f6b54
--- /dev/null
+++ b/src/bin/stats/stats.spec.in
@@ -0,0 +1,61 @@
+{
+ "module_spec": {
+ "module_name": "Stats",
+ "module_description": "Stats daemon",
+ "config_data": [],
+ "commands": [
+ {
+ "command_name": "status",
+ "command_description": "identify whether stats module is alive or not",
+ "command_args": []
+ },
+ {
+ "command_name": "show",
+ "command_description": "show the specified/all statistics data",
+ "command_args": [
+ {
+ "item_name": "stats_item_name",
+ "item_type": "string",
+ "item_optional": true,
+ "item_default": ""
+ }
+ ]
+ },
+ {
+ "command_name": "set",
+ "command_description": "set the value of specified name in statistics data",
+ "command_args": [
+ {
+ "item_name": "stats_data",
+ "item_type": "map",
+ "item_optional": false,
+ "item_default": {},
+ "map_item_spec": []
+ }
+ ]
+ },
+ {
+ "command_name": "remove",
+ "command_description": "remove the specified name from statistics data",
+ "command_args": [
+ {
+ "item_name": "stats_item_name",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": ""
+ }
+ ]
+ },
+ {
+ "command_name": "reset",
+ "command_description": "reset all statistics data to default values except for several constant names",
+ "command_args": []
+ },
+ {
+ "command_name": "shutdown",
+ "command_description": "Shut down the stats module",
+ "command_args": []
+ }
+ ]
+ }
+}
diff --git a/src/bin/stats/stats.spec.pre.in b/src/bin/stats/stats.spec.pre.in
deleted file mode 100644
index 6970250..0000000
--- a/src/bin/stats/stats.spec.pre.in
+++ /dev/null
@@ -1,140 +0,0 @@
-{
- "module_spec": {
- "module_name": "Stats",
- "module_description": "Stats daemon",
- "config_data": [
- {
- "item_name": "report_time",
- "item_type": "string",
- "item_optional": false,
- "item_default": "1970-01-01T00:00:00Z",
- "item_title": "Report time",
- "item_description": "A date time when stats module reports",
- "item_format": "date-time"
- },
- {
- "item_name": "bind10.boot_time",
- "item_type": "string",
- "item_optional": false,
- "item_default": "1970-01-01T00:00:00Z",
- "item_title": "stats.BootTime",
- "item_description": "A date time when bind10 process starts initially",
- "item_format": "date-time"
- },
- {
- "item_name": "stats.boot_time",
- "item_type": "string",
- "item_optional": false,
- "item_default": "1970-01-01T00:00:00Z",
- "item_title": "stats.BootTime",
- "item_description": "A date time when the stats module starts initially or when the stats module restarts",
- "item_format": "date-time"
- },
- {
- "item_name": "stats.start_time",
- "item_type": "string",
- "item_optional": false,
- "item_default": "1970-01-01T00:00:00Z",
- "item_title": "stats.StartTime",
- "item_description": "A date time when the stats module starts collecting data or resetting values last time",
- "item_format": "date-time"
- },
- {
- "item_name": "stats.last_update_time",
- "item_type": "string",
- "item_optional": false,
- "item_default": "1970-01-01T00:00:00Z",
- "item_title": "stats.LastUpdateTime",
- "item_description": "The latest date time when the stats module receives from other modules like auth server or boss process and so on",
- "item_format": "date-time"
- },
- {
- "item_name": "stats.timestamp",
- "item_type": "real",
- "item_optional": false,
- "item_default": 0.0,
- "item_title": "stats.Timestamp",
- "item_description": "A current time stamp since epoch time (1970-01-01T00:00:00Z)",
- "item_format": "second"
- },
- {
- "item_name": "stats.lname",
- "item_type": "string",
- "item_optional": false,
- "item_default": "",
- "item_title": "stats.LocalName",
- "item_description": "A localname of stats module given via CC protocol"
- },
- {
- "item_name": "auth.queries.tcp",
- "item_type": "integer",
- "item_optional": false,
- "item_default": 0,
- "item_title": "auth.queries.tcp",
- "item_description": "A number of total query counts which all auth servers receive over TCP since they started initially"
- },
- {
- "item_name": "auth.queries.udp",
- "item_type": "integer",
- "item_optional": false,
- "item_default": 0,
- "item_title": "auth.queries.udp",
- "item_description": "A number of total query counts which all auth servers receive over UDP since they started initially"
- }
- ],
- "commands": [
- {
- "command_name": "status",
- "command_description": "identify whether stats module is alive or not",
- "command_args": []
- },
- {
- "command_name": "show",
- "command_description": "show the specified/all statistics data",
- "command_args": [
- {
- "item_name": "stats_item_name",
- "item_type": "string",
- "item_optional": true,
- "item_default": ""
- }
- ]
- },
- {
- "command_name": "set",
- "command_description": "set the value of specified name in statistics data",
- "command_args": [
- {
- "item_name": "stats_data",
- "item_type": "map",
- "item_optional": false,
- "item_default": {},
- "map_item_spec": []
- }
- ]
- },
- {
- "command_name": "remove",
- "command_description": "remove the specified name from statistics data",
- "command_args": [
- {
- "item_name": "stats_item_name",
- "item_type": "string",
- "item_optional": false,
- "item_default": ""
- }
- ]
- },
- {
- "command_name": "reset",
- "command_description": "reset all statistics data to default values except for several constant names",
- "command_args": []
- },
- {
- "command_name": "shutdown",
- "command_description": "Shut down the stats module",
- "command_args": []
- }
- ]
- }
-}
diff --git a/src/bin/stats/stats_httpd.py.in b/src/bin/stats/stats_httpd.py.in
new file mode 100644
index 0000000..97e9c78
--- /dev/null
+++ b/src/bin/stats/stats_httpd.py.in
@@ -0,0 +1,485 @@
+#!@PYTHON@
+
+# Copyright (C) 2011 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""
+A standalone HTTP server for HTTP/XML interface of statistics in BIND 10
+
+"""
+import sys; sys.path.append ('@@PYTHONPATH@@')
+import os
+import time
+import errno
+import select
+from optparse import OptionParser, OptionValueError
+import http.server
+import socket
+import string
+import xml.etree.ElementTree
+
+import isc.cc
+import isc.config
+import isc.util.process
+
+# If B10_FROM_SOURCE is set in the environment, we use data files
+# from a directory relative to that, otherwise we use the ones
+# installed on the system
+if "B10_FROM_SOURCE" in os.environ:
+ BASE_LOCATION = os.environ["B10_FROM_SOURCE"] + os.sep + \
+ "src" + os.sep + "bin" + os.sep + "stats"
+else:
+ PREFIX = "@prefix@"
+ DATAROOTDIR = "@datarootdir@"
+ BASE_LOCATION = "@datadir@" + os.sep + "@PACKAGE@"
+ BASE_LOCATION = BASE_LOCATION.replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
+SPECFILE_LOCATION = BASE_LOCATION + os.sep + "stats-httpd.spec"
+SCHEMA_SPECFILE_LOCATION = BASE_LOCATION + os.sep + "stats-schema.spec"
+XML_TEMPLATE_LOCATION = BASE_LOCATION + os.sep + "stats-httpd-xml.tpl"
+XSD_TEMPLATE_LOCATION = BASE_LOCATION + os.sep + "stats-httpd-xsd.tpl"
+XSL_TEMPLATE_LOCATION = BASE_LOCATION + os.sep + "stats-httpd-xsl.tpl"
+
+# These variables are paths part of URL.
+# eg. "http://${address}" + XXX_URL_PATH
+XML_URL_PATH = '/bind10/statistics/xml'
+XSD_URL_PATH = '/bind10/statistics/xsd'
+XSL_URL_PATH = '/bind10/statistics/xsl'
+# TODO: This should be considered later.
+XSD_NAMESPACE = 'http://bind10.isc.org' + XSD_URL_PATH
+DEFAULT_CONFIG = dict(listen_on=[('127.0.0.1', 8000)])
+
+# Assign this process name
+isc.util.process.rename()
+
+class HttpHandler(http.server.BaseHTTPRequestHandler):
+ """HTTP handler class for HttpServer class. The class inhrits the super
+ class http.server.BaseHTTPRequestHandler. It implemets do_GET()
+ and do_HEAD() and orverrides log_message()"""
+ def do_GET(self):
+ body = self.send_head()
+ if body is not None:
+ self.wfile.write(body.encode())
+
+ def do_HEAD(self):
+ self.send_head()
+
+ def send_head(self):
+ try:
+ if self.path == XML_URL_PATH:
+ body = self.server.xml_handler()
+ elif self.path == XSD_URL_PATH:
+ body = self.server.xsd_handler()
+ elif self.path == XSL_URL_PATH:
+ body = self.server.xsl_handler()
+ else:
+ if self.path == '/' and 'Host' in self.headers.keys():
+ # redirect to XML URL only when requested with '/'
+ self.send_response(302)
+ self.send_header(
+ "Location",
+ "http://" + self.headers.get('Host') + XML_URL_PATH)
+ self.end_headers()
+ return None
+ else:
+ # Couldn't find HOST
+ self.send_error(404)
+ return None
+ except StatsHttpdError as err:
+ self.send_error(500)
+ if self.server.verbose:
+ self.server.log_writer(
+ "[b10-stats-httpd] %s\n" % err)
+ return None
+ else:
+ self.send_response(200)
+ self.send_header("Content-type", "text/xml")
+ self.send_header("Content-Length", len(body))
+ self.end_headers()
+ return body
+
+ def log_message(self, format, *args):
+ """Change the default log format"""
+ if self.server.verbose:
+ self.server.log_writer(
+ "[b10-stats-httpd] %s - - [%s] %s\n" %
+ (self.address_string(),
+ self.log_date_time_string(),
+ format%args))
+
+class HttpServerError(Exception):
+ """Exception class for HttpServer class. It is intended to be
+ passed from the HttpServer object to the StatsHttpd object."""
+ pass
+
+class HttpServer(http.server.HTTPServer):
+ """HTTP Server class. The class inherits the super
+ http.server.HTTPServer. Some parameters are specified as
+ arguments, which are xml_handler, xsd_handler, xsl_handler, and
+ log_writer. These all are parameters which the StatsHttpd object
+ has. The handler parameters are references of functions which
+ return body of each document. The last parameter log_writer is
+ reference of writer function to just write to
+ sys.stderr.write. They are intended to be referred by HttpHandler
+ object."""
+ def __init__(self, server_address, handler,
+ xml_handler, xsd_handler, xsl_handler, log_writer, verbose=False):
+ self.server_address = server_address
+ self.xml_handler = xml_handler
+ self.xsd_handler = xsd_handler
+ self.xsl_handler = xsl_handler
+ self.log_writer = log_writer
+ self.verbose = verbose
+ http.server.HTTPServer.__init__(self, server_address, handler)
+
+class StatsHttpdError(Exception):
+ """Exception class for StatsHttpd class. It is intended to be
+ thrown from the the StatsHttpd object to the HttpHandler object or
+ main routine."""
+ pass
+
+class StatsHttpd:
+ """The main class of HTTP server of HTTP/XML interface for
+ statistics module. It handles HTTP requests, and command channel
+ and config channel CC session. It uses select.select function
+ while waiting for clients requests."""
+ def __init__(self, verbose=False):
+ self.verbose = verbose
+ self.running = False
+ self.poll_intval = 0.5
+ self.write_log = sys.stderr.write
+ self.mccs = None
+ self.httpd = []
+ self.open_mccs()
+ self.load_config()
+ self.load_templates()
+ self.open_httpd()
+
+ def open_mccs(self):
+ """Opens a ModuleCCSession object"""
+ # create ModuleCCSession
+ if self.verbose:
+ self.write_log("[b10-stats-httpd] Starting CC Session\n")
+ self.mccs = isc.config.ModuleCCSession(
+ SPECFILE_LOCATION, self.config_handler, self.command_handler)
+ self.cc_session = self.mccs._session
+ # read spec file of stats module and subscribe 'Stats'
+ self.stats_module_spec = isc.config.module_spec_from_file(SCHEMA_SPECFILE_LOCATION)
+ self.stats_config_spec = self.stats_module_spec.get_config_spec()
+ self.stats_module_name = self.stats_module_spec.get_module_name()
+
+ def close_mccs(self):
+ """Closes a ModuleCCSession object"""
+ if self.mccs is None:
+ return
+ if self.verbose:
+ self.write_log("[b10-stats-httpd] Closing CC Session\n")
+ self.mccs.close()
+ self.mccs = None
+
+ def load_config(self, new_config={}):
+ """Loads configuration from spec file or new configuration
+ from the config manager"""
+ # load config
+ if len(new_config) > 0:
+ self.config.update(new_config)
+ else:
+ self.config = DEFAULT_CONFIG
+ self.config.update(
+ dict([
+ (itm['item_name'], self.mccs.get_value(itm['item_name'])[0])
+ for itm in self.mccs.get_module_spec().get_config_spec()
+ ])
+ )
+ # set addresses and ports for HTTP
+ self.http_addrs = [ (cf['address'], cf['port']) for cf in self.config['listen_on'] ]
+
+ def open_httpd(self):
+ """Opens sockets for HTTP. Iterating each HTTP address to be
+ configured in spec file"""
+ for addr in self.http_addrs:
+ self.httpd.append(self._open_httpd(addr))
+
+ def _open_httpd(self, server_address, address_family=None):
+ try:
+ # try IPv6 at first
+ if address_family is not None:
+ HttpServer.address_family = address_family
+ elif socket.has_ipv6:
+ HttpServer.address_family = socket.AF_INET6
+ httpd = HttpServer(
+ server_address, HttpHandler,
+ self.xml_handler, self.xsd_handler, self.xsl_handler,
+ self.write_log, self.verbose)
+ except (socket.gaierror, socket.error,
+ OverflowError, TypeError) as err:
+ # try IPv4 next
+ if HttpServer.address_family == socket.AF_INET6:
+ httpd = self._open_httpd(server_address, socket.AF_INET)
+ else:
+ raise HttpServerError(
+ "Invalid address %s, port %s: %s: %s" %
+ (server_address[0], server_address[1],
+ err.__class__.__name__, err))
+ else:
+ if self.verbose:
+ self.write_log(
+ "[b10-stats-httpd] Started on address %s, port %s\n" %
+ server_address)
+ return httpd
+
+ def close_httpd(self):
+ """Closes sockets for HTTP"""
+ if len(self.httpd) == 0:
+ return
+ for ht in self.httpd:
+ if self.verbose:
+ self.write_log(
+ "[b10-stats-httpd] Closing address %s, port %s\n" %
+ (ht.server_address[0], ht.server_address[1])
+ )
+ ht.server_close()
+ self.httpd = []
+
+ def start(self):
+ """Starts StatsHttpd objects to run. Waiting for client
+ requests by using select.select functions"""
+ self.mccs.start()
+ self.running = True
+ while self.running:
+ try:
+ (rfd, wfd, xfd) = select.select(
+ self.get_sockets(), [], [], self.poll_intval)
+ except select.error as err:
+ # select.error exception is caught only in the case of
+ # EINTR, or in other cases it is just thrown.
+ if err.args[0] == errno.EINTR:
+ (rfd, wfd, xfd) = ([], [], [])
+ else:
+ raise
+ # FIXME: This module can handle only one request at a
+ # time. If someone sends only part of the request, we block
+ # waiting for it until we time out.
+ # But it isn't so big issue for administration purposes.
+ for fd in rfd + xfd:
+ if fd == self.mccs.get_socket():
+ self.mccs.check_command(nonblock=False)
+ continue
+ for ht in self.httpd:
+ if fd == ht.socket:
+ ht.handle_request()
+ break
+ self.stop()
+
+ def stop(self):
+ """Stops the running StatsHttpd objects. Closes CC session and
+ HTTP handling sockets"""
+ if self.verbose:
+ self.write_log("[b10-stats-httpd] Shutting down\n")
+ self.close_httpd()
+ self.close_mccs()
+
+ def get_sockets(self):
+ """Returns sockets to select.select"""
+ sockets = []
+ if self.mccs is not None:
+ sockets.append(self.mccs.get_socket())
+ if len(self.httpd) > 0:
+ for ht in self.httpd:
+ sockets.append(ht.socket)
+ return sockets
+
+ def config_handler(self, new_config):
+ """Config handler for the ModuleCCSession object. It resets
+ addresses and ports to listen HTTP requests on."""
+ if self.verbose:
+ self.write_log("[b10-stats-httpd] Loading config : %s\n" % str(new_config))
+ for key in new_config.keys():
+ if key not in DEFAULT_CONFIG:
+ if self.verbose:
+ self.write_log(
+ "[b10-stats-httpd] Unknown known config: %s" % key)
+ return isc.config.ccsession.create_answer(
+ 1, "Unknown known config: %s" % key)
+ # backup old config
+ old_config = self.config.copy()
+ self.close_httpd()
+ self.load_config(new_config)
+ try:
+ self.open_httpd()
+ except HttpServerError as err:
+ if self.verbose:
+ self.write_log("[b10-stats-httpd] %s\n" % err)
+ self.write_log("[b10-stats-httpd] Restoring old config\n")
+ # restore old config
+ self.config_handler(old_config)
+ return isc.config.ccsession.create_answer(
+ 1, "[b10-stats-httpd] %s" % err)
+ else:
+ return isc.config.ccsession.create_answer(0)
+
+ def command_handler(self, command, args):
+ """Command handler for the ModuleCCSesson object. It handles
+ "status" and "shutdown" commands."""
+ if command == "status":
+ if self.verbose:
+ self.write_log("[b10-stats-httpd] Received 'status' command\n")
+ return isc.config.ccsession.create_answer(
+ 0, "Stats Httpd is up. (PID " + str(os.getpid()) + ")")
+ elif command == "shutdown":
+ if self.verbose:
+ self.write_log("[b10-stats-httpd] Received 'shutdown' command\n")
+ self.running = False
+ return isc.config.ccsession.create_answer(
+ 0, "Stats Httpd is shutting down.")
+ else:
+ if self.verbose:
+ self.write_log("[b10-stats-httpd] Received unknown command\n")
+ return isc.config.ccsession.create_answer(
+ 1, "Unknown command: " + str(command))
+
+ def get_stats_data(self):
+ """Requests statistics data to the Stats daemon and returns
+ the data which obtains from it"""
+ try:
+ seq = self.cc_session.group_sendmsg(
+ isc.config.ccsession.create_command('show'),
+ self.stats_module_name)
+ (answer, env) = self.cc_session.group_recvmsg(False, seq)
+ if answer:
+ (rcode, value) = isc.config.ccsession.parse_answer(answer)
+ except (isc.cc.session.SessionTimeout,
+ isc.cc.session.SessionError) as err:
+ raise StatsHttpdError("%s: %s" %
+ (err.__class__.__name__, err))
+ else:
+ if rcode == 0:
+ return value
+ else:
+ raise StatsHttpdError("Stats module: %s" % str(value))
+
+ def get_stats_spec(self):
+ """Just returns spec data"""
+ return self.stats_config_spec
+
+ def load_templates(self):
+ """Setup the bodies of XSD and XSL documents to be responds to
+ HTTP clients. Before that it also creates XML tag structures by
+ using xml.etree.ElementTree.Element class and substitutes
+ concrete strings with parameters embed in the string.Template
+ object."""
+ # for XSD
+ xsd_root = xml.etree.ElementTree.Element("all") # started with "all" tag
+ for item in self.get_stats_spec():
+ element = xml.etree.ElementTree.Element(
+ "element",
+ dict( name=item["item_name"],
+ type=item["item_type"] if item["item_type"].lower() != 'real' else 'float',
+ minOccurs="1",
+ maxOccurs="1" ),
+ )
+ annotation = xml.etree.ElementTree.Element("annotation")
+ appinfo = xml.etree.ElementTree.Element("appinfo")
+ documentation = xml.etree.ElementTree.Element("documentation")
+ appinfo.text = item["item_title"]
+ documentation.text = item["item_description"]
+ annotation.append(appinfo)
+ annotation.append(documentation)
+ element.append(annotation)
+ xsd_root.append(element)
+ xsd_string = xml.etree.ElementTree.tostring(xsd_root)
+ self.xsd_body = self.open_template(XSD_TEMPLATE_LOCATION).substitute(
+ xsd_string=xsd_string,
+ xsd_namespace=XSD_NAMESPACE
+ )
+ assert self.xsd_body is not None
+
+ # for XSL
+ xsd_root = xml.etree.ElementTree.Element(
+ "xsl:template",
+ dict(match="*")) # started with xml:template tag
+ for item in self.get_stats_spec():
+ tr = xml.etree.ElementTree.Element("tr")
+ td1 = xml.etree.ElementTree.Element(
+ "td", { "class" : "title",
+ "title" : item["item_description"] })
+ td1.text = item["item_title"]
+ td2 = xml.etree.ElementTree.Element("td")
+ xsl_valueof = xml.etree.ElementTree.Element(
+ "xsl:value-of",
+ dict(select=item["item_name"]))
+ td2.append(xsl_valueof)
+ tr.append(td1)
+ tr.append(td2)
+ xsd_root.append(tr)
+ xsl_string = xml.etree.ElementTree.tostring(xsd_root)
+ self.xsl_body = self.open_template(XSL_TEMPLATE_LOCATION).substitute(
+ xsl_string=xsl_string,
+ xsd_namespace=XSD_NAMESPACE)
+ assert self.xsl_body is not None
+
+ def xml_handler(self):
+ """Handler which requests to Stats daemon to obtain statistics
+ data and returns the body of XML document"""
+ xml_list=[]
+ for (k, v) in self.get_stats_data().items():
+ (k, v) = (str(k), str(v))
+ elem = xml.etree.ElementTree.Element(k)
+ elem.text = v
+ xml_list.append(
+ xml.etree.ElementTree.tostring(elem))
+ xml_string = "".join(xml_list)
+ self.xml_body = self.open_template(XML_TEMPLATE_LOCATION).substitute(
+ xml_string=xml_string,
+ xsd_namespace=XSD_NAMESPACE,
+ xsd_url_path=XSD_URL_PATH,
+ xsl_url_path=XSL_URL_PATH)
+ assert self.xml_body is not None
+ return self.xml_body
+
+ def xsd_handler(self):
+ """Handler which just returns the body of XSD document"""
+ return self.xsd_body
+
+ def xsl_handler(self):
+ """Handler which just returns the body of XSL document"""
+ return self.xsl_body
+
+ def open_template(self, file_name):
+ """It opens a template file, and it loads all lines to a
+ string variable and returns string. Template object includes
+ the variable. Limitation of a file size isn't needed there."""
+ lines = "".join(
+ open(file_name, 'r').readlines())
+ assert lines is not None
+ return string.Template(lines)
+
+if __name__ == "__main__":
+ try:
+ parser = OptionParser()
+ parser.add_option(
+ "-v", "--verbose", dest="verbose", action="store_true",
+ help="display more about what is going on")
+ (options, args) = parser.parse_args()
+ stats_httpd = StatsHttpd(verbose=options.verbose)
+ stats_httpd.start()
+ except OptionValueError:
+ sys.exit("[b10-stats-httpd] Error parsing options")
+ except isc.cc.session.SessionError as se:
+ sys.exit("[b10-stats-httpd] Error creating module, "
+ + "is the command channel daemon running?")
+ except HttpServerError as hse:
+ sys.exit("[b10-stats-httpd] %s" % hse)
+ except KeyboardInterrupt as kie:
+ sys.exit("[b10-stats-httpd] Interrupted, exiting")
diff --git a/src/bin/stats/stats_stub.py.in b/src/bin/stats/stats_stub.py.in
deleted file mode 100755
index 4a4a641..0000000
--- a/src/bin/stats/stats_stub.py.in
+++ /dev/null
@@ -1,154 +0,0 @@
-#!@PYTHON@
-
-# Copyright (C) 2010 Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-__version__ = "$Revision$"
-
-import sys; sys.path.append ('@@PYTHONPATH@@')
-import os
-import time
-from optparse import OptionParser, OptionValueError
-from isc.config.ccsession import ModuleCCSession, create_command, parse_answer, parse_command, create_answer
-from isc.cc import Session, SessionError
-from stats import get_datetime
-
-# for setproctitle
-import isc.util.process
-isc.util.process.rename()
-
-# If B10_FROM_BUILD is set in the environment, we use data files
-# from a directory relative to that, otherwise we use the ones
-# installed on the system
-if "B10_FROM_BUILD" in os.environ:
- SPECFILE_LOCATION = os.environ["B10_FROM_BUILD"] + "/src/bin/stats/stats.spec"
-else:
- PREFIX = "@prefix@"
- DATAROOTDIR = "@datarootdir@"
- SPECFILE_LOCATION = "@datadir@/@PACKAGE@/stats.spec".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
-
-class CCSessionStub:
- """
- This class is intended to behaves as a sender to Stats module. It
- creates MoudleCCSession object and send specified command.
- """
- def __init__(self, session=None, verbose=False):
- # create ModuleCCSession object
- self.verbose = verbose
- self.cc_session = ModuleCCSession(SPECFILE_LOCATION,
- self.__dummy, self.__dummy, session)
- self.module_name = self.cc_session._module_name
- self.session = self.cc_session._session
-
- def __dummy(self, *args):
- pass
-
- def send_command(self, command, args):
- """
- send command to stats module with args
- """
- cmd = create_command(command, args)
- if self.verbose:
- sys.stdout.write("[b10-stats_stub] send command : " + str(cmd) + "\n")
- seq = self.session.group_sendmsg(cmd, self.module_name)
- msg, env = self.session.group_recvmsg(False, seq) # non-blocking is False
- if self.verbose:
- sys.stdout.write("[b10-stats_stub] received env : " + str(env) + "\n")
- sys.stdout.write("[b10-stats_stub] received message : " + str(msg) + "\n")
- (ret, arg) = (None, None)
- if 'result' in msg:
- ret, arg = parse_answer(msg)
- elif 'command' in msg:
- ret, arg = parse_command(msg)
- self.session.group_reply(env, create_answer(0))
- return ret, arg, env
-
-class BossModuleStub:
- """
- This class is customized from CCSessionStub and is intended to behaves
- as a virtual Boss module to send to Stats Module.
- """
- def __init__(self, session=None, verbose=False):
- self.stub = CCSessionStub(session=session, verbose=verbose)
-
- def send_boottime(self):
- return self.stub.send_command("set", {"stats_data": {"bind10.boot_time": get_datetime()}})
-
-class AuthModuleStub:
- """
- This class is customized CCSessionStub and is intended to behaves
- as a virtual Auth module to send to Stats Module.
- """
- def __init__(self, session=None, verbose=False):
- self.stub = CCSessionStub(session=session, verbose=verbose)
- self.count = { "udp": 0, "tcp": 0 }
-
- def send_udp_query_count(self, cmd="set", cnt=0):
- """
- count up udp query count
- """
- prt = "udp"
- self.count[prt] = 1
- if cnt > 0:
- self.count[prt] = cnt
- return self.stub.send_command(cmd,
- {"stats_data":
- {"auth.queries."+prt: self.count[prt]}
- })
-
- def send_tcp_query_count(self, cmd="set", cnt=0):
- """
- set udp query count
- """
- prt = "tcp"
- self.count[prt] = self.count[prt] + 1
- if cnt > 0:
- self.count[prt] = cnt
- return self.stub.send_command(cmd,
- {"stats_data":
- {"auth.queries."+prt: self.count[prt]}
- })
-
-def main(session=None):
- try:
- parser=OptionParser()
- parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
- help="display more about what is going on")
- (options, args) = parser.parse_args()
- stub = CCSessionStub(session=session, verbose=options.verbose)
- boss = BossModuleStub(session=stub.session, verbose=options.verbose)
- auth = AuthModuleStub(session=stub.session, verbose=options.verbose)
- stub.send_command("status", None)
- boss.send_boottime()
- t_cnt=0
- u_cnt=81120
- auth.send_udp_query_count(cnt=u_cnt) # This is an example.
- while True:
- u_cnt = u_cnt + 1
- t_cnt = t_cnt + 1
- auth.send_udp_query_count(cnt=u_cnt)
- auth.send_tcp_query_count(cnt=t_cnt)
- time.sleep(1)
-
- except OptionValueError:
- sys.stderr.write("[b10-stats_stub] Error parsing options\n")
- except SessionError as se:
- sys.stderr.write("[b10-stats_stub] Error creating Stats module, "
- + "is the command channel daemon running?\n")
- except KeyboardInterrupt as kie:
- sys.stderr.write("[b10-stats_stub] Interrupted, exiting\n")
-
-if __name__ == "__main__":
- main()
diff --git a/src/bin/stats/tests/Makefile.am b/src/bin/stats/tests/Makefile.am
index 9e94050..5a13277 100644
--- a/src/bin/stats/tests/Makefile.am
+++ b/src/bin/stats/tests/Makefile.am
@@ -1,8 +1,8 @@
-SUBDIRS = isc testdata
+SUBDIRS = isc http testdata
PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
-PYTESTS = b10-stats_test.py b10-stats_stub_test.py
-EXTRA_DIST = $(PYTESTS) fake_time.py
-CLEANFILES = fake_time.pyc
+PYTESTS = b10-stats_test.py b10-stats-httpd_test.py
+EXTRA_DIST = $(PYTESTS) fake_time.py fake_socket.py fake_select.py
+CLEANFILES = fake_time.pyc fake_socket.pyc fake_select.pyc
# test using command-line arguments, so use check-local target instead of TESTS
check-local:
@@ -14,6 +14,6 @@ endif
for pytest in $(PYTESTS) ; do \
echo Running test: $$pytest ; \
env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/stats:$(abs_top_builddir)/src/bin/stats/tests \
- B10_FROM_BUILD=$(abs_top_builddir) \
+ B10_FROM_SOURCE=$(abs_top_srcdir) \
$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
done
diff --git a/src/bin/stats/tests/b10-stats-httpd_test.py b/src/bin/stats/tests/b10-stats-httpd_test.py
new file mode 100644
index 0000000..07999ea
--- /dev/null
+++ b/src/bin/stats/tests/b10-stats-httpd_test.py
@@ -0,0 +1,444 @@
+# Copyright (C) 2011 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import unittest
+import os
+import http.server
+import string
+import fake_select
+import imp
+import sys
+import fake_socket
+
+import isc.cc
+
+import stats_httpd
+stats_httpd.socket = fake_socket
+stats_httpd.select = fake_select
+
+DUMMY_DATA = {
+ "auth.queries.tcp": 10000,
+ "auth.queries.udp": 12000,
+ "bind10.boot_time": "2011-03-04T11:59:05Z",
+ "report_time": "2011-03-04T11:59:19Z",
+ "stats.boot_time": "2011-03-04T11:59:06Z",
+ "stats.last_update_time": "2011-03-04T11:59:07Z",
+ "stats.lname": "4d70d40a_c at host",
+ "stats.start_time": "2011-03-04T11:59:06Z",
+ "stats.timestamp": 1299239959.560846
+ }
+
+def push_answer(stats_httpd):
+ stats_httpd.cc_session.group_sendmsg(
+ { 'result':
+ [ 0, DUMMY_DATA ] }, "Stats")
+
+def pull_query(stats_httpd):
+ (msg, env) = stats_httpd.cc_session.group_recvmsg()
+ if 'result' in msg:
+ (ret, arg) = isc.config.ccsession.parse_answer(msg)
+ else:
+ (ret, arg) = isc.config.ccsession.parse_command(msg)
+ return (ret, arg, env)
+
+class TestHttpHandler(unittest.TestCase):
+ """Tests for HttpHandler class"""
+
+ def setUp(self):
+ self.verbose = True
+ self.stats_httpd = stats_httpd.StatsHttpd(self.verbose)
+ self.assertTrue(type(self.stats_httpd.httpd) is list)
+ self.httpd = self.stats_httpd.httpd
+ for ht in self.httpd:
+ self.assertTrue(ht.verbose)
+ self.stats_httpd.cc_session.verbose = False
+
+ def test_do_GET(self):
+ for ht in self.httpd:
+ self._test_do_GET(ht._handler)
+
+ def _test_do_GET(self, handler):
+
+ # URL is '/bind10/statistics/xml'
+ handler.path = stats_httpd.XML_URL_PATH
+ push_answer(self.stats_httpd)
+ handler.do_GET()
+ (ret, arg, env) = pull_query(self.stats_httpd)
+ self.assertEqual(ret, "show")
+ self.assertIsNone(arg)
+ self.assertTrue('group' in env)
+ self.assertEqual(env['group'], 'Stats')
+ self.assertEqual(handler.response.code, 200)
+ self.assertEqual(handler.response.headers["Content-type"], "text/xml")
+ self.assertTrue(handler.response.headers["Content-Length"] > 0)
+ self.assertTrue(handler.response.wrote_headers)
+ self.assertTrue(handler.response.body.find(stats_httpd.XSD_NAMESPACE)>0)
+ self.assertTrue(handler.response.body.find(stats_httpd.XSD_URL_PATH)>0)
+ for (k, v) in DUMMY_DATA.items():
+ self.assertTrue(handler.response.body.find(str(k))>0)
+ self.assertTrue(handler.response.body.find(str(v))>0)
+
+ # URL is '/bind10/statitics/xsd'
+ handler.path = stats_httpd.XSD_URL_PATH
+ handler.do_GET()
+ self.assertEqual(handler.response.code, 200)
+ self.assertEqual(handler.response.headers["Content-type"], "text/xml")
+ self.assertTrue(handler.response.headers["Content-Length"] > 0)
+ self.assertTrue(handler.response.wrote_headers)
+ self.assertTrue(handler.response.body.find(stats_httpd.XSD_NAMESPACE)>0)
+ for (k, v) in DUMMY_DATA.items():
+ self.assertTrue(handler.response.body.find(str(k))>0)
+
+ # URL is '/bind10/statitics/xsl'
+ handler.path = stats_httpd.XSL_URL_PATH
+ handler.do_GET()
+ self.assertEqual(handler.response.code, 200)
+ self.assertEqual(handler.response.headers["Content-type"], "text/xml")
+ self.assertTrue(handler.response.headers["Content-Length"] > 0)
+ self.assertTrue(handler.response.wrote_headers)
+ self.assertTrue(handler.response.body.find(stats_httpd.XSD_NAMESPACE)>0)
+ for (k, v) in DUMMY_DATA.items():
+ self.assertTrue(handler.response.body.find(str(k))>0)
+
+ # 302 redirect
+ handler.path = '/'
+ handler.headers = {'Host': 'my.host.domain'}
+ handler.do_GET()
+ self.assertEqual(handler.response.code, 302)
+ self.assertEqual(handler.response.headers["Location"],
+ "http://my.host.domain%s" % stats_httpd.XML_URL_PATH)
+
+ # 404 NotFound
+ handler.path = '/path/to/foo/bar'
+ handler.headers = {}
+ handler.do_GET()
+ self.assertEqual(handler.response.code, 404)
+
+ # failure case(connection with Stats is down)
+ handler.path = stats_httpd.XML_URL_PATH
+ push_answer(self.stats_httpd)
+ self.assertFalse(self.stats_httpd.cc_session._socket._closed)
+ self.stats_httpd.cc_session._socket._closed = True
+ handler.do_GET()
+ self.stats_httpd.cc_session._socket._closed = False
+ self.assertEqual(handler.response.code, 500)
+ self.stats_httpd.cc_session._clear_queues()
+
+ # failure case(Stats module returns err)
+ handler.path = stats_httpd.XML_URL_PATH
+ self.stats_httpd.cc_session.group_sendmsg(
+ { 'result': [ 1, "I have an error." ] }, "Stats")
+ self.assertFalse(self.stats_httpd.cc_session._socket._closed)
+ self.stats_httpd.cc_session._socket._closed = False
+ handler.do_GET()
+ self.assertEqual(handler.response.code, 500)
+ self.stats_httpd.cc_session._clear_queues()
+
+ def test_do_HEAD(self):
+ for ht in self.httpd:
+ self._test_do_HEAD(ht._handler)
+
+ def _test_do_HEAD(self, handler):
+ handler.path = '/path/to/foo/bar'
+ handler.do_HEAD()
+ self.assertEqual(handler.response.code, 404)
+
+ def test_log_message(self):
+ for ht in self.httpd:
+ self._test_log_message(ht._handler)
+
+ def _test_log_message(self, handler):
+ # switch write_log function
+ handler.server.log_writer = handler.response._write_log
+ log_message = 'ABCDEFG'
+ handler.log_message("%s", log_message)
+ self.assertEqual(handler.response.log,
+ "[b10-stats-httpd] %s - - [%s] %s\n" %
+ (handler.address_string(),
+ handler.log_date_time_string(),
+ log_message))
+
+class TestHttpServerError(unittest.TestCase):
+ """Tests for HttpServerError exception"""
+
+ def test_raises(self):
+ try:
+ raise stats_httpd.HttpServerError('Nothing')
+ except stats_httpd.HttpServerError as err:
+ self.assertEqual(str(err), 'Nothing')
+
+class TestHttpServer(unittest.TestCase):
+ """Tests for HttpServer class"""
+
+ def test_httpserver(self):
+ self.verbose = True
+ self.stats_httpd = stats_httpd.StatsHttpd(self.verbose)
+ self.stats_httpd.cc_session.verbose = False
+ for ht in self.stats_httpd.httpd:
+ self.assertTrue(ht.server_address in self.stats_httpd.http_addrs)
+ self.assertEqual(ht.verbose, self.verbose)
+ self.assertEqual(ht.xml_handler, self.stats_httpd.xml_handler)
+ self.assertEqual(ht.xsd_handler, self.stats_httpd.xsd_handler)
+ self.assertEqual(ht.xsl_handler, self.stats_httpd.xsl_handler)
+ self.assertEqual(ht.log_writer, self.stats_httpd.write_log)
+ self.assertTrue(isinstance(ht._handler, stats_httpd.HttpHandler))
+ self.assertTrue(isinstance(ht.socket, fake_socket.socket))
+
+class TestStatsHttpdError(unittest.TestCase):
+ """Tests for StatsHttpdError exception"""
+
+ def test_raises(self):
+ try:
+ raise stats_httpd.StatsHttpdError('Nothing')
+ except stats_httpd.StatsHttpdError as err:
+ self.assertEqual(str(err), 'Nothing')
+
+class TestStatsHttpd(unittest.TestCase):
+ """Tests for StatsHttpd class"""
+
+ def setUp(self):
+ self.verbose = True
+ fake_socket._CLOSED = False
+ fake_socket.has_ipv6 = True
+ self.stats_httpd = stats_httpd.StatsHttpd(self.verbose)
+ self.stats_httpd.cc_session.verbose = False
+
+ def tearDown(self):
+ self.stats_httpd.stop()
+
+ def test_init(self):
+ self.assertTrue(self.stats_httpd.verbose)
+ self.assertFalse(self.stats_httpd.mccs.get_socket()._closed)
+ self.assertEqual(self.stats_httpd.mccs.get_socket().fileno(),
+ id(self.stats_httpd.mccs.get_socket()))
+ for ht in self.stats_httpd.httpd:
+ self.assertFalse(ht.socket._closed)
+ self.assertEqual(ht.socket.fileno(), id(ht.socket))
+ fake_socket._CLOSED = True
+ self.assertRaises(isc.cc.session.SessionError,
+ stats_httpd.StatsHttpd)
+ fake_socket._CLOSED = False
+
+ def test_mccs(self):
+ self.stats_httpd.open_mccs()
+ self.assertTrue(
+ isinstance(self.stats_httpd.mccs.get_socket(), fake_socket.socket))
+ self.assertTrue(
+ isinstance(self.stats_httpd.cc_session, isc.cc.session.Session))
+ self.assertTrue(
+ isinstance(self.stats_httpd.stats_module_spec, isc.config.ModuleSpec))
+ for cfg in self.stats_httpd.stats_config_spec:
+ self.assertTrue('item_name' in cfg)
+ self.assertTrue(cfg['item_name'] in DUMMY_DATA)
+ self.assertTrue(len(self.stats_httpd.stats_config_spec), len(DUMMY_DATA))
+
+ def test_load_config(self):
+ self.stats_httpd.load_config()
+ self.assertTrue(('127.0.0.1', 8000) in set(self.stats_httpd.http_addrs))
+
+ def test_httpd(self):
+ # dual stack (addresses is ipv4 and ipv6)
+ fake_socket.has_ipv6 = True
+ self.assertTrue(('127.0.0.1', 8000) in set(self.stats_httpd.http_addrs))
+ self.stats_httpd.http_addrs = [ ('::1', 8000), ('127.0.0.1', 8000) ]
+ self.assertTrue(
+ stats_httpd.HttpServer.address_family in set([fake_socket.AF_INET, fake_socket.AF_INET6]))
+ self.stats_httpd.open_httpd()
+ for ht in self.stats_httpd.httpd:
+ self.assertTrue(isinstance(ht.socket, fake_socket.socket))
+ self.stats_httpd.close_httpd()
+
+ # dual stack (address is ipv6)
+ fake_socket.has_ipv6 = True
+ self.stats_httpd.http_addrs = [ ('::1', 8000) ]
+ self.stats_httpd.open_httpd()
+ for ht in self.stats_httpd.httpd:
+ self.assertTrue(isinstance(ht.socket, fake_socket.socket))
+ self.stats_httpd.close_httpd()
+
+ # dual stack (address is ipv4)
+ fake_socket.has_ipv6 = True
+ self.stats_httpd.http_addrs = [ ('127.0.0.1', 8000) ]
+ self.stats_httpd.open_httpd()
+ for ht in self.stats_httpd.httpd:
+ self.assertTrue(isinstance(ht.socket, fake_socket.socket))
+ self.stats_httpd.close_httpd()
+
+ # only-ipv4 single stack
+ fake_socket.has_ipv6 = False
+ self.stats_httpd.http_addrs = [ ('127.0.0.1', 8000) ]
+ self.stats_httpd.open_httpd()
+ for ht in self.stats_httpd.httpd:
+ self.assertTrue(isinstance(ht.socket, fake_socket.socket))
+ self.stats_httpd.close_httpd()
+
+ # only-ipv4 single stack (force set ipv6 )
+ fake_socket.has_ipv6 = False
+ self.stats_httpd.http_addrs = [ ('::1', 8000) ]
+ self.assertRaises(stats_httpd.HttpServerError,
+ self.stats_httpd.open_httpd)
+
+ # hostname
+ self.stats_httpd.http_addrs = [ ('localhost', 8000) ]
+ self.stats_httpd.open_httpd()
+ for ht in self.stats_httpd.httpd:
+ self.assertTrue(isinstance(ht.socket, fake_socket.socket))
+ self.stats_httpd.close_httpd()
+
+ self.stats_httpd.http_addrs = [ ('my.host.domain', 8000) ]
+ self.stats_httpd.open_httpd()
+ for ht in self.stats_httpd.httpd:
+ self.assertTrue(isinstance(ht.socket, fake_socket.socket))
+ self.stats_httpd.close_httpd()
+
+ # over flow of port number
+ self.stats_httpd.http_addrs = [ ('', 80000) ]
+ self.assertRaises(stats_httpd.HttpServerError, self.stats_httpd.open_httpd)
+ # negative
+ self.stats_httpd.http_addrs = [ ('', -8000) ]
+ self.assertRaises(stats_httpd.HttpServerError, self.stats_httpd.open_httpd)
+ # alphabet
+ self.stats_httpd.http_addrs = [ ('', 'ABCDE') ]
+ self.assertRaises(stats_httpd.HttpServerError, self.stats_httpd.open_httpd)
+
+ def test_start(self):
+ self.stats_httpd.cc_session.group_sendmsg(
+ { 'command': [ "shutdown" ] }, "StatsHttpd")
+ self.stats_httpd.start()
+ self.stats_httpd = stats_httpd.StatsHttpd(self.verbose)
+ self.stats_httpd.cc_session.verbose = False
+ self.assertRaises(
+ fake_select.error, self.stats_httpd.start)
+
+ def test_stop(self):
+ # success case
+ fake_socket._CLOSED = False
+ self.stats_httpd.stop()
+ self.assertFalse(self.stats_httpd.running)
+ self.assertIsNone(self.stats_httpd.mccs)
+ for ht in self.stats_httpd.httpd:
+ self.assertTrue(ht.socket._closed)
+ self.assertTrue(self.stats_httpd.cc_session._socket._closed)
+ # failure case
+ self.stats_httpd.cc_session._socket._closed = False
+ self.stats_httpd.open_mccs()
+ self.stats_httpd.cc_session._socket._closed = True
+ self.stats_httpd.stop() # No excetion raises
+ self.stats_httpd.cc_session._socket._closed = False
+
+ def test_open_template(self):
+ # successful conditions
+ tmpl = self.stats_httpd.open_template(stats_httpd.XML_TEMPLATE_LOCATION)
+ self.assertTrue(isinstance(tmpl, string.Template))
+ opts = dict(
+ xml_string="<dummy></dummy>",
+ xsd_namespace="http://host/path/to/",
+ xsd_url_path="/path/to/",
+ xsl_url_path="/path/to/")
+ lines = tmpl.substitute(opts)
+ for n in opts:
+ self.assertTrue(lines.find(opts[n])>0)
+ tmpl = self.stats_httpd.open_template(stats_httpd.XSD_TEMPLATE_LOCATION)
+ self.assertTrue(isinstance(tmpl, string.Template))
+ opts = dict(
+ xsd_string="<dummy></dummy>",
+ xsd_namespace="http://host/path/to/")
+ lines = tmpl.substitute(opts)
+ for n in opts:
+ self.assertTrue(lines.find(opts[n])>0)
+ tmpl = self.stats_httpd.open_template(stats_httpd.XSL_TEMPLATE_LOCATION)
+ self.assertTrue(isinstance(tmpl, string.Template))
+ opts = dict(
+ xsl_string="<dummy></dummy>",
+ xsd_namespace="http://host/path/to/")
+ lines = tmpl.substitute(opts)
+ for n in opts:
+ self.assertTrue(lines.find(opts[n])>0)
+ # unsuccessful condition
+ self.assertRaises(
+ IOError,
+ self.stats_httpd.open_template, '/path/to/foo/bar')
+
+ def test_commands(self):
+ self.assertEqual(self.stats_httpd.command_handler("status", None),
+ isc.config.ccsession.create_answer(
+ 0, "Stats Httpd is up. (PID " + str(os.getpid()) + ")"))
+ self.stats_httpd.running = True
+ self.assertEqual(self.stats_httpd.command_handler("shutdown", None),
+ isc.config.ccsession.create_answer(
+ 0, "Stats Httpd is shutting down."))
+ self.assertFalse(self.stats_httpd.running)
+ self.assertEqual(
+ self.stats_httpd.command_handler("__UNKNOWN_COMMAND__", None),
+ isc.config.ccsession.create_answer(
+ 1, "Unknown command: __UNKNOWN_COMMAND__"))
+
+ def test_config(self):
+ self.assertEqual(
+ self.stats_httpd.config_handler(dict(_UNKNOWN_KEY_=None)),
+ isc.config.ccsession.create_answer(
+ 1, "Unknown known config: _UNKNOWN_KEY_"))
+ self.assertEqual(
+ self.stats_httpd.config_handler(
+ dict(listen_on=[dict(address="::2",port=8000)])),
+ isc.config.ccsession.create_answer(0))
+ self.assertTrue("listen_on" in self.stats_httpd.config)
+ for addr in self.stats_httpd.config["listen_on"]:
+ self.assertTrue("address" in addr)
+ self.assertTrue("port" in addr)
+ self.assertTrue(addr["address"] == "::2")
+ self.assertTrue(addr["port"] == 8000)
+
+ self.assertEqual(
+ self.stats_httpd.config_handler(
+ dict(listen_on=[dict(address="::1",port=80)])),
+ isc.config.ccsession.create_answer(0))
+ self.assertTrue("listen_on" in self.stats_httpd.config)
+ for addr in self.stats_httpd.config["listen_on"]:
+ self.assertTrue("address" in addr)
+ self.assertTrue("port" in addr)
+ self.assertTrue(addr["address"] == "::1")
+ self.assertTrue(addr["port"] == 80)
+
+ self.assertEqual(
+ self.stats_httpd.config_handler(
+ dict(listen_on=[dict(address="1.2.3.4",port=54321)])),
+ isc.config.ccsession.create_answer(0))
+ self.assertTrue("listen_on" in self.stats_httpd.config)
+ for addr in self.stats_httpd.config["listen_on"]:
+ self.assertTrue("address" in addr)
+ self.assertTrue("port" in addr)
+ self.assertTrue(addr["address"] == "1.2.3.4")
+ self.assertTrue(addr["port"] == 54321)
+ (ret, arg) = isc.config.ccsession.parse_answer(
+ self.stats_httpd.config_handler(
+ dict(listen_on=[dict(address="1.2.3.4",port=543210)]))
+ )
+ self.assertEqual(ret, 1)
+
+ def test_for_without_B10_FROM_SOURCE(self):
+ # just lets it go through the code without B10_FROM_SOURCE env
+ # variable
+ if "B10_FROM_SOURCE" in os.environ:
+ tmppath = os.environ["B10_FROM_SOURCE"]
+ os.environ.pop("B10_FROM_SOURCE")
+ imp.reload(stats_httpd)
+ os.environ["B10_FROM_SOURCE"] = tmppath
+ imp.reload(stats_httpd)
+ stats_httpd.socket = fake_socket
+ stats_httpd.select = fake_select
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/src/bin/stats/tests/b10-stats_stub_test.py b/src/bin/stats/tests/b10-stats_stub_test.py
deleted file mode 100644
index b8983c5..0000000
--- a/src/bin/stats/tests/b10-stats_stub_test.py
+++ /dev/null
@@ -1,115 +0,0 @@
-# Copyright (C) 2010 Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-__version__ = "$Revision$"
-
-#
-# Tests for the stats stub module
-#
-import unittest
-import time
-import os
-import imp
-import stats_stub
-from isc.cc.session import Session
-from stats_stub import CCSessionStub, BossModuleStub, AuthModuleStub
-from stats import get_datetime
-
-class TestStats(unittest.TestCase):
-
- def setUp(self):
- self.session = Session()
- self.stub = CCSessionStub(session=self.session, verbose=True)
- self.boss = BossModuleStub(session=self.session, verbose=True)
- self.auth = AuthModuleStub(session=self.session, verbose=True)
- self.env = {'from': self.session.lname, 'group': 'Stats',
- 'instance': '*', 'to':'*',
- 'type':'send','seq':0}
- self.result_ok = {'result': [0]}
-
- def tearDown(self):
- self.session.close()
-
- def test_stub(self):
- """
- Test for send_command of CCSessionStub object
- """
- env = self.env
- result_ok = self.result_ok
- self.assertEqual(('status', None, env),
- self.stub.send_command('status', None))
- self.assertEqual(result_ok, self.session.get_message("Stats", None))
- self.assertEqual(('shutdown', None, env),
- self.stub.send_command('shutdown', None))
- self.assertEqual(result_ok, self.session.get_message("Stats", None))
- self.assertEqual(('show', None, env),
- self.stub.send_command('show', None))
- self.assertEqual(result_ok, self.session.get_message("Stats", None))
- self.assertEqual(('set', {'atest': 100.0}, env),
- self.stub.send_command('set', {'atest': 100.0}))
- self.assertEqual(result_ok, self.session.get_message("Stats", None))
-
- def test_boss_stub(self):
- """
- Test for send_command of BossModuleStub object
- """
- env = self.env
- result_ok = self.result_ok
- self.assertEqual(('set', {"stats_data":
- {"bind10.boot_time": get_datetime()}
- }, env), self.boss.send_boottime())
- self.assertEqual(result_ok, self.session.get_message("Stats", None))
-
- def test_auth_stub(self):
- """
- Test for send_command of AuthModuleStub object
- """
- env = self.env
- result_ok = self.result_ok
- self.assertEqual(
- ('set', {"stats_data": {"auth.queries.udp": 1}}, env),
- self.auth.send_udp_query_count())
- self.assertEqual(result_ok, self.session.get_message("Stats", None))
- self.assertEqual(
- ('set', {"stats_data": {"auth.queries.tcp": 1}}, env),
- self.auth.send_tcp_query_count())
- self.assertEqual(result_ok, self.session.get_message("Stats", None))
- self.assertEqual(
- ('set', {"stats_data": {"auth.queries.udp": 100}}, env),
- self.auth.send_udp_query_count(cmd='set', cnt=100))
- self.assertEqual(result_ok, self.session.get_message("Stats", None))
- self.assertEqual(
- ('set', {"stats_data": {"auth.queries.tcp": 99}}, env),
- self.auth.send_tcp_query_count(cmd='set', cnt=99))
- self.assertEqual(result_ok, self.session.get_message("Stats", None))
-
- def test_func_main(self):
- # explicitly make failed
- self.session.close()
- stats_stub.main(session=self.session)
-
- def test_osenv(self):
- """
- test for not having environ "B10_FROM_BUILD"
- """
- if "B10_FROM_BUILD" in os.environ:
- path = os.environ["B10_FROM_BUILD"]
- os.environ.pop("B10_FROM_BUILD")
- imp.reload(stats_stub)
- os.environ["B10_FROM_BUILD"] = path
- imp.reload(stats_stub)
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/src/bin/stats/tests/b10-stats_test.py b/src/bin/stats/tests/b10-stats_test.py
index 3566bc4..eccabdc 100644
--- a/src/bin/stats/tests/b10-stats_test.py
+++ b/src/bin/stats/tests/b10-stats_test.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2010,2011 Internet Systems Consortium.
+# Copyright (C) 2010, 2011 Internet Systems Consortium.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@@ -23,7 +23,11 @@ import unittest
import imp
from isc.cc.session import Session, SessionError
from isc.config.ccsession import ModuleCCSession, ModuleCCSessionError
+from fake_time import time, strftime, gmtime
import stats
+stats.time = time
+stats.strftime = strftime
+stats.gmtime = gmtime
from stats import SessionSubject, CCSessionListener, get_timestamp, get_datetime
from fake_time import _TEST_TIME_SECS, _TEST_TIME_STRF
@@ -535,12 +539,19 @@ class TestStats2(unittest.TestCase):
Test for specfile
"""
- if "B10_FROM_BUILD" in os.environ:
+ if "B10_FROM_SOURCE" in os.environ:
self.assertEqual(stats.SPECFILE_LOCATION,
- os.environ["B10_FROM_BUILD"] + "/src/bin/stats/stats.spec")
+ os.environ["B10_FROM_SOURCE"] + os.sep + \
+ "src" + os.sep + "bin" + os.sep + "stats" + \
+ os.sep + "stats.spec")
+ self.assertEqual(stats.SCHEMA_SPECFILE_LOCATION,
+ os.environ["B10_FROM_SOURCE"] + os.sep + \
+ "src" + os.sep + "bin" + os.sep + "stats" + \
+ os.sep + "stats-schema.spec")
imp.reload(stats)
# change path of SPECFILE_LOCATION
stats.SPECFILE_LOCATION = TEST_SPECFILE_LOCATION
+ stats.SCHEMA_SPECFILE_LOCATION = TEST_SPECFILE_LOCATION
self.assertEqual(stats.SPECFILE_LOCATION, TEST_SPECFILE_LOCATION)
self.subject = stats.SessionSubject(session=self.session, verbose=True)
self.session = self.subject.session
@@ -631,13 +642,13 @@ class TestStats2(unittest.TestCase):
def test_osenv(self):
"""
- test for not having environ "B10_FROM_BUILD"
+ test for not having environ "B10_FROM_SOURCE"
"""
- if "B10_FROM_BUILD" in os.environ:
- path = os.environ["B10_FROM_BUILD"]
- os.environ.pop("B10_FROM_BUILD")
+ if "B10_FROM_SOURCE" in os.environ:
+ path = os.environ["B10_FROM_SOURCE"]
+ os.environ.pop("B10_FROM_SOURCE")
imp.reload(stats)
- os.environ["B10_FROM_BUILD"] = path
+ os.environ["B10_FROM_SOURCE"] = path
imp.reload(stats)
def result_ok(*args):
diff --git a/src/bin/stats/tests/fake_select.py b/src/bin/stats/tests/fake_select.py
new file mode 100644
index 0000000..ca0ca82
--- /dev/null
+++ b/src/bin/stats/tests/fake_select.py
@@ -0,0 +1,43 @@
+# Copyright (C) 2011 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""
+A mock-up module of select
+
+*** NOTE ***
+It is only for testing stats_httpd module and not reusable for
+external module.
+"""
+
+import fake_socket
+import errno
+
+class error(Exception):
+ pass
+
+def select(rlst, wlst, xlst, timeout):
+ if type(timeout) != int and type(timeout) != float:
+ raise TypeError("Error: %s must be integer or float"
+ % timeout.__class__.__name__)
+ for s in rlst + wlst + xlst:
+ if type(s) != fake_socket.socket:
+ raise TypeError("Error: %s must be a dummy socket"
+ % s.__class__.__name__)
+ s._called = s._called + 1
+ if s._called > 3:
+ raise error("Something is happened!")
+ elif s._called > 2:
+ raise error(errno.EINTR)
+ return (rlst, wlst, xlst)
diff --git a/src/bin/stats/tests/fake_socket.py b/src/bin/stats/tests/fake_socket.py
new file mode 100644
index 0000000..4e3a458
--- /dev/null
+++ b/src/bin/stats/tests/fake_socket.py
@@ -0,0 +1,70 @@
+# Copyright (C) 2011 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""
+A mock-up module of socket
+
+*** NOTE ***
+It is only for testing stats_httpd module and not reusable for
+external module.
+"""
+
+import re
+
+AF_INET = 'AF_INET'
+AF_INET6 = 'AF_INET6'
+_ADDRFAMILY = AF_INET
+has_ipv6 = True
+_CLOSED = False
+
+class gaierror(Exception):
+ pass
+
+class error(Exception):
+ pass
+
+class socket:
+
+ def __init__(self, family=None):
+ if family is None:
+ self.address_family = _ADDRFAMILY
+ else:
+ self.address_family = family
+ self._closed = _CLOSED
+ if self._closed:
+ raise error('socket is already closed!')
+ self._called = 0
+
+ def close(self):
+ self._closed = True
+
+ def fileno(self):
+ return id(self)
+
+ def bind(self, server_class):
+ (self.server_address, self.server_port) = server_class
+ if self.address_family not in set([AF_INET, AF_INET6]):
+ raise error("Address family not supported by protocol: %s" % self.address_family)
+ if self.address_family == AF_INET6 and not has_ipv6:
+ raise error("Address family not supported in this machine: %s has_ipv6: %s"
+ % (self.address_family, str(has_ipv6)))
+ if self.address_family == AF_INET and re.search(':', self.server_address) is not None:
+ raise gaierror("Address family for hostname not supported : %s %s" % (self.server_address, self.address_family))
+ if self.address_family == AF_INET6 and re.search(':', self.server_address) is None:
+ raise error("Cannot assign requested address : %s" % str(self.server_address))
+ if type(self.server_port) is not int:
+ raise TypeError("an integer is required: %s" % str(self.server_port))
+ if self.server_port < 0 or self.server_port > 65535:
+ raise OverflowError("port number must be 0-65535.: %s" % str(self.server_port))
diff --git a/src/bin/stats/tests/http/Makefile.am b/src/bin/stats/tests/http/Makefile.am
new file mode 100644
index 0000000..879e8a8
--- /dev/null
+++ b/src/bin/stats/tests/http/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = __init__.py server.py
+CLEANFILES = __init__.pyc server.pyc
diff --git a/src/bin/stats/tests/http/__init__.py b/src/bin/stats/tests/http/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/bin/stats/tests/http/server.py b/src/bin/stats/tests/http/server.py
new file mode 100644
index 0000000..70ed6fa
--- /dev/null
+++ b/src/bin/stats/tests/http/server.py
@@ -0,0 +1,96 @@
+# Copyright (C) 2011 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""
+A mock-up module of http.server
+
+*** NOTE ***
+It is only for testing stats_httpd module and not reusable for
+external module.
+"""
+
+import fake_socket
+
+class DummyHttpResponse:
+ def __init__(self, path):
+ self.path = path
+ self.headers={}
+ self.log = ""
+
+ def _write_log(self, msg):
+ self.log = self.log + msg
+
+class HTTPServer:
+ """
+ A mock-up class of http.server.HTTPServer
+ """
+ address_family = fake_socket.AF_INET
+ def __init__(self, server_class, handler_class):
+ self.socket = fake_socket.socket(self.address_family)
+ self.server_class = server_class
+ self.socket.bind(self.server_class)
+ self._handler = handler_class(None, None, self)
+
+ def handle_request(self):
+ pass
+
+ def server_close(self):
+ self.socket.close()
+
+class BaseHTTPRequestHandler:
+ """
+ A mock-up class of http.server.BaseHTTPRequestHandler
+ """
+
+ def __init__(self, request, client_address, server):
+ self.path = "/path/to"
+ self.headers = {}
+ self.server = server
+ self.response = DummyHttpResponse(path=self.path)
+ self.response.write = self._write
+ self.wfile = self.response
+
+ def send_response(self, code=0):
+ if self.path != self.response.path:
+ self.response = DummyHttpResponse(path=self.path)
+ self.response.code = code
+
+ def send_header(self, key, value):
+ if self.path != self.response.path:
+ self.response = DummyHttpResponse(path=self.path)
+ self.response.headers[key] = value
+
+ def end_headers(self):
+ if self.path != self.response.path:
+ self.response = DummyHttpResponse(path=self.path)
+ self.response.wrote_headers = True
+
+ def send_error(self, code, message=None):
+ if self.path != self.response.path:
+ self.response = DummyHttpResponse(path=self.path)
+ self.response.code = code
+ self.response.body = message
+
+ def address_string(self):
+ return 'dummyhost'
+
+ def log_date_time_string(self):
+ return '[DD/MM/YYYY HH:MI:SS]'
+
+ def _write(self, obj):
+ if self.path != self.response.path:
+ self.response = DummyHttpResponse(path=self.path)
+ self.response.body = obj.decode()
+
diff --git a/src/bin/stats/tests/isc/cc/session.py b/src/bin/stats/tests/isc/cc/session.py
index 4d12adc..e16d6a9 100644
--- a/src/bin/stats/tests/isc/cc/session.py
+++ b/src/bin/stats/tests/isc/cc/session.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2010 Internet Systems Consortium.
+# Copyright (C) 2010,2011 Internet Systems Consortium.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@@ -13,11 +13,16 @@
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-# This module is a mock-up class of isc.cc.session
+"""
+A mock-up module of isc.cc.session
-__version__ = "$Revision$"
+*** NOTE ***
+It is only for testing stats_httpd module and not reusable for
+external module.
+"""
import sys
+import fake_socket
# set a dummy lname
_TEST_LNAME = '123abc at xxxx'
@@ -33,12 +38,18 @@ class Queue():
class SessionError(Exception):
pass
+class SessionTimeout(Exception):
+ pass
+
class Session:
def __init__(self, socket_file=None, verbose=False):
self._lname = _TEST_LNAME
self.message_queue = []
self.old_message_queue = []
- self._socket = True
+ try:
+ self._socket = fake_socket.socket()
+ except fake_socket.error as se:
+ raise SessionError(se)
self.verbose = verbose
@property
@@ -46,13 +57,17 @@ class Session:
return self._lname
def close(self):
- self._socket = False
+ self._socket.close()
+
+ def _clear_queues(self):
+ while len(self.message_queue) > 0:
+ self.dequeue()
def _next_sequence(self, que=None):
return len(self.message_queue)
def enqueue(self, msg=None, env={}):
- if not self._socket:
+ if self._socket._closed:
raise SessionError("Session has been closed.")
seq = self._next_sequence()
env.update({"seq": 0}) # fixed here
@@ -62,12 +77,12 @@ class Session:
sys.stdout.write("[Session] enqueue: " + str(que.dump()) + "\n")
return seq
- def dequeue(self, seq=0):
- if not self._socket:
+ def dequeue(self):
+ if self._socket._closed:
raise SessionError("Session has been closed.")
que = None
try:
- que = self.message_queue.pop(seq)
+ que = self.message_queue.pop(0) # always pop at index 0
self.old_message_queue.append(que)
except IndexError:
que = Queue()
@@ -76,7 +91,7 @@ class Session:
return que
def get_queue(self, seq=None):
- if not self._socket:
+ if self._socket._closed:
raise SessionError("Session has been closed.")
if seq is None:
seq = len(self.message_queue) - 1
@@ -99,7 +114,7 @@ class Session:
"instance": instance })
def group_recvmsg(self, nonblock=True, seq=0):
- que = self.dequeue(seq)
+ que = self.dequeue()
return que.msg, que.env
def group_reply(self, routing, msg):
@@ -112,7 +127,7 @@ class Session:
"reply": routing["seq"] })
def get_message(self, group, to='*'):
- if not self._socket:
+ if self._socket._closed:
raise SessionError("Session has been closed.")
que = Queue()
for q in self.message_queue:
@@ -124,3 +139,10 @@ class Session:
sys.stdout.write("[Session] get_message: " + str(que.dump()) + "\n")
return q.msg
+ def group_subscribe(self, group, instance = "*"):
+ if self._socket._closed:
+ raise SessionError("Session has been closed.")
+
+ def group_unsubscribe(self, group, instance = "*"):
+ if self._socket._closed:
+ raise SessionError("Session has been closed.")
diff --git a/src/bin/stats/tests/isc/config/ccsession.py b/src/bin/stats/tests/isc/config/ccsession.py
index fc285a7..a4e9c37 100644
--- a/src/bin/stats/tests/isc/config/ccsession.py
+++ b/src/bin/stats/tests/isc/config/ccsession.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2010 Internet Systems Consortium.
+# Copyright (C) 2010,2011 Internet Systems Consortium.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@@ -13,16 +13,22 @@
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-# This module is a mock-up class of isc.cc.session
+"""
+A mock-up module of isc.cc.session
-__version__ = "$Revision$"
+*** NOTE ***
+It is only for testing stats_httpd module and not reusable for
+external module.
+"""
import json
+import os
from isc.cc.session import Session
COMMAND_CONFIG_UPDATE = "config_update"
def parse_answer(msg):
+ assert 'result' in msg
try:
return msg['result'][0], msg['result'][1]
except IndexError:
@@ -35,6 +41,7 @@ def create_answer(rcode, arg = None):
return { 'result': [ rcode, arg ] }
def parse_command(msg):
+ assert 'command' in msg
try:
return msg['command'][0], msg['command'][1]
except IndexError:
@@ -47,9 +54,21 @@ def create_command(command_name, params = None):
return {"command": [command_name, params]}
def module_spec_from_file(spec_file, check = True):
- file = open(spec_file)
- module_spec = json.loads(file.read())
- return ModuleSpec(module_spec['module_spec'], check)
+ try:
+ file = open(spec_file)
+ json_str = file.read()
+ module_spec = json.loads(json_str)
+ file.close()
+ return ModuleSpec(module_spec['module_spec'], check)
+ except IOError as ioe:
+ raise ModuleSpecError("JSON read error: " + str(ioe))
+ except ValueError as ve:
+ raise ModuleSpecError("JSON parse error: " + str(ve))
+ except KeyError as err:
+ raise ModuleSpecError("Data definition has no module_spec element")
+
+class ModuleSpecError(Exception):
+ pass
class ModuleSpec:
def __init__(self, module_spec, check = True):
@@ -67,10 +86,34 @@ class ModuleSpec:
class ModuleCCSessionError(Exception):
pass
+class DataNotFoundError(Exception):
+ pass
+
class ConfigData:
def __init__(self, specification):
self.specification = specification
+ def get_value(self, identifier):
+ """Returns a tuple where the first item is the value at the
+ given identifier, and the second item is absolutely False
+ even if the value is an unset default or not. Raises an
+ DataNotFoundError if the identifier is not found in the
+ specification file.
+ *** NOTE ***
+ There are some differences from the original method. This
+ method never handles local settings like the original
+ method. But these different behaviors aren't so big issues
+ for a mock-up method of stats_httpd because stats_httpd
+ calls this method at only first."""
+ for config_map in self.get_module_spec().get_config_spec():
+ if config_map['item_name'] == identifier:
+ if 'item_default' in config_map:
+ return config_map['item_default'], False
+ raise DataNotFoundError("item_name %s is not found in the specfile" % identifier)
+
+ def get_module_spec(self):
+ return self.specification
+
class ModuleCCSession(ConfigData):
def __init__(self, spec_file_name, config_handler, command_handler, cc_session = None):
module_spec = module_spec_from_file(spec_file_name)
@@ -111,3 +154,7 @@ class ModuleCCSession(ConfigData):
def get_module_spec(self):
return self.specification
+
+ def get_socket(self):
+ return self._session._socket
+
diff --git a/src/bin/stats/tests/isc/util/process.py b/src/bin/stats/tests/isc/util/process.py
index 7274a48..0f764c1 100644
--- a/src/bin/stats/tests/isc/util/process.py
+++ b/src/bin/stats/tests/isc/util/process.py
@@ -13,6 +13,9 @@
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-# A dummy function of isc.util.process.rename()
+"""
+A dummy function of isc.util.process.rename()
+"""
+
def rename(name=None):
pass
diff --git a/src/bin/stats/tests/isc/utils/Makefile.am b/src/bin/stats/tests/isc/utils/Makefile.am
deleted file mode 100644
index b09fdee..0000000
--- a/src/bin/stats/tests/isc/utils/Makefile.am
+++ /dev/null
@@ -1,2 +0,0 @@
-EXTRA_DIST = __init__.py process.py
-CLEANFILES = __init__.pyc process.pyc
diff --git a/src/bin/stats/tests/isc/utils/__init__.py b/src/bin/stats/tests/isc/utils/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/bin/stats/tests/isc/utils/process.py b/src/bin/stats/tests/isc/utils/process.py
deleted file mode 100644
index 4c0cf8c..0000000
--- a/src/bin/stats/tests/isc/utils/process.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright (C) 2010 Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-# A dummy function of isc.utils.process.rename()
-def rename(name=None):
- pass
diff --git a/src/bin/stats/tests/stats_test.in b/src/bin/stats/tests/stats_test.in
deleted file mode 100644
index a3279a7..0000000
--- a/src/bin/stats/tests/stats_test.in
+++ /dev/null
@@ -1,31 +0,0 @@
-#! /bin/sh
-
-# Copyright (C) 2010 Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-PYTHON_EXEC=${PYTHON_EXEC:- at PYTHON@}
-export PYTHON_EXEC
-
-PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_srcdir@/src/bin/stats:@abs_top_srcdir@/src/bin/stats/tests
-export PYTHONPATH
-
-B10_FROM_BUILD=@abs_top_builddir@
-export B10_FROM_BUILD
-
-TEST_PATH=@abs_top_srcdir@/src/bin/stats/tests
-
-cd ${TEST_PATH}
-${PYTHON_EXEC} -O b10-stats_test.py $*
-${PYTHON_EXEC} -O b10-stats_stub_test.py $*
diff --git a/src/bin/xfrin/tests/Makefile.am b/src/bin/xfrin/tests/Makefile.am
index dfa7714..d4efbc7 100644
--- a/src/bin/xfrin/tests/Makefile.am
+++ b/src/bin/xfrin/tests/Makefile.am
@@ -6,7 +6,7 @@ EXTRA_DIST = $(PYTESTS)
# required by loadable python modules.
LIBRARY_PATH_PLACEHOLDER =
if SET_ENV_LIBRARY_PATH
-LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/xfr/.libs:$$$(ENV_LIBRARY_PATH)
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/xfr/.libs:$$$(ENV_LIBRARY_PATH)
endif
# test using command-line arguments, so use check-local target instead of TESTS
diff --git a/src/bin/xfrin/tests/xfrin_test.py b/src/bin/xfrin/tests/xfrin_test.py
index 04d04a6..0ccbbb8 100644
--- a/src/bin/xfrin/tests/xfrin_test.py
+++ b/src/bin/xfrin/tests/xfrin_test.py
@@ -35,6 +35,8 @@ TEST_MASTER_IPV6_ADDRINFO = (socket.AF_INET6, socket.SOCK_STREAM,
# If some other process uses this port test will fail.
TEST_MASTER_PORT = '53535'
+TSIG_KEY = TSIGKey("example.com:SFuWd/q99SzF8Yzd1QbB9g==")
+
soa_rdata = Rdata(RRType.SOA(), TEST_RRCLASS,
'master.example.com. admin.example.com ' +
'1234 3600 1800 2419200 7200')
@@ -51,6 +53,13 @@ default_answers = [soa_rrset]
class XfrinTestException(Exception):
pass
+def strip_mutable_tsig_data(data):
+ # Unfortunately we cannot easily compare TSIG RR because we can't tweak
+ # current time. As a work around this helper function strips off the time
+ # dependent part of TSIG RDATA, i.e., the MAC (assuming HMAC-MD5) and
+ # Time Signed.
+ return data[0:-32] + data[-26:-22] + data[-6:]
+
class MockXfrin(Xfrin):
# This is a class attribute of a callable object that specifies a non
# default behavior triggered in _cc_check_command(). Specific test methods
@@ -60,6 +69,7 @@ class MockXfrin(Xfrin):
check_command_hook = None
def _cc_setup(self):
+ self._tsig_key_str = None
pass
def _get_db_file(self):
@@ -196,10 +206,46 @@ class TestXfrinConnection(unittest.TestCase):
RRClass.CH())
c.close()
+ def test_send_query(self):
+ def create_msg(query_type):
+ msg = Message(Message.RENDER)
+ query_id = 0x1035
+ msg.set_qid(query_id)
+ msg.set_opcode(Opcode.QUERY())
+ msg.set_rcode(Rcode.NOERROR())
+ query_question = Question(Name("example.com."), RRClass.IN(), query_type)
+ msg.add_question(query_question)
+ return msg
+ self.conn._create_query = create_msg
+ # soa request
+ self.conn._send_query(RRType.SOA())
+ self.assertEqual(self.conn.query_data, b'\x00\x1d\x105\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\x06\x00\x01')
+ # axfr request
+ self.conn._send_query(RRType.AXFR())
+ self.assertEqual(self.conn.query_data, b'\x00\x1d\x105\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\xfc\x00\x01')
+
+ # soa request with tsig
+ self.conn._tsig_ctx = TSIGContext(TSIG_KEY)
+ self.conn._send_query(RRType.SOA())
+ tsig_soa_data = strip_mutable_tsig_data(self.conn.query_data)
+ self.assertEqual(tsig_soa_data, b'\x00n\x105\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x07example\x03com\x00\x00\x06\x00\x01\x07example\x03com\x00\x00\xfa\x00\xff\x00\x00\x00\x00\x00:\x08hmac-md5\x07sig-alg\x03reg\x03int\x00\x01,\x00\x10\x105\x00\x00\x00\x00')
+
+ # axfr request with tsig
+ self.conn._send_query(RRType.AXFR())
+ tsig_axfr_data = strip_mutable_tsig_data(self.conn.query_data)
+ self.assertEqual(tsig_axfr_data, b'\x00n\x105\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x07example\x03com\x00\x00\xfc\x00\x01\x07example\x03com\x00\x00\xfa\x00\xff\x00\x00\x00\x00\x00:\x08hmac-md5\x07sig-alg\x03reg\x03int\x00\x01,\x00\x10\x105\x00\x00\x00\x00')
+
def test_response_with_invalid_msg(self):
self.conn.reply_data = b'aaaxxxx'
self.assertRaises(XfrinTestException, self._handle_xfrin_response)
+ def test_response_with_tsig(self):
+ self.conn._tsig_ctx = TSIGContext(TSIG_KEY)
+ # server tsig check fail, return with RCODE 9 (NOTAUTH)
+ self.conn._send_query(RRType.SOA())
+ self.conn.reply_data = self.conn.create_response_data(rcode=Rcode.NOTAUTH())
+ self.assertRaises(XfrinException, self._handle_xfrin_response)
+
def test_response_without_end_soa(self):
self.conn._send_query(RRType.AXFR())
self.conn.reply_data = self.conn.create_response_data()
@@ -399,15 +445,20 @@ class TestXfrinRecorder(unittest.TestCase):
class TestXfrin(unittest.TestCase):
def setUp(self):
+ # redirect output
+ self.stderr_backup = sys.stderr
+ sys.stderr = open(os.devnull, 'w')
self.xfr = MockXfrin()
self.args = {}
self.args['zone_name'] = TEST_ZONE_NAME
self.args['port'] = TEST_MASTER_PORT
self.args['master'] = TEST_MASTER_IPV4_ADDRESS
self.args['db_file'] = TEST_DB_FILE
+ self.args['tsig_key'] = ''
def tearDown(self):
self.xfr.shutdown()
+ sys.stderr= self.stderr_backup
def _do_parse_zone_name_class(self):
return self.xfr._parse_zone_name_and_class(self.args)
diff --git a/src/bin/xfrin/xfrin.py.in b/src/bin/xfrin/xfrin.py.in
index 10a866e..1bf46c1 100755
--- a/src/bin/xfrin/xfrin.py.in
+++ b/src/bin/xfrin/xfrin.py.in
@@ -67,15 +67,16 @@ DEFAULT_MASTER = '127.0.0.1'
def log_error(msg):
sys.stderr.write("[b10-xfrin] %s\n" % str(msg))
-class XfrinException(Exception):
+class XfrinException(Exception):
pass
class XfrinConnection(asyncore.dispatcher):
- '''Do xfrin in this class. '''
+ '''Do xfrin in this class. '''
def __init__(self,
sock_map, zone_name, rrclass, db_file, shutdown_event,
- master_addrinfo, verbose = False, idle_timeout = 60):
+ master_addrinfo, tsig_key_str = None, verbose = False,
+ idle_timeout = 60):
''' idle_timeout: max idle time for read data from socket.
db_file: specify the data source file.
check_soa: when it's true, check soa first before sending xfr query
@@ -93,6 +94,9 @@ class XfrinConnection(asyncore.dispatcher):
self._shutdown_event = shutdown_event
self._verbose = verbose
self._master_address = master_addrinfo[2]
+ self._tsig_ctx = None
+ if tsig_key_str is not None:
+ self._tsig_ctx = TSIGContext(TSIGKey(tsig_key_str))
def connect_to_master(self):
'''Connect to master in TCP.'''
@@ -130,9 +134,14 @@ class XfrinConnection(asyncore.dispatcher):
msg = self._create_query(query_type)
render = MessageRenderer()
- msg.to_wire(render)
- header_len = struct.pack('H', socket.htons(render.get_length()))
+ # XXX Currently, python wrapper doesn't accept 'None' parameter in this case,
+ # we should remove the if statement and use a universal interface later.
+ if self._tsig_ctx is not None:
+ msg.to_wire(render, self._tsig_ctx)
+ else:
+ msg.to_wire(render)
+ header_len = struct.pack('H', socket.htons(render.get_length()))
self._send_data(header_len)
self._send_data(render.get_data())
@@ -142,7 +151,7 @@ class XfrinConnection(asyncore.dispatcher):
_get_request_response so that we can test the rest of the code without
involving actual communication with a remote server.'''
asyncore.loop(self._idle_timeout, map=self._sock_map, count=1)
-
+
def _get_request_response(self, size):
recv_size = 0
data = b''
@@ -176,7 +185,7 @@ class XfrinConnection(asyncore.dispatcher):
# strict we should be (see the comment in _check_response_header())
self._check_response_header(msg)
- # TODO, need select soa record from data source then compare the two
+ # TODO, need select soa record from data source then compare the two
# serial, current just return OK, since this function hasn't been used
# now.
return XFRIN_OK
@@ -290,14 +299,14 @@ class XfrinConnection(asyncore.dispatcher):
msg = Message(Message.PARSE)
msg.from_wire(recvdata)
self._check_response_status(msg)
-
+
answer_section = msg.get_section(Message.SECTION_ANSWER)
for rr in self._handle_answer_section(answer_section):
yield rr
if self._soa_rr_count == 2:
break
-
+
if self._shutdown_event.is_set():
raise XfrinException('xfrin is forced to stop')
@@ -322,16 +331,18 @@ class XfrinConnection(asyncore.dispatcher):
sys.stdout.write('[b10-xfrin] %s\n' % str(msg))
-def process_xfrin(server, xfrin_recorder, zone_name, rrclass, db_file,
- shutdown_event, master_addrinfo, check_soa, verbose):
+def process_xfrin(server, xfrin_recorder, zone_name, rrclass, db_file,
+ shutdown_event, master_addrinfo, check_soa, verbose,
+ tsig_key_str):
xfrin_recorder.increment(zone_name)
sock_map = {}
conn = XfrinConnection(sock_map, zone_name, rrclass, db_file,
- shutdown_event, master_addrinfo, verbose)
+ shutdown_event, master_addrinfo,
+ tsig_key_str, verbose)
ret = XFRIN_FAIL
if conn.connect_to_master():
ret = conn.do_xfrin(check_soa)
-
+
# Publish the zone transfer result news, so zonemgr can reset the
# zone timer, and xfrout can notify the zone's slaves if the result
# is success.
@@ -379,11 +390,11 @@ class Xfrin:
self._verbose = verbose
def _cc_setup(self):
- '''This method is used only as part of initialization, but is
- implemented separately for convenience of unit tests; by letting
- the test code override this method we can test most of this class
+ '''This method is used only as part of initialization, but is
+ implemented separately for convenience of unit tests; by letting
+ the test code override this method we can test most of this class
without requiring a command channel.'''
- # Create one session for sending command to other modules, because the
+ # Create one session for sending command to other modules, because the
# listening session will block the send operation.
self._send_cc_session = isc.cc.Session()
self._module_cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
@@ -394,15 +405,17 @@ class Xfrin:
self._max_transfers_in = config_data.get("transfers_in")
self._master_addr = config_data.get('master_addr') or self._master_addr
self._master_port = config_data.get('master_port') or self._master_port
+ self._tsig_key_str = config_data.get('tsig_key') or None
def _cc_check_command(self):
- '''This is a straightforward wrapper for cc.check_command,
- but provided as a separate method for the convenience
+ '''This is a straightforward wrapper for cc.check_command,
+ but provided as a separate method for the convenience
of unit tests.'''
self._module_cc.check_command(False)
def config_handler(self, new_config):
self._max_transfers_in = new_config.get("transfers_in") or self._max_transfers_in
+ self._tsig_key_str = new_config.get('tsig_key') or None
if ('master_addr' in new_config) or ('master_port' in new_config):
# User should change the port and address together.
try:
@@ -420,7 +433,7 @@ class Xfrin:
return create_answer(0)
def shutdown(self):
- ''' shutdown the xfrin process. the thread which is doing xfrin should be
+ ''' shutdown the xfrin process. the thread which is doing xfrin should be
terminated.
'''
self._shutdown_event.set()
@@ -436,30 +449,32 @@ class Xfrin:
if command == 'shutdown':
self._shutdown_event.set()
elif command == 'notify' or command == REFRESH_FROM_ZONEMGR:
- # Xfrin receives the refresh/notify command from zone manager.
- # notify command maybe has the parameters which
+ # Xfrin receives the refresh/notify command from zone manager.
+ # notify command maybe has the parameters which
# specify the notifyfrom address and port, according the RFC1996, zone
# transfer should starts first from the notifyfrom, but now, let 'TODO' it.
(zone_name, rrclass) = self._parse_zone_name_and_class(args)
(master_addr) = build_addr_info(self._master_addr, self._master_port)
- ret = self.xfrin_start(zone_name,
- rrclass,
+ ret = self.xfrin_start(zone_name,
+ rrclass,
self._get_db_file(),
master_addr,
+ self._tsig_key_str,
True)
answer = create_answer(ret[0], ret[1])
elif command == 'retransfer' or command == 'refresh':
# Xfrin receives the retransfer/refresh from cmdctl(sent by bindctl).
- # If the command has specified master address, do transfer from the
- # master address, or else do transfer from the configured masters.
+ # If the command has specified master address, do transfer from the
+ # master address, or else do transfer from the configured masters.
(zone_name, rrclass) = self._parse_zone_name_and_class(args)
master_addr = self._parse_master_and_port(args)
db_file = args.get('db_file') or self._get_db_file()
- ret = self.xfrin_start(zone_name,
- rrclass,
- db_file,
+ ret = self.xfrin_start(zone_name,
+ rrclass,
+ db_file,
master_addr,
+ self._tsig_key_str,
(False if command == 'retransfer' else True))
answer = create_answer(ret[0], ret[1])
@@ -483,14 +498,14 @@ class Xfrin:
rrclass = RRClass(rrclass)
except InvalidRRClass as e:
raise XfrinException('invalid RRClass: ' + rrclass)
-
+
return zone_name, rrclass
def _parse_master_and_port(self, args):
port = args.get('port') or self._master_port
master = args.get('master') or self._master_addr
return build_addr_info(master, port)
-
+
def _get_db_file(self):
#TODO, the db file path should be got in auth server's configuration
# if we need access to this configuration more often, we
@@ -506,12 +521,12 @@ class Xfrin:
db_file = os.environ["B10_FROM_BUILD"] + os.sep + "bind10_zones.sqlite3"
self._module_cc.remove_remote_config(AUTH_SPECFILE_LOCATION)
return db_file
-
+
def publish_xfrin_news(self, zone_name, zone_class, xfr_result):
'''Send command to xfrout/zone manager module.
- If xfrin has finished successfully for one zone, tell the good
+ If xfrin has finished successfully for one zone, tell the good
news(command: zone_new_data_ready) to zone manager and xfrout.
- if xfrin failed, just tell the bad news to zone manager, so that
+ if xfrin failed, just tell the bad news to zone manager, so that
it can reset the refresh timer for that zone. '''
param = {'zone_name': zone_name, 'zone_class': zone_class.to_text()}
if xfr_result == XFRIN_OK:
@@ -531,8 +546,8 @@ class Xfrin:
seq)
except isc.cc.session.SessionTimeout:
pass # for now we just ignore the failure
- except socket.error as err:
- log_error("Fail to send message to %s and %s, msgq may has been killed"
+ except socket.error as err:
+ log_error("Fail to send message to %s and %s, msgq may has been killed"
% (XFROUT_MODULE_NAME, ZONE_MANAGER_MODULE_NAME))
else:
msg = create_command(ZONE_XFRIN_FAILED, param)
@@ -545,14 +560,14 @@ class Xfrin:
except isc.cc.session.SessionTimeout:
pass # for now we just ignore the failure
except socket.error as err:
- log_error("Fail to send message to %s, msgq may has been killed"
+ log_error("Fail to send message to %s, msgq may has been killed"
% ZONE_MANAGER_MODULE_NAME)
def startup(self):
while not self._shutdown_event.is_set():
self._cc_check_command()
- def xfrin_start(self, zone_name, rrclass, db_file, master_addrinfo,
+ def xfrin_start(self, zone_name, rrclass, db_file, master_addrinfo, tsig_key_str,
check_soa = True):
if "pydnspp" not in sys.modules:
return (1, "xfrin failed, can't load dns message python library: 'pydnspp'")
@@ -571,7 +586,8 @@ class Xfrin:
db_file,
self._shutdown_event,
master_addrinfo, check_soa,
- self._verbose))
+ self._verbose,
+ tsig_key_str))
xfrin_thread.start()
return (0, 'zone xfrin is started')
diff --git a/src/bin/xfrin/xfrin.spec b/src/bin/xfrin/xfrin.spec
index 61ddaad..46bad69 100644
--- a/src/bin/xfrin/xfrin.spec
+++ b/src/bin/xfrin/xfrin.spec
@@ -19,6 +19,11 @@
"item_type": "integer",
"item_optional": false,
"item_default": 53
+ },
+ { "item_name": "tsig_key",
+ "item_type": "string",
+ "item_optional": true,
+ "item_default": ""
}
],
"commands": [
diff --git a/src/bin/xfrout/tests/Makefile.am b/src/bin/xfrout/tests/Makefile.am
index 1ec3c06..11916af 100644
--- a/src/bin/xfrout/tests/Makefile.am
+++ b/src/bin/xfrout/tests/Makefile.am
@@ -6,7 +6,7 @@ EXTRA_DIST = $(PYTESTS)
# required by loadable python modules.
LIBRARY_PATH_PLACEHOLDER =
if SET_ENV_LIBRARY_PATH
-LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/util/io/.libs:$$$(ENV_LIBRARY_PATH)
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/util/io/.libs:$$$(ENV_LIBRARY_PATH)
endif
# test using command-line arguments, so use check-local target instead of TESTS
diff --git a/src/bin/zonemgr/tests/zonemgr_test.py b/src/bin/zonemgr/tests/zonemgr_test.py
index c6d151d..479ca68 100644
--- a/src/bin/zonemgr/tests/zonemgr_test.py
+++ b/src/bin/zonemgr/tests/zonemgr_test.py
@@ -21,11 +21,12 @@ import os
import tempfile
from zonemgr import *
-ZONE_NAME_CLASS1_IN = ("sd.cn.", "IN")
-ZONE_NAME_CLASS2_CH = ("tw.cn.", "CH")
-ZONE_NAME_CLASS3_IN = ("example.com", "IN")
-ZONE_NAME_CLASS1_CH = ("sd.cn.", "CH")
-ZONE_NAME_CLASS2_IN = ("tw.cn.", "IN")
+ZONE_NAME_CLASS1_IN = ("example.net.", "IN")
+ZONE_NAME_CLASS1_CH = ("example.net.", "CH")
+ZONE_NAME_CLASS2_IN = ("example.org.", "IN")
+ZONE_NAME_CLASS2_CH = ("example.org.", "CH")
+ZONE_NAME_CLASS3_IN = ("example.com.", "IN")
+ZONE_NAME_CLASS3_CH = ("example.com.", "CH")
MAX_TRANSFER_TIMEOUT = 14400
LOWERBOUND_REFRESH = 10
@@ -80,12 +81,12 @@ class MyZonemgrRefresh(ZonemgrRefresh):
self._refresh_jitter = 0.25
def get_zone_soa(zone_name, db_file):
- if zone_name == 'sd.cn.':
- return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None,
- 'a.dns.cn. root.cnnic.cn. 2009073106 7200 3600 2419200 21600')
- elif zone_name == 'tw.cn.':
- return (1, 2, 'tw.cn.', 'cn.sd.', 21600, 'SOA', None,
- 'a.dns.cn. root.cnnic.cn. 2009073112 7200 3600 2419200 21600')
+ if zone_name == 'example.net.':
+ return (1, 2, 'example.net.', 'example.net.sd.', 21600, 'SOA', None,
+ 'a.example.net. root.example.net. 2009073106 7200 3600 2419200 21600')
+ elif zone_name == 'example.org.':
+ return (1, 2, 'example.org.', 'example.org.sd.', 21600, 'SOA', None,
+ 'a.example.org. root.example.org. 2009073112 7200 3600 2419200 21600')
else:
return None
sqlite3_ds.get_zone_soa = get_zone_soa
@@ -94,15 +95,15 @@ class MyZonemgrRefresh(ZonemgrRefresh):
self._slave_socket, FakeConfig())
current_time = time.time()
self._zonemgr_refresh_info = {
- ('sd.cn.', 'IN'): {
+ ('example.net.', 'IN'): {
'last_refresh_time': current_time,
'next_refresh_time': current_time + 6500,
- 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600',
+ 'zone_soa_rdata': 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600',
'zone_state': 0},
- ('tw.cn.', 'CH'): {
+ ('example.org.', 'CH'): {
'last_refresh_time': current_time,
'next_refresh_time': current_time + 6900,
- 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073112 7200 3600 2419200 21600',
+ 'zone_soa_rdata': 'a.example.org. root.example.org. 2009073112 7200 3600 2419200 21600',
'zone_state': 0}
}
@@ -157,6 +158,7 @@ class TestZonemgrRefresh(unittest.TestCase):
self.assertFalse(self.zone_refresh._zone_not_exist(ZONE_NAME_CLASS2_CH))
self.assertTrue(self.zone_refresh._zone_not_exist(ZONE_NAME_CLASS2_IN))
self.assertTrue(self.zone_refresh._zone_not_exist(ZONE_NAME_CLASS3_IN))
+ self.assertTrue(self.zone_refresh._zone_not_exist(ZONE_NAME_CLASS3_CH))
def test_set_zone_notify_timer(self):
time1 = time.time()
@@ -179,20 +181,20 @@ class TestZonemgrRefresh(unittest.TestCase):
self.assertTrue(self.zone_refresh._zone_is_expired(ZONE_NAME_CLASS1_IN))
def test_get_zone_soa_rdata(self):
- soa_rdata1 = 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600'
- soa_rdata2 = 'a.dns.cn. root.cnnic.cn. 2009073112 7200 3600 2419200 21600'
+ soa_rdata1 = 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600'
+ soa_rdata2 = 'a.example.org. root.example.org. 2009073112 7200 3600 2419200 21600'
self.assertEqual(soa_rdata1, self.zone_refresh._get_zone_soa_rdata(ZONE_NAME_CLASS1_IN))
self.assertRaises(KeyError, self.zone_refresh._get_zone_soa_rdata, ZONE_NAME_CLASS1_CH)
self.assertEqual(soa_rdata2, self.zone_refresh._get_zone_soa_rdata(ZONE_NAME_CLASS2_CH))
self.assertRaises(KeyError, self.zone_refresh._get_zone_soa_rdata, ZONE_NAME_CLASS2_IN)
def test_zonemgr_reload_zone(self):
- soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600'
+ soa_rdata = 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600'
# We need to restore this not to harm other tests
old_get_zone_soa = sqlite3_ds.get_zone_soa
def get_zone_soa(zone_name, db_file):
- return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None,
- 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600')
+ return (1, 2, 'example.net.', 'example.net.sd.', 21600, 'SOA', None,
+ 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600')
sqlite3_ds.get_zone_soa = get_zone_soa
self.zone_refresh.zonemgr_reload_zone(ZONE_NAME_CLASS1_IN)
@@ -274,15 +276,15 @@ class TestZonemgrRefresh(unittest.TestCase):
self.assertTrue(self.zone_refresh._zone_mgr_is_empty())
def test_zonemgr_add_zone(self):
- soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600'
+ soa_rdata = 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600'
# This needs to be restored. The following test actually failed if we left
# this unclean
old_get_zone_soa = sqlite3_ds.get_zone_soa
time1 = time.time()
def get_zone_soa(zone_name, db_file):
- return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None,
- 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600')
+ return (1, 2, 'example.net.', 'example.net.sd.', 21600, 'SOA', None,
+ 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600')
sqlite3_ds.get_zone_soa = get_zone_soa
@@ -314,15 +316,15 @@ class TestZonemgrRefresh(unittest.TestCase):
current_time = time.time()
self.assertTrue(zone_timeout <= current_time)
self.assertRaises(ZonemgrException, self.zone_refresh.zone_handle_notify,\
- ("org.cn.", "IN"), "127.0.0.1")
+ ZONE_NAME_CLASS3_CH, "127.0.0.1")
self.assertRaises(ZonemgrException, self.zone_refresh.zone_handle_notify,\
ZONE_NAME_CLASS3_IN, "127.0.0.1")
def test_zone_refresh_success(self):
- soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600'
+ soa_rdata = 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600'
def get_zone_soa(zone_name, db_file):
- return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None,
- 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600')
+ return (1, 2, 'example.net.', 'example.net.sd.', 21600, 'SOA', None,
+ 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600')
sqlite3_ds.get_zone_soa = get_zone_soa
time1 = time.time()
self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"] = ZONE_REFRESHING
@@ -337,11 +339,11 @@ class TestZonemgrRefresh(unittest.TestCase):
last_refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["last_refresh_time"]
self.assertTrue(time1 <= last_refresh_time)
self.assertTrue(last_refresh_time <= time2)
- self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_success, ("org.cn.", "CH"))
+ self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_success, ("example.test.", "CH"))
self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_success, ZONE_NAME_CLASS3_IN)
def test_zone_refresh_fail(self):
- soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600'
+ soa_rdata = 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600'
time1 = time.time()
self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"] = ZONE_REFRESHING
self.zone_refresh.zone_refresh_fail(ZONE_NAME_CLASS1_IN)
@@ -357,22 +359,22 @@ class TestZonemgrRefresh(unittest.TestCase):
self.zone_refresh.zone_refresh_fail(ZONE_NAME_CLASS1_IN)
self.assertEqual(ZONE_EXPIRED, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"])
- self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ("org.cn.", "CH"))
+ self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ZONE_NAME_CLASS3_CH)
self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ZONE_NAME_CLASS3_IN)
def test_find_need_do_refresh_zone(self):
time1 = time.time()
self.zone_refresh._zonemgr_refresh_info = {
- ("sd.cn.","IN"):{
+ ("example.net.","IN"):{
'last_refresh_time': time1,
'next_refresh_time': time1 + 7200,
- 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600',
+ 'zone_soa_rdata': 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600',
'zone_state': ZONE_OK},
- ("tw.cn.","CH"):{
+ ("example.org.","CH"):{
'last_refresh_time': time1 - 7200,
'next_refresh_time': time1,
'refresh_timeout': time1 + MAX_TRANSFER_TIMEOUT,
- 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073112 7200 3600 2419200 21600',
+ 'zone_soa_rdata': 'a.example.org. root.example.org. 2009073112 7200 3600 2419200 21600',
'zone_state': ZONE_REFRESHING}
}
zone_need_refresh = self.zone_refresh._find_need_do_refresh_zone()
@@ -385,10 +387,10 @@ class TestZonemgrRefresh(unittest.TestCase):
def test_do_refresh(self):
time1 = time.time()
self.zone_refresh._zonemgr_refresh_info = {
- ("sd.cn.", "IN"):{
+ ("example.net.", "IN"):{
'last_refresh_time': time1 - 7200,
'next_refresh_time': time1 - 1,
- 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600',
+ 'zone_soa_rdata': 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600',
'zone_state': ZONE_OK}
}
self.zone_refresh._do_refresh(ZONE_NAME_CLASS1_IN)
@@ -416,10 +418,10 @@ class TestZonemgrRefresh(unittest.TestCase):
"""
time1 = time.time()
self.zone_refresh._zonemgr_refresh_info = {
- ("sd.cn.", "IN"):{
+ ("example.net.", "IN"):{
'last_refresh_time': time1 - 7200,
'next_refresh_time': time1 - 1,
- 'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600',
+ 'zone_soa_rdata': 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600',
'zone_state': ZONE_OK}
}
self.zone_refresh._check_sock = self.zone_refresh._master_socket
@@ -465,19 +467,19 @@ class TestZonemgrRefresh(unittest.TestCase):
# Put something in
config.set_zone_list_from_name_classes([ZONE_NAME_CLASS1_IN])
self.zone_refresh.update_config_data(config)
- self.assertTrue(("sd.cn.", "IN") in
+ self.assertTrue(("example.net.", "IN") in
self.zone_refresh._zonemgr_refresh_info)
# This one does not exist
config.set_zone_list_from_name_classes(["example.net", "CH"])
self.assertRaises(ZonemgrException,
self.zone_refresh.update_config_data, config)
# So it should not affect the old ones
- self.assertTrue(("sd.cn.", "IN") in
+ self.assertTrue(("example.net.", "IN") in
self.zone_refresh._zonemgr_refresh_info)
# Make sure it works even when we "accidentally" forget the final dot
- config.set_zone_list_from_name_classes([("sd.cn", "IN")])
+ config.set_zone_list_from_name_classes([("example.net", "IN")])
self.zone_refresh.update_config_data(config)
- self.assertTrue(("sd.cn.", "IN") in
+ self.assertTrue(("example.net.", "IN") in
self.zone_refresh._zonemgr_refresh_info)
def tearDown(self):
@@ -532,7 +534,7 @@ class TestZonemgr(unittest.TestCase):
self.assertEqual(self.zonemgr.config_handler(config_data1),
{"result": [0]})
self.assertEqual(config_data1, self.zonemgr._config_data)
- config_data2 = {"zone_name" : "sd.cn.", "port" : "53", "master" : "192.168.1.1"}
+ config_data2 = {"zone_name" : "example.net.", "port" : "53", "master" : "192.168.1.1"}
self.zonemgr.config_handler(config_data2)
self.assertEqual(config_data1, self.zonemgr._config_data)
# jitter should not be bigger than half of the original value
@@ -553,11 +555,11 @@ class TestZonemgr(unittest.TestCase):
self.assertEqual("initdb.file", self.zonemgr.get_db_file())
def test_parse_cmd_params(self):
- params1 = {"zone_name" : "org.cn", "zone_class" : "CH", "master" : "127.0.0.1"}
- answer1 = (("org.cn", "CH"), "127.0.0.1")
+ params1 = {"zone_name" : "example.com.", "zone_class" : "CH", "master" : "127.0.0.1"}
+ answer1 = (ZONE_NAME_CLASS3_CH, "127.0.0.1")
self.assertEqual(answer1, self.zonemgr._parse_cmd_params(params1, ZONE_NOTIFY_COMMAND))
- params2 = {"zone_name" : "org.cn", "zone_class" : "CH"}
- answer2 = ("org.cn", "CH")
+ params2 = {"zone_name" : "example.com.", "zone_class" : "IN"}
+ answer2 = ZONE_NAME_CLASS3_IN
self.assertEqual(answer2, self.zonemgr._parse_cmd_params(params2, ZONE_XFRIN_SUCCESS_COMMAND))
self.assertRaises(ZonemgrException, self.zonemgr._parse_cmd_params, params2, ZONE_NOTIFY_COMMAND)
params1 = {"zone_class" : "CH"}
diff --git a/src/cppcheck-suppress.lst b/src/cppcheck-suppress.lst
index e9c4beb..4659dc4 100644
--- a/src/cppcheck-suppress.lst
+++ b/src/cppcheck-suppress.lst
@@ -12,4 +12,4 @@ functionConst:src/lib/cache/rrset_cache.h
// Intentional self assignment tests. Suppress warning about them.
selfAssignment:src/lib/dns/tests/name_unittest.cc:293
selfAssignment:src/lib/dns/tests/rdata_unittest.cc:228
-selfAssignment:src/lib/dns/tests/tsigkey_unittest.cc:104
+selfAssignment:src/lib/dns/tests/tsigkey_unittest.cc:125
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 81455c4..81ddd18 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -1,2 +1,3 @@
-SUBDIRS = exceptions util dns cc config python xfr bench log asiolink \
- asiodns nsas cache resolve testutils datasrc server_common
+SUBDIRS = exceptions util log cryptolink dns cc config python xfr \
+ bench asiolink asiodns nsas cache resolve testutils datasrc \
+ server_common
diff --git a/src/lib/asiodns/Makefile.am b/src/lib/asiodns/Makefile.am
index 4bcdde6..2a6c3ac 100644
--- a/src/lib/asiodns/Makefile.am
+++ b/src/lib/asiodns/Makefile.am
@@ -8,12 +8,17 @@ AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
AM_CXXFLAGS = $(B10_CXXFLAGS)
-CLEANFILES = *.gcno *.gcda
+CLEANFILES = *.gcno *.gcda asiodef.h asiodef.cc
+
+# Define rule to build logging source files from message file
+asiodef.h asiodef.cc: asiodef.mes
+ $(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/asiodns/asiodef.mes
+
+BUILT_SOURCES = asiodef.h asiodef.cc
lib_LTLIBRARIES = libasiodns.la
libasiodns_la_SOURCES = dns_answer.h
libasiodns_la_SOURCES += asiodns.h
-libasiodns_la_SOURCES += asiodef.cc asiodef.h
libasiodns_la_SOURCES += dns_lookup.h
libasiodns_la_SOURCES += dns_server.h
libasiodns_la_SOURCES += dns_service.cc dns_service.h
@@ -21,7 +26,9 @@ libasiodns_la_SOURCES += tcp_server.cc tcp_server.h
libasiodns_la_SOURCES += udp_server.cc udp_server.h
libasiodns_la_SOURCES += io_fetch.cc io_fetch.h
-EXTRA_DIST = asiodef.msg
+nodist_libasiodns_la_SOURCES = asiodef.cc asiodef.h
+
+EXTRA_DIST = asiodef.mes
# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
# B10_CXXFLAGS)
diff --git a/src/lib/asiodns/asiodef.cc b/src/lib/asiodns/asiodef.cc
deleted file mode 100644
index 127e848..0000000
--- a/src/lib/asiodns/asiodef.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// File created from asiodef.msg on Mon Feb 28 17:15:30 2011
-
-#include <cstddef>
-#include <log/message_types.h>
-#include <log/message_initializer.h>
-
-namespace isc {
-namespace asiodns {
-
-extern const isc::log::MessageID ASIODNS_FETCHCOMP = "FETCHCOMP";
-extern const isc::log::MessageID ASIODNS_FETCHSTOP = "FETCHSTOP";
-extern const isc::log::MessageID ASIODNS_OPENSOCK = "OPENSOCK";
-extern const isc::log::MessageID ASIODNS_RECVSOCK = "RECVSOCK";
-extern const isc::log::MessageID ASIODNS_RECVTMO = "RECVTMO";
-extern const isc::log::MessageID ASIODNS_SENDSOCK = "SENDSOCK";
-extern const isc::log::MessageID ASIODNS_UNKORIGIN = "UNKORIGIN";
-extern const isc::log::MessageID ASIODNS_UNKRESULT = "UNKRESULT";
-
-} // namespace asiodns
-} // namespace isc
-
-namespace {
-
-const char* values[] = {
- "FETCHCOMP", "upstream fetch to %s(%d) has now completed",
- "FETCHSTOP", "upstream fetch to %s(%d) has been stopped",
- "OPENSOCK", "error %d opening %s socket to %s(%d)",
- "RECVSOCK", "error %d reading %s data from %s(%d)",
- "RECVTMO", "receive timeout while waiting for data from %s(%d)",
- "SENDSOCK", "error %d sending data using %s to %s(%d)",
- "UNKORIGIN", "unknown origin for ASIO error code %d (protocol: %s, address %s)",
- "UNKRESULT", "unknown result (%d) when IOFetch::stop() was executed for I/O to %s(%d)",
- NULL
-};
-
-const isc::log::MessageInitializer initializer(values);
-
-} // Anonymous namespace
-
diff --git a/src/lib/asiodns/asiodef.h b/src/lib/asiodns/asiodef.h
deleted file mode 100644
index 50aa8a9..0000000
--- a/src/lib/asiodns/asiodef.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// File created from asiodef.msg on Mon Feb 28 17:15:30 2011
-
-#ifndef __ASIODEF_H
-#define __ASIODEF_H
-
-#include <log/message_types.h>
-
-namespace isc {
-namespace asiodns {
-
-extern const isc::log::MessageID ASIODNS_FETCHCOMP;
-extern const isc::log::MessageID ASIODNS_FETCHSTOP;
-extern const isc::log::MessageID ASIODNS_OPENSOCK;
-extern const isc::log::MessageID ASIODNS_RECVSOCK;
-extern const isc::log::MessageID ASIODNS_RECVTMO;
-extern const isc::log::MessageID ASIODNS_SENDSOCK;
-extern const isc::log::MessageID ASIODNS_UNKORIGIN;
-extern const isc::log::MessageID ASIODNS_UNKRESULT;
-
-} // namespace asiodns
-} // namespace isc
-
-#endif // __ASIODEF_H
diff --git a/src/lib/asiodns/asiodef.mes b/src/lib/asiodns/asiodef.mes
new file mode 100644
index 0000000..3f2e80c
--- /dev/null
+++ b/src/lib/asiodns/asiodef.mes
@@ -0,0 +1,56 @@
+# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+$PREFIX ASIODNS_
+$NAMESPACE isc::asiodns
+
+% FETCHCOMP upstream fetch to %1(%2) has now completed
+A debug message, this records the the upstream fetch (a query made by the
+resolver on behalf of its client) to the specified address has completed.
+
+% FETCHSTOP upstream fetch to %1(%2) has been stopped
+An external component has requested the halting of an upstream fetch. This
+is an allowed operation, and the message should only appear if debug is
+enabled.
+
+% OPENSOCK error %1 opening %2 socket to %3(%4)
+The asynchronous I/O code encountered an error when trying to open a socket
+of the specified protocol in order to send a message to the target address.
+The the number of the system error that cause the problem is given in the
+message.
+
+% RECVSOCK error %1 reading %2 data from %3(%4)
+The asynchronous I/O code encountered an error when trying read data from
+the specified address on the given protocol. The the number of the system
+error that cause the problem is given in the message.
+
+% SENDSOCK error %1 sending data using %2 to %3(%4)
+The asynchronous I/O code encountered an error when trying send data to
+the specified address on the given protocol. The the number of the system
+error that cause the problem is given in the message.
+
+% RECVTMO receive timeout while waiting for data from %1(%2)
+An upstream fetch from the specified address timed out. This may happen for
+any number of reasons and is most probably a problem at the remote server
+or a problem on the network. The message will only appear if debug is
+enabled.
+
+% UNKORIGIN unknown origin for ASIO error code %1 (protocol: %2, address %3)
+This message should not appear and indicates an internal error if it does.
+Please enter a bug report.
+
+% UNKRESULT unknown result (%1) when IOFetch::stop() was executed for I/O to %2(%3)
+The termination method of the resolver's upstream fetch class was called with
+an unknown result code (which is given in the message). This message should
+not appear and may indicate an internal error. Please enter a bug report.
diff --git a/src/lib/asiodns/asiodef.msg b/src/lib/asiodns/asiodef.msg
deleted file mode 100644
index 7f86acb..0000000
--- a/src/lib/asiodns/asiodef.msg
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-# PERFORMANCE OF THIS SOFTWARE.
-
-$PREFIX ASIODNS_
-$NAMESPACE isc::asiodns
-
-FETCHCOMP upstream fetch to %s(%d) has now completed
-+ A debug message, this records the the upstream fetch (a query made by the
-+ resolver on behalf of its client) to the specified address has completed.
-
-FETCHSTOP upstream fetch to %s(%d) has been stopped
-+ An external component has requested the halting of an upstream fetch. This
-+ is an allowed operation, and the message should only appear if debug is
-+ enabled.
-
-OPENSOCK error %d opening %s socket to %s(%d)
-+ The asynchronous I/O code encountered an error when trying to open a socket
-+ of the specified protocol in order to send a message to the target address.
-+ The the number of the system error that cause the problem is given in the
-+ message.
-
-RECVSOCK error %d reading %s data from %s(%d)
-+ The asynchronous I/O code encountered an error when trying read data from
-+ the specified address on the given protocol. The the number of the system
-+ error that cause the problem is given in the message.
-
-SENDSOCK error %d sending data using %s to %s(%d)
-+ The asynchronous I/O code encountered an error when trying send data to
-+ the specified address on the given protocol. The the number of the system
-+ error that cause the problem is given in the message.
-
-RECVTMO receive timeout while waiting for data from %s(%d)
-+ An upstream fetch from the specified address timed out. This may happen for
-+ any number of reasons and is most probably a problem at the remote server
-+ or a problem on the network. The message will only appear if debug is
-+ enabled.
-
-UNKORIGIN unknown origin for ASIO error code %d (protocol: %s, address %s)
-+ This message should not appear and indicates an internal error if it does.
-+ Please enter a bug report.
-
-UNKRESULT unknown result (%d) when IOFetch::stop() was executed for I/O to %s(%d)
-+ The termination method of the resolver's upstream fetch class was called with
-+ an unknown result code (which is given in the message). This message should
-+ not appear and may indicate an internal error. Please enter a bug report.
diff --git a/src/lib/asiodns/io_fetch.cc b/src/lib/asiodns/io_fetch.cc
index 8f57d8e..e535381 100644
--- a/src/lib/asiodns/io_fetch.cc
+++ b/src/lib/asiodns/io_fetch.cc
@@ -35,11 +35,11 @@
#include <asiolink/udp_endpoint.h>
#include <asiolink/udp_socket.h>
-#include <dns/message.h>
#include <dns/messagerenderer.h>
#include <dns/opcode.h>
#include <dns/rcode.h>
#include <log/logger.h>
+#include <log/macros.h>
#include <asiodns/asiodef.h>
#include <asiodns/io_fetch.h>
@@ -61,7 +61,17 @@ namespace asiodns {
/// Use the ASIO logger
+namespace {
+
isc::log::Logger logger("asiolink");
+// Log debug verbosity
+enum {
+ DBG_IMPORTANT = 1,
+ DBG_COMMON = 20,
+ DBG_ALL = 50
+};
+
+}
/// \brief IOFetch Data
///
@@ -80,7 +90,6 @@ struct IOFetchData {
///< Socket to use for I/O
boost::scoped_ptr<IOEndpoint> remote_snd;///< Where the fetch is sent
boost::scoped_ptr<IOEndpoint> remote_rcv;///< Where the response came from
- isc::dns::Question question; ///< Question to be asked
OutputBufferPtr msgbuf; ///< Wire buffer for question
OutputBufferPtr received; ///< Received data put here
IOFetch::Callback* callback; ///< Called on I/O Completion
@@ -110,7 +119,6 @@ struct IOFetchData {
/// \param proto Either IOFetch::TCP or IOFetch::UDP.
/// \param service I/O Service object to handle the asynchronous
/// operations.
- /// \param query DNS question to send to the upstream server.
/// \param address IP address of upstream server
/// \param port Port to use for the query
/// \param buff Output buffer into which the response (in wire format)
@@ -122,8 +130,8 @@ struct IOFetchData {
///
/// TODO: May need to alter constructor (see comment 4 in Trac ticket #554)
IOFetchData(IOFetch::Protocol proto, IOService& service,
- const isc::dns::Question& query, const IOAddress& address,
- uint16_t port, OutputBufferPtr& buff, IOFetch::Callback* cb, int wait)
+ const IOAddress& address, uint16_t port, OutputBufferPtr& buff,
+ IOFetch::Callback* cb, int wait)
:
socket((proto == IOFetch::UDP) ?
static_cast<IOAsioSocket<IOFetch>*>(
@@ -139,7 +147,6 @@ struct IOFetchData {
static_cast<IOEndpoint*>(new UDPEndpoint(address, port)) :
static_cast<IOEndpoint*>(new TCPEndpoint(address, port))
),
- question(query),
msgbuf(new OutputBuffer(512)),
received(buff),
callback(cb),
@@ -174,10 +181,10 @@ struct IOFetchData {
IOFetch::IOFetch(Protocol protocol, IOService& service,
const isc::dns::Question& question, const IOAddress& address, uint16_t port,
OutputBufferPtr& buff, Callback* cb, int wait)
- :
- data_(new IOFetchData(protocol, service, question, address,
- port, buff, cb, wait))
{
+ MessagePtr query_msg(new Message(Message::RENDER));
+ initIOFetch(query_msg, protocol, service, question, address, port, buff,
+ cb, wait);
}
IOFetch::IOFetch(Protocol protocol, IOService& service,
@@ -185,14 +192,56 @@ IOFetch::IOFetch(Protocol protocol, IOService& service,
OutputBufferPtr& buff, Callback* cb, int wait)
:
data_(new IOFetchData(protocol, service,
- isc::dns::Question(isc::dns::Name("dummy.example.org"),
- isc::dns::RRClass::IN(), isc::dns::RRType::A()),
address, port, buff, cb, wait))
{
data_->msgbuf = outpkt;
data_->packet = true;
}
+IOFetch::IOFetch(Protocol protocol, IOService& service,
+ ConstMessagePtr query_message, const IOAddress& address, uint16_t port,
+ OutputBufferPtr& buff, Callback* cb, int wait)
+{
+ MessagePtr msg(new Message(Message::RENDER));
+
+ msg->setHeaderFlag(Message::HEADERFLAG_RD,
+ query_message->getHeaderFlag(Message::HEADERFLAG_RD));
+ msg->setHeaderFlag(Message::HEADERFLAG_CD,
+ query_message->getHeaderFlag(Message::HEADERFLAG_CD));
+
+ ConstEDNSPtr edns(query_message->getEDNS());
+ const bool dnssec_ok = edns && edns->getDNSSECAwareness();
+ if (edns) {
+ EDNSPtr edns_response(new EDNS());
+ edns_response->setDNSSECAwareness(dnssec_ok);
+ // TODO: We should make our own edns bufsize length configurable
+ edns_response->setUDPSize(Message::DEFAULT_MAX_EDNS0_UDPSIZE);
+ msg->setEDNS(edns_response);
+ }
+
+ initIOFetch(msg, protocol, service,
+ **(query_message->beginQuestion()),
+ address, port, buff, cb, wait);
+}
+
+void
+IOFetch::initIOFetch(MessagePtr& query_msg, Protocol protocol, IOService& service,
+ const isc::dns::Question& question,
+ const IOAddress& address, uint16_t port,
+ OutputBufferPtr& buff, Callback* cb, int wait)
+{
+ data_ = boost::shared_ptr<IOFetchData>(new IOFetchData(
+ protocol, service, address, port, buff, cb, wait));
+
+ query_msg->setQid(data_->qid);
+ query_msg->setOpcode(Opcode::QUERY());
+ query_msg->setRcode(Rcode::NOERROR());
+ query_msg->setHeaderFlag(Message::HEADERFLAG_RD);
+ query_msg->addQuestion(question);
+ MessageRenderer renderer(*data_->msgbuf);
+ query_msg->toWire(renderer);
+}
+
// Return protocol in use.
IOFetch::Protocol
@@ -224,17 +273,7 @@ IOFetch::operator()(asio::error_code ec, size_t length) {
// first two bytes of the packet).
data_->msgbuf->writeUint16At(data_->qid, 0);
- } else {
- // A question was given, construct the packet
- Message msg(Message::RENDER);
- msg.setQid(data_->qid);
- msg.setOpcode(Opcode::QUERY());
- msg.setRcode(Rcode::NOERROR());
- msg.setHeaderFlag(Message::HEADERFLAG_RD);
- msg.addQuestion(data_->question);
- MessageRenderer renderer(*data_->msgbuf);
- msg.toWire(renderer);
- }
+ }
}
// If we timeout, we stop, which will can cancel outstanding I/Os and
@@ -331,42 +370,34 @@ IOFetch::stop(Result result) {
// numbers indicating the most important information. The relative
// values are somewhat arbitrary.
//
- // Although Logger::debug checks the debug flag internally, doing it
- // below before calling Logger::debug avoids the overhead of a string
- // conversion in the common case when debug is not enabled.
- //
// TODO: Update testing of stopped_ if threads are used.
data_->stopped = true;
switch (result) {
case TIME_OUT:
- if (logger.isDebugEnabled(1)) {
- logger.debug(20, ASIODNS_RECVTMO,
- data_->remote_snd->getAddress().toText().c_str(),
- static_cast<int>(data_->remote_snd->getPort()));
- }
+ LOG_DEBUG(logger, DBG_COMMON, ASIODNS_RECVTMO).
+ arg(data_->remote_snd->getAddress().toText()).
+ arg(data_->remote_snd->getPort());
break;
case SUCCESS:
- if (logger.isDebugEnabled(50)) {
- logger.debug(30, ASIODNS_FETCHCOMP,
- data_->remote_rcv->getAddress().toText().c_str(),
- static_cast<int>(data_->remote_rcv->getPort()));
- }
+ LOG_DEBUG(logger, DBG_ALL, ASIODNS_FETCHCOMP).
+ arg(data_->remote_rcv->getAddress().toText()).
+ arg(data_->remote_rcv->getPort());
break;
case STOPPED:
// Fetch has been stopped for some other reason. This is
// allowed but as it is unusual it is logged, but with a lower
// debug level than a timeout (which is totally normal).
- logger.debug(1, ASIODNS_FETCHSTOP,
- data_->remote_snd->getAddress().toText().c_str(),
- static_cast<int>(data_->remote_snd->getPort()));
+ LOG_DEBUG(logger, DBG_IMPORTANT, ASIODNS_FETCHSTOP).
+ arg(data_->remote_snd->getAddress().toText()).
+ arg(data_->remote_snd->getPort());
break;
default:
- logger.error(ASIODNS_UNKRESULT, static_cast<int>(result),
- data_->remote_snd->getAddress().toText().c_str(),
- static_cast<int>(data_->remote_snd->getPort()));
+ LOG_ERROR(logger, ASIODNS_UNKRESULT).
+ arg(data_->remote_snd->getAddress().toText()).
+ arg(data_->remote_snd->getPort());
}
// Stop requested, cancel and I/O's on the socket and shut it down,
@@ -394,14 +425,12 @@ void IOFetch::logIOFailure(asio::error_code ec) {
(data_->origin == ASIODNS_UNKORIGIN));
static const char* PROTOCOL[2] = {"TCP", "UDP"};
- logger.error(data_->origin,
- ec.value(),
- ((data_->remote_snd->getProtocol() == IPPROTO_TCP) ?
- PROTOCOL[0] : PROTOCOL[1]),
- data_->remote_snd->getAddress().toText().c_str(),
- static_cast<int>(data_->remote_snd->getPort()));
+ LOG_ERROR(logger, data_->origin).arg(ec.value()).
+ arg((data_->remote_snd->getProtocol() == IPPROTO_TCP) ?
+ PROTOCOL[0] : PROTOCOL[1]).
+ arg(data_->remote_snd->getAddress().toText()).
+ arg(data_->remote_snd->getPort());
}
} // namespace asiodns
} // namespace isc {
-
diff --git a/src/lib/asiodns/io_fetch.h b/src/lib/asiodns/io_fetch.h
index 98c917d..9626ffe 100644
--- a/src/lib/asiodns/io_fetch.h
+++ b/src/lib/asiodns/io_fetch.h
@@ -29,6 +29,7 @@
#include <util/buffer.h>
#include <dns/question.h>
+#include <dns/message.h>
namespace isc {
namespace asiodns {
@@ -136,6 +137,20 @@ public:
uint16_t port, isc::util::OutputBufferPtr& buff, Callback* cb,
int wait = -1);
+ /// \brief Constructor
+ /// This constructor has one parameter "query_message", which
+ /// is the shared_ptr to a full query message. It's different
+ /// with above contructor which has only question section. All
+ /// other parameters are same.
+ ///
+ /// \param query_message the shared_ptr to a full query message
+ /// got from a query client.
+ IOFetch(Protocol protocol, isc::asiolink::IOService& service,
+ isc::dns::ConstMessagePtr query_message,
+ const isc::asiolink::IOAddress& address,
+ uint16_t port, isc::util::OutputBufferPtr& buff, Callback* cb,
+ int wait = -1);
+
/// \brief Constructor.
///
/// Creates the object that will handle the upstream fetch.
@@ -184,6 +199,15 @@ public:
void stop(Result reason = STOPPED);
private:
+ /// \brief IOFetch Initialization Function.
+ /// All the parameters are same with the constructor, except
+ /// parameter "query_message"
+ /// \param query_message the message to be sent out.
+ void initIOFetch(isc::dns::MessagePtr& query_message, Protocol protocol,
+ isc::asiolink::IOService& service, const isc::dns::Question& question,
+ const isc::asiolink::IOAddress& address, uint16_t port,
+ isc::util::OutputBufferPtr& buff, Callback* cb, int wait);
+
/// \brief Log I/O Failure
///
/// Records an I/O failure to the log file
diff --git a/src/lib/asiolink/Makefile.am b/src/lib/asiolink/Makefile.am
index 66d5eda..22b3a8e 100644
--- a/src/lib/asiolink/Makefile.am
+++ b/src/lib/asiolink/Makefile.am
@@ -2,7 +2,6 @@ SUBDIRS = . tests
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES)
-AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
AM_CXXFLAGS = $(B10_CXXFLAGS)
diff --git a/src/lib/asiolink/interval_timer.h b/src/lib/asiolink/interval_timer.h
index 0831d44..8de16cb 100644
--- a/src/lib/asiolink/interval_timer.h
+++ b/src/lib/asiolink/interval_timer.h
@@ -22,7 +22,7 @@
namespace isc {
namespace asiolink {
-struct IntervalTimerImpl;
+class IntervalTimerImpl;
/// \brief The \c IntervalTimer class is a wrapper for the ASIO
/// \c asio::deadline_timer class.
diff --git a/src/lib/asiolink/io_service.h b/src/lib/asiolink/io_service.h
index 438667c..75aaee6 100644
--- a/src/lib/asiolink/io_service.h
+++ b/src/lib/asiolink/io_service.h
@@ -22,7 +22,7 @@ namespace asio {
namespace isc {
namespace asiolink {
-struct IOServiceImpl;
+class IOServiceImpl;
/// \brief The \c IOService class is a wrapper for the ASIO \c io_service
/// class.
diff --git a/src/lib/asiolink/tests/Makefile.am b/src/lib/asiolink/tests/Makefile.am
index 37d9ef3..c0d7af6 100644
--- a/src/lib/asiolink/tests/Makefile.am
+++ b/src/lib/asiolink/tests/Makefile.am
@@ -1,6 +1,5 @@
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES)
-AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/bin
AM_CPPFLAGS += -I$(top_builddir)/src/lib/util -I$(top_srcdir)/src/util
AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
@@ -11,14 +10,18 @@ if USE_STATIC_LINK
AM_LDFLAGS = -static
endif
+# Some versions of GCC warn about some versions of Boost regarding
+# missing initializer for members in its posix_time.
+# https://svn.boost.org/trac/boost/ticket/3477
+# But older GCC compilers don't have the flag.
+AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
+
CLEANFILES = *.gcno *.gcda
TESTS =
if HAVE_GTEST
TESTS += run_unittests
run_unittests_SOURCES = run_unittests.cc
-run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.h
-run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
run_unittests_SOURCES += io_address_unittest.cc
run_unittests_SOURCES += io_endpoint_unittest.cc
run_unittests_SOURCES += io_socket_unittest.cc
@@ -32,7 +35,6 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += $(SQLITE_LIBS)
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
diff --git a/src/lib/asiolink/tests/interval_timer_unittest.cc b/src/lib/asiolink/tests/interval_timer_unittest.cc
index c24e60e..8e8ef81 100644
--- a/src/lib/asiolink/tests/interval_timer_unittest.cc
+++ b/src/lib/asiolink/tests/interval_timer_unittest.cc
@@ -18,7 +18,7 @@
#include <asio.hpp>
#include <asiolink/asiolink.h>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
namespace {
// TODO: Consider this margin
@@ -166,16 +166,22 @@ TEST_F(IntervalTimerTest, startIntervalTimer) {
io_service_.run();
// reaches here after timer expired
// delta: difference between elapsed time and 100 milliseconds.
+ boost::posix_time::time_duration test_runtime =
+ boost::posix_time::microsec_clock::universal_time() - start;
+ EXPECT_FALSE(test_runtime.is_negative()) <<
+ "test duration " << test_runtime <<
+ " negative - clock skew?";
boost::posix_time::time_duration delta =
- (boost::posix_time::microsec_clock::universal_time() - start)
- - boost::posix_time::millisec(100);
+ test_runtime - boost::posix_time::milliseconds(100);
if (delta.is_negative()) {
delta.invert_sign();
}
// expect TimerCallBack is called; timer_called_ is true
EXPECT_TRUE(timer_called_);
// expect interval is 100 milliseconds +/- TIMER_MARGIN_MSEC.
- EXPECT_TRUE(delta < TIMER_MARGIN_MSEC);
+ EXPECT_TRUE(delta < TIMER_MARGIN_MSEC) <<
+ "delta " << delta.total_milliseconds() << "msec " <<
+ ">= " << TIMER_MARGIN_MSEC.total_milliseconds();
}
TEST_F(IntervalTimerTest, destructIntervalTimer) {
@@ -283,14 +289,20 @@ TEST_F(IntervalTimerTest, overwriteIntervalTimer) {
// + 400 milliseconds for TimerCallBackOverwriter (stop)
// = 800 milliseconds.
// delta: difference between elapsed time and 400 + 100 milliseconds
+ boost::posix_time::time_duration test_runtime =
+ boost::posix_time::microsec_clock::universal_time() - start;
+ EXPECT_FALSE(test_runtime.is_negative()) <<
+ "test duration " << test_runtime <<
+ " negative - clock skew?";
boost::posix_time::time_duration delta =
- (boost::posix_time::microsec_clock::universal_time() - start)
- - boost::posix_time::millisec(400 + 100);
+ test_runtime - boost::posix_time::milliseconds(400 + 100);
if (delta.is_negative()) {
delta.invert_sign();
}
// expect callback function is updated: TimerCallBack is called
EXPECT_TRUE(timer_called_);
// expect interval is updated
- EXPECT_TRUE(delta < TIMER_MARGIN_MSEC);
+ EXPECT_TRUE(delta < TIMER_MARGIN_MSEC) <<
+ "delta " << delta.total_milliseconds() << " msec " <<
+ ">= " << TIMER_MARGIN_MSEC.total_milliseconds();
}
diff --git a/src/lib/asiolink/tests/run_unittests.cc b/src/lib/asiolink/tests/run_unittests.cc
index c285f9e..97bcb65 100644
--- a/src/lib/asiolink/tests/run_unittests.cc
+++ b/src/lib/asiolink/tests/run_unittests.cc
@@ -22,7 +22,6 @@ main(int argc, char* argv[])
{
::testing::InitGoogleTest(&argc, argv); // Initialize Google test
isc::log::setRootLoggerName("unittest"); // Set a root logger name
- isc::UnitTestUtil::addDataPath(TEST_DATA_DIR); // Add location of test data
return (RUN_ALL_TESTS());
}
diff --git a/src/lib/cc/Makefile.am b/src/lib/cc/Makefile.am
index 44033e9..9d5b188 100644
--- a/src/lib/cc/Makefile.am
+++ b/src/lib/cc/Makefile.am
@@ -11,6 +11,7 @@ if USE_GXX
# avoid the error. As a short term workaround we suppress this warning
# for the entire this module. See also src/bin/auth/Makefile.am.
AM_CXXFLAGS += -Wno-unused-parameter
+AM_CXXFLAGS += -fno-strict-aliasing
endif
if USE_CLANGPP
# Likewise, ASIO header files will trigger various warnings with clang++.
diff --git a/src/lib/cc/tests/Makefile.am b/src/lib/cc/tests/Makefile.am
index 535c464..71e6988 100644
--- a/src/lib/cc/tests/Makefile.am
+++ b/src/lib/cc/tests/Makefile.am
@@ -26,7 +26,6 @@ run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
endif
diff --git a/src/lib/config/Makefile.am b/src/lib/config/Makefile.am
index 580f240..52337ad 100644
--- a/src/lib/config/Makefile.am
+++ b/src/lib/config/Makefile.am
@@ -2,10 +2,24 @@ SUBDIRS = . tests
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/log -I$(top_builddir)/src/lib/log
AM_CPPFLAGS += $(BOOST_INCLUDES)
-AM_CXXFLAGS = $(B10_CXXFLAGS) -Wno-strict-aliasing
+
+# Define rule to build logging source files from message file
+configdef.h configdef.cc: configdef.mes
+ $(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/config/configdef.mes
+
+BUILT_SOURCES = configdef.h configdef.cc
lib_LTLIBRARIES = libcfgclient.la
-libcfgclient_la_SOURCES = config_data.h config_data.cc module_spec.h module_spec.cc ccsession.cc ccsession.h
+libcfgclient_la_SOURCES = config_data.h config_data.cc
+libcfgclient_la_SOURCES += module_spec.h module_spec.cc
+libcfgclient_la_SOURCES += ccsession.cc ccsession.h
+libcfgclient_la_SOURCES += config_log.h config_log.cc
+
+nodist_libcfgclient_la_SOURCES = configdef.h configdef.cc
+
+# The message file should be in the distribution.
+EXTRA_DIST = configdef.mes
-CLEANFILES = *.gcno *.gcda
+CLEANFILES = *.gcno *.gcda configdef.h configdef.cc
diff --git a/src/lib/config/ccsession.cc b/src/lib/config/ccsession.cc
index 69621a4..1b5e47d 100644
--- a/src/lib/config/ccsession.cc
+++ b/src/lib/config/ccsession.cc
@@ -12,12 +12,6 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-//
-// todo: generalize this and make it into a specific API for all modules
-// to use (i.e. connect to cc, send config and commands, get config,
-// react on config change announcements)
-//
-
#include <config.h>
#include <stdexcept>
@@ -38,6 +32,7 @@
#include <cc/session.h>
#include <exceptions/exceptions.h>
+#include <config/config_log.h>
#include <config/ccsession.h>
using namespace std;
@@ -164,18 +159,18 @@ ModuleCCSession::readModuleSpecification(const std::string& filename) {
// this file should be declared in a @something@ directive
file.open(filename.c_str());
if (!file) {
- cout << "error opening " << filename << ": " << strerror(errno) << endl;
- exit(1);
+ LOG_ERROR(config_logger, CONFIG_FOPEN_ERR).arg(filename).arg(strerror(errno));
+ isc_throw(CCSessionInitError, strerror(errno));
}
try {
module_spec = moduleSpecFromFile(file, true);
} catch (const JSONError& pe) {
- cout << "Error parsing module specification file: " << pe.what() << endl;
- exit(1);
+ LOG_ERROR(config_logger, CONFIG_JSON_PARSE).arg(filename).arg(pe.what());
+ isc_throw(CCSessionInitError, pe.what());
} catch (const ModuleSpecError& dde) {
- cout << "Error reading module specification file: " << dde.what() << endl;
- exit(1);
+ LOG_ERROR(config_logger, CONFIG_MODULE_SPEC).arg(filename).arg(dde.what());
+ isc_throw(CCSessionInitError, dde.what());
}
file.close();
return (module_spec);
@@ -223,7 +218,8 @@ ModuleCCSession::ModuleCCSession(
int rcode;
ConstElementPtr err = parseAnswer(rcode, answer);
if (rcode != 0) {
- std::cerr << "[" << module_name_ << "] Error in specification: " << answer << std::endl;
+ LOG_ERROR(config_logger, CONFIG_MANAGER_MOD_SPEC).arg(answer->str());
+ isc_throw(CCSessionInitError, answer->str());
}
setLocalConfig(Element::fromJSON("{}"));
@@ -236,7 +232,8 @@ ModuleCCSession::ModuleCCSession(
if (rcode == 0) {
handleConfigUpdate(new_config);
} else {
- std::cerr << "[" << module_name_ << "] Error getting config: " << new_config << std::endl;
+ LOG_ERROR(config_logger, CONFIG_MANAGER_CONFIG).arg(new_config->str());
+ isc_throw(CCSessionInitError, answer->str());
}
}
@@ -348,15 +345,13 @@ ModuleCCSession::checkCommand() {
answer = checkModuleCommand(cmd_str, target_module, arg);
}
} catch (const CCSessionError& re) {
- // TODO: Once we have logging and timeouts, we should not
- // answer here (potential interference)
- answer = createAnswer(1, re.what());
+ LOG_ERROR(config_logger, CONFIG_CCSESSION_MSG).arg(re.what());
}
if (!isNull(answer)) {
session_.reply(routing, answer);
}
}
-
+
return (0);
}
diff --git a/src/lib/config/ccsession.h b/src/lib/config/ccsession.h
index d8d1eeb..7364876 100644
--- a/src/lib/config/ccsession.h
+++ b/src/lib/config/ccsession.h
@@ -135,6 +135,15 @@ public:
};
///
+/// \brief This exception is thrown if the constructor fails
+///
+class CCSessionInitError : public isc::Exception {
+public:
+ CCSessionInitError(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+///
/// \brief This module keeps a connection to the command channel,
/// holds configuration information, and handles messages from
/// the command channel
@@ -154,6 +163,11 @@ public:
* AbstractSession without establishing the session.
* Note: the design decision on who is responsible for establishing the
* session is in flux, and may change in near future.
+ *
+ * \exception CCSessionInitError when the initialization fails,
+ * either because the file cannot be read or there is
+ * a communication problem with the config manager.
+ *
* @param command_handler A callback function pointer to be called when
* a control command from a remote agent needs to be performed on the
* local module.
diff --git a/src/lib/config/config_log.cc b/src/lib/config/config_log.cc
new file mode 100644
index 0000000..672b9f1
--- /dev/null
+++ b/src/lib/config/config_log.cc
@@ -0,0 +1,26 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+/// Defines the logger used by the config lib
+
+#include "config/config_log.h"
+
+namespace isc {
+namespace config {
+
+isc::log::Logger config_logger("config");
+
+} // namespace nsas
+} // namespace isc
+
diff --git a/src/lib/config/config_log.h b/src/lib/config/config_log.h
new file mode 100644
index 0000000..22e5a5c
--- /dev/null
+++ b/src/lib/config/config_log.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __CONFIG_LOG__H
+#define __CONFIG_LOG__H
+
+#include <log/macros.h>
+#include "configdef.h"
+
+namespace isc {
+namespace config {
+
+/// \brief Config Logging
+///
+/// Defines logger object for config log messages
+
+/// \brief Config Logger
+///
+/// Define the logger used to log messages. We could define it in multiple
+/// modules, but defining in a single module and linking to it saves time and
+/// space.
+extern isc::log::Logger config_logger; // isc::config::config_logger is the CONFIG logger
+
+} // namespace config
+} // namespace isc
+
+#endif // __CONFIG_LOG__H
diff --git a/src/lib/config/configdef.mes b/src/lib/config/configdef.mes
new file mode 100644
index 0000000..4c3c991
--- /dev/null
+++ b/src/lib/config/configdef.mes
@@ -0,0 +1,50 @@
+# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+$PREFIX CONFIG_
+$NAMESPACE isc::config
+
+% FOPEN_ERR error opening %1: %2
+There was an error opening the given file.
+
+% JSON_PARSE JSON parse error in %1: %2
+There was a parse error in the JSON file. The given file does not appear
+to be in valid JSON format. Please verify that the filename is correct
+and that the contents are valid JSON.
+
+% MODULE_SPEC module specification error in %1: %2
+The given file does not appear to be a valid specification file. Please
+verify that the filename is correct and that its contents are a valid
+BIND10 module specification.
+
+% MANAGER_MOD_SPEC module specification not accepted by cfgmgr: %1
+The module specification file for this module was rejected by the
+configuration manager. The full error message answer from the
+configuration manager is appended to the log error. The most likely
+cause is that the module is of a different (specification file) version
+than the running configuration manager.
+
+% MANAGER_CONFIG error getting configuration from cfgmgr: %1
+The configuration manager returned an error when this module requested
+the configuration. The full error message answer from the configuration
+manager is appended to the log error. The most likely cause is that
+the module is of a different (command specification) version than the
+running configuration manager.
+
+% CCSESSION_MSG error in CC session message: %1
+There was a problem with an incoming message on the command and control
+channel. The message does not appear to be a valid command, and is
+missing a required element or contains an unknown data format. This
+most likely means that another BIND10 module is sending a bad message.
+The message itself is ignored by this module.
diff --git a/src/lib/config/tests/Makefile.am b/src/lib/config/tests/Makefile.am
index 0cebdbf..0d2c29b 100644
--- a/src/lib/config/tests/Makefile.am
+++ b/src/lib/config/tests/Makefile.am
@@ -24,6 +24,7 @@ run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
run_unittests_LDADD += libfake_session.la
run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
diff --git a/src/lib/config/tests/ccsession_unittests.cc b/src/lib/config/tests/ccsession_unittests.cc
index 43663bd..f566949 100644
--- a/src/lib/config/tests/ccsession_unittests.cc
+++ b/src/lib/config/tests/ccsession_unittests.cc
@@ -264,10 +264,7 @@ TEST_F(CCSessionTest, checkCommand) {
session.addMessage(el("{ \"command\": \"bad_command\" }"), "Spec29", "*");
result = mccs.checkCommand();
- EXPECT_EQ(1, session.getMsgQueue()->size());
- msg = session.getFirstMessage(group, to);
- EXPECT_EQ("{ \"result\": [ 1, \"Command part in command message missing, empty, or not a list\" ] }", msg->str());
- EXPECT_EQ(0, result);
+ EXPECT_EQ(0, session.getMsgQueue()->size());
session.addMessage(el("{ \"command\": [ \"bad_command\" ] }"),
"Spec29", "*");
@@ -432,4 +429,24 @@ TEST_F(CCSessionTest, ignoreRemoteConfigCommands) {
EXPECT_EQ(0, session.getMsgQueue()->size());
}
+TEST_F(CCSessionTest, initializationFail) {
+ // bad specification
+ EXPECT_THROW(ModuleCCSession(ccspecfile("spec8.spec"), session,
+ NULL, NULL), CCSessionInitError);
+
+ // file that does not exist
+ EXPECT_THROW(ModuleCCSession(ccspecfile("does_not_exist_spec"),
+ session, NULL, NULL),
+ CCSessionInitError);
+
+
+ session.getMessages()->add(createAnswer(1, el("\"just an error\"")));
+
+ EXPECT_FALSE(session.haveSubscription("Spec29", "*"));
+ EXPECT_THROW(ModuleCCSession(ccspecfile("spec29.spec"), session,
+ my_config_handler, my_command_handler),
+ CCSessionInitError);
+ EXPECT_TRUE(session.haveSubscription("Spec29", "*"));
+}
+
}
diff --git a/src/lib/config/tests/fake_session.cc b/src/lib/config/tests/fake_session.cc
index 29744c7..5f79d48 100644
--- a/src/lib/config/tests/fake_session.cc
+++ b/src/lib/config/tests/fake_session.cc
@@ -52,16 +52,14 @@ listContains(ConstElementPtr list, ConstElementPtr el) {
void
listRemove(ElementPtr list, ConstElementPtr el) {
- int i = -1;
+ int i = 0;
BOOST_FOREACH(ConstElementPtr s_el, list->listValue()) {
if (*el == *s_el) {
- i = 0;
+ list->remove(i);
+ return;
}
i++;
}
- if (i >= 0) {
- list->remove(i);
- }
}
// endwant
diff --git a/src/lib/config/tests/run_unittests.cc b/src/lib/config/tests/run_unittests.cc
index 0908071..fab90f5 100644
--- a/src/lib/config/tests/run_unittests.cc
+++ b/src/lib/config/tests/run_unittests.cc
@@ -13,9 +13,16 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <gtest/gtest.h>
+#include <log/logger_support.h>
int
main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
+
+ // TODO: UNCOMMENT ON MERGE
+ // (this is the call we want in master, but branch point does not
+ // have this yet)
+ //isc::log::initLogger();
+
return (RUN_ALL_TESTS());
}
diff --git a/src/lib/cryptolink/Makefile.am b/src/lib/cryptolink/Makefile.am
new file mode 100644
index 0000000..93f3443
--- /dev/null
+++ b/src/lib/cryptolink/Makefile.am
@@ -0,0 +1,14 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES) $(BOTAN_INCLUDES)
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+CLEANFILES = *.gcno *.gcda
+
+lib_LTLIBRARIES = libcryptolink.la
+
+libcryptolink_la_SOURCES = cryptolink.h cryptolink.cc
+libcryptolink_la_SOURCES += crypto_hmac.h crypto_hmac.cc
+
+libcryptolink_la_LIBADD = ${BOTAN_LDFLAGS} ${BOTAN_RPATH}
diff --git a/src/lib/cryptolink/crypto_hmac.cc b/src/lib/cryptolink/crypto_hmac.cc
new file mode 100644
index 0000000..d20c85b
--- /dev/null
+++ b/src/lib/cryptolink/crypto_hmac.cc
@@ -0,0 +1,246 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <cryptolink.h>
+#include <cryptolink/crypto_hmac.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <botan/botan.h>
+#include <botan/hmac.h>
+#include <botan/hash.h>
+#include <botan/types.h>
+
+namespace {
+const char*
+getBotanHashAlgorithmName(isc::cryptolink::HashAlgorithm algorithm) {
+ switch (algorithm) {
+ case isc::cryptolink::MD5:
+ return ("MD5");
+ break;
+ case isc::cryptolink::SHA1:
+ return ("SHA-1");
+ break;
+ case isc::cryptolink::SHA256:
+ return ("SHA-256");
+ break;
+ case isc::cryptolink::UNKNOWN_HASH:
+ return ("Unknown");
+ break;
+ }
+ // compiler should have prevented us to reach this, since we have
+ // no default. But we need a return value anyway
+ return ("Unknown");
+}
+
+} // local namespace
+
+
+namespace isc {
+namespace cryptolink {
+
+class HMACImpl {
+public:
+ explicit HMACImpl(const void* secret, size_t secret_len,
+ const HashAlgorithm hash_algorithm) {
+ Botan::HashFunction* hash;
+ try {
+ hash = Botan::get_hash(
+ getBotanHashAlgorithmName(hash_algorithm));
+ } catch (const Botan::Algorithm_Not_Found&) {
+ isc_throw(isc::cryptolink::UnsupportedAlgorithm,
+ "Unknown hash algorithm: " + hash_algorithm);
+ } catch (const Botan::Exception& exc) {
+ isc_throw(isc::cryptolink::LibraryError, exc.what());
+ }
+
+ hmac_.reset(new Botan::HMAC(hash));
+
+ // If the key length is larger than the block size, we hash the
+ // key itself first.
+ try {
+ if (secret_len > hash->HASH_BLOCK_SIZE) {
+ Botan::SecureVector<Botan::byte> hashed_key =
+ hash->process(static_cast<const Botan::byte*>(secret),
+ secret_len);
+ hmac_->set_key(hashed_key.begin(), hashed_key.size());
+ } else {
+ hmac_->set_key(static_cast<const Botan::byte*>(secret),
+ secret_len);
+ }
+ } catch (const Botan::Invalid_Key_Length& ikl) {
+ isc_throw(BadKey, ikl.what());
+ } catch (const Botan::Exception& exc) {
+ isc_throw(isc::cryptolink::LibraryError, exc.what());
+ }
+ }
+
+ ~HMACImpl() { }
+
+ size_t getOutputLength() const {
+ return (hmac_->OUTPUT_LENGTH);
+ }
+
+ void update(const void* data, const size_t len) {
+ try {
+ hmac_->update(static_cast<const Botan::byte*>(data), len);
+ } catch (const Botan::Exception& exc) {
+ isc_throw(isc::cryptolink::LibraryError, exc.what());
+ }
+ }
+
+ void sign(isc::util::OutputBuffer& result, size_t len) {
+ try {
+ Botan::SecureVector<Botan::byte> b_result(hmac_->final());
+
+ if (len == 0 || len > b_result.size()) {
+ len = b_result.size();
+ }
+ result.writeData(b_result.begin(), len);
+ } catch (const Botan::Exception& exc) {
+ isc_throw(isc::cryptolink::LibraryError, exc.what());
+ }
+ }
+
+ void sign(void* result, size_t len) {
+ try {
+ Botan::SecureVector<Botan::byte> b_result(hmac_->final());
+ size_t output_size = getOutputLength();
+ if (output_size > len) {
+ output_size = len;
+ }
+ memcpy(result, b_result.begin(), output_size);
+ } catch (const Botan::Exception& exc) {
+ isc_throw(isc::cryptolink::LibraryError, exc.what());
+ }
+ }
+
+ std::vector<uint8_t> sign(size_t len) {
+ try {
+ Botan::SecureVector<Botan::byte> b_result(hmac_->final());
+ if (len == 0 || len > b_result.size()) {
+ return (std::vector<uint8_t>(b_result.begin(), b_result.end()));
+ } else {
+ return (std::vector<uint8_t>(b_result.begin(), &b_result[len]));
+ }
+ } catch (const Botan::Exception& exc) {
+ isc_throw(isc::cryptolink::LibraryError, exc.what());
+ }
+ }
+
+
+ bool verify(const void* sig, size_t len) {
+ // Botan's verify_mac checks if len matches the output_length,
+ // which causes it to fail for truncated signatures, so we do
+ // the check ourselves
+ // SEE BELOW FOR TEMPORARY CHANGE
+ try {
+ Botan::SecureVector<Botan::byte> our_mac = hmac_->final();
+ if (len < getOutputLength()) {
+ // Currently we don't support truncated signature. To avoid
+ // validating too short signature accidently, we enforce the
+ // standard signature size for the moment.
+ // Once we support truncation correctly, this if-clause should
+ // (and the capitalized comment above) be removed.
+ return (false);
+ }
+ if (len == 0 || len > getOutputLength()) {
+ len = getOutputLength();
+ }
+ return (Botan::same_mem(&our_mac[0],
+ static_cast<const unsigned char*>(sig),
+ len));
+ } catch (const Botan::Exception& exc) {
+ isc_throw(isc::cryptolink::LibraryError, exc.what());
+ }
+ }
+
+private:
+ boost::scoped_ptr<Botan::HMAC> hmac_;
+};
+
+HMAC::HMAC(const void* secret, size_t secret_length,
+ const HashAlgorithm hash_algorithm)
+{
+ impl_ = new HMACImpl(secret, secret_length, hash_algorithm);
+}
+
+HMAC::~HMAC() {
+ delete impl_;
+}
+
+size_t
+HMAC::getOutputLength() const {
+ return (impl_->getOutputLength());
+}
+
+void
+HMAC::update(const void* data, const size_t len) {
+ impl_->update(data, len);
+}
+
+void
+HMAC::sign(isc::util::OutputBuffer& result, size_t len) {
+ impl_->sign(result, len);
+}
+
+void
+HMAC::sign(void* result, size_t len) {
+ impl_->sign(result, len);
+}
+
+std::vector<uint8_t>
+HMAC::sign(size_t len) {
+ return impl_->sign(len);
+}
+
+bool
+HMAC::verify(const void* sig, const size_t len) {
+ return (impl_->verify(sig, len));
+}
+
+void
+signHMAC(const void* data, size_t data_len, const void* secret,
+ size_t secret_len, const HashAlgorithm hash_algorithm,
+ isc::util::OutputBuffer& result, size_t len)
+{
+ boost::scoped_ptr<HMAC> hmac(
+ CryptoLink::getCryptoLink().createHMAC(secret,
+ secret_len,
+ hash_algorithm));
+ hmac->update(data, data_len);
+ hmac->sign(result, len);
+}
+
+
+bool
+verifyHMAC(const void* data, const size_t data_len, const void* secret,
+ size_t secret_len, const HashAlgorithm hash_algorithm,
+ const void* sig, const size_t sig_len)
+{
+ boost::scoped_ptr<HMAC> hmac(
+ CryptoLink::getCryptoLink().createHMAC(secret,
+ secret_len,
+ hash_algorithm));
+ hmac->update(data, data_len);
+ return (hmac->verify(sig, sig_len));
+}
+
+void
+deleteHMAC(HMAC* hmac) {
+ delete hmac;
+}
+
+} // namespace cryptolink
+} // namespace isc
diff --git a/src/lib/cryptolink/crypto_hmac.h b/src/lib/cryptolink/crypto_hmac.h
new file mode 100644
index 0000000..2eb0d0e
--- /dev/null
+++ b/src/lib/cryptolink/crypto_hmac.h
@@ -0,0 +1,209 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <util/buffer.h>
+
+#include <boost/noncopyable.hpp>
+
+#include <cryptolink/cryptolink.h>
+
+#ifndef _ISC_CRYPTO_HMAC_H
+#define _ISC_CRYPTO_HMAC_H
+
+namespace isc {
+namespace cryptolink {
+
+/// Forward declaration, pimpl style
+class HMACImpl;
+
+/// \brief HMAC support
+///
+/// This class is used to create and verify HMAC signatures. Instances
+/// can be created with CryptoLink::createHMAC()
+///
+class HMAC : private boost::noncopyable {
+private:
+ /// \brief Constructor from a secret and a hash algorithm
+ ///
+ /// \exception UnsupportedAlgorithmException if the given algorithm
+ /// is unknown or not supported by the underlying library
+ /// \exception InvalidKeyLength if the given key secret_len is bad
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ ///
+ /// Notes: if the secret is longer than the block size of its
+ /// algorithm, the constructor will run it through the hash
+ /// algorithm, and use the digest as the secret for this HMAC
+ /// operation
+ ///
+ /// \param secret The secret to sign with
+ /// \param len The length of the secret
+ /// \param hash_algorithm The hash algorithm
+ HMAC(const void* secret, size_t secret_len,
+ const HashAlgorithm hash_algorithm);
+
+ friend HMAC* CryptoLink::createHMAC(const void*, size_t,
+ const HashAlgorithm);
+
+public:
+ /// \brief Destructor
+ ~HMAC();
+
+ /// \brief Returns the output size of the digest
+ ///
+ /// \return output size of the digest
+ size_t getOutputLength() const;
+
+ /// \brief Add data to digest
+ ///
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ ///
+ /// \param data The data to add
+ /// \param len The size of the data
+ void update(const void* data, const size_t len);
+
+ /// \brief Calculate the final signature
+ ///
+ /// The result will be appended to the given outputbuffer
+ ///
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ ///
+ /// \param result The OutputBuffer to append the result to
+ /// \param len The number of bytes from the result to copy. If this
+ /// value is smaller than the algorithms output size, the
+ /// result will be truncated. If this value is larger, or 0
+ /// (the default), it will be ignored
+ void sign(isc::util::OutputBuffer& result, size_t len = 0);
+
+ /// \brief Calculate the final signature
+ ///
+ /// len bytes of data from the result will be copied to *result
+ /// If len is larger than the output size, only output_size bytes
+ /// will be copied. If it is smaller, the output will be truncated
+ ///
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ ///
+ /// At least len bytes of data must be available for writing at
+ /// result
+ void sign(void* result, size_t len);
+
+ /// \brief Calculate the final signatre
+ ///
+ /// The result will be returned as a std::vector<uint8_t>
+ ///
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ ///
+ /// \param len The number of bytes from the result to copy. If this
+ /// value is smaller than the algorithms output size, the
+ /// result will be truncated. If this value is larger, or 0
+ /// (the default), it will be ignored
+ /// \return a vector containing the signature
+ std::vector<uint8_t> sign(size_t len = 0);
+
+ /// \brief Verify an existing signature
+ ///
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ ///
+ /// \param sig The signature to verify
+ /// \param len The length of the signature. If this is non-zero,
+ /// and smaller than the output length of the algorithm,
+ /// only len bytes will be checked
+ /// \return true if the signature is correct, false otherwise
+ bool verify(const void* sig, size_t len);
+
+private:
+ HMACImpl* impl_;
+};
+
+/// \brief Create an HMAC signature for the given data
+///
+/// This is a convenience function that calculates the hmac signature,
+/// given a fixed amount of data. Internally it does the same as
+/// creating an HMAC object, feeding it the data, and calculating the
+/// resulting signature.
+///
+/// \exception UnsupportedAlgorithm if the given algorithm is unknown
+/// or not supported by the underlying library
+/// \exception BadKey if the given key secret_len is bad
+/// \exception LibraryError if there was any unexpected exception
+/// in the underlying library
+///
+/// Notes: if the secret is longer than the block size of its
+/// algorithm, the constructor will run it through the hash
+/// algorithm, and use the digest as the secret for this HMAC
+/// operation
+///
+/// \param data The data to sign
+/// \param data_len The length of the data
+/// \param secret The secret to sign with
+/// \param secret_len The length of the secret
+/// \param hash_algorithm The hash algorithm
+/// \param result The signature will be appended to this buffer
+/// \param len If this is non-zero and less than the output size,
+/// the result will be truncated to len bytes
+void signHMAC(const void* data,
+ const size_t data_len,
+ const void* secret,
+ size_t secret_len,
+ const HashAlgorithm hash_algorithm,
+ isc::util::OutputBuffer& result,
+ size_t len = 0);
+
+/// \brief Verify an HMAC signature for the given data
+///
+/// This is a convenience function that verifies an hmac signature,
+/// given a fixed amount of data. Internally it does the same as
+/// creating an HMAC object, feeding it the data, and checking the
+/// resulting signature.
+///
+/// \exception UnsupportedAlgorithm if the given algorithm is unknown
+/// or not supported by the underlying library
+/// \exception BadKey if the given key secret_len is bad
+/// \exception LibraryError if there was any unexpected exception
+/// in the underlying library
+///
+/// Notes: if the secret is longer than the block size of its
+/// algorithm, the constructor will run it through the hash
+/// algorithm, and use the digest as the secret for this HMAC
+/// operation
+///
+/// \param data The data to verify
+/// \param data_len The length of the data
+/// \param secret The secret to sign with
+/// \param secret_len The length of the secret
+/// \param hash_algorithm The hash algorithm
+/// \param sig The signature to verify
+/// \param sig_len The length of the signature
+/// \return True if the signature verifies, false if not
+bool verifyHMAC(const void* data,
+ const size_t data_len,
+ const void* secret,
+ size_t secret_len,
+ const HashAlgorithm hash_algorithm,
+ const void* sig,
+ const size_t sig_len);
+
+/// \brief Delete an HMAC object
+void deleteHMAC(HMAC* hmac);
+
+} // namespace cryptolink
+} // namespace isc
+
+#endif // __ISC_CRYPTO_HMAC
+
diff --git a/src/lib/cryptolink/cryptolink.cc b/src/lib/cryptolink/cryptolink.cc
new file mode 100644
index 0000000..d1c375d
--- /dev/null
+++ b/src/lib/cryptolink/cryptolink.cc
@@ -0,0 +1,69 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <cryptolink/cryptolink.h>
+#include <cryptolink/crypto_hmac.h>
+
+#include <botan/botan.h>
+
+namespace isc {
+namespace cryptolink {
+
+// For Botan, we use the CryptoLink class object in RAII style
+class CryptoLinkImpl {
+private:
+ Botan::LibraryInitializer botan_init_;
+};
+
+CryptoLink::~CryptoLink() {
+ delete impl_;
+}
+
+CryptoLink&
+CryptoLink::getCryptoLink() {
+ CryptoLink& c = getCryptoLinkInternal();
+ if (c.impl_ == NULL) {
+ c.initialize();
+ }
+ return (c);
+}
+
+CryptoLink&
+CryptoLink::getCryptoLinkInternal() {
+ static CryptoLink instance;
+ return (instance);
+}
+
+void
+CryptoLink::initialize() {
+ CryptoLink& c = getCryptoLinkInternal();
+ if (c.impl_ == NULL) {
+ try {
+ c.impl_ = new CryptoLinkImpl();
+ } catch (const Botan::Exception& ex) {
+ isc_throw(InitializationError, ex.what());
+ }
+ }
+}
+
+HMAC*
+CryptoLink::createHMAC(const void* secret, size_t secret_len,
+ const HashAlgorithm hash_algorithm)
+{
+ return (new HMAC(secret, secret_len, hash_algorithm));
+}
+
+} // namespace cryptolink
+} // namespace isc
+
diff --git a/src/lib/cryptolink/cryptolink.h b/src/lib/cryptolink/cryptolink.h
new file mode 100644
index 0000000..1583136
--- /dev/null
+++ b/src/lib/cryptolink/cryptolink.h
@@ -0,0 +1,204 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef _ISC_CRYPTO_H
+#define _ISC_CRYPTO_H
+
+#include <string>
+#include <util/buffer.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/noncopyable.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <memory>
+
+namespace isc {
+namespace cryptolink {
+
+/// \brief Hash algorithm identifiers
+enum HashAlgorithm {
+ MD5 = 0, ///< MD5
+ SHA1 = 1, ///< SHA-1
+ SHA256 = 2, ///< SHA-256
+ UNKNOWN_HASH = 3 ///< This value can be used in conversion
+ /// functions, to be returned when the
+ /// input is unknown (but a value MUST be
+ /// returned), for instance when the input
+ /// is a Name or a string, and the return
+ /// value is a HashAlgorithm.
+};
+
+// Forward declaration for createHMAC()
+class HMAC;
+
+/// General exception class that is the base for all crypto-related
+/// exceptions
+class CryptoLinkError : public Exception {
+public:
+ CryptoLinkError(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+/// This exception is thrown if there was a problem initializing the
+/// crypto library
+class InitializationError : public CryptoLinkError {
+public:
+ InitializationError(const char* file, size_t line, const char* what) :
+ CryptoLinkError(file, line, what) {}
+};
+
+/// This exception is thrown when a cryptographic action is requested
+/// for an algorithm that is not supported by the underlying library.
+class UnsupportedAlgorithm : public CryptoLinkError {
+public:
+ UnsupportedAlgorithm(const char* file, size_t line, const char* what) :
+ CryptoLinkError(file, line, what) {}
+};
+
+/// This exception is thrown when the underlying library could not
+/// handle the key data.
+class BadKey : public CryptoLinkError {
+public:
+ BadKey(const char* file, size_t line, const char* what) :
+ CryptoLinkError(file, line, what) {}
+};
+
+/// This exception is raised when a general error that was not
+/// specifically caught is thrown by the underlying library. It
+/// is replaced by this one so as not have 'external' exceptions
+/// bubbling up
+class LibraryError : public CryptoLinkError {
+public:
+ LibraryError(const char* file, size_t line, const char* what) :
+ CryptoLinkError(file, line, what) {}
+};
+
+/// Forward declaration for pimpl
+class CryptoLinkImpl;
+
+/// \brief Singleton entry point and factory class
+///
+/// This is a singleton class that serves as the entry point to
+/// the underlying cryptography library, and as a factory for objects
+/// within the cryptolink library.
+///
+/// There is only one way to access it, through getCryptoLink(), which
+/// returns a reference to the initialized library. On the first call,
+/// it will be initialized automatically. You can however initialize it
+/// manually through a call to the initalize(), before your first call
+/// to getCryptoLink. Any subsequent call to initialize() will be a
+/// noop.
+///
+/// In order for the CryptoLink library to be sure that the underlying
+/// library has been initialized, and because we do not want to add
+/// such a check to every class and function within it, we have made
+/// the constructors of all classes within cryptolink private. This way
+/// a caller cannot instantiate an object before the library is
+/// initialized, but must use CryptoLink's create method (e.g.
+/// createHMAC()), which enforces (automatic) initialization.
+///
+/// In order for the CryptoLink class to be able to create objects that
+/// have private constructors, it is declared a friend class of these
+/// classes.
+///
+/// Since these factory functions return bare pointers, we also provide
+/// deleter functions for them (e.g. deleteHMAC()), so that a caller
+/// can use that to make sure it uses the correct delete operator (the
+/// one defined at compilation time of this library). A way to make
+/// sure you do not forget this, is to place the result of the create
+/// functions in a shared_ptr with the corresponding deleter function.
+///
+/// \note All other classes within cryptolink should have private
+/// constructors as well, and should have a factory function from
+/// CryptoLink, and a deleter function.
+///
+// Internal note: we can use this class later to initialize and manage
+// dynamic (PKCS#11) libs
+class CryptoLink : private boost::noncopyable {
+public:
+ /// \brief Returns a reference to the singleton instance
+ ///
+ /// If the library has not been initialized yet, it will be
+ /// initialized with some default values.
+ ///
+ /// Since this class is noncopyable, you must use the return
+ /// value directly, or store it in a reference variable.
+ ///
+ /// \exception InitializationError if initialization fails
+ ///
+ /// \return Reference to the singleton instance
+ static CryptoLink& getCryptoLink();
+
+ /// \brief Initialize the library manually
+ ///
+ /// If the library has already been initialized (either by a call
+ /// to initialize() or automatically in getCryptoLink()), this
+ /// function does nothing.
+ ///
+ /// \note A call to initialize() is not strictly necessary with
+ /// the current implementation.
+ ///
+ /// \exception InitializationError if initialization fails
+ ///
+ static void initialize();
+
+ /// \brief Factory function for HMAC objects
+ ///
+ /// CryptoLink objects cannot be constructed directly. This
+ /// function creates a new HMAC object usable for signing or
+ /// verification.
+ ///
+ /// The caller is responsible for deleting the object, and it is
+ /// therefore highly recommended to place the return value of this
+ /// function in a scoped_ptr or shared_ptr.
+ ///
+ /// Notes: if the secret is longer than the block size of its
+ /// algorithm, the constructor will run it through the hash
+ /// algorithm, and use the digest as the secret for this HMAC
+ /// operation
+ ///
+ /// If you want to safely delete objects created with this method,
+ /// you can use the function deleteHMAC() as defined in
+ /// crypto_hmac.h
+ ///
+ /// \exception UnsupportedAlgorithmException if the given algorithm
+ /// is unknown or not supported by the underlying library
+ /// \exception InvalidKeyLength if the given key secret_len is bad
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ ///
+ /// \param secret The secret to sign with
+ /// \param secret_len The length of the secret
+ /// \param hash_algorithm The hash algorithm
+ HMAC* createHMAC(const void* secret, size_t secret_len,
+ const HashAlgorithm hash_algorithm);
+
+private:
+ // To enable us to use an optional explicit initialization call,
+ // the 'real' instance getter is private
+ static CryptoLink& getCryptoLinkInternal();
+
+ // To prevent people constructing their own, we make the constructor
+ // private too.
+ CryptoLink() : impl_(NULL) {}
+ ~CryptoLink();
+
+ CryptoLinkImpl* impl_;
+};
+
+} // namespace cryptolink
+} // namespace isc
+
+#endif // _ISC_CRYPTO_H
diff --git a/src/lib/cryptolink/tests/Makefile.am b/src/lib/cryptolink/tests/Makefile.am
new file mode 100644
index 0000000..c8b5e26
--- /dev/null
+++ b/src/lib/cryptolink/tests/Makefile.am
@@ -0,0 +1,26 @@
+SUBDIRS = .
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES = run_unittests.cc
+run_unittests_SOURCES += crypto_unittests.cc
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+run_unittests_LDADD = $(GTEST_LDADD)
+run_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libcryptolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/cryptolink/tests/crypto_unittests.cc b/src/lib/cryptolink/tests/crypto_unittests.cc
new file mode 100644
index 0000000..a1ffaab
--- /dev/null
+++ b/src/lib/cryptolink/tests/crypto_unittests.cc
@@ -0,0 +1,519 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <gtest/gtest.h>
+
+#include <cryptolink/cryptolink.h>
+#include <cryptolink/crypto_hmac.h>
+
+#include <util/buffer.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/shared_ptr.hpp>
+
+using namespace isc::util;
+using namespace isc::cryptolink;
+
+namespace {
+ void checkData(const uint8_t* data, const uint8_t* expected,
+ size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ ASSERT_EQ(expected[i], data[i]);
+ }
+ }
+
+ void checkBuffer(const OutputBuffer& buf, const uint8_t* expected,
+ size_t len)
+ {
+ ASSERT_EQ(len, buf.getLength());
+ checkData(static_cast<const uint8_t*>(buf.getData()), expected,
+ len);
+ }
+
+ // Sign and verify with the convenience functions
+ void doHMACTestConv(const std::string& data,
+ const void* secret,
+ size_t secret_len,
+ const HashAlgorithm hash_algorithm,
+ const uint8_t* expected_hmac,
+ size_t hmac_len) {
+ OutputBuffer data_buf(data.size());
+ data_buf.writeData(data.c_str(), data.size());
+ OutputBuffer hmac_sig(0);
+
+ // Sign it
+ signHMAC(data_buf.getData(), data_buf.getLength(),
+ secret, secret_len, hash_algorithm, hmac_sig, hmac_len);
+
+ // Check if the signature is what we expect
+ checkBuffer(hmac_sig, expected_hmac, hmac_len);
+
+ // Check whether we can verify it ourselves
+ EXPECT_TRUE(verifyHMAC(data_buf.getData(), data_buf.getLength(),
+ secret, secret_len, hash_algorithm,
+ hmac_sig.getData(),
+ hmac_sig.getLength()));
+
+ // Change the sig by flipping the first octet, and check
+ // whether verification fails then
+ hmac_sig.writeUint8At(~hmac_sig[0], 0);
+ EXPECT_FALSE(verifyHMAC(data_buf.getData(), data_buf.getLength(),
+ secret, secret_len, hash_algorithm,
+ hmac_sig.getData(),
+ hmac_sig.getLength()));
+ }
+
+ // Sign and verify with an instantiation of an HMAC object
+ void doHMACTestDirect(const std::string& data,
+ const void* secret,
+ size_t secret_len,
+ const HashAlgorithm hash_algorithm,
+ const uint8_t* expected_hmac,
+ size_t hmac_len) {
+ OutputBuffer data_buf(data.size());
+ data_buf.writeData(data.c_str(), data.size());
+ OutputBuffer hmac_sig(1);
+ CryptoLink& crypto = CryptoLink::getCryptoLink();
+
+ // Sign it
+ boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
+ secret_len,
+ hash_algorithm),
+ deleteHMAC);
+ hmac_sign->update(data_buf.getData(), data_buf.getLength());
+ hmac_sign->sign(hmac_sig, hmac_len);
+
+ // Check if the signature is what we expect
+ checkBuffer(hmac_sig, expected_hmac, hmac_len);
+
+ // Check whether we can verify it ourselves
+ boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
+ secret_len,
+ hash_algorithm),
+ deleteHMAC);
+ hmac_verify->update(data_buf.getData(), data_buf.getLength());
+ EXPECT_TRUE(hmac_verify->verify(hmac_sig.getData(),
+ hmac_sig.getLength()));
+
+ // Change the sig by flipping the first octet, and check
+ // whether verification fails then
+ hmac_sig.writeUint8At(~hmac_sig[0], 0);
+ EXPECT_FALSE(hmac_verify->verify(hmac_sig.getData(),
+ hmac_sig.getLength()));
+ }
+
+ void doHMACTestVector(const std::string& data,
+ const void* secret,
+ size_t secret_len,
+ const HashAlgorithm hash_algorithm,
+ const uint8_t* expected_hmac,
+ size_t hmac_len) {
+ CryptoLink& crypto = CryptoLink::getCryptoLink();
+ boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
+ secret_len,
+ hash_algorithm),
+ deleteHMAC);
+ hmac_sign->update(data.c_str(), data.size());
+ std::vector<uint8_t> sig = hmac_sign->sign(hmac_len);
+ ASSERT_EQ(hmac_len, sig.size());
+ checkData(&sig[0], expected_hmac, hmac_len);
+
+ boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
+ secret_len,
+ hash_algorithm),
+ deleteHMAC);
+ hmac_verify->update(data.c_str(), data.size());
+ EXPECT_TRUE(hmac_verify->verify(&sig[0], sig.size()));
+
+ sig[0] = ~sig[0];
+ EXPECT_FALSE(hmac_verify->verify(&sig[0], sig.size()));
+ }
+
+ void doHMACTestArray(const std::string& data,
+ const void* secret,
+ size_t secret_len,
+ const HashAlgorithm hash_algorithm,
+ const uint8_t* expected_hmac,
+ size_t hmac_len) {
+ CryptoLink& crypto = CryptoLink::getCryptoLink();
+ boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
+ secret_len,
+ hash_algorithm),
+ deleteHMAC);
+ hmac_sign->update(data.c_str(), data.size());
+
+ // note: this is not exception-safe, and can leak, but
+ // if there is an unexpected exception in the code below we
+ // have more important things to fix.
+ uint8_t* sig = new uint8_t[hmac_len];
+
+ hmac_sign->sign(sig, hmac_len);
+ checkData(sig, expected_hmac, hmac_len);
+
+ boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
+ secret_len,
+ hash_algorithm),
+ deleteHMAC);
+ hmac_verify->update(data.c_str(), data.size());
+ EXPECT_TRUE(hmac_verify->verify(sig, hmac_len));
+
+ sig[0] = ~sig[0];
+ EXPECT_FALSE(hmac_verify->verify(sig, hmac_len));
+
+ delete[] sig;
+ }
+
+ void doHMACTest(const std::string& data,
+ const void* secret,
+ size_t secret_len,
+ const HashAlgorithm hash_algorithm,
+ const uint8_t* expected_hmac,
+ size_t hmac_len) {
+ doHMACTestConv(data, secret, secret_len, hash_algorithm,
+ expected_hmac, hmac_len);
+ doHMACTestDirect(data, secret, secret_len, hash_algorithm,
+ expected_hmac, hmac_len);
+ doHMACTestVector(data, secret, secret_len, hash_algorithm,
+ expected_hmac, hmac_len);
+ doHMACTestArray(data, secret, secret_len, hash_algorithm,
+ expected_hmac, hmac_len);
+ }
+}
+
+//
+// Test values taken from RFC 2202
+//
+TEST(CryptoLinkTest, HMAC_MD5_RFC2202_SIGN) {
+ const uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b };
+ const uint8_t hmac_expected[] = { 0x92, 0x94, 0x72, 0x7a, 0x36,
+ 0x38, 0xbb, 0x1c, 0x13, 0xf4,
+ 0x8e, 0xf8, 0x15, 0x8b, 0xfc,
+ 0x9d };
+ doHMACTest("Hi There", secret, 16, MD5, hmac_expected, 16);
+
+ const uint8_t hmac_expected2[] = { 0x75, 0x0c, 0x78, 0x3e, 0x6a,
+ 0xb0, 0xb5, 0x03, 0xea, 0xa8,
+ 0x6e, 0x31, 0x0a, 0x5d, 0xb7,
+ 0x38 };
+ doHMACTest("what do ya want for nothing?", "Jefe", 4, MD5,
+ hmac_expected2, 16);
+
+ const uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa };
+ const uint8_t hmac_expected3[] = { 0x56, 0xbe, 0x34, 0x52, 0x1d,
+ 0x14, 0x4c, 0x88, 0xdb, 0xb8,
+ 0xc7, 0x33, 0xf0, 0xe8, 0xb3,
+ 0xf6};
+ doHMACTest(std::string(50, 0xdd), secret3, 16, MD5, hmac_expected3, 16);
+
+ const std::string data4(50, 0xcd);
+ const uint8_t secret4[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+ 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+ 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19 };
+ const uint8_t hmac_expected4[] = { 0x69, 0x7e, 0xaf, 0x0a, 0xca,
+ 0x3a, 0x3a, 0xea, 0x3a, 0x75,
+ 0x16, 0x47, 0x46, 0xff, 0xaa,
+ 0x79 };
+ doHMACTest(data4, secret4, 25, MD5, hmac_expected4, 16);
+
+ const uint8_t hmac_expected6[] = { 0x6b, 0x1a, 0xb7, 0xfe, 0x4b,
+ 0xd7, 0xbf, 0x8f, 0x0b, 0x62,
+ 0xe6, 0xce, 0x61, 0xb9, 0xd0,
+ 0xcd };
+ doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
+ std::string(80, 0xaa).c_str(), 80, MD5, hmac_expected6, 16);
+
+ const uint8_t hmac_expected7[] = { 0x6f, 0x63, 0x0f, 0xad, 0x67,
+ 0xcd, 0xa0, 0xee, 0x1f, 0xb1,
+ 0xf5, 0x62, 0xdb, 0x3a, 0xa5,
+ 0x3e };
+ doHMACTest("Test Using Larger Than Block-Size Key and Larger Than "
+ "One Block-Size Data",
+ std::string(80, 0xaa).c_str(), 80, MD5, hmac_expected7, 16);
+}
+
+// Temporarily disabled
+TEST(CryptoLinkTest, DISABLED_HMAC_MD5_RFC2202_SIGN_TRUNCATED) {
+ const uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c };
+ const uint8_t hmac_expected5[] = { 0x56, 0x46, 0x1e, 0xf2, 0x34,
+ 0x2e, 0xdc, 0x00, 0xf9, 0xba,
+ 0xb9, 0x95, 0x69, 0x0e, 0xfd,
+ 0x4c };
+ doHMACTest("Test With Truncation", secret5, 16, MD5,
+ hmac_expected5, 16);
+ doHMACTest("Test With Truncation", secret5, 16, MD5,
+ hmac_expected5, 12);
+}
+
+//
+// Test values taken from RFC 2202
+//
+TEST(CryptoLinkTest, HMAC_SHA1_RFC2202_SIGN) {
+ const uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
+ const uint8_t hmac_expected[] = { 0xb6, 0x17, 0x31, 0x86, 0x55,
+ 0x05, 0x72, 0x64, 0xe2, 0x8b,
+ 0xc0, 0xb6, 0xfb, 0x37, 0x8c,
+ 0x8e, 0xf1, 0x46, 0xbe, 0x00 };
+ doHMACTest("Hi There", secret, 20, SHA1, hmac_expected, 20);
+
+ const uint8_t hmac_expected2[] = { 0xef, 0xfc, 0xdf, 0x6a, 0xe5,
+ 0xeb, 0x2f, 0xa2, 0xd2, 0x74,
+ 0x16, 0xd5, 0xf1, 0x84, 0xdf,
+ 0x9c, 0x25, 0x9a, 0x7c, 0x79 };
+ doHMACTest("what do ya want for nothing?", "Jefe", 4, SHA1,
+ hmac_expected2, 20);
+
+ const uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa };
+ const uint8_t hmac_expected3[] = { 0x12, 0x5d, 0x73, 0x42, 0xb9,
+ 0xac, 0x11, 0xcd, 0x91, 0xa3,
+ 0x9a, 0xf4, 0x8a, 0xa1, 0x7b,
+ 0x4f, 0x63, 0xf1, 0x75, 0xd3 };
+ doHMACTest(std::string(50, 0xdd), secret3, 20, SHA1, hmac_expected3, 20);
+
+ const uint8_t secret4[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+ 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+ 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19 };
+ const uint8_t hmac_expected4[] = { 0x4c, 0x90, 0x07, 0xf4, 0x02,
+ 0x62, 0x50, 0xc6, 0xbc, 0x84,
+ 0x14, 0xf9, 0xbf, 0x50, 0xc8,
+ 0x6c, 0x2d, 0x72, 0x35, 0xda };
+ doHMACTest(std::string(50, 0xcd), secret4, 25, SHA1, hmac_expected4, 20);
+
+ const uint8_t hmac_expected6[] = { 0xaa, 0x4a, 0xe5, 0xe1, 0x52,
+ 0x72, 0xd0, 0x0e, 0x95, 0x70,
+ 0x56, 0x37, 0xce, 0x8a, 0x3b,
+ 0x55, 0xed, 0x40, 0x21, 0x12 };
+ doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
+ std::string(80, 0xaa).c_str(), 80, SHA1, hmac_expected6, 20);
+
+ const uint8_t hmac_expected7[] = { 0xe8, 0xe9, 0x9d, 0x0f, 0x45,
+ 0x23, 0x7d, 0x78, 0x6d, 0x6b,
+ 0xba, 0xa7, 0x96, 0x5c, 0x78,
+ 0x08, 0xbb, 0xff, 0x1a, 0x91 };
+ doHMACTest("Test Using Larger Than Block-Size Key and Larger Than "
+ "One Block-Size Data",
+ std::string(80, 0xaa).c_str(), 80, SHA1, hmac_expected7, 20);
+}
+
+// Temporarily disabled
+TEST(CryptoLinkTest, DISABLED_HMAC_SHA1_RFC2202_SIGN_TRUNCATED) {
+ const uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c };
+ const uint8_t hmac_expected5[] = { 0x4c, 0x1a, 0x03, 0x42, 0x4b,
+ 0x55, 0xe0, 0x7f, 0xe7, 0xf2,
+ 0x7b, 0xe1, 0xd5, 0x8b, 0xb9,
+ 0x32, 0x4a, 0x9a, 0x5a, 0x04 };
+ doHMACTest("Test With Truncation", secret5, 20, SHA1,
+ hmac_expected5, 20);
+ doHMACTest("Test With Truncation", secret5, 20, SHA1,
+ hmac_expected5, 12);
+}
+
+//
+// Test values taken from RFC 4231
+//
+TEST(CryptoLinkTest, HMAC_SHA256_RFC2202_SIGN) {
+ const uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
+ const uint8_t hmac_expected[] = { 0xb0, 0x34, 0x4c, 0x61, 0xd8,
+ 0xdb, 0x38, 0x53, 0x5c, 0xa8,
+ 0xaf, 0xce, 0xaf, 0x0b, 0xf1,
+ 0x2b, 0x88, 0x1d, 0xc2, 0x00,
+ 0xc9, 0x83, 0x3d, 0xa7, 0x26,
+ 0xe9, 0x37, 0x6c, 0x2e, 0x32,
+ 0xcf, 0xf7 };
+ doHMACTest("Hi There", secret, 20, SHA256, hmac_expected, 32);
+
+ const uint8_t hmac_expected2[] = { 0x5b, 0xdc, 0xc1, 0x46, 0xbf,
+ 0x60, 0x75, 0x4e, 0x6a, 0x04,
+ 0x24, 0x26, 0x08, 0x95, 0x75,
+ 0xc7, 0x5a, 0x00, 0x3f, 0x08,
+ 0x9d, 0x27, 0x39, 0x83, 0x9d,
+ 0xec, 0x58, 0xb9, 0x64, 0xec,
+ 0x38, 0x43 };
+ doHMACTest("what do ya want for nothing?", "Jefe", 4, SHA256,
+ hmac_expected2, 32);
+
+ const uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa };
+ const uint8_t hmac_expected3[] = { 0x77, 0x3e, 0xa9, 0x1e, 0x36,
+ 0x80, 0x0e, 0x46, 0x85, 0x4d,
+ 0xb8, 0xeb, 0xd0, 0x91, 0x81,
+ 0xa7, 0x29, 0x59, 0x09, 0x8b,
+ 0x3e, 0xf8, 0xc1, 0x22, 0xd9,
+ 0x63, 0x55, 0x14, 0xce, 0xd5,
+ 0x65, 0xfe };
+ doHMACTest(std::string(50, 0xdd), secret3, 20, SHA256, hmac_expected3, 32);
+
+ const uint8_t secret4[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+ 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+ 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19 };
+ const uint8_t hmac_expected4[] = { 0x82, 0x55, 0x8a, 0x38, 0x9a,
+ 0x44, 0x3c, 0x0e, 0xa4, 0xcc,
+ 0x81, 0x98, 0x99, 0xf2, 0x08,
+ 0x3a, 0x85, 0xf0, 0xfa, 0xa3,
+ 0xe5, 0x78, 0xf8, 0x07, 0x7a,
+ 0x2e, 0x3f, 0xf4, 0x67, 0x29,
+ 0x66, 0x5b };
+ doHMACTest(std::string(50, 0xcd), secret4, 25, SHA256, hmac_expected4, 32);
+
+ const uint8_t hmac_expected6[] = { 0x60, 0xe4, 0x31, 0x59, 0x1e,
+ 0xe0, 0xb6, 0x7f, 0x0d, 0x8a,
+ 0x26, 0xaa, 0xcb, 0xf5, 0xb7,
+ 0x7f, 0x8e, 0x0b, 0xc6, 0x21,
+ 0x37, 0x28, 0xc5, 0x14, 0x05,
+ 0x46, 0x04, 0x0f, 0x0e, 0xe3,
+ 0x7f, 0x54 };
+ doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
+ std::string(131, 0xaa).c_str(), 131, SHA256, hmac_expected6, 32);
+
+ const uint8_t hmac_expected7[] = { 0x9b, 0x09, 0xff, 0xa7, 0x1b,
+ 0x94, 0x2f, 0xcb, 0x27, 0x63,
+ 0x5f, 0xbc, 0xd5, 0xb0, 0xe9,
+ 0x44, 0xbf, 0xdc, 0x63, 0x64,
+ 0x4f, 0x07, 0x13, 0x93, 0x8a,
+ 0x7f, 0x51, 0x53, 0x5c, 0x3a,
+ 0x35, 0xe2 };
+ doHMACTest("This is a test using a larger than block-size key and a"
+ " larger than block-size data. The key needs to be hashe"
+ "d before being used by the HMAC algorithm.",
+ std::string(131, 0xaa).c_str(), 131, SHA256, hmac_expected7, 32);
+}
+
+TEST(CryptoLinkTest, DISABLED_HMAC_SHA256_RFC2202_SIGN_TRUNCATED) {
+ const uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c };
+ const uint8_t hmac_expected5[] = { 0xa3, 0xb6, 0x16, 0x74, 0x73,
+ 0x10, 0x0e, 0xe0, 0x6e, 0x0c,
+ 0x79, 0x6c, 0x29, 0x55, 0x55,
+ 0x2b };
+ doHMACTest("Test With Truncation", secret5, 20, SHA256,
+ hmac_expected5, 16);
+}
+
+namespace {
+ size_t
+ sigVectorLength(HashAlgorithm alg, size_t len) {
+ boost::shared_ptr<HMAC> hmac_sign(
+ CryptoLink::getCryptoLink().createHMAC("asdf", 4, alg),
+ deleteHMAC);
+ hmac_sign->update("asdf", 4);
+ const std::vector<uint8_t> sig = hmac_sign->sign(len);
+ return (sig.size());
+ }
+
+ size_t
+ sigBufferLength(HashAlgorithm alg, size_t len) {
+ boost::shared_ptr<HMAC> hmac_sign(
+ CryptoLink::getCryptoLink().createHMAC("asdf", 4, alg),
+ deleteHMAC);
+ hmac_sign->update("asdf", 4);
+ OutputBuffer sig(0);
+ hmac_sign->sign(sig, len);
+ return (sig.getLength());
+ }
+}
+
+TEST(CryptoLinkTest, HMACSigLengthArgument) {
+ std::vector<uint8_t> sig;
+
+ EXPECT_EQ(16, sigVectorLength(MD5, 0));
+ EXPECT_EQ(8, sigVectorLength(MD5, 8));
+ EXPECT_EQ(16, sigVectorLength(MD5, 16));
+ EXPECT_EQ(16, sigVectorLength(MD5, 40));
+ EXPECT_EQ(16, sigVectorLength(MD5, 2000));
+
+ EXPECT_EQ(20, sigBufferLength(SHA1, 0));
+ EXPECT_EQ(8, sigBufferLength(SHA1, 8));
+ EXPECT_EQ(20, sigBufferLength(SHA1, 20));
+ EXPECT_EQ(20, sigBufferLength(SHA1, 40));
+ EXPECT_EQ(20, sigBufferLength(SHA1, 2000));
+
+ EXPECT_EQ(32, sigBufferLength(SHA256, 0));
+ EXPECT_EQ(8, sigBufferLength(SHA256, 8));
+ EXPECT_EQ(32, sigBufferLength(SHA256, 32));
+ EXPECT_EQ(32, sigBufferLength(SHA256, 40));
+ EXPECT_EQ(32, sigBufferLength(SHA256, 3200));
+
+ EXPECT_EQ(16, sigBufferLength(MD5, 0));
+ EXPECT_EQ(8, sigBufferLength(MD5, 8));
+ EXPECT_EQ(16, sigBufferLength(MD5, 16));
+ EXPECT_EQ(16, sigBufferLength(MD5, 40));
+ EXPECT_EQ(16, sigBufferLength(MD5, 2000));
+
+ EXPECT_EQ(20, sigBufferLength(SHA1, 0));
+ EXPECT_EQ(8, sigBufferLength(SHA1, 8));
+ EXPECT_EQ(20, sigBufferLength(SHA1, 20));
+ EXPECT_EQ(20, sigBufferLength(SHA1, 40));
+ EXPECT_EQ(20, sigBufferLength(SHA1, 2000));
+
+ EXPECT_EQ(32, sigBufferLength(SHA256, 0));
+ EXPECT_EQ(8, sigBufferLength(SHA256, 8));
+ EXPECT_EQ(32, sigBufferLength(SHA256, 32));
+ EXPECT_EQ(32, sigBufferLength(SHA256, 40));
+ EXPECT_EQ(32, sigBufferLength(SHA256, 3200));
+}
+
+TEST(CryptoLinkTest, BadKey) {
+ OutputBuffer data_buf(0);
+ OutputBuffer hmac_sig(0);
+ CryptoLink& crypto = CryptoLink::getCryptoLink();
+
+ EXPECT_THROW(crypto.createHMAC(NULL, 0, MD5), BadKey);
+ EXPECT_THROW(crypto.createHMAC(NULL, 0, UNKNOWN_HASH), UnsupportedAlgorithm);
+
+ EXPECT_THROW(signHMAC(data_buf.getData(), data_buf.getLength(),
+ NULL, 0, MD5, hmac_sig), BadKey);
+ EXPECT_THROW(signHMAC(data_buf.getData(), data_buf.getLength(),
+ NULL, 0, UNKNOWN_HASH, hmac_sig),
+ UnsupportedAlgorithm);
+
+ EXPECT_THROW(verifyHMAC(data_buf.getData(), data_buf.getLength(),
+ NULL, 0, MD5, hmac_sig.getData(),
+ hmac_sig.getLength()), BadKey);
+ EXPECT_THROW(verifyHMAC(data_buf.getData(), data_buf.getLength(),
+ NULL, 0, UNKNOWN_HASH, hmac_sig.getData(),
+ hmac_sig.getLength()),
+ UnsupportedAlgorithm);
+}
+
+TEST(CryptoLinkTest, Singleton) {
+ const CryptoLink& c1 = CryptoLink::getCryptoLink();
+ const CryptoLink& c2 = CryptoLink::getCryptoLink();
+ ASSERT_EQ(&c1, &c2);
+}
diff --git a/src/lib/cryptolink/tests/run_unittests.cc b/src/lib/cryptolink/tests/run_unittests.cc
new file mode 100644
index 0000000..d16327e
--- /dev/null
+++ b/src/lib/cryptolink/tests/run_unittests.cc
@@ -0,0 +1,22 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+
+int
+main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ return (RUN_ALL_TESTS());
+}
diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am
index adb1d41..e028186 100644
--- a/src/lib/datasrc/Makefile.am
+++ b/src/lib/datasrc/Makefile.am
@@ -7,7 +7,7 @@ AM_CPPFLAGS += $(SQLITE_CFLAGS)
AM_CXXFLAGS = $(B10_CXXFLAGS)
-CLEANFILES = *.gcno *.gcda
+CLEANFILES = *.gcno *.gcda messagedef.h messagedef.cc
lib_LTLIBRARIES = libdatasrc.la
libdatasrc_la_SOURCES = data_source.h data_source.cc
@@ -20,3 +20,16 @@ libdatasrc_la_SOURCES += zonetable.h zonetable.cc
libdatasrc_la_SOURCES += memory_datasrc.h memory_datasrc.cc
libdatasrc_la_SOURCES += zone.h
libdatasrc_la_SOURCES += result.h
+libdatasrc_la_SOURCES += logger.h logger.cc
+nodist_libdatasrc_la_SOURCES = messagedef.h messagedef.cc
+
+libdatasrc_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
+libdatasrc_la_LIBADD += $(top_builddir)/src/lib/dns/libdns++.la
+libdatasrc_la_LIBADD += $(top_builddir)/src/lib/log/liblog.la
+libdatasrc_la_LIBADD += $(top_builddir)/src/lib/cc/libcc.la
+
+BUILT_SOURCES = messagedef.h messagedef.cc
+messagedef.h messagedef.cc: Makefile messagedef.mes
+ $(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/datasrc/messagedef.mes
+
+EXTRA_DIST = messagedef.mes
diff --git a/src/lib/datasrc/cache.cc b/src/lib/datasrc/cache.cc
index 6fff754..8e9487d 100644
--- a/src/lib/datasrc/cache.cc
+++ b/src/lib/datasrc/cache.cc
@@ -24,6 +24,7 @@
#include <list>
#include <datasrc/cache.h>
+#include <datasrc/logger.h>
using namespace std;
using namespace isc::dns;
@@ -204,16 +205,21 @@ public:
// HotCacheImpl constructor
HotCacheImpl::HotCacheImpl(int slots, bool enabled) :
enabled_(enabled), slots_(slots), count_(0)
-{}
+{
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_CACHE_CREATE);
+}
// Insert a cache node into the cache
inline void
HotCacheImpl::insert(const CacheNodePtr node) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_INSERT).
+ arg(node->getRRset()->getName());
std::map<Question, CacheNodePtr>::const_iterator iter;
iter = map_.find(node->question);
if (iter != map_.end()) {
CacheNodePtr old = iter->second;
if (old && old->isValid()) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_OLD_FOUND);
remove(old);
}
}
@@ -225,6 +231,7 @@ HotCacheImpl::insert(const CacheNodePtr node) {
++count_;
if (slots_ != 0 && count_ > slots_) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_FULL);
remove(lru_.back());
}
}
@@ -245,6 +252,8 @@ HotCacheImpl::promote(CacheNodePtr node) {
// Remove a node from the LRU list and the map
void
HotCacheImpl::remove(ConstCacheNodePtr node) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_REMOVE).
+ arg(node->getRRset()->getName());
lru_.erase(node->lru_entry_);
map_.erase(node->question);
--count_;
@@ -257,6 +266,7 @@ HotCache::HotCache(const int slots) {
// HotCache destructor
HotCache::~HotCache() {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_CACHE_DESTROY);
delete impl_;
}
@@ -303,18 +313,21 @@ HotCache::retrieve(const Name& n, const RRClass& c, const RRType& t,
std::map<Question, CacheNodePtr>::const_iterator iter;
iter = impl_->map_.find(Question(n, c, t));
if (iter == impl_->map_.end()) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_NOT_FOUND).arg(n);
return (false);
}
CacheNodePtr node = iter->second;
if (node->isValid()) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_FOUND).arg(n);
impl_->promote(node);
rrset = node->getRRset();
flags = node->getFlags();
return (true);
}
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_EXPIRED).arg(n);
impl_->remove(node);
return (false);
}
@@ -328,6 +341,9 @@ HotCache::setSlots(const int slots) {
return;
}
+ logger.info(DATASRC_CACHE_SLOTS).arg(slots).arg(max(0, impl_->count_ -
+ slots));
+
while (impl_->slots_ != 0 && impl_->count_ > impl_->slots_) {
impl_->remove(impl_->lru_.back());
}
@@ -343,6 +359,11 @@ HotCache::getSlots() const {
void
HotCache::setEnabled(const bool e) {
impl_->enabled_ = e;
+ if (e) {
+ logger.info(DATASRC_CACHE_ENABLE);
+ } else {
+ logger.info(DATASRC_CACHE_DISABLE);
+ }
}
/// Indicate whether the cache is enabled
diff --git a/src/lib/datasrc/data_source.cc b/src/lib/datasrc/data_source.cc
index 90e1dd7..4e1fcde 100644
--- a/src/lib/datasrc/data_source.cc
+++ b/src/lib/datasrc/data_source.cc
@@ -25,6 +25,7 @@
#include <datasrc/cache.h>
#include <datasrc/data_source.h>
#include <datasrc/query.h>
+#include <datasrc/logger.h>
#include <util/encode/base32hex.h>
#include <util/hash/sha1.h>
@@ -83,7 +84,7 @@ class ZoneInfo {
public:
ZoneInfo(DataSrc* ts,
const isc::dns::Name& n,
- const isc::dns::RRClass& c,
+ const isc::dns::RRClass& c,
const isc::dns::RRType& t = isc::dns::RRType::ANY()) :
top_source_(ts),
dsm_(((t == RRType::DS() && n.getLabelCount() != 1)
@@ -123,6 +124,8 @@ getAdditional(Query& q, ConstRRsetPtr rrset) {
const Rdata& rd(it->getCurrent());
if (rrset->getType() == RRType::NS()) {
const generic::NS& ns = dynamic_cast<const generic::NS&>(rd);
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_GET_NS_ADDITIONAL).
+ arg(ns.getNSName()).arg(rrset->getName());
q.tasks().push(QueryTaskPtr(
new QueryTask(q, ns.getNSName(),
Message::SECTION_ADDITIONAL,
@@ -130,6 +133,8 @@ getAdditional(Query& q, ConstRRsetPtr rrset) {
QueryTask::GETADDITIONAL)));
} else if (rrset->getType() == RRType::MX()) {
const generic::MX& mx = dynamic_cast<const generic::MX&>(rd);
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_GET_MX_ADDITIONAL).
+ arg(mx.getMXName()).arg(rrset->getName());
q.tasks().push(QueryTaskPtr(
new QueryTask(q, mx.getMXName(),
Message::SECTION_ADDITIONAL,
@@ -143,11 +148,14 @@ getAdditional(Query& q, ConstRRsetPtr rrset) {
// understand DNAME
void
synthesizeCname(QueryTaskPtr task, RRsetPtr rrset, RRsetList& target) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_SYNTH_CNAME).
+ arg(rrset->getName());
RdataIteratorPtr it = rrset->getRdataIterator();
// More than one DNAME RR in the RRset is illegal, so we only have
// to process the first one.
if (it->isLast()) {
+ logger.error(DATASRC_QUERY_EMPTY_DNAME).arg(rrset->getName());
return;
}
@@ -171,16 +179,20 @@ synthesizeCname(QueryTaskPtr task, RRsetPtr rrset, RRsetList& target) {
// to by a CNAME record
void
chaseCname(Query& q, QueryTaskPtr task, RRsetPtr rrset) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_FOLLOW_CNAME).
+ arg(rrset->getName());
RdataIteratorPtr it = rrset->getRdataIterator();
// More than one CNAME RR in the RRset is illegal, so we only have
// to process the first one.
if (it->isLast()) {
+ logger.error(DATASRC_QUERY_EMPTY_CNAME).arg(rrset->getName());
return;
}
// Stop chasing CNAMES after 16 lookups, to prevent loops
if (q.tooMany()) {
+ logger.error(DATASRC_QUERY_TOO_MANY_CNAMES).arg(rrset->getName());
return;
}
@@ -194,6 +206,8 @@ chaseCname(Query& q, QueryTaskPtr task, RRsetPtr rrset) {
// Check the cache for data which can answer the current query task.
bool
checkCache(QueryTask& task, RRsetList& target) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_CHECK_CACHE).
+ arg(task.qname).arg(task.qtype);
HotCache& cache = task.q.getCache();
RRsetList rrsets;
RRsetPtr rrset;
@@ -206,6 +220,9 @@ checkCache(QueryTask& task, RRsetList& target) {
// ANY queries must be handled by the low-level data source,
// or the results won't be guaranteed to be complete
if (task.qtype == RRType::ANY() || task.qclass == RRClass::ANY()) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA,
+ DATASRC_QUERY_NO_CACHE_ANY_SIMPLE).arg(task.qname).
+ arg(task.qtype).arg(task.qclass);
break;
}
@@ -235,6 +252,8 @@ checkCache(QueryTask& task, RRsetList& target) {
case QueryTask::AUTH_QUERY: // Find exact RRset or CNAME
if (task.qtype == RRType::ANY() || task.qclass == RRClass::ANY()) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_NO_CACHE_ANY_AUTH).
+ arg(task.qname).arg(task.qtype).arg(task.qclass);
break;
}
@@ -353,30 +372,43 @@ DataSrc::Result
doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
HotCache& cache = task.q.getCache();
RRsetPtr rrset;
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_DO_QUERY).arg(task.qname).
+ arg(task.qtype);
+
+ // First off, make sure at least we have a matching zone in some data
+ // source. We must do this before checking the cache, because it can
+ // happen that the matching zone has been removed after an RRset of that
+ // zone is cached. Such inconsistency will cause various problems,
+ // including a crash.
+ const DataSrc* ds = zoneinfo.getDataSource();
+ const Name* const zonename = zoneinfo.getEnclosingZone();
+ if (ds == NULL) {
+ task.flags |= DataSrc::NO_SUCH_ZONE;
+ logger.info(DATASRC_QUERY_NO_ZONE).arg(task.qname).arg(task.qclass);
+ return (DataSrc::SUCCESS);
+ }
- // First, check the cache for matching data
+ // Then check the cache for matching data
if (checkCache(task, target)) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_CACHED).
+ arg(task.qname).arg(task.qtype);
return (DataSrc::SUCCESS);
}
// Requested data weren't in the cache (or were, but had expired),
// so now we proceed with the low-level data source lookup, and cache
// whatever we find.
- const DataSrc* ds = zoneinfo.getDataSource();
- const Name* const zonename = zoneinfo.getEnclosingZone();
-
- if (ds == NULL) {
- task.flags |= DataSrc::NO_SUCH_ZONE;
- return (DataSrc::SUCCESS);
- }
DataSrc::Result result;
switch (task.op) {
case QueryTask::SIMPLE_QUERY:
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_IS_SIMPLE).
+ arg(task.qname).arg(task.qtype);
result = ds->findExactRRset(task.qname, task.qclass, task.qtype,
target, task.flags, zonename);
if (result != DataSrc::SUCCESS) {
+ logger.error(DATASRC_QUERY_SIMPLE_FAIL).arg(result);
return (result);
}
@@ -398,10 +430,13 @@ doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
return (result);
case QueryTask::AUTH_QUERY:
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_IS_AUTH).
+ arg(task.qname).arg(task.qtype);
result = ds->findRRset(task.qname, task.qclass, task.qtype,
target, task.flags, zonename);
if (result != DataSrc::SUCCESS) {
+ logger.error(DATASRC_QUERY_AUTH_FAIL).arg(result);
return (result);
}
@@ -434,10 +469,16 @@ doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
case QueryTask::GLUE_QUERY:
case QueryTask::NOGLUE_QUERY:
+ LOG_DEBUG(logger, DBG_TRACE_DATA, task.op == QueryTask::GLUE_QUERY ?
+ DATASRC_QUERY_IS_GLUE : DATASRC_QUERY_IS_NOGLUE).
+ arg(task.qname).arg(task.qtype);
result = ds->findAddrs(task.qname, task.qclass, target,
task.flags, zonename);
if (result != DataSrc::SUCCESS) {
+ logger.error(task.op == QueryTask::GLUE_QUERY ?
+ DATASRC_QUERY_GLUE_FAIL : DATASRC_QUERY_NOGLUE_FAIL).
+ arg(result);
return (result);
}
@@ -463,10 +504,13 @@ doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
return (result);
case QueryTask::REF_QUERY:
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_IS_REF).
+ arg(task.qname).arg(task.qtype);
result = ds->findReferral(task.qname, task.qclass, target,
task.flags, zonename);
if (result != DataSrc::SUCCESS) {
+ logger.error(DATASRC_QUERY_REF_FAIL).arg(result);
return (result);
}
@@ -500,6 +544,7 @@ doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
}
// Not reached
+ logger.error(DATASRC_QUERY_INVALID_OP);
return (DataSrc::ERROR);
}
@@ -511,6 +556,8 @@ inline void
addToMessage(Query& q, const Message::Section sect, RRsetPtr rrset,
bool no_dnssec = false)
{
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_RRSET).
+ arg(rrset->getName()).arg(rrset->getType());
Message& m = q.message();
if (no_dnssec) {
if (rrset->getType() == RRType::RRSIG() ||
@@ -529,6 +576,7 @@ addToMessage(Query& q, const Message::Section sect, RRsetPtr rrset,
// Copy referral information into the authority section of a message
inline void
copyAuth(Query& q, RRsetList& auth) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_COPY_AUTH);
BOOST_FOREACH(RRsetPtr rrset, auth) {
if (rrset->getType() == RRType::DNAME()) {
continue;
@@ -566,6 +614,9 @@ refQuery(const Query& q, const Name& name, ZoneInfo& zoneinfo,
// they'll be handled in a normal lookup in the zone.
inline bool
hasDelegation(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_DELEGATION).
+ arg(task->qname);
+
const Name* const zonename = zoneinfo.getEnclosingZone();
if (zonename == NULL) {
if (task->state == QueryTask::GETANSWER) {
@@ -631,6 +682,7 @@ addSOA(Query& q, ZoneInfo& zoneinfo) {
RRsetList soa;
const Name* const zonename = zoneinfo.getEnclosingZone();
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_SOA).arg(*zonename);
QueryTask newtask(q, *zonename, RRType::SOA(), QueryTask::SIMPLE_QUERY);
RETERR(doQueryTask(newtask, zoneinfo, soa));
if (newtask.flags != 0) {
@@ -644,6 +696,7 @@ addSOA(Query& q, ZoneInfo& zoneinfo) {
inline DataSrc::Result
addNSEC(Query& q, const Name& name, ZoneInfo& zoneinfo) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_NSEC).arg(name);
RRsetList nsec;
QueryTask newtask(q, name, RRType::NSEC(), QueryTask::SIMPLE_QUERY);
@@ -660,9 +713,11 @@ inline DataSrc::Result
getNsec3(Query& q, ZoneInfo& zoneinfo, string& hash, RRsetPtr& target) {
const DataSrc* ds = zoneinfo.getDataSource();
const Name* const zonename = zoneinfo.getEnclosingZone();
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_NSEC3).arg(*zonename);
if (ds == NULL) {
q.message().setRcode(Rcode::SERVFAIL());
+ logger.error(DATASRC_QUERY_NO_DS_NSEC3).arg(*zonename);
return (DataSrc::ERROR);
}
@@ -765,6 +820,7 @@ proveNX(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, const bool wildcard) {
const DataSrc* ds = zoneinfo.getDataSource();
if (ds == NULL) {
m.setRcode(Rcode::SERVFAIL());
+ logger.error(DATASRC_QUERY_NO_DS_NSEC).arg(*zonename);
return (DataSrc::ERROR);
}
ds->findPreviousName(task->qname, nsecname, zonename);
@@ -793,6 +849,7 @@ proveNX(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, const bool wildcard) {
// Attempt a wildcard lookup
inline DataSrc::Result
tryWildcard(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, bool& found) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_WILDCARD).arg(task->qname);
Message& m = q.message();
DataSrc::Result result;
found = false;
@@ -846,6 +903,8 @@ tryWildcard(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, bool& found) {
result = proveNX(q, task, zoneinfo, true);
if (result != DataSrc::SUCCESS) {
m.setRcode(Rcode::SERVFAIL());
+ logger.error(DATASRC_QUERY_WILDCARD_PROVENX_FAIL).
+ arg(task->qname).arg(result);
return (DataSrc::ERROR);
}
}
@@ -868,6 +927,8 @@ tryWildcard(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, bool& found) {
RRsetList auth;
if (!refQuery(q, *zonename, zoneinfo, auth)) {
+ logger.error(DATASRC_QUERY_WILDCARD_REFERRAL).arg(task->qname).
+ arg(result);
return (DataSrc::ERROR);
}
@@ -883,6 +944,8 @@ tryWildcard(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, bool& found) {
//
void
DataSrc::doQuery(Query& q) {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_QUERY_PROCESS).arg(q.qname()).
+ arg(q.qclass());
Message& m = q.message();
vector<RRsetPtr> additional;
@@ -900,6 +963,7 @@ DataSrc::doQuery(Query& q) {
// Can't query directly for RRSIG.
if (task->qtype == RRType::RRSIG()) {
m.setRcode(Rcode::REFUSED());
+ logger.warn(DATASRC_QUERY_RRSIG).arg(task->qname);
return;
}
@@ -907,6 +971,7 @@ DataSrc::doQuery(Query& q) {
if (task->op == QueryTask::SIMPLE_QUERY ||
task->op == QueryTask::REF_QUERY) {
m.setRcode(Rcode::SERVFAIL());
+ logger.error(DATASRC_QUERY_MISPLACED_TASK);
return;
}
@@ -926,6 +991,7 @@ DataSrc::doQuery(Query& q) {
result = doQueryTask(*task, zoneinfo, data);
if (result != SUCCESS) {
m.setRcode(Rcode::SERVFAIL());
+ logger.error(DATASRC_QUERY_TASK_FAIL).arg(result);
return;
}
@@ -935,6 +1001,7 @@ DataSrc::doQuery(Query& q) {
if (task->flags == NO_SUCH_ZONE) {
if (task->state == QueryTask::GETANSWER) {
m.setRcode(Rcode::REFUSED());
+ // No need to log it here, it was already logged in doQueryTask
return;
}
continue;
@@ -976,6 +1043,7 @@ DataSrc::doQuery(Query& q) {
RRsetList auth;
if (!refQuery(q, Name(*zonename), zoneinfo, auth) ||
!findRRsetFromList(auth, RRType::NS())) {
+ logger.error(DATASRC_QUERY_MISSING_NS).arg(*zonename);
isc_throw(DataSourceError,
"NS RR not found in " << *zonename << "/" <<
q.qclass());
@@ -1000,10 +1068,12 @@ DataSrc::doQuery(Query& q) {
continue;
default:
+ logger.error(DATASRC_UNEXPECTED_QUERY_STATE);
isc_throw (Unexpected, "unexpected query state");
}
} else if (result == ERROR || result == NOT_IMPLEMENTED) {
m.setRcode(Rcode::SERVFAIL());
+ logger.error(DATASRC_QUERY_FAIL);
return;
} else if ((task->flags & CNAME_FOUND) != 0) {
// The qname node contains a CNAME. Add a new task to the
@@ -1021,6 +1091,7 @@ DataSrc::doQuery(Query& q) {
m.setHeaderFlag(Message::HEADERFLAG_AA, false);
if (!refQuery(q, task->qname, zoneinfo, auth)) {
m.setRcode(Rcode::SERVFAIL());
+ logger.error(DATASRC_QUERY_BAD_REFERRAL).arg(task->qname);
return;
}
BOOST_FOREACH (RRsetPtr rrset, auth) {
@@ -1052,6 +1123,7 @@ DataSrc::doQuery(Query& q) {
result = tryWildcard(q, task, zoneinfo, wildcard_found);
if (result != SUCCESS) {
m.setRcode(Rcode::SERVFAIL());
+ logger.error(DATASRC_QUERY_WILDCARD_FAIL).arg(task->qname);
return;
}
@@ -1073,6 +1145,7 @@ DataSrc::doQuery(Query& q) {
result = addSOA(q, zoneinfo);
if (result != SUCCESS) {
+ logger.error(DATASRC_QUERY_MISSING_SOA).arg(*zonename);
isc_throw(DataSourceError,
"SOA RR not found in " << *zonename <<
"/" << q.qclass());
@@ -1089,6 +1162,7 @@ DataSrc::doQuery(Query& q) {
result = proveNX(q, task, zoneinfo, false);
if (result != DataSrc::SUCCESS) {
m.setRcode(Rcode::SERVFAIL());
+ logger.error(DATASRC_QUERY_PROVENX_FAIL).arg(task->qname);
return;
}
}
@@ -1097,6 +1171,7 @@ DataSrc::doQuery(Query& q) {
} else {
// Should never be reached!
m.setRcode(Rcode::SERVFAIL());
+ logger.error(DATASRC_QUERY_UNKNOWN_RESULT);
return;
}
}
@@ -1192,7 +1267,10 @@ DataSrc::findReferral(const Name& qname, const RRClass& qclass,
void
MetaDataSrc::addDataSrc(ConstDataSrcPtr data_src) {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_META_ADD);
if (getClass() != RRClass::ANY() && data_src->getClass() != getClass()) {
+ logger.error(DATASRC_META_ADD_CLASS_MISMATCH).
+ arg(data_src->getClass()).arg(getClass());
isc_throw(Unexpected, "class mismatch");
}
@@ -1201,6 +1279,7 @@ MetaDataSrc::addDataSrc(ConstDataSrcPtr data_src) {
void
MetaDataSrc::removeDataSrc(ConstDataSrcPtr data_src) {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_META_REMOVE);
std::vector<ConstDataSrcPtr>::iterator it, itr;
for (it = data_sources.begin(); it != data_sources.end(); ++it) {
if (*it == data_src) {
diff --git a/src/lib/datasrc/logger.cc b/src/lib/datasrc/logger.cc
new file mode 100644
index 0000000..846e43b
--- /dev/null
+++ b/src/lib/datasrc/logger.cc
@@ -0,0 +1,23 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <datasrc/logger.h>
+
+namespace isc {
+namespace datasrc {
+
+isc::log::Logger logger("datasrc");
+
+}
+}
diff --git a/src/lib/datasrc/logger.h b/src/lib/datasrc/logger.h
new file mode 100644
index 0000000..7c2828d
--- /dev/null
+++ b/src/lib/datasrc/logger.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __DATASRC_LOGGER_H
+#define __DATASRC_LOGGER_H
+
+#include <log/macros.h>
+#include <datasrc/messagedef.h>
+
+/// \file logger.h
+/// \brief Data Source library global logger
+///
+/// This holds the logger for the data source library. It is a private header
+/// and should not be included in any publicly used header, only in local
+/// cc files.
+
+namespace isc {
+namespace datasrc {
+
+/// \brief The logger for this library
+extern isc::log::Logger logger;
+
+enum {
+ /// \brief Trace basic operations
+ DBG_TRACE_BASIC = 10,
+ /// \brief Trace data changes and lookups as well
+ DBG_TRACE_DATA = 20,
+ /// \brief Detailed even about how the lookups happen
+ DBG_TRACE_DETAILED = 50
+};
+
+}
+}
+
+#endif
diff --git a/src/lib/datasrc/memory_datasrc.cc b/src/lib/datasrc/memory_datasrc.cc
index 5230ced..3c57d1b 100644
--- a/src/lib/datasrc/memory_datasrc.cc
+++ b/src/lib/datasrc/memory_datasrc.cc
@@ -24,6 +24,7 @@
#include <datasrc/memory_datasrc.h>
#include <datasrc/rbtree.h>
+#include <datasrc/logger.h>
using namespace std;
using namespace isc::dns;
@@ -94,6 +95,8 @@ struct MemoryZone::MemoryZoneImpl {
l > origin_labels;
--l, wname = wname.split(1)) {
if (wname.isWildcard()) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ADD_WILDCARD).
+ arg(name);
// Ensure a separate level exists for the "wildcarding" name,
// and mark the node as "wild".
DomainNode* node;
@@ -130,10 +133,13 @@ struct MemoryZone::MemoryZoneImpl {
// (depending on how we support DNSSEC). We should revisit it
// at that point.
if (!domain->empty()) {
+ LOG_ERROR(logger, DATASRC_MEM_CNAME_TO_NONEMPTY).
+ arg(rrset->getName());
isc_throw(AddError, "CNAME can't be added with other data for "
<< rrset->getName());
}
} else if (domain->find(RRType::CNAME()) != domain->end()) {
+ LOG_ERROR(logger, DATASRC_MEM_CNAME_COEXIST).arg(rrset->getName());
isc_throw(AddError, "CNAME and " << rrset->getType() <<
" can't coexist for " << rrset->getName());
}
@@ -151,6 +157,7 @@ struct MemoryZone::MemoryZoneImpl {
(rrset->getType() == RRType::NS() &&
domain->find(RRType::DNAME()) != domain->end())))
{
+ LOG_ERROR(logger, DATASRC_MEM_DNAME_NS).arg(rrset->getName());
isc_throw(AddError, "DNAME can't coexist with NS in non-apex "
"domain " << rrset->getName());
}
@@ -172,6 +179,8 @@ struct MemoryZone::MemoryZoneImpl {
// XXX: this is not only for CNAME or DNAME. We should generalize
// this code for all other "singleton RR types" (such as SOA) in a
// separate task.
+ LOG_ERROR(logger, DATASRC_MEM_SINGLETON).arg(rrset->getName()).
+ arg(rrset->getType());
isc_throw(AddError, "multiple RRs of singleton type for "
<< rrset->getName());
}
@@ -180,6 +189,8 @@ struct MemoryZone::MemoryZoneImpl {
if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
compare.getRelation() != NameComparisonResult::EQUAL)
{
+ LOG_ERROR(logger, DATASRC_MEM_OUT_OF_ZONE).arg(rrset->getName()).
+ arg(origin_);
isc_throw(OutOfZone, "The name " << rrset->getName() <<
" is not contained in zone " << origin_);
}
@@ -194,10 +205,14 @@ struct MemoryZone::MemoryZoneImpl {
// behavior.
if (rrset->getName().isWildcard()) {
if (rrset->getType() == RRType::NS()) {
+ LOG_ERROR(logger, DATASRC_MEM_WILDCARD_NS).
+ arg(rrset->getName());
isc_throw(AddError, "Invalid NS owner name (wildcard): " <<
rrset->getName());
}
if (rrset->getType() == RRType::DNAME()) {
+ LOG_ERROR(logger, DATASRC_MEM_WILDCARD_DNAME).
+ arg(rrset->getName());
isc_throw(AddError, "Invalid DNAME owner name (wildcard): " <<
rrset->getName());
}
@@ -210,6 +225,8 @@ struct MemoryZone::MemoryZoneImpl {
*/
// Implementation of MemoryZone::add
result::Result add(const ConstRRsetPtr& rrset, DomainTree* domains) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ADD_RRSET).
+ arg(rrset->getName()).arg(rrset->getType()).arg(origin_);
// Sanitize input
addValidation(rrset);
@@ -271,6 +288,8 @@ struct MemoryZone::MemoryZoneImpl {
void addFromLoad(const ConstRRsetPtr& set, DomainTree* domains) {
switch (add(set, domains)) {
case result::EXIST:
+ LOG_ERROR(logger, DATASRC_MEM_DUP_RRSET).
+ arg(set->getName()).arg(set->getType());
isc_throw(dns::MasterLoadError, "Duplicate rrset: " <<
set->toText());
case result::SUCCESS:
@@ -307,6 +326,8 @@ struct MemoryZone::MemoryZoneImpl {
const Domain::const_iterator foundDNAME(node.getData()->find(
RRType::DNAME()));
if (foundDNAME != node.getData()->end()) {
+ LOG_DEBUG(logger, DBG_TRACE_DETAILED,
+ DATASRC_MEM_DNAME_ENCOUNTERED);
state->dname_node_ = &node;
state->rrset_ = foundDNAME->second;
// No more processing below the DNAME (RFC 2672, section 3
@@ -328,6 +349,8 @@ struct MemoryZone::MemoryZoneImpl {
return (false);
}
+ LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_NS_ENCOUNTERED);
+
// BIND 9 checks if this node is not the origin. That's probably
// because it can support multiple versions for dynamic updates
// and IXFR, and it's possible that the callback is called at
@@ -363,6 +386,8 @@ struct MemoryZone::MemoryZoneImpl {
rrset, bool rename)
{
if (rename) {
+ LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_RENAME).
+ arg(rrset->getName()).arg(name);
/*
* We lose a signature here. But it would be wrong anyway, because
* the name changed. This might turn out to be unimportant in
@@ -385,6 +410,8 @@ struct MemoryZone::MemoryZoneImpl {
FindResult find(const Name& name, RRType type,
RRsetList* target, const FindOptions options) const
{
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FIND).arg(name).
+ arg(type);
// Get the node
DomainNode* node(NULL);
FindState state(options);
@@ -411,12 +438,16 @@ struct MemoryZone::MemoryZoneImpl {
* is NULL.
*/
if (state.dname_node_ != NULL) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DNAME_FOUND).
+ arg(state.rrset_->getName());
// We were traversing a DNAME node (and wanted to go
// lower below it), so return the DNAME
return (FindResult(DNAME, prepareRRset(name, state.rrset_,
rename)));
}
if (state.zonecut_node_ != NULL) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DELEG_FOUND).
+ arg(state.rrset_->getName());
return (FindResult(DELEGATION, prepareRRset(name,
state.rrset_, rename)));
}
@@ -426,6 +457,8 @@ struct MemoryZone::MemoryZoneImpl {
// the zone but is empty. Treat it as NXRRSET.
if (node_path.getLastComparisonResult().getRelation() ==
NameComparisonResult::SUPERDOMAIN) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUPER_STOP).
+ arg(node_path.getAbsoluteName()).arg(name);
return (FindResult(NXRRSET, ConstRRsetPtr()));
}
@@ -463,6 +496,8 @@ struct MemoryZone::MemoryZoneImpl {
if (node_path.getLastComparisonResult().getRelation() ==
NameComparisonResult::COMMONANCESTOR && node_path.
getLastComparisonResult().getCommonLabels() > 1) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA,
+ DATASRC_MEM_WILDCARD_CANCEL).arg(name);
return (FindResult(NXDOMAIN, ConstRRsetPtr()));
}
Name wildcard(Name("*").concatenate(
@@ -485,6 +520,8 @@ struct MemoryZone::MemoryZoneImpl {
// fall through
case DomainTree::NOTFOUND:
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NOTFOUND).
+ arg(name);
return (FindResult(NXDOMAIN, ConstRRsetPtr()));
case DomainTree::EXACTMATCH: // This one is OK, handle it
break;
@@ -496,6 +533,8 @@ struct MemoryZone::MemoryZoneImpl {
// If there is an exact match but the node is empty, it's equivalent
// to NXRRSET.
if (node->isEmpty()) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DOMAIN_EMPTY).
+ arg(name);
return (FindResult(NXRRSET, ConstRRsetPtr()));
}
@@ -506,6 +545,8 @@ struct MemoryZone::MemoryZoneImpl {
if (node->getFlag(DomainNode::FLAG_CALLBACK) && node != origin_data_) {
found = node->getData()->find(RRType::NS());
if (found != node->getData()->end()) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA,
+ DATASRC_MEM_EXACT_DELEGATION).arg(name);
return (FindResult(DELEGATION, prepareRRset(name,
found->second, rename)));
}
@@ -521,23 +562,30 @@ struct MemoryZone::MemoryZoneImpl {
boost::const_pointer_cast<RRset>(prepareRRset(name,
found->second, rename)));
}
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ANY_SUCCESS).
+ arg(name);
return (FindResult(SUCCESS, ConstRRsetPtr()));
}
found = node->getData()->find(type);
if (found != node->getData()->end()) {
// Good, it is here
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUCCESS).arg(name).
+ arg(type);
return (FindResult(SUCCESS, prepareRRset(name, found->second,
rename)));
} else {
// Next, try CNAME.
found = node->getData()->find(RRType::CNAME());
if (found != node->getData()->end()) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_CNAME).arg(name);
return (FindResult(CNAME, prepareRRset(name, found->second,
rename)));
}
}
// No exact match or CNAME. Return NXRRSET.
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NXRRSET).arg(type).
+ arg(name);
return (FindResult(NXRRSET, ConstRRsetPtr()));
}
};
@@ -545,9 +593,13 @@ struct MemoryZone::MemoryZoneImpl {
MemoryZone::MemoryZone(const RRClass& zone_class, const Name& origin) :
impl_(new MemoryZoneImpl(zone_class, origin))
{
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_CREATE).arg(origin).
+ arg(zone_class);
}
MemoryZone::~MemoryZone() {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_DESTROY).arg(getOrigin()).
+ arg(getClass());
delete impl_;
}
@@ -576,6 +628,8 @@ MemoryZone::add(const ConstRRsetPtr& rrset) {
void
MemoryZone::load(const string& filename) {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_LOAD).arg(getOrigin()).
+ arg(filename);
// Load it into a temporary tree
MemoryZoneImpl::DomainTree tmp;
masterLoad(filename.c_str(), getOrigin(), getClass(),
@@ -588,6 +642,8 @@ MemoryZone::load(const string& filename) {
void
MemoryZone::swap(MemoryZone& zone) {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_SWAP).arg(getOrigin()).
+ arg(zone.getOrigin());
std::swap(impl_, zone.impl_);
}
@@ -628,6 +684,9 @@ MemoryDataSrc::addZone(ZonePtr zone) {
"Null pointer is passed to MemoryDataSrc::addZone()");
}
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_ADD_ZONE).
+ arg(zone->getOrigin()).arg(zone->getClass().toText());
+
const result::Result result = impl_->zone_table.addZone(zone);
if (result == result::SUCCESS) {
++impl_->zone_count;
@@ -637,6 +696,7 @@ MemoryDataSrc::addZone(ZonePtr zone) {
MemoryDataSrc::FindResult
MemoryDataSrc::findZone(const isc::dns::Name& name) const {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_FIND_ZONE).arg(name);
return (FindResult(impl_->zone_table.findZone(name).code,
impl_->zone_table.findZone(name).zone));
}
diff --git a/src/lib/datasrc/messagedef.mes b/src/lib/datasrc/messagedef.mes
new file mode 100644
index 0000000..2fc5c6b
--- /dev/null
+++ b/src/lib/datasrc/messagedef.mes
@@ -0,0 +1,498 @@
+# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+$PREFIX DATASRC_
+$NAMESPACE isc::datasrc
+
+# \brief Messages for the data source library
+
+% CACHE_CREATE creating the hotspot cache
+Debug information that the hotspot cache was created at startup.
+
+% CACHE_DESTROY destroying the hotspot cache
+Debug information. The hotspot cache is being destroyed.
+
+% CACHE_INSERT inserting item '%1' into the cache
+Debug information. It means a new item is being inserted into the hotspot
+cache.
+
+% CACHE_OLD_FOUND older instance of cache item found, replacing
+Debug information. While inserting an item into the hotspot cache, an older
+instance of an item with the same name was found. The old instance will be
+removed. This should be directly followed by CACHE_REMOVE.
+
+% CACHE_FULL cache is full, dropping oldest
+Debug information. After inserting an item into the hotspot cache, the
+maximum number of items was exceeded, so the least recently used item will
+be dropped. This should be directly followed by CACHE_REMOVE.
+
+% CACHE_REMOVE removing '%1' from the cache
+Debug information. An item is being removed from the hotspot cache.
+
+% CACHE_NOT_FOUND the item '%1' was not found
+Debug information. It was attempted to look up an item in the hotspot cache,
+but it is not there.
+
+% CACHE_FOUND the item '%1' was found
+Debug information. An item was successfully looked up in the hotspot cache.
+
+% CACHE_EXPIRED the item '%1' is expired
+Debug information. There was an attempt to look up an item in the hotspot
+cache. And the item was actually there, but it was too old, so it was removed
+instead and nothing is reported (the external behaviour is the same as with
+CACHE_NOT_FOUND).
+
+% CACHE_SLOTS setting the cache size to '%1', dropping '%2' items
+The maximum allowed number of items of the hotspot cache is set to the given
+number. If there are too many, some of them will be dropped. The size of 0
+means no limit.
+
+% CACHE_ENABLE enabling the cache
+The hotspot cache is enabled from now on.
+
+% CACHE_DISABLE disabling the cache
+The hotspot cache is disabled from now on. It is not going to store
+information or return anything.
+
+% QUERY_SYNTH_CNAME synthesizing CNAME from DNAME on '%1'
+Debug information. While answering a query, a DNAME was met. The DNAME itself
+will be returned, but along with it a CNAME for clients which don't understand
+DNAMEs will be synthesized.
+
+% QUERY_EMPTY_DNAME the DNAME on '%1' is empty
+During an attempt to synthesize CNAME from this DNAME it was discovered the
+DNAME is empty (it has no records). This indicates problem with supplied data.
+
+% QUERY_GET_NS_ADDITIONAL addition of A/AAAA for '%1' requested by NS '%2'
+Debug information. While processing a query, a NS record was met. It
+references the mentioned address, so A/AAAA records for it are looked up
+and put it into the additional section.
+
+% QUERY_GET_MX_ADDITIONAL addition of A/AAAA for '%1' requested by MX '%2'
+Debug information. While processing a query, a MX record was met. It
+references the mentioned address, so A/AAAA records for it are looked up
+and put it into the additional section.
+
+% QUERY_FOLLOW_CNAME following CNAME at '%1'
+Debug information. The domain is a CNAME (or a DNAME and we created a CNAME
+for it already), so it's being followed.
+
+% QUERY_EMPTY_CNAME cNAME at '%1' is empty
+There was an CNAME and it was being followed. But it contains no records,
+so there's nowhere to go. There will be no answer. This indicates a problem
+with supplied data.
+We tried to follow
+
+% QUERY_TOO_MANY_CNAMES cNAME chain limit exceeded at '%1'
+A CNAME led to another CNAME and it led to another, and so on. After 16
+CNAMEs, the software gave up. Long CNAME chains are discouraged, and this
+might possibly be a loop as well. Note that some of the CNAMEs might have
+been synthesized from DNAMEs. This indicates problem with supplied data.
+
+% QUERY_CHECK_CACHE checking cache for '%1/%2'
+Debug information. While processing a query, lookup to the hotspot cache
+is being made.
+
+% QUERY_NO_CACHE_ANY_SIMPLE ignoring cache for ANY query (%1/%2 in %3 class)
+Debug information. The hotspot cache is ignored for ANY queries for consistency
+reasons.
+
+% QUERY_NO_CACHE_ANY_AUTH ignoring cache for ANY query (%1/%2 in %3 class)
+Debug information. The hotspot cache is ignored for authoritative ANY queries
+for consistency reasons.
+
+% DO_QUERY handling query for '%1/%2'
+Debug information. We're processing some internal query for given name and
+type.
+
+% QUERY_NO_ZONE no zone containing '%1' in class '%2'
+Lookup of domain failed because the data have no zone that contain the
+domain. Maybe someone sent a query to the wrong server for some reason.
+
+% QUERY_CACHED data for %1/%2 found in cache
+Debug information. The requested data were found in the hotspot cache, so
+no query is sent to the real data source.
+
+% QUERY_IS_SIMPLE simple query (%1/%2)
+Debug information. The last DO_QUERY is a simple query.
+
+% QUERY_IS_AUTH auth query (%1/%2)
+Debug information. The last DO_QUERY is an auth query.
+
+% QUERY_IS_GLUE glue query (%1/%2)
+Debug information. The last DO_QUERY is query for glue addresses.
+
+% QUERY_IS_NOGLUE query for non-glue addresses (%1/%2)
+Debug information. The last DO_QUERY is query for addresses that are not
+glue.
+
+% QUERY_IS_REF query for referral (%1/%2)
+Debug information. The last DO_QUERY is query for referral information.
+
+% QUERY_SIMPLE_FAIL the underlying data source failed with %1
+The underlying data source failed to answer the simple query. 1 means some
+error, 2 is not implemented. The data source should have logged the specific
+error already.
+
+% QUERY_AUTH_FAIL the underlying data source failed with %1
+The underlying data source failed to answer the authoritative query. 1 means
+some error, 2 is not implemented. The data source should have logged the
+specific error already.
+
+% QUERY_GLUE_FAIL the underlying data source failed with %1
+The underlying data source failed to answer the glue query. 1 means some error,
+2 is not implemented. The data source should have logged the specific error
+already.
+
+% QUERY_NOGLUE_FAIL the underlying data source failed with %1
+The underlying data source failed to answer the no-glue query. 1 means some
+error, 2 is not implemented. The data source should have logged the specific
+error already.
+
+% QUERY_REF_FAIL the underlying data source failed with %1
+The underlying data source failed to answer the query for referral information.
+1 means some error, 2 is not implemented. The data source should have logged
+the specific error already.
+
+% QUERY_INVALID_OP invalid query operation requested
+This indicates a programmer error. The DO_QUERY was called with unknown
+operation code.
+
+% QUERY_ADD_RRSET adding RRset '%1/%2' to message
+Debug information. An RRset is being added to the response message.
+
+% QUERY_COPY_AUTH copying authoritative section into message
+Debug information. The whole referral information is being copied into the
+response message.
+
+% QUERY_DELEGATION looking for delegation on the path to '%1'
+Debug information. The software is trying to identify delegation points on the
+way down to the given domain.
+
+% QUERY_ADD_SOA adding SOA of '%1'
+Debug information. A SOA record of the given zone is being added to the
+authority section of the response message.
+
+% QUERY_ADD_NSEC adding NSEC record for '%1'
+Debug information. A NSEC record covering this zone is being added.
+
+% QUERY_ADD_NSEC3 adding NSEC3 record of zone '%1'
+Debug information. A NSEC3 record for the given zone is being added to the
+response message.
+
+% QUERY_NO_DS_NSEC3 there's no DS record in the '%1' zone
+An attempt to add a NSEC3 record into the message failed, because the zone does
+not have any DS record. This indicates problem with the provided data.
+
+% QUERY_NO_DS_NSEC there's no DS record in the '%1' zone
+An attempt to add a NSEC record into the message failed, because the zone does
+not have any DS record. This indicates problem with the provided data.
+
+% QUERY_WILDCARD looking for a wildcard covering '%1'
+Debug information. A direct match wasn't found, so a wildcard covering the
+domain is being looked for now.
+
+% QUERY_WILDCARD_PROVENX_FAIL unable to prove nonexistence of '%1' (%2)
+While processing a wildcard, it wasn't possible to prove nonexistence of the
+given domain or record. The code is 1 for error and 2 for not implemented.
+
+% QUERY_WILDCARD_REFERRAL unable to find referral info for '%1' (%2)
+While processing a wildcard, a referral was met. But it wasn't possible to get
+enough information for it. The code is 1 for error, 2 for not implemented.
+
+% QUERY_PROCESS processing query '%1/%2' in the '%3' class
+Debug information. A sure query is being processed now.
+
+% QUERY_RRSIG unable to answer RRSIG query
+The server is unable to answer a direct query for RRSIG type, but was asked
+to do so.
+
+% QUERY_MISPLACED_TASK task of this type should not be here
+This indicates a programming error. A task was found in the internal task
+queue, but this kind of task wasn't designed to be inside the queue (it should
+be handled right away, not queued).
+
+% QUERY_TASK_FAIL task failed with %1
+The query subtask failed. The reason should have been reported by the subtask
+already. The code is 1 for error, 2 for not implemented.
+
+% QUERY_MISSING_NS missing NS records for '%1'
+NS records should have been put into the authority section. However, this zone
+has none. This indicates problem with provided data.
+
+% UNEXPECTED_QUERY_STATE unexpected query state
+This indicates a programming error. An internal task of unknown type was
+generated.
+
+% QUERY_FAIL query failed
+Some subtask of query processing failed. The reason should have been reported
+already. We are returning SERVFAIL.
+
+% QUERY_BAD_REFERRAL bad referral to '%1'
+The domain lives in another zone. But it is not possible to generate referral
+information for it.
+
+% QUERY_WILDCARD_FAIL error processing wildcard for '%1'
+During an attempt to cover the domain by a wildcard an error happened. The
+exact kind was hopefully already reported.
+
+% QUERY_MISSING_SOA the zone '%1' has no SOA
+The answer should have been a negative one (eg. of nonexistence of something).
+To do so, a SOA record should be put into the authority section, but the zone
+does not have one. This indicates problem with provided data.
+
+% QUERY_PROVENX_FAIL unable to prove nonexistence of '%1'
+The user wants DNSSEC and we discovered the entity doesn't exist (either
+domain or the record). But there was an error getting NSEC/NSEC3 record
+to prove the nonexistence.
+
+% QUERY_UNKNOWN_RESULT unknown result of subtask
+This indicates a programmer error. The answer of subtask doesn't look like
+anything known.
+
+% META_ADD adding a data source into meta data source
+Debug information. Yet another data source is being added into the meta data
+source. (probably at startup or reconfiguration)
+
+% META_ADD_CLASS_MISMATCH mismatch between classes '%1' and '%2'
+It was attempted to add a data source into a meta data source. But their
+classes do not match.
+
+% META_REMOVE removing data source from meta data source
+Debug information. A data source is being removed from meta data source.
+
+% MEM_ADD_WILDCARD adding wildcards for '%1'
+Debug information. Some special marks above each * in wildcard name are needed.
+They are being added now for this name.
+
+% MEM_CNAME_TO_NONEMPTY can't add CNAME to domain with other data in '%1'
+Someone or something tried to add a CNAME into a domain that already contains
+some other data. But the protocol forbids coexistence of CNAME with anything
+(RFC 1034, section 3.6.2). This indicates a problem with provided data.
+
+% MEM_CNAME_COEXIST can't add data to CNAME in domain '%1'
+This is the same problem as in MEM_CNAME_TO_NONEMPTY, but it happened the
+other way around -- adding some outher data to CNAME.
+
+% MEM_DNAME_NS dNAME and NS can't coexist in non-apex domain '%1'
+It was requested for DNAME and NS records to be put into the same domain
+which is not the apex (the top of the zone). This is forbidden by RFC
+2672, section 3. This indicates a problem with provided data.
+
+% MEM_SINGLETON trying to add multiple RRs for domain '%1' and type '%2'
+Some resource types are singletons -- only one is allowed in a domain
+(for example CNAME or SOA). This indicates a problem with provided data.
+
+% MEM_OUT_OF_ZONE domain '%1' doesn't belong to zone '%2'
+It was attempted to add the domain into a zone that shouldn't have it
+(eg. the domain is not subdomain of the zone origin). This indicates a
+problem with provided data.
+
+% MEM_WILDCARD_NS nS record in wildcard domain '%1'
+The software refuses to load NS records into a wildcard domain. It isn't
+explicitly forbidden, but the protocol is ambiguous about how this should
+behave and BIND 9 refuses that as well. Please describe your intention using
+different tools.
+
+% MEM_WILDCARD_DNAME dNAME record in wildcard domain '%1'
+The software refuses to load DNAME records into a wildcard domain. It isn't
+explicitly forbidden, but the protocol is ambiguous about how this should
+behave and BIND 9 refuses that as well. Please describe your intention using
+different tools.
+
+% MEM_ADD_RRSET adding RRset '%1/%2' into zone '%3'
+Debug information. An RRset is being added to the in-memory data source.
+
+% MEM_DUP_RRSET duplicate RRset '%1/%2'
+An RRset is being inserted into in-memory data source for a second time. The
+original version must be removed first. Note that loading master files where an
+RRset is split into multiple locations is not supported yet.
+
+% MEM_DNAME_ENCOUNTERED encountered a DNAME
+Debug information. While searching for the requested domain, a DNAME was
+encountered on the way. This may lead to redirection to a different domain and
+stop the search.
+
+% MEM_NS_ENCOUNTERED encountered a NS
+Debug information. While searching for the requested domain, a NS was
+encountered on the way (a delegation). This may lead to stop of the search.
+
+% MEM_RENAME renaming RRset from '%1' to '%2'
+Debug information. A RRset is being generated from a different RRset (most
+probably a wildcard). So it must be renamed to whatever the user asked for. In
+fact, it's impossible to rename RRsets with our libraries, so a new one is
+created and all resource records are copied over.
+
+% MEM_FIND find '%1/%2'
+Debug information. A search for the requested RRset is being started.
+
+% MEM_DNAME_FOUND DNAME found at '%1'
+Debug information. A DNAME was found instead of the requested information.
+
+% MEM_DELEG_FOUND delegation found at '%1'
+Debug information. A delegation point was found above the requested record.
+
+% MEM_SUPER_STOP stopped at superdomain '%1', domain '%2' is empty
+Debug information. The search stopped at a superdomain of the requested
+domain. The domain is a empty nonterminal, therefore it is treated as NXRRSET
+case (eg. the domain exists, but it doesn't have the requested record type).
+
+% MEM_WILDCARD_CANCEL wildcard match canceled for '%1'
+Debug information. A domain above wildcard was reached, but there's something
+below the requested domain. Therefore the wildcard doesn't apply here. This
+behaviour is specified by RFC 1034, section 4.3.3
+
+% MEM_NOTFOUND requested domain '%1' not found
+Debug information. The requested domain does not exist.
+
+% MEM_DOMAIN_EMPTY requested domain '%1' is empty
+Debug information. The requested domain exists in the tree of domains, but
+it is empty. Therefore it doesn't contain the requested resource type.
+
+% MEM_EXACT_DELEGATION delegation at the exact domain '%1'
+Debug information. There's a NS record at the requested domain. This means
+this zone is not authoritative for the requested domain, but a delegation
+should be followed. The requested domain is an apex of some zone.
+
+% MEM_ANY_SUCCESS ANY query for '%1' successful
+Debug information. The domain was found and an ANY type query is being answered
+by providing everything found inside the domain.
+
+% MEM_SUCCESS query for '%1/%2' successful
+Debug information. The requested record was found.
+
+% MEM_CNAME CNAME at the domain '%1'
+Debug information. The requested domain is an alias to a different domain,
+returning the CNAME instead.
+
+% MEM_NXRRSET no such type '%1' at '%2'
+Debug information. The domain exists, but it doesn't hold any record of the
+requested type.
+
+% MEM_CREATE creating zone '%1' in '%2' class
+Debug information. A representation of a zone for the in-memory data source is
+being created.
+
+% MEM_DESTROY destroying zone '%1' in '%2' class
+Debug information. A zone from in-memory data source is being destroyed.
+
+% MEM_LOAD loading zone '%1' from file '%2'
+Debug information. The content of master file is being loaded into the memory.
+
+% MEM_SWAP swapping contents of two zone representations ('%1' and '%2')
+Debug information. The contents of two in-memory zones are being exchanged.
+This is usual practice to do some manipulation in exception-safe manner -- the
+new data are prepared in a different zone object and when it works, they are
+swapped. The old one contains the new data and the other one can be safely
+destroyed.
+
+% MEM_ADD_ZONE adding zone '%1/%2'
+Debug information. A zone is being added into the in-memory data source.
+
+% MEM_FIND_ZONE looking for zone '%1'
+Debug information. A zone object for this zone is being searched for in the
+in-memory data source.
+
+% STATIC_CREATE creating the static datasource
+Debug information. The static data source (the one holding stuff like
+version.bind) is being created.
+
+% STATIC_BAD_CLASS static data source can handle CH only
+For some reason, someone asked the static data source a query that is not in
+the CH class.
+
+% STATIC_FIND looking for '%1/%2'
+Debug information. This resource record set is being looked up in the static
+data source.
+
+% SQLITE_FINDREC looking for record '%1/%2'
+Debug information. The SQLite data source is looking up records of given name
+and type in the database.
+
+% SQLITE_ENCLOSURE looking for zone containing '%1'
+Debug information. The SQLite data source is trying to identify, which zone
+should hold this domain.
+
+% SQLITE_ENCLOSURE_BAD_CLASS class mismatch looking for a zone ('%1' and '%2')
+The SQLite data source can handle only one class at a time and it was asked
+to identify which zone is holding data of a different class.
+
+% SQLITE_ENCLOSURE_NOTFOUND no zone contains it
+Debug information. The last SQLITE_ENCLOSURE query was unsuccessful, there's
+no such zone in our data.
+
+% SQLITE_PREVIOUS looking for name previous to '%1'
+Debug information. We're trying to look up name preceding the supplied one.
+
+% SQLITE_PREVIOUS_NO_ZONE no zone containing '%1'
+The SQLite data source tried to identify name preceding this one. But this
+one is not contained in any zone in the data source.
+
+% SQLITE_FIND_NSEC3 looking for NSEC3 in zone '%1' for hash '%2'
+Debug information. We're trying to look up a NSEC3 record in the SQLite data
+source.
+
+% SQLITE_FIND_NSEC3_NO_ZONE no such zone '%1'
+The SQLite data source was asked to provide a NSEC3 record for given zone.
+But it doesn't contain that zone.
+
+% SQLITE_FIND looking for RRset '%1/%2'
+Debug information. The SQLite data source is looking up a resource record
+set.
+
+% SQLITE_FIND_BAD_CLASS class mismatch looking for an RRset ('%1' and '%2')
+The SQLite data source was looking up an RRset, but the data source contains
+different class than the query was for.
+
+% SQLITE_FINDEXACT looking for exact RRset '%1/%2'
+Debug information. The SQLite data source is looking up an exact resource
+record.
+
+% SQLITE_FINDEXACT_BAD_CLASS class mismatch looking for an RRset ('%1' and '%2')
+The SQLite data source was looking up an exact RRset, but the data source
+contains different class than the query was for.
+
+% SQLITE_FINDADDRS looking for A/AAAA addresses for '%1'
+Debug information. The data source is looking up the addresses for given
+domain name.
+
+% SQLITE_FINDADDRS_BAD_CLASS class mismatch looking for addresses ('%1' and '%2')
+The SQLite data source was looking up A/AAAA addresses, but the data source
+contains different class than the query was for.
+
+% SQLITE_FINDREF looking for referral at '%1'
+Debug information. The SQLite data source is identifying if this domain is
+a referral and where it goes.
+
+% SQLITE_FINDREF_BAD_CLASS class mismatch looking for referral ('%1' and '%2')
+The SQLite data source was trying to identify, if there's a referral. But
+it contains different class than the query was for.
+
+% SQLITE_CREATE sQLite data source created
+Debug information. An instance of SQLite data source is being created.
+
+% SQLITE_DESTROY sQLite data source destroyed
+Debug information. An instance of SQLite data source is being destroyed.
+
+% SQLITE_SETUP setting up SQLite database
+The database for SQLite data source was found empty. It is assumed this is the
+first run and it is being initialized with current schema. It'll still contain
+no data, but it will be ready for use.
+
+% SQLITE_OPEN opening SQLite database '%1'
+Debug information. The SQLite data source is loading an SQLite database in
+the provided file.
+
+% SQLITE_CLOSE closing SQLite database
+Debug information. The SQLite data source is closing the database file.
diff --git a/src/lib/datasrc/sqlite3_datasrc.cc b/src/lib/datasrc/sqlite3_datasrc.cc
index ab910ba..22f035b 100644
--- a/src/lib/datasrc/sqlite3_datasrc.cc
+++ b/src/lib/datasrc/sqlite3_datasrc.cc
@@ -18,6 +18,7 @@
#include <sqlite3.h>
#include <datasrc/sqlite3_datasrc.h>
+#include <datasrc/logger.h>
#include <dns/rrttl.h>
#include <dns/rdata.h>
@@ -227,6 +228,8 @@ Sqlite3DataSrc::findRecords(const Name& name, const RRType& rdtype,
RRsetList& target, const Name* zonename,
const Mode mode, uint32_t& flags) const
{
+ LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_SQLITE_FINDREC).arg(name).
+ arg(rdtype);
flags = 0;
int zone_id = (zonename == NULL) ? findClosest(name, NULL) :
findClosest(*zonename, NULL);
@@ -345,12 +348,17 @@ Sqlite3DataSrc::findClosest(const Name& name, unsigned int* position) const {
void
Sqlite3DataSrc::findClosestEnclosure(DataSrcMatch& match) const {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_ENCLOSURE).
+ arg(match.getName());
if (match.getClass() != getClass() && match.getClass() != RRClass::ANY()) {
+ LOG_ERROR(logger, DATASRC_SQLITE_ENCLOSURE_BAD_CLASS).arg(getClass()).
+ arg(match.getClass());
return;
}
unsigned int position;
if (findClosest(match.getName(), &position) == -1) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_ENCLOSURE_NOTFOUND);
return;
}
@@ -362,9 +370,11 @@ Sqlite3DataSrc::findPreviousName(const Name& qname,
Name& target,
const Name* zonename) const
{
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_PREVIOUS).arg(qname);
const int zone_id = (zonename == NULL) ?
findClosest(qname, NULL) : findClosest(*zonename, NULL);
if (zone_id < 0) {
+ LOG_ERROR(logger, DATASRC_SQLITE_PREVIOUS_NO_ZONE).arg(qname.toText());
return (ERROR);
}
@@ -402,8 +412,11 @@ Sqlite3DataSrc::findCoveringNSEC3(const Name& zonename,
string& hashstr,
RRsetList& target) const
{
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FIND_NSEC3).
+ arg(zonename).arg(hashstr);
const int zone_id = findClosest(zonename, NULL);
if (zone_id < 0) {
+ LOG_ERROR(logger, DATASRC_SQLITE_FIND_NSEC3_NO_ZONE).arg(zonename);
return (ERROR);
}
@@ -484,7 +497,11 @@ Sqlite3DataSrc::findRRset(const Name& qname,
uint32_t& flags,
const Name* zonename) const
{
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FIND).arg(qname).
+ arg(qtype);
if (qclass != getClass() && qclass != RRClass::ANY()) {
+ LOG_ERROR(logger, DATASRC_SQLITE_FIND_BAD_CLASS).arg(getClass()).
+ arg(qclass);
return (ERROR);
}
findRecords(qname, qtype, target, zonename, NORMAL, flags);
@@ -499,7 +516,11 @@ Sqlite3DataSrc::findExactRRset(const Name& qname,
uint32_t& flags,
const Name* zonename) const
{
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FINDEXACT).arg(qname).
+ arg(qtype);
if (qclass != getClass() && qclass != RRClass::ANY()) {
+ LOG_ERROR(logger, DATASRC_SQLITE_FINDEXACT_BAD_CLASS).arg(getClass()).
+ arg(qclass);
return (ERROR);
}
findRecords(qname, qtype, target, zonename, NORMAL, flags);
@@ -523,7 +544,10 @@ Sqlite3DataSrc::findAddrs(const Name& qname,
uint32_t& flags,
const Name* zonename) const
{
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FINDADDRS).arg(qname);
if (qclass != getClass() && qclass != RRClass::ANY()) {
+ LOG_ERROR(logger, DATASRC_SQLITE_FINDADDRS_BAD_CLASS).arg(getClass()).
+ arg(qclass);
return (ERROR);
}
findRecords(qname, RRType::ANY(), target, zonename, ADDRESS, flags);
@@ -537,8 +561,11 @@ Sqlite3DataSrc::findReferral(const Name& qname,
uint32_t& flags,
const Name* zonename) const
{
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FINDREF).arg(qname);
if (qclass != getClass() && qclass != RRClass::ANY()) {
- return (ERROR);
+ LOG_ERROR(logger, DATASRC_SQLITE_FINDREF_BAD_CLASS).arg(getClass()).
+ arg(qclass);
+ return (ERROR);
}
findRecords(qname, RRType::ANY(), target, zonename, DELEGATION, flags);
return (SUCCESS);
@@ -546,9 +573,12 @@ Sqlite3DataSrc::findReferral(const Name& qname,
Sqlite3DataSrc::Sqlite3DataSrc() :
dbparameters(new Sqlite3Parameters)
-{}
+{
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CREATE);
+}
Sqlite3DataSrc::~Sqlite3DataSrc() {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_DESTROY);
if (dbparameters->db_ != NULL) {
close();
}
@@ -635,6 +665,7 @@ checkAndSetupSchema(Sqlite3Initializer* initializer) {
initializer->params_.version_ = sqlite3_column_int(prepared, 0);
sqlite3_finalize(prepared);
} else {
+ logger.info(DATASRC_SQLITE_SETUP);
if (prepared != NULL) {
sqlite3_finalize(prepared);
}
@@ -664,6 +695,7 @@ checkAndSetupSchema(Sqlite3Initializer* initializer) {
//
void
Sqlite3DataSrc::open(const string& name) {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_OPEN).arg(name);
if (dbparameters->db_ != NULL) {
isc_throw(DataSourceError, "Duplicate SQLite open with " << name);
}
@@ -683,6 +715,7 @@ Sqlite3DataSrc::open(const string& name) {
//
DataSrc::Result
Sqlite3DataSrc::close(void) {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CLOSE);
if (dbparameters->db_ == NULL) {
isc_throw(DataSourceError,
"SQLite data source is being closed before open");
diff --git a/src/lib/datasrc/static_datasrc.cc b/src/lib/datasrc/static_datasrc.cc
index 025078a..dee14b9 100644
--- a/src/lib/datasrc/static_datasrc.cc
+++ b/src/lib/datasrc/static_datasrc.cc
@@ -26,6 +26,7 @@
#include <datasrc/data_source.h>
#include <datasrc/static_datasrc.h>
+#include <datasrc/logger.h>
using namespace std;
using namespace isc::dns;
@@ -112,6 +113,7 @@ StaticDataSrcImpl::StaticDataSrcImpl() :
}
StaticDataSrc::StaticDataSrc() {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_STATIC_CREATE);
setClass(RRClass::CH());
impl_ = new StaticDataSrcImpl;
}
@@ -155,8 +157,11 @@ StaticDataSrc::findRRset(const Name& qname,
RRsetList& target, uint32_t& flags,
const Name* const zonename) const
{
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_STATIC_FIND).arg(qname).
+ arg(qtype);
flags = 0;
if (qclass != getClass() && qclass != RRClass::ANY()) {
+ LOG_ERROR(logger, DATASRC_STATIC_BAD_CLASS);
return (ERROR);
}
diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am
index f09b4b7..ad4374a 100644
--- a/src/lib/datasrc/tests/Makefile.am
+++ b/src/lib/datasrc/tests/Makefile.am
@@ -27,15 +27,17 @@ run_unittests_SOURCES += test_datasrc.h test_datasrc.cc
run_unittests_SOURCES += rbtree_unittest.cc
run_unittests_SOURCES += zonetable_unittest.cc
run_unittests_SOURCES += memory_datasrc_unittest.cc
+run_unittests_SOURCES += logger_unittest.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += $(SQLITE_LIBS)
-run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libtestutils.la
run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/libdatasrc.la
run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libtestutils.la
endif
noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/datasrc/tests/datasrc_unittest.cc b/src/lib/datasrc/tests/datasrc_unittest.cc
index 01de77a..cd1a40c 100644
--- a/src/lib/datasrc/tests/datasrc_unittest.cc
+++ b/src/lib/datasrc/tests/datasrc_unittest.cc
@@ -1092,6 +1092,22 @@ TEST_F(DataSrcTest, DISABLED_synthesizedCnameTooLong) {
RRClass::IN(), RRType::A());
}
+TEST_F(DataSrcTest, cacheDataInNonexistentZone) {
+ // This test emulates the situation where an RRset in some zone of some
+ // data source is cached and then the zone is removed from the data source.
+ // When there is such a substantial inconsistency between the cache and
+ // the real data source, we should honor the latter. More important,
+ // the inconsistency shouldn't cause any disruption such as a crash.
+
+ const Name qname("nosuchzone.example");
+ RRsetPtr rrset(new RRset(qname, RRClass::IN(), RRType::A(), RRTTL(0)));
+ cache.addPositive(rrset, DataSrc::REFERRAL);
+
+ createAndProcessQuery(qname, RRClass::IN(), RRType::A(), false);
+ headerCheck(msg, qid, Rcode::REFUSED(), opcodeval, QR_FLAG | RD_FLAG,
+ 1, 0, 0, 0);
+}
+
// Tests of the DataSrcMatch class start here
class DataSrcMatchTest : public ::testing::Test {
protected:
diff --git a/src/lib/datasrc/tests/logger_unittest.cc b/src/lib/datasrc/tests/logger_unittest.cc
new file mode 100644
index 0000000..df5a41c
--- /dev/null
+++ b/src/lib/datasrc/tests/logger_unittest.cc
@@ -0,0 +1,31 @@
+// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+
+#include <datasrc/logger.h>
+
+using namespace isc::datasrc;
+
+namespace {
+
+TEST(CacheLogger, name) {
+ // This does not check the name only, but the fact the logger is created
+ // The dot is because of empty root logger
+ std::string name(logger.getName());
+ EXPECT_EQ(name.size() - 8, name.rfind(".datasrc")) <<
+ "Wrong logger name: " << name;
+}
+
+}
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 5a7151e..887ac09 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -17,48 +17,52 @@ EXTRA_DIST += rrtype-placeholder.h
# NOTE: when an rdata file is added, please also add to this list:
EXTRA_DIST += rdata/any_255/tsig_250.cc
EXTRA_DIST += rdata/any_255/tsig_250.h
-EXTRA_DIST += rdata/in_1/aaaa_28.cc
-EXTRA_DIST += rdata/in_1/aaaa_28.h
-EXTRA_DIST += rdata/in_1/a_1.cc
-EXTRA_DIST += rdata/in_1/a_1.h
EXTRA_DIST += rdata/ch_3/a_1.cc
EXTRA_DIST += rdata/ch_3/a_1.h
-EXTRA_DIST += rdata/generic/mx_15.h
-EXTRA_DIST += rdata/generic/rrsig_46.cc
+EXTRA_DIST += rdata/generic/cname_5.cc
+EXTRA_DIST += rdata/generic/cname_5.h
+EXTRA_DIST += rdata/generic/detail/nsec_bitmap.cc
+EXTRA_DIST += rdata/generic/detail/nsec_bitmap.h
EXTRA_DIST += rdata/generic/dname_39.cc
-EXTRA_DIST += rdata/generic/rrsig_46.h
EXTRA_DIST += rdata/generic/dname_39.h
-EXTRA_DIST += rdata/generic/ns_2.cc
-EXTRA_DIST += rdata/generic/nsec_47.cc
-EXTRA_DIST += rdata/generic/ns_2.h
-EXTRA_DIST += rdata/generic/nsec_47.h
-EXTRA_DIST += rdata/generic/opt_41.cc
-EXTRA_DIST += rdata/generic/soa_6.cc
-EXTRA_DIST += rdata/generic/cname_5.cc
EXTRA_DIST += rdata/generic/dnskey_48.cc
-EXTRA_DIST += rdata/generic/opt_41.h
-EXTRA_DIST += rdata/generic/soa_6.h
-EXTRA_DIST += rdata/generic/cname_5.h
EXTRA_DIST += rdata/generic/dnskey_48.h
EXTRA_DIST += rdata/generic/ds_43.cc
EXTRA_DIST += rdata/generic/ds_43.h
-EXTRA_DIST += rdata/generic/txt_16.cc
-EXTRA_DIST += rdata/generic/txt_16.h
EXTRA_DIST += rdata/generic/mx_15.cc
-EXTRA_DIST += rdata/generic/nsec3param_51.h
-EXTRA_DIST += rdata/generic/nsec3param_51.cc
+EXTRA_DIST += rdata/generic/mx_15.h
+EXTRA_DIST += rdata/generic/ns_2.cc
+EXTRA_DIST += rdata/generic/ns_2.h
EXTRA_DIST += rdata/generic/nsec3_50.cc
EXTRA_DIST += rdata/generic/nsec3_50.h
+EXTRA_DIST += rdata/generic/nsec3param_51.cc
+EXTRA_DIST += rdata/generic/nsec3param_51.h
+EXTRA_DIST += rdata/generic/nsec_47.cc
+EXTRA_DIST += rdata/generic/nsec_47.h
+EXTRA_DIST += rdata/generic/opt_41.cc
+EXTRA_DIST += rdata/generic/opt_41.h
EXTRA_DIST += rdata/generic/ptr_12.cc
EXTRA_DIST += rdata/generic/ptr_12.h
+EXTRA_DIST += rdata/generic/rp_17.cc
+EXTRA_DIST += rdata/generic/rp_17.h
+EXTRA_DIST += rdata/generic/rrsig_46.cc
+EXTRA_DIST += rdata/generic/rrsig_46.h
+EXTRA_DIST += rdata/generic/soa_6.cc
+EXTRA_DIST += rdata/generic/soa_6.h
+EXTRA_DIST += rdata/generic/txt_16.cc
+EXTRA_DIST += rdata/generic/txt_16.h
EXTRA_DIST += rdata/hs_4/a_1.cc
EXTRA_DIST += rdata/hs_4/a_1.h
+EXTRA_DIST += rdata/in_1/a_1.cc
+EXTRA_DIST += rdata/in_1/a_1.h
+EXTRA_DIST += rdata/in_1/aaaa_28.cc
+EXTRA_DIST += rdata/in_1/aaaa_28.h
#EXTRA_DIST += rdata/template.cc
#EXTRA_DIST += rdata/template.h
# auto-generate by gen-rdatacode.py:
BUILT_SOURCES = rrclass.h rrtype.h rrparamregistry.cc
-#TODO: check this###BUILT_SOURCES = rdataclass.h rdataclass.cc
+BUILT_SOURCES += rdataclass.h rdataclass.cc
lib_LTLIBRARIES = libdns++.la
@@ -80,15 +84,22 @@ libdns___la_SOURCES += rrsetlist.h rrsetlist.cc
libdns___la_SOURCES += rrttl.h rrttl.cc
libdns___la_SOURCES += rrtype.cc
libdns___la_SOURCES += question.h question.cc
+libdns___la_SOURCES += tsig.h tsig.cc
+libdns___la_SOURCES += tsigerror.h tsigerror.cc
libdns___la_SOURCES += tsigkey.h tsigkey.cc
+libdns___la_SOURCES += tsigrecord.h tsigrecord.cc
libdns___la_SOURCES += rdata/generic/detail/nsec_bitmap.h
libdns___la_SOURCES += rdata/generic/detail/nsec_bitmap.cc
libdns___la_CPPFLAGS = $(AM_CPPFLAGS)
-libdns___la_LIBADD = $(top_builddir)/src/lib/util/libutil.la
+# Most applications of libdns++ will only implicitly rely on libcryptolink,
+# so we add the dependency here so that the applications don't have to link
+# libcryptolink explicitly.
+libdns___la_LIBADD = $(top_builddir)/src/lib/cryptolink/libcryptolink.la
+libdns___la_LIBADD += $(top_builddir)/src/lib/util/libutil.la
-nodist_libdns___la_SOURCES = rdataclass.cc rrclass.h rrtype.h
-nodist_libdns___la_SOURCES += rrparamregistry.cc
+nodist_libdns___include_HEADERS = rdataclass.h rrclass.h rrtype.h
+nodist_libdns___la_SOURCES = rdataclass.cc rrparamregistry.cc
rrclass.h: rrclass-placeholder.h
rrtype.h: rrtype-placeholder.h
@@ -106,13 +117,10 @@ libdns___include_HEADERS = \
question.h \
rcode.h \
rdata.h \
- rdataclass.h \
- rrclass.h \
rrparamregistry.h \
rrset.h \
rrsetlist.h \
rrttl.h \
- rrtype.h \
tsigkey.h
# Purposely not installing these headers:
# util/*.h: used only internally, and not actually DNS specific
diff --git a/src/lib/dns/edns.cc b/src/lib/dns/edns.cc
index 5405dab..447b479 100644
--- a/src/lib/dns/edns.cc
+++ b/src/lib/dns/edns.cc
@@ -110,19 +110,25 @@ EDNS::toText() const {
return (ret);
}
+namespace {
+/// Helper function to define unified implementation for the public versions
+/// of toWire().
template <typename Output>
int
-EDNS::toWire(Output& output, const uint8_t extended_rcode) const {
+toWireCommon(Output& output, const uint8_t version,
+ const uint16_t udp_size, const bool dnssec_aware,
+ const uint8_t extended_rcode)
+{
// Render EDNS OPT RR
uint32_t extrcode_flags = extended_rcode << EXTRCODE_SHIFT;
- extrcode_flags |= (version_ << VERSION_SHIFT) & VERSION_MASK;
- if (dnssec_aware_) {
+ extrcode_flags |= (version << VERSION_SHIFT) & VERSION_MASK;
+ if (dnssec_aware) {
extrcode_flags |= EXTFLAG_DO;
}
// Construct an RRset corresponding to the EDNS.
// We don't support any options for now, so the OPT RR can be empty.
- RRsetPtr edns_rrset(new RRset(Name::ROOT_NAME(), RRClass(udp_size_),
+ RRsetPtr edns_rrset(new RRset(Name::ROOT_NAME(), RRClass(udp_size),
RRType::OPT(), RRTTL(extrcode_flags)));
edns_rrset->addRdata(ConstRdataPtr(new generic::OPT()));
@@ -130,9 +136,12 @@ EDNS::toWire(Output& output, const uint8_t extended_rcode) const {
return (1);
}
+}
unsigned int
-EDNS::toWire(MessageRenderer& renderer, const uint8_t extended_rcode) const {
+EDNS::toWire(AbstractMessageRenderer& renderer,
+ const uint8_t extended_rcode) const
+{
// If adding the OPT RR would exceed the size limit, don't do it.
// 11 = len(".") + type(2byte) + class(2byte) + TTL(4byte) + RDLEN(2byte)
// (RDATA is empty in this simple implementation)
@@ -140,12 +149,16 @@ EDNS::toWire(MessageRenderer& renderer, const uint8_t extended_rcode) const {
return (0);
}
- return (toWire<MessageRenderer>(renderer, extended_rcode));
+ return (toWireCommon(renderer, version_, udp_size_, dnssec_aware_,
+ extended_rcode));
}
unsigned int
-EDNS::toWire(isc::util::OutputBuffer& buffer, const uint8_t extended_rcode) const {
- return (toWire<isc::util::OutputBuffer>(buffer, extended_rcode));
+EDNS::toWire(isc::util::OutputBuffer& buffer,
+ const uint8_t extended_rcode) const
+{
+ return (toWireCommon(buffer, version_, udp_size_, dnssec_aware_,
+ extended_rcode));
}
EDNS*
diff --git a/src/lib/dns/edns.h b/src/lib/dns/edns.h
index b794183..a7bc4c4 100644
--- a/src/lib/dns/edns.h
+++ b/src/lib/dns/edns.h
@@ -32,7 +32,7 @@ namespace dns {
class EDNS;
class Name;
-class MessageRenderer;
+class AbstractMessageRenderer;
class RRClass;
class RRTTL;
class RRType;
@@ -314,7 +314,7 @@ public:
/// \param extended_rcode Upper 8 bits of extended RCODE to be rendered as
/// part of the EDNS OPT RR.
/// \return 1 if the OPT RR fits in the message size limit; otherwise 0.
- unsigned int toWire(MessageRenderer& renderer,
+ unsigned int toWire(AbstractMessageRenderer& renderer,
const uint8_t extended_rcode) const;
/// \brief Render the \c EDNS in the wire format.
@@ -354,12 +354,6 @@ public:
// something like this.
//void addOption();
-private:
- /// Helper method to define unified implementation for the public versions
- /// of toWire().
- template <typename Output>
- int toWire(Output& output, const uint8_t extended_rcode) const;
-
public:
/// \brief The highest EDNS version this implementation supports.
static const uint8_t SUPPORTED_VERSION = 0;
@@ -386,7 +380,7 @@ private:
///
/// The intended usage of this function is to parse an OPT RR of an incoming
/// DNS message, while updating the RCODE of the message.
-/// One common usage patter is as follows:
+/// One common usage pattern is as follows:
///
/// \code Message msg;
/// ...
diff --git a/src/lib/dns/message.cc b/src/lib/dns/message.cc
index d1025d1..bf7ccd5 100644
--- a/src/lib/dns/message.cc
+++ b/src/lib/dns/message.cc
@@ -15,6 +15,7 @@
#include <stdint.h>
#include <algorithm>
+#include <cassert>
#include <string>
#include <sstream>
#include <vector>
@@ -40,6 +41,7 @@
#include <dns/rrtype.h>
#include <dns/rrttl.h>
#include <dns/rrset.h>
+#include <dns/tsig.h>
using namespace std;
using namespace boost;
@@ -81,7 +83,7 @@ const unsigned int HEADERFLAG_MASK = 0x87b0;
const uint16_t MESSAGE_REPLYPRESERVE = (Message::HEADERFLAG_RD |
Message::HEADERFLAG_CD);
-const char *sectiontext[] = {
+const char* const sectiontext[] = {
"QUESTION",
"ANSWER",
"AUTHORITY",
@@ -114,8 +116,8 @@ public:
vector<QuestionPtr> questions_;
vector<RRsetPtr> rrsets_[NUM_SECTIONS];
ConstEDNSPtr edns_;
+ ConstTSIGRecordPtr tsig_rr_;
- // tsig/sig0: TODO
// RRsetsSorter* sorter_; : TODO
void init();
@@ -123,6 +125,17 @@ public:
void setRcode(const Rcode& rcode);
int parseQuestion(InputBuffer& buffer);
int parseSection(const Message::Section section, InputBuffer& buffer);
+ void addRR(Message::Section section, const Name& name,
+ const RRClass& rrclass, const RRType& rrtype,
+ const RRTTL& ttl, ConstRdataPtr rdata);
+ void addEDNS(Message::Section section, const Name& name,
+ const RRClass& rrclass, const RRType& rrtype,
+ const RRTTL& ttl, const Rdata& rdata);
+ void addTSIG(Message::Section section, unsigned int count,
+ const InputBuffer& buffer, size_t start_position,
+ const Name& name, const RRClass& rrclass,
+ const RRTTL& ttl, const Rdata& rdata);
+ void toWire(AbstractMessageRenderer& renderer, TSIGContext* tsig_ctx);
};
MessageImpl::MessageImpl(Message::Mode mode) :
@@ -140,6 +153,7 @@ MessageImpl::init() {
rcode_ = NULL;
opcode_ = NULL;
edns_ = EDNSPtr();
+ tsig_rr_ = ConstTSIGRecordPtr();
for (int i = 0; i < NUM_SECTIONS; ++i) {
counts_[i] = 0;
@@ -164,6 +178,154 @@ MessageImpl::setRcode(const Rcode& rcode) {
rcode_ = &rcode_placeholder_;
}
+namespace {
+// This helper class is used by MessageImpl::toWire() to render a set of
+// RRsets of a specific section of message to a given MessageRenderer.
+//
+// A RenderSection object is expected to be used with a QuestionIterator or
+// SectionIterator. Its operator() is called for each RRset as the iterator
+// iterates over the corresponding section, and it renders the RRset to
+// the given MessageRenderer, while counting the number of RRs (note: not
+// RRsets) successfully rendered. If the MessageRenderer reports the need
+// for truncation (via its isTruncated() method), the RenderSection object
+// stops rendering further RRsets. In addition, unless partial_ok (given on
+// construction) is true, it removes any RRs that are partially rendered
+// from the MessageRenderer.
+//
+// On the completion of rendering the entire section, the owner of the
+// RenderSection object can get the number of rendered RRs via the
+// getTotalCount() method.
+template <typename T>
+struct RenderSection {
+ RenderSection(AbstractMessageRenderer& renderer, const bool partial_ok) :
+ counter_(0), renderer_(renderer), partial_ok_(partial_ok),
+ truncated_(false)
+ {}
+ void operator()(const T& entry) {
+ // If it's already truncated, ignore the rest of the section.
+ if (truncated_) {
+ return;
+ }
+ const size_t pos0 = renderer_.getLength();
+ counter_ += entry->toWire(renderer_);
+ if (renderer_.isTruncated()) {
+ truncated_ = true;
+ if (!partial_ok_) {
+ // roll back to the end of the previous RRset.
+ renderer_.trim(renderer_.getLength() - pos0);
+ }
+ }
+ }
+ unsigned int getTotalCount() { return (counter_); }
+ unsigned int counter_;
+ AbstractMessageRenderer& renderer_;
+ const bool partial_ok_;
+ bool truncated_;
+};
+}
+
+void
+MessageImpl::toWire(AbstractMessageRenderer& renderer, TSIGContext* tsig_ctx) {
+ if (mode_ != Message::RENDER) {
+ isc_throw(InvalidMessageOperation,
+ "Message rendering attempted in non render mode");
+ }
+ if (rcode_ == NULL) {
+ isc_throw(InvalidMessageOperation,
+ "Message rendering attempted without Rcode set");
+ }
+ if (opcode_ == NULL) {
+ isc_throw(InvalidMessageOperation,
+ "Message rendering attempted without Opcode set");
+ }
+
+ // reserve room for the header
+ renderer.skip(HEADERLEN);
+
+ uint16_t qdcount =
+ for_each(questions_.begin(), questions_.end(),
+ RenderSection<QuestionPtr>(renderer, false)).getTotalCount();
+
+ // TODO: sort RRsets in each section based on configuration policy.
+ uint16_t ancount = 0;
+ if (!renderer.isTruncated()) {
+ ancount =
+ for_each(rrsets_[Message::SECTION_ANSWER].begin(),
+ rrsets_[Message::SECTION_ANSWER].end(),
+ RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
+ }
+ uint16_t nscount = 0;
+ if (!renderer.isTruncated()) {
+ nscount =
+ for_each(rrsets_[Message::SECTION_AUTHORITY].begin(),
+ rrsets_[Message::SECTION_AUTHORITY].end(),
+ RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
+ }
+ uint16_t arcount = 0;
+ if (renderer.isTruncated()) {
+ flags_ |= Message::HEADERFLAG_TC;
+ } else {
+ arcount =
+ for_each(rrsets_[Message::SECTION_ADDITIONAL].begin(),
+ rrsets_[Message::SECTION_ADDITIONAL].end(),
+ RenderSection<RRsetPtr>(renderer, false)).getTotalCount();
+ }
+
+ // Add EDNS OPT RR if necessary. Basically, we add it only when EDNS
+ // has been explicitly set. However, if the RCODE would require it and
+ // no EDNS has been set we generate a temporary local EDNS and use it.
+ if (!renderer.isTruncated()) {
+ ConstEDNSPtr local_edns = edns_;
+ if (!local_edns && rcode_->getExtendedCode() != 0) {
+ local_edns = ConstEDNSPtr(new EDNS());
+ }
+ if (local_edns) {
+ arcount += local_edns->toWire(renderer, rcode_->getExtendedCode());
+ }
+ }
+
+ // Adjust the counter buffer.
+ // XXX: these may not be equal to the number of corresponding entries
+ // in rrsets_[] or questions_ if truncation occurred or an EDNS OPT RR
+ // was inserted. This is not good, and we should revisit the entire
+ // design.
+ counts_[Message::SECTION_QUESTION] = qdcount;
+ counts_[Message::SECTION_ANSWER] = ancount;
+ counts_[Message::SECTION_AUTHORITY] = nscount;
+ counts_[Message::SECTION_ADDITIONAL] = arcount;
+
+ // fill in the header
+ size_t header_pos = 0;
+ renderer.writeUint16At(qid_, header_pos);
+ header_pos += sizeof(uint16_t);
+
+ uint16_t codes_and_flags =
+ (opcode_->getCode() << OPCODE_SHIFT) & OPCODE_MASK;
+ codes_and_flags |= (rcode_->getCode() & RCODE_MASK);
+ codes_and_flags |= (flags_ & HEADERFLAG_MASK);
+ renderer.writeUint16At(codes_and_flags, header_pos);
+ header_pos += sizeof(uint16_t);
+ // TODO: should avoid repeated pattern
+ renderer.writeUint16At(qdcount, header_pos);
+ header_pos += sizeof(uint16_t);
+ renderer.writeUint16At(ancount, header_pos);
+ header_pos += sizeof(uint16_t);
+ renderer.writeUint16At(nscount, header_pos);
+ header_pos += sizeof(uint16_t);
+ renderer.writeUint16At(arcount, header_pos);
+
+ // Add TSIG, if necessary, at the end of the message.
+ // TODO: truncate case consideration
+ if (tsig_ctx != NULL) {
+ tsig_ctx->sign(qid_, renderer.getData(),
+ renderer.getLength())->toWire(renderer);
+
+ // update the ARCOUNT for the TSIG RR. Note that for a sane DNS
+ // message arcount should never overflow to 0.
+ renderer.writeUint16At(++arcount, header_pos);
+ }
+}
+
Message::Message(Mode mode) :
impl_(new MessageImpl(mode))
{}
@@ -262,6 +424,16 @@ Message::setEDNS(ConstEDNSPtr edns) {
impl_->edns_ = edns;
}
+const TSIGRecord*
+Message::getTSIGRecord() const {
+ if (impl_->mode_ != Message::PARSE) {
+ isc_throw(InvalidMessageOperation,
+ "getTSIGRecord performed in non-parse mode");
+ }
+
+ return (impl_->tsig_rr_.get());
+}
+
unsigned int
Message::getRRCount(const Section section) const {
if (section >= MessageImpl::NUM_SECTIONS) {
@@ -363,129 +535,14 @@ Message::addQuestion(const Question& question) {
addQuestion(QuestionPtr(new Question(question)));
}
-namespace {
-template <typename T>
-struct RenderSection {
- RenderSection(MessageRenderer& renderer, const bool partial_ok) :
- counter_(0), renderer_(renderer), partial_ok_(partial_ok),
- truncated_(false)
- {}
- void operator()(const T& entry) {
- // If it's already truncated, ignore the rest of the section.
- if (truncated_) {
- return;
- }
- const size_t pos0 = renderer_.getLength();
- counter_ += entry->toWire(renderer_);
- if (renderer_.isTruncated()) {
- truncated_ = true;
- if (!partial_ok_) {
- // roll back to the end of the previous RRset.
- renderer_.trim(renderer_.getLength() - pos0);
- }
- }
- }
- unsigned int getTotalCount() { return (counter_); }
- unsigned int counter_;
- MessageRenderer& renderer_;
- const bool partial_ok_;
- bool truncated_;
-};
+void
+Message::toWire(AbstractMessageRenderer& renderer) {
+ impl_->toWire(renderer, NULL);
}
void
-Message::toWire(MessageRenderer& renderer) {
- if (impl_->mode_ != Message::RENDER) {
- isc_throw(InvalidMessageOperation,
- "Message rendering attempted in non render mode");
- }
- if (impl_->rcode_ == NULL) {
- isc_throw(InvalidMessageOperation,
- "Message rendering attempted without Rcode set");
- }
- if (impl_->opcode_ == NULL) {
- isc_throw(InvalidMessageOperation,
- "Message rendering attempted without Opcode set");
- }
-
- // reserve room for the header
- renderer.skip(HEADERLEN);
-
- uint16_t qdcount =
- for_each(impl_->questions_.begin(), impl_->questions_.end(),
- RenderSection<QuestionPtr>(renderer, false)).getTotalCount();
-
- // TBD: sort RRsets in each section based on configuration policy.
- uint16_t ancount = 0;
- if (!renderer.isTruncated()) {
- ancount =
- for_each(impl_->rrsets_[SECTION_ANSWER].begin(),
- impl_->rrsets_[SECTION_ANSWER].end(),
- RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
- }
- uint16_t nscount = 0;
- if (!renderer.isTruncated()) {
- nscount =
- for_each(impl_->rrsets_[SECTION_AUTHORITY].begin(),
- impl_->rrsets_[SECTION_AUTHORITY].end(),
- RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
- }
- uint16_t arcount = 0;
- if (renderer.isTruncated()) {
- setHeaderFlag(HEADERFLAG_TC, true);
- } else {
- arcount =
- for_each(impl_->rrsets_[SECTION_ADDITIONAL].begin(),
- impl_->rrsets_[SECTION_ADDITIONAL].end(),
- RenderSection<RRsetPtr>(renderer, false)).getTotalCount();
- }
-
- // Add EDNS OPT RR if necessary. Basically, we add it only when EDNS
- // has been explicitly set. However, if the RCODE would require it and
- // no EDNS has been set we generate a temporary local EDNS and use it.
- if (!renderer.isTruncated()) {
- ConstEDNSPtr local_edns = impl_->edns_;
- if (!local_edns && impl_->rcode_->getExtendedCode() != 0) {
- local_edns = ConstEDNSPtr(new EDNS());
- }
- if (local_edns) {
- arcount += local_edns->toWire(renderer,
- impl_->rcode_->getExtendedCode());
- }
- }
-
- // Adjust the counter buffer.
- // XXX: these may not be equal to the number of corresponding entries
- // in rrsets_[] or questions_ if truncation occurred or an EDNS OPT RR
- // was inserted. This is not good, and we should revisit the entire
- // design.
- impl_->counts_[SECTION_QUESTION] = qdcount;
- impl_->counts_[SECTION_ANSWER] = ancount;
- impl_->counts_[SECTION_AUTHORITY] = nscount;
- impl_->counts_[SECTION_ADDITIONAL] = arcount;
-
- // TBD: TSIG, SIG(0) etc.
-
- // fill in the header
- size_t header_pos = 0;
- renderer.writeUint16At(impl_->qid_, header_pos);
- header_pos += sizeof(uint16_t);
-
- uint16_t codes_and_flags =
- (impl_->opcode_->getCode() << OPCODE_SHIFT) & OPCODE_MASK;
- codes_and_flags |= (impl_->rcode_->getCode() & RCODE_MASK);
- codes_and_flags |= (impl_->flags_ & HEADERFLAG_MASK);
- renderer.writeUint16At(codes_and_flags, header_pos);
- header_pos += sizeof(uint16_t);
- // XXX: should avoid repeated pattern (TODO)
- renderer.writeUint16At(qdcount, header_pos);
- header_pos += sizeof(uint16_t);
- renderer.writeUint16At(ancount, header_pos);
- header_pos += sizeof(uint16_t);
- renderer.writeUint16At(nscount, header_pos);
- header_pos += sizeof(uint16_t);
- renderer.writeUint16At(arcount, header_pos);
- header_pos += sizeof(uint16_t);
+Message::toWire(AbstractMessageRenderer& renderer, TSIGContext& tsig_ctx) {
+ impl_->toWire(renderer, &tsig_ctx);
}
void
@@ -613,6 +670,9 @@ MessageImpl::parseSection(const Message::Section section,
unsigned int added = 0;
for (unsigned int count = 0; count < counts_[section]; ++count) {
+ // We need to remember the start position for TSIG processing
+ const size_t start_position = buffer.getPosition();
+
const Name name(buffer);
// buffer must store at least RR TYPE, RR CLASS, TTL, and RDLEN.
@@ -630,32 +690,12 @@ MessageImpl::parseSection(const Message::Section section,
ConstRdataPtr rdata = createRdata(rrtype, rrclass, buffer, rdlen);
if (rrtype == RRType::OPT()) {
- if (section != Message::SECTION_ADDITIONAL) {
- isc_throw(DNSMessageFORMERR,
- "EDNS OPT RR found in an invalid section");
- }
- if (edns_) {
- isc_throw(DNSMessageFORMERR, "multiple EDNS OPT RR found");
- }
-
- uint8_t extended_rcode;
- edns_ = ConstEDNSPtr(createEDNSFromRR(name, rrclass, rrtype, ttl,
- *rdata, extended_rcode));
- setRcode(Rcode(rcode_->getCode(), extended_rcode));
- continue;
+ addEDNS(section, name, rrclass, rrtype, ttl, *rdata);
+ } else if (rrtype == RRType::TSIG()) {
+ addTSIG(section, count, buffer, start_position, name, rrclass, ttl,
+ *rdata);
} else {
- vector<RRsetPtr>::iterator it =
- find_if(rrsets_[section].begin(), rrsets_[section].end(),
- MatchRR(name, rrtype, rrclass));
- if (it != rrsets_[section].end()) {
- (*it)->setTTL(min((*it)->getTTL(), ttl));
- (*it)->addRdata(rdata);
- } else {
- RRsetPtr rrset =
- RRsetPtr(new RRset(name, rrclass, rrtype, ttl));
- rrset->addRdata(rdata);
- rrsets_[section].push_back(rrset);
- }
+ addRR(section, name, rrclass, rrtype, ttl, rdata);
++added;
}
}
@@ -663,6 +703,65 @@ MessageImpl::parseSection(const Message::Section section,
return (added);
}
+void
+MessageImpl::addRR(Message::Section section, const Name& name,
+ const RRClass& rrclass, const RRType& rrtype,
+ const RRTTL& ttl, ConstRdataPtr rdata)
+{
+ vector<RRsetPtr>::iterator it =
+ find_if(rrsets_[section].begin(), rrsets_[section].end(),
+ MatchRR(name, rrtype, rrclass));
+ if (it != rrsets_[section].end()) {
+ (*it)->setTTL(min((*it)->getTTL(), ttl));
+ (*it)->addRdata(rdata);
+ } else {
+ RRsetPtr rrset(new RRset(name, rrclass, rrtype, ttl));
+ rrset->addRdata(rdata);
+ rrsets_[section].push_back(rrset);
+ }
+}
+
+void
+MessageImpl::addEDNS(Message::Section section, const Name& name,
+ const RRClass& rrclass, const RRType& rrtype,
+ const RRTTL& ttl, const Rdata& rdata)
+{
+ if (section != Message::SECTION_ADDITIONAL) {
+ isc_throw(DNSMessageFORMERR,
+ "EDNS OPT RR found in an invalid section");
+ }
+ if (edns_) {
+ isc_throw(DNSMessageFORMERR, "multiple EDNS OPT RR found");
+ }
+
+ uint8_t extended_rcode;
+ edns_ = ConstEDNSPtr(createEDNSFromRR(name, rrclass, rrtype, ttl, rdata,
+ extended_rcode));
+ setRcode(Rcode(rcode_->getCode(), extended_rcode));
+}
+
+void
+MessageImpl::addTSIG(Message::Section section, unsigned int count,
+ const InputBuffer& buffer, size_t start_position,
+ const Name& name, const RRClass& rrclass,
+ const RRTTL& ttl, const Rdata& rdata)
+{
+ if (section != Message::SECTION_ADDITIONAL) {
+ isc_throw(DNSMessageFORMERR,
+ "TSIG RR found in an invalid section");
+ }
+ if (count != counts_[section] - 1) {
+ isc_throw(DNSMessageFORMERR, "TSIG RR is not the last record");
+ }
+ if (tsig_rr_) {
+ isc_throw(DNSMessageFORMERR, "multiple TSIG RRs found");
+ }
+ tsig_rr_ = ConstTSIGRecordPtr(new TSIGRecord(name, rrclass,
+ ttl, rdata,
+ buffer.getPosition() -
+ start_position));
+}
+
namespace {
template <typename T>
struct SectionFormatter {
@@ -696,31 +795,31 @@ Message::toText() const {
// for simplicity we don't consider extended rcode (unlike BIND9)
s += ", status: " + impl_->rcode_->toText();
s += ", id: " + boost::lexical_cast<string>(impl_->qid_);
- s += "\n;; flags: ";
+ s += "\n;; flags:";
if (getHeaderFlag(HEADERFLAG_QR)) {
- s += "qr ";
+ s += " qr";
}
if (getHeaderFlag(HEADERFLAG_AA)) {
- s += "aa ";
+ s += " aa";
}
if (getHeaderFlag(HEADERFLAG_TC)) {
- s += "tc ";
+ s += " tc";
}
if (getHeaderFlag(HEADERFLAG_RD)) {
- s += "rd ";
+ s += " rd";
}
if (getHeaderFlag(HEADERFLAG_RA)) {
- s += "ra ";
+ s += " ra";
}
if (getHeaderFlag(HEADERFLAG_AD)) {
- s += "ad ";
+ s += " ad";
}
if (getHeaderFlag(HEADERFLAG_CD)) {
- s += "cd ";
+ s += " cd";
}
// for simplicity, don't consider the update case for now
- s += "; QUESTION: " +
+ s += "; QUERY: " + // note: not "QUESTION" to be compatible with BIND 9 dig
lexical_cast<string>(impl_->counts_[SECTION_QUESTION]);
s += ", ANSWER: " +
lexical_cast<string>(impl_->counts_[SECTION_ANSWER]);
@@ -731,6 +830,9 @@ Message::toText() const {
if (impl_->edns_ != NULL) {
++arcount;
}
+ if (impl_->tsig_rr_ != NULL) {
+ ++arcount;
+ }
s += ", ADDITIONAL: " + lexical_cast<string>(arcount) + "\n";
if (impl_->edns_ != NULL) {
@@ -767,6 +869,11 @@ Message::toText() const {
SectionFormatter<RRsetPtr>(SECTION_ADDITIONAL, s));
}
+ if (impl_->tsig_rr_ != NULL) {
+ s += "\n;; TSIG PSEUDOSECTION:\n";
+ s += impl_->tsig_rr_->toText();
+ }
+
return (s);
}
diff --git a/src/lib/dns/message.h b/src/lib/dns/message.h
index 5601299..fcc53e9 100644
--- a/src/lib/dns/message.h
+++ b/src/lib/dns/message.h
@@ -33,6 +33,8 @@ class InputBuffer;
}
namespace dns {
+class TSIGContext;
+class TSIGRecord;
///
/// \brief A standard DNS module exception that is thrown if a wire format
@@ -80,7 +82,7 @@ public:
typedef uint16_t qid_t;
-class MessageRenderer;
+class AbstractMessageRenderer;
class Message;
class MessageImpl;
class Opcode;
@@ -368,6 +370,25 @@ public:
/// \c Message.
void setEDNS(ConstEDNSPtr edns);
+ /// \brief Return, if any, the TSIG record contained in the received
+ /// message.
+ ///
+ /// Currently, this method is only intended to return a TSIG record
+ /// for an incoming message built via the \c fromWire() method in the
+ /// PARSE mode. A call to this method in the RENDER mode is invalid and
+ /// result in an exception. Also, calling this method is meaningless
+ /// unless \c fromWire() is performed.
+ ///
+ /// The returned pointer is valid only during the lifetime of the
+ /// \c Message object and until \c clear() is called. The \c Message
+ /// object retains the ownership of \c TSIGRecord; the caller must not
+ /// try to delete it.
+ ///
+ /// \exception InvalidMessageOperation Message is not in the PARSE mode.
+ ///
+ /// \return A pointer to the stored \c TSIGRecord or \c NULL.
+ const TSIGRecord* getTSIGRecord() const;
+
/// \brief Returns the number of RRs contained in the given section.
///
/// In the \c PARSE mode, the returned value may not be identical to
@@ -523,13 +544,31 @@ public:
/// class \c InvalidMessageOperation will be thrown.
std::string toText() const;
- /// \brief Render the message in wire formant into a \c MessageRenderer
+ /// \brief Render the message in wire formant into a message renderer
/// object.
///
/// This \c Message must be in the \c RENDER mode and both \c Opcode and
/// \c Rcode must have been set beforehand; otherwise, an exception of
/// class \c InvalidMessageOperation will be thrown.
- void toWire(MessageRenderer& renderer);
+ ///
+ /// \param renderer DNS message rendering context that encapsulates the
+ /// output buffer and name compression information.
+ void toWire(AbstractMessageRenderer& renderer);
+
+ /// \brief Render the message in wire formant into a message renderer
+ /// object with TSIG.
+ ///
+ /// This method is similar to the other version of \c toWire(), but
+ /// it will also add a TSIG RR with (in many cases) the TSIG MAC for
+ /// the message along with the given TSIG context (\c tsig_ctx).
+ /// The TSIG RR will be placed at the end of \c renderer.
+ /// \c tsig_ctx will be updated based on the fact it was used for signing
+ /// and with the latest MAC.
+ ///
+ /// \param renderer See the other version
+ /// \param tsig_ctx A TSIG context that is to be used for signing the
+ /// message
+ void toWire(AbstractMessageRenderer& renderer, TSIGContext& tsig_ctx);
/// \brief Parse the header section of the \c Message.
void parseHeader(isc::util::InputBuffer& buffer);
@@ -562,7 +601,18 @@ private:
/// that ongoing state information will not be lost if the object
/// that originated the asynchronous call falls out of scope.
typedef boost::shared_ptr<Message> MessagePtr;
+typedef boost::shared_ptr<const Message> ConstMessagePtr;
+/// Insert the \c Message as a string into stream.
+///
+/// This method convert \c message into a string and inserts it into the
+/// output stream \c os.
+///
+/// \param os A \c std::ostream object on which the insertion operation is
+/// performed.
+/// \param record A \c Message object output by the operation.
+/// \return A reference to the same \c std::ostream object referenced by
+/// parameter \c os after the insertion operation.
std::ostream& operator<<(std::ostream& os, const Message& message);
}
}
diff --git a/src/lib/dns/messagerenderer.cc b/src/lib/dns/messagerenderer.cc
index 6438fb0..767aca9 100644
--- a/src/lib/dns/messagerenderer.cc
+++ b/src/lib/dns/messagerenderer.cc
@@ -228,8 +228,9 @@ MessageRenderer::writeName(const Name& name, const bool compress) {
name.toWire(impl_->nbuffer_);
unsigned int i;
- std::set<NameCompressNode>::const_iterator notfound = impl_->nodeset_.end();
- std::set<NameCompressNode>::const_iterator n = notfound;
+ std::set<NameCompressNode, NameCompare>::const_iterator notfound =
+ impl_->nodeset_.end();
+ std::set<NameCompressNode, NameCompare>::const_iterator n = notfound;
// Find the longest ancestor name in the rendered set that matches the
// given name.
diff --git a/src/lib/dns/python/Makefile.am b/src/lib/dns/python/Makefile.am
index 9d171cd..1c9afc7 100644
--- a/src/lib/dns/python/Makefile.am
+++ b/src/lib/dns/python/Makefile.am
@@ -6,6 +6,9 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
pyexec_LTLIBRARIES = pydnspp.la
pydnspp_la_SOURCES = pydnspp.cc pydnspp_common.cc
+pydnspp_la_SOURCES += rcode_python.cc rcode_python.h
+pydnspp_la_SOURCES += tsigerror_python.cc tsigerror_python.h
+pydnspp_la_SOURCES += tsigerror_python_inc.cc
pydnspp_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
pydnspp_la_LDFLAGS = $(PYTHON_LDFLAGS)
@@ -25,6 +28,7 @@ EXTRA_DIST += rrttl_python.cc
EXTRA_DIST += rdata_python.cc
EXTRA_DIST += rrtype_python.cc
EXTRA_DIST += tsigkey_python.cc
+EXTRA_DIST += tsig_python.cc
# Python prefers .so, while some OSes (specifically MacOS) use a different
# suffix for dynamic objects. -module is necessary to work this around.
diff --git a/src/lib/dns/python/message_python.cc b/src/lib/dns/python/message_python.cc
index 058312e..381b7bc 100644
--- a/src/lib/dns/python/message_python.cc
+++ b/src/lib/dns/python/message_python.cc
@@ -17,15 +17,16 @@
using namespace isc::dns;
using namespace isc::util;
+namespace {
//
// Declaration of the custom exceptions
// Initialization and addition of these go in the initModulePart
// function at the end of this file
//
-static PyObject* po_MessageTooShort;
-static PyObject* po_InvalidMessageSection;
-static PyObject* po_InvalidMessageOperation;
-static PyObject* po_InvalidMessageUDPSize;
+PyObject* po_MessageTooShort;
+PyObject* po_InvalidMessageSection;
+PyObject* po_InvalidMessageOperation;
+PyObject* po_InvalidMessageUDPSize;
//
// Definition of the classes
@@ -36,10 +37,6 @@ static PyObject* po_InvalidMessageUDPSize;
// and a type description
//
-// Section
-//
-
-//
// Message
//
@@ -55,36 +52,36 @@ public:
//
// General creation and destruction
-static int Message_init(s_Message* self, PyObject* args);
-static void Message_destroy(s_Message* self);
-
-static PyObject* Message_getHeaderFlag(s_Message* self, PyObject* args);
-static PyObject* Message_setHeaderFlag(s_Message* self, PyObject* args);
-static PyObject* Message_getQid(s_Message* self);
-static PyObject* Message_setQid(s_Message* self, PyObject* args);
-static PyObject* Message_getRcode(s_Message* self);
-static PyObject* Message_setRcode(s_Message* self, PyObject* args);
-static PyObject* Message_getOpcode(s_Message* self);
-static PyObject* Message_setOpcode(s_Message* self, PyObject* args);
-static PyObject* Message_getEDNS(s_Message* self);
-static PyObject* Message_setEDNS(s_Message* self, PyObject* args);
-static PyObject* Message_getRRCount(s_Message* self, PyObject* args);
+int Message_init(s_Message* self, PyObject* args);
+void Message_destroy(s_Message* self);
+
+PyObject* Message_getHeaderFlag(s_Message* self, PyObject* args);
+PyObject* Message_setHeaderFlag(s_Message* self, PyObject* args);
+PyObject* Message_getQid(s_Message* self);
+PyObject* Message_setQid(s_Message* self, PyObject* args);
+PyObject* Message_getRcode(s_Message* self);
+PyObject* Message_setRcode(s_Message* self, PyObject* args);
+PyObject* Message_getOpcode(s_Message* self);
+PyObject* Message_setOpcode(s_Message* self, PyObject* args);
+PyObject* Message_getEDNS(s_Message* self);
+PyObject* Message_setEDNS(s_Message* self, PyObject* args);
+PyObject* Message_getRRCount(s_Message* self, PyObject* args);
// use direct iterators for these? (or simply lists for now?)
-static PyObject* Message_getQuestion(s_Message* self);
-static PyObject* Message_getSection(s_Message* self, PyObject* args);
+PyObject* Message_getQuestion(s_Message* self);
+PyObject* Message_getSection(s_Message* self, PyObject* args);
//static PyObject* Message_beginQuestion(s_Message* self, PyObject* args);
//static PyObject* Message_endQuestion(s_Message* self, PyObject* args);
//static PyObject* Message_beginSection(s_Message* self, PyObject* args);
//static PyObject* Message_endSection(s_Message* self, PyObject* args);
-static PyObject* Message_addQuestion(s_Message* self, PyObject* args);
-static PyObject* Message_addRRset(s_Message* self, PyObject* args);
-static PyObject* Message_clear(s_Message* self, PyObject* args);
-static PyObject* Message_makeResponse(s_Message* self);
-static PyObject* Message_toText(s_Message* self);
-static PyObject* Message_str(PyObject* self);
-static PyObject* Message_toWire(s_Message* self, PyObject* args);
-static PyObject* Message_fromWire(s_Message* self, PyObject* args);
+PyObject* Message_addQuestion(s_Message* self, PyObject* args);
+PyObject* Message_addRRset(s_Message* self, PyObject* args);
+PyObject* Message_clear(s_Message* self, PyObject* args);
+PyObject* Message_makeResponse(s_Message* self);
+PyObject* Message_toText(s_Message* self);
+PyObject* Message_str(PyObject* self);
+PyObject* Message_toWire(s_Message* self, PyObject* args);
+PyObject* Message_fromWire(s_Message* self, PyObject* args);
// This list contains the actual set of functions we have in
// python. Each entry has
@@ -92,7 +89,7 @@ static PyObject* Message_fromWire(s_Message* self, PyObject* args);
// 2. Our static function here
// 3. Argument type
// 4. Documentation
-static PyMethodDef Message_methods[] = {
+PyMethodDef Message_methods[] = {
{ "get_header_flag", reinterpret_cast<PyCFunction>(Message_getHeaderFlag),
METH_VARARGS,
"Return whether the specified header flag bit is set in the "
@@ -175,7 +172,7 @@ static PyMethodDef Message_methods[] = {
// This defines the complete type for reflection in python and
// parsing of PyObject* to s_Message
// Most of the functions are not actually implemented and NULL here.
-static PyTypeObject message_type = {
+PyTypeObject message_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"pydnspp.Message",
sizeof(s_Message), // tp_basicsize
@@ -225,7 +222,7 @@ static PyTypeObject message_type = {
0 // tp_version_tag
};
-static int
+int
Message_init(s_Message* self, PyObject* args) {
int i;
@@ -248,14 +245,14 @@ Message_init(s_Message* self, PyObject* args) {
return (-1);
}
-static void
+void
Message_destroy(s_Message* self) {
delete self->message;
self->message = NULL;
Py_TYPE(self)->tp_free(self);
}
-static PyObject*
+PyObject*
Message_getHeaderFlag(s_Message* self, PyObject* args) {
unsigned int messageflag;
if (!PyArg_ParseTuple(args, "I", &messageflag)) {
@@ -273,7 +270,7 @@ Message_getHeaderFlag(s_Message* self, PyObject* args) {
}
}
-static PyObject*
+PyObject*
Message_setHeaderFlag(s_Message* self, PyObject* args) {
long messageflag;
PyObject *on = Py_True;
@@ -304,12 +301,12 @@ Message_setHeaderFlag(s_Message* self, PyObject* args) {
}
}
-static PyObject*
+PyObject*
Message_getQid(s_Message* self) {
return (Py_BuildValue("I", self->message->getQid()));
}
-static PyObject*
+PyObject*
Message_setQid(s_Message* self, PyObject* args) {
long id;
if (!PyArg_ParseTuple(args, "l", &id)) {
@@ -333,21 +330,21 @@ Message_setQid(s_Message* self, PyObject* args) {
}
}
-static PyObject*
+PyObject*
Message_getRcode(s_Message* self) {
s_Rcode* rcode;
rcode = static_cast<s_Rcode*>(rcode_type.tp_alloc(&rcode_type, 0));
if (rcode != NULL) {
- rcode->rcode = NULL;
+ rcode->cppobj = NULL;
try {
- rcode->rcode = new Rcode(self->message->getRcode());
+ rcode->cppobj = new Rcode(self->message->getRcode());
} catch (const InvalidMessageOperation& imo) {
PyErr_SetString(po_InvalidMessageOperation, imo.what());
} catch (...) {
PyErr_SetString(po_IscException, "Unexpected exception");
}
- if (rcode->rcode == NULL) {
+ if (rcode->cppobj == NULL) {
Py_DECREF(rcode);
return (NULL);
}
@@ -356,14 +353,14 @@ Message_getRcode(s_Message* self) {
return (rcode);
}
-static PyObject*
+PyObject*
Message_setRcode(s_Message* self, PyObject* args) {
s_Rcode* rcode;
if (!PyArg_ParseTuple(args, "O!", &rcode_type, &rcode)) {
return (NULL);
}
try {
- self->message->setRcode(*rcode->rcode);
+ self->message->setRcode(*rcode->cppobj);
Py_RETURN_NONE;
} catch (const InvalidMessageOperation& imo) {
PyErr_SetString(po_InvalidMessageOperation, imo.what());
@@ -371,7 +368,7 @@ Message_setRcode(s_Message* self, PyObject* args) {
}
}
-static PyObject*
+PyObject*
Message_getOpcode(s_Message* self) {
s_Opcode* opcode;
@@ -394,7 +391,7 @@ Message_getOpcode(s_Message* self) {
return (opcode);
}
-static PyObject*
+PyObject*
Message_setOpcode(s_Message* self, PyObject* args) {
s_Opcode* opcode;
if (!PyArg_ParseTuple(args, "O!", &opcode_type, &opcode)) {
@@ -409,7 +406,7 @@ Message_setOpcode(s_Message* self, PyObject* args) {
}
}
-static PyObject*
+PyObject*
Message_getEDNS(s_Message* self) {
s_EDNS* edns;
EDNS* edns_body;
@@ -429,7 +426,7 @@ Message_getEDNS(s_Message* self) {
return (edns);
}
-static PyObject*
+PyObject*
Message_setEDNS(s_Message* self, PyObject* args) {
s_EDNS* edns;
if (!PyArg_ParseTuple(args, "O!", &edns_type, &edns)) {
@@ -444,7 +441,7 @@ Message_setEDNS(s_Message* self, PyObject* args) {
}
}
-static PyObject*
+PyObject*
Message_getRRCount(s_Message* self, PyObject* args) {
unsigned int section;
if (!PyArg_ParseTuple(args, "I", §ion)) {
@@ -463,7 +460,7 @@ Message_getRRCount(s_Message* self, PyObject* args) {
}
// TODO use direct iterators for these? (or simply lists for now?)
-static PyObject*
+PyObject*
Message_getQuestion(s_Message* self) {
QuestionIterator qi, qi_end;
try {
@@ -502,7 +499,7 @@ Message_getQuestion(s_Message* self) {
return (list);
}
-static PyObject*
+PyObject*
Message_getSection(s_Message* self, PyObject* args) {
unsigned int section;
if (!PyArg_ParseTuple(args, "I", §ion)) {
@@ -559,7 +556,7 @@ Message_getSection(s_Message* self, PyObject* args) {
//static PyObject* Message_beginSection(s_Message* self, PyObject* args);
//static PyObject* Message_endSection(s_Message* self, PyObject* args);
//static PyObject* Message_addQuestion(s_Message* self, PyObject* args);
-static PyObject*
+PyObject*
Message_addQuestion(s_Message* self, PyObject* args) {
s_Question *question;
@@ -572,7 +569,7 @@ Message_addQuestion(s_Message* self, PyObject* args) {
Py_RETURN_NONE;
}
-static PyObject*
+PyObject*
Message_addRRset(s_Message* self, PyObject* args) {
PyObject *sign = Py_False;
int section;
@@ -599,7 +596,7 @@ Message_addRRset(s_Message* self, PyObject* args) {
}
}
-static PyObject*
+PyObject*
Message_clear(s_Message* self, PyObject* args) {
int i;
if (PyArg_ParseTuple(args, "i", &i)) {
@@ -620,13 +617,13 @@ Message_clear(s_Message* self, PyObject* args) {
}
}
-static PyObject*
+PyObject*
Message_makeResponse(s_Message* self) {
self->message->makeResponse();
Py_RETURN_NONE;
}
-static PyObject*
+PyObject*
Message_toText(s_Message* self) {
// Py_BuildValue makes python objects from native data
try {
@@ -641,7 +638,7 @@ Message_toText(s_Message* self) {
}
}
-static PyObject*
+PyObject*
Message_str(PyObject* self) {
// Simply call the to_text method we already defined
return (PyObject_CallMethod(self,
@@ -649,13 +646,20 @@ Message_str(PyObject* self) {
const_cast<char*>("")));
}
-static PyObject*
+PyObject*
Message_toWire(s_Message* self, PyObject* args) {
s_MessageRenderer* mr;
+ s_TSIGContext* tsig_ctx = NULL;
- if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
+ if (PyArg_ParseTuple(args, "O!|O!", &messagerenderer_type, &mr,
+ &tsig_context_type, &tsig_ctx)) {
try {
- self->message->toWire(*mr->messagerenderer);
+ if (tsig_ctx == NULL) {
+ self->message->toWire(*mr->messagerenderer);
+ } else {
+ self->message->toWire(*mr->messagerenderer,
+ *tsig_ctx->tsig_ctx);
+ }
// If we return NULL it is seen as an error, so use this for
// None returns
Py_RETURN_NONE;
@@ -671,7 +675,7 @@ Message_toWire(s_Message* self, PyObject* args) {
return (NULL);
}
-static PyObject*
+PyObject*
Message_fromWire(s_Message* self, PyObject* args) {
const char* b;
Py_ssize_t len;
@@ -765,3 +769,4 @@ initModulePart_Message(PyObject* mod) {
return (true);
}
+} // end of unnamed namespace
diff --git a/src/lib/dns/python/pydnspp.cc b/src/lib/dns/python/pydnspp.cc
index 27dbae6..0be346e 100644
--- a/src/lib/dns/python/pydnspp.cc
+++ b/src/lib/dns/python/pydnspp.cc
@@ -32,20 +32,32 @@
#include <exceptions/exceptions.h>
#include <util/buffer.h>
+
#include <dns/exceptions.h>
#include <dns/name.h>
#include <dns/messagerenderer.h>
-#include <dns/python/pydnspp_common.h>
+#include "pydnspp_common.h"
+namespace isc {
+namespace dns {
+namespace python {
// For our 'general' isc::Exceptions
-static PyObject* po_IscException;
-static PyObject* po_InvalidParameter;
+PyObject* po_IscException;
+PyObject* po_InvalidParameter;
// For our own isc::dns::Exception
-static PyObject* po_DNSMessageBADVERS;
+PyObject* po_DNSMessageBADVERS;
+}
+}
+}
+
+#include "rcode_python.h"
+#include "tsigerror_python.h"
// order is important here!
+using namespace isc::dns::python;
+
#include <dns/python/messagerenderer_python.cc>
#include <dns/python/name_python.cc> // needs Messagerenderer
#include <dns/python/rrclass_python.cc> // needs Messagerenderer
@@ -56,15 +68,16 @@ static PyObject* po_DNSMessageBADVERS;
#include <dns/python/question_python.cc> // needs RRClass, RRType, RRTTL,
// Name
#include <dns/python/tsigkey_python.cc> // needs Name
+#include <dns/python/tsig_python.cc> // needs tsigkey
#include <dns/python/opcode_python.cc>
-#include <dns/python/rcode_python.cc>
#include <dns/python/edns_python.cc> // needs Messagerenderer, Rcode
#include <dns/python/message_python.cc> // needs RRset, Question
//
// Definition of the module
//
-static PyModuleDef pydnspp = {
+namespace {
+PyModuleDef pydnspp = {
{ PyObject_HEAD_INIT(NULL) NULL, 0, NULL},
"pydnspp",
"Python bindings for the classes in the isc::dns namespace.\n\n"
@@ -79,10 +92,11 @@ static PyModuleDef pydnspp = {
NULL,
NULL
};
+}
PyMODINIT_FUNC
PyInit_pydnspp(void) {
- PyObject *mod = PyModule_Create(&pydnspp);
+ PyObject* mod = PyModule_Create(&pydnspp);
if (mod == NULL) {
return (NULL);
}
@@ -153,6 +167,14 @@ PyInit_pydnspp(void) {
return (NULL);
}
+ if (!initModulePart_TSIGError(mod)) {
+ return (NULL);
+ }
+
+ if (!initModulePart_TSIGContext(mod)) {
+ return (NULL);
+ }
+
return (mod);
}
diff --git a/src/lib/dns/python/pydnspp_common.cc b/src/lib/dns/python/pydnspp_common.cc
index 6c26367..8ca763a 100644
--- a/src/lib/dns/python/pydnspp_common.cc
+++ b/src/lib/dns/python/pydnspp_common.cc
@@ -15,6 +15,9 @@
#include <Python.h>
#include <pydnspp_common.h>
+namespace isc {
+namespace dns {
+namespace python {
int
readDataFromSequence(uint8_t *data, size_t len, PyObject* sequence) {
PyObject* el = NULL;
@@ -44,8 +47,15 @@ readDataFromSequence(uint8_t *data, size_t len, PyObject* sequence) {
}
-void addClassVariable(PyTypeObject& c, const char* name,
- PyObject* obj)
-{
- PyDict_SetItemString(c.tp_dict, name, obj);
+int
+addClassVariable(PyTypeObject& c, const char* name, PyObject* obj) {
+ if (obj == NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "NULL object is specified for a class variable");
+ return (-1);
+ }
+ return (PyDict_SetItemString(c.tp_dict, name, obj));
+}
+}
+}
}
diff --git a/src/lib/dns/python/pydnspp_common.h b/src/lib/dns/python/pydnspp_common.h
index 32e2b78..ed90998 100644
--- a/src/lib/dns/python/pydnspp_common.h
+++ b/src/lib/dns/python/pydnspp_common.h
@@ -15,9 +15,22 @@
#ifndef __LIBDNS_PYTHON_COMMON_H
#define __LIBDNS_PYTHON_COMMON_H 1
-//
-// Shared functions for python/c API
-//
+#include <Python.h>
+
+#include <stdexcept>
+#include <string>
+
+#include <util/python/pycppwrapper_util.h>
+
+namespace isc {
+namespace dns {
+namespace python {
+// For our 'general' isc::Exceptions
+extern PyObject* po_IscException;
+extern PyObject* po_InvalidParameter;
+
+// For our own isc::dns::Exception
+extern PyObject* po_DNSMessageBADVERS;
// This function reads 'bytes' from a sequence
// This sequence can be anything that implements the Sequence interface,
@@ -31,6 +44,12 @@
// case nothing is removed
int readDataFromSequence(uint8_t *data, size_t len, PyObject* sequence);
-void addClassVariable(PyTypeObject& c, const char* name, PyObject* obj);
-
+int addClassVariable(PyTypeObject& c, const char* name, PyObject* obj);
+} // namespace python
+} // namespace dns
+} // namespace isc
#endif // __LIBDNS_PYTHON_COMMON_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/python/rcode_python.cc b/src/lib/dns/python/rcode_python.cc
index b80a93c..b594ad3 100644
--- a/src/lib/dns/python/rcode_python.cc
+++ b/src/lib/dns/python/rcode_python.cc
@@ -12,9 +12,17 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <Python.h>
+
+#include <exceptions/exceptions.h>
+
#include <dns/rcode.h>
+#include "pydnspp_common.h"
+#include "rcode_python.h"
+
using namespace isc::dns;
+using namespace isc::dns::python;
//
// Declaration of the custom exceptions (None for this class)
@@ -27,25 +35,14 @@ using namespace isc::dns;
// and static wrappers around the methods we export), a list of methods,
// and a type description
-namespace {
//
// Rcode
//
-// We added a helper variable static_code here
-// Since we can create Rcodes dynamically with Rcode(int), but also
-// use the static globals (Rcode::NOERROR() etc), we use this
-// variable to see if the code came from one of the latter, in which
-// case Rcode_destroy should not free it (the other option is to
-// allocate new Rcodes for every use of the static ones, but this
-// seems more efficient).
-class s_Rcode : public PyObject {
-public:
- s_Rcode() : rcode(NULL), static_code(false) {}
- const Rcode* rcode;
- bool static_code;
-};
+// Trivial constructor.
+s_Rcode::s_Rcode() : cppobj(NULL), static_code(false) {}
+namespace {
int Rcode_init(s_Rcode* const self, PyObject* args);
void Rcode_destroy(s_Rcode* const self);
@@ -118,57 +115,6 @@ PyMethodDef Rcode_methods[] = {
{ NULL, NULL, 0, NULL }
};
-PyTypeObject rcode_type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "pydnspp.Rcode",
- sizeof(s_Rcode), // tp_basicsize
- 0, // tp_itemsize
- (destructor)Rcode_destroy, // tp_dealloc
- NULL, // tp_print
- NULL, // tp_getattr
- NULL, // tp_setattr
- NULL, // tp_reserved
- NULL, // tp_repr
- NULL, // tp_as_number
- NULL, // tp_as_sequence
- NULL, // tp_as_mapping
- NULL, // tp_hash
- NULL, // tp_call
- Rcode_str, // tp_str
- NULL, // tp_getattro
- NULL, // tp_setattro
- NULL, // tp_as_buffer
- Py_TPFLAGS_DEFAULT, // tp_flags
- "The Rcode class objects represent standard RCODEs"
- "of the header section of DNS messages.",
- NULL, // tp_traverse
- NULL, // tp_clear
- (richcmpfunc)Rcode_richcmp, // tp_richcompare
- 0, // tp_weaklistoffset
- NULL, // tp_iter
- NULL, // tp_iternext
- Rcode_methods, // tp_methods
- NULL, // tp_members
- NULL, // tp_getset
- NULL, // tp_base
- NULL, // tp_dict
- NULL, // tp_descr_get
- NULL, // tp_descr_set
- 0, // tp_dictoffset
- (initproc)Rcode_init, // tp_init
- NULL, // tp_alloc
- PyType_GenericNew, // tp_new
- NULL, // tp_free
- NULL, // tp_is_gc
- NULL, // tp_bases
- NULL, // tp_mro
- NULL, // tp_cache
- NULL, // tp_subclasses
- NULL, // tp_weaklist
- NULL, // tp_del
- 0 // tp_version_tag
-};
-
int
Rcode_init(s_Rcode* const self, PyObject* args) {
long code = 0;
@@ -193,9 +139,9 @@ Rcode_init(s_Rcode* const self, PyObject* args) {
}
try {
if (ext_code == -1) {
- self->rcode = new Rcode(code);
+ self->cppobj = new Rcode(code);
} else {
- self->rcode = new Rcode(code, ext_code);
+ self->cppobj = new Rcode(code, ext_code);
}
self->static_code = false;
} catch (const isc::OutOfRange& ex) {
@@ -211,27 +157,27 @@ Rcode_init(s_Rcode* const self, PyObject* args) {
void
Rcode_destroy(s_Rcode* const self) {
// Depending on whether we created the rcode or are referring
- // to a global one, we do or do not delete self->rcode here
+ // to a global one, we do or do not delete self->cppobj here
if (!self->static_code) {
- delete self->rcode;
+ delete self->cppobj;
}
- self->rcode = NULL;
+ self->cppobj = NULL;
Py_TYPE(self)->tp_free(self);
}
PyObject*
Rcode_getCode(const s_Rcode* const self) {
- return (Py_BuildValue("I", self->rcode->getCode()));
+ return (Py_BuildValue("I", self->cppobj->getCode()));
}
PyObject*
Rcode_getExtendedCode(const s_Rcode* const self) {
- return (Py_BuildValue("I", self->rcode->getExtendedCode()));
+ return (Py_BuildValue("I", self->cppobj->getExtendedCode()));
}
PyObject*
Rcode_toText(const s_Rcode* const self) {
- return (Py_BuildValue("s", self->rcode->toText().c_str()));
+ return (Py_BuildValue("s", self->cppobj->toText().c_str()));
}
PyObject*
@@ -245,7 +191,7 @@ PyObject*
Rcode_createStatic(const Rcode& rcode) {
s_Rcode* ret = PyObject_New(s_Rcode, &rcode_type);
if (ret != NULL) {
- ret->rcode = &rcode;
+ ret->cppobj = &rcode;
ret->static_code = true;
}
return (ret);
@@ -357,10 +303,10 @@ Rcode_richcmp(const s_Rcode* const self, const s_Rcode* const other,
PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode");
return (NULL);
case Py_EQ:
- c = (*self->rcode == *other->rcode);
+ c = (*self->cppobj == *other->cppobj);
break;
case Py_NE:
- c = (*self->rcode != *other->rcode);
+ c = (*self->cppobj != *other->cppobj);
break;
case Py_GT:
PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode");
@@ -374,6 +320,61 @@ Rcode_richcmp(const s_Rcode* const self, const s_Rcode* const other,
else
Py_RETURN_FALSE;
}
+} // end of unnamed namespace
+
+namespace isc {
+namespace dns {
+namespace python {
+PyTypeObject rcode_type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "pydnspp.Rcode",
+ sizeof(s_Rcode), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)Rcode_destroy, // tp_dealloc
+ NULL, // tp_print
+ NULL, // tp_getattr
+ NULL, // tp_setattr
+ NULL, // tp_reserved
+ NULL, // tp_repr
+ NULL, // tp_as_number
+ NULL, // tp_as_sequence
+ NULL, // tp_as_mapping
+ NULL, // tp_hash
+ NULL, // tp_call
+ Rcode_str, // tp_str
+ NULL, // tp_getattro
+ NULL, // tp_setattro
+ NULL, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT, // tp_flags
+ "The Rcode class objects represent standard RCODEs"
+ "of the header section of DNS messages.",
+ NULL, // tp_traverse
+ NULL, // tp_clear
+ reinterpret_cast<richcmpfunc>(Rcode_richcmp), // tp_richcompare
+ 0, // tp_weaklistoffset
+ NULL, // tp_iter
+ NULL, // tp_iternext
+ Rcode_methods, // tp_methods
+ NULL, // tp_members
+ NULL, // tp_getset
+ NULL, // tp_base
+ NULL, // tp_dict
+ NULL, // tp_descr_get
+ NULL, // tp_descr_set
+ 0, // tp_dictoffset
+ (initproc)Rcode_init, // tp_init
+ NULL, // tp_alloc
+ PyType_GenericNew, // tp_new
+ NULL, // tp_free
+ NULL, // tp_is_gc
+ NULL, // tp_bases
+ NULL, // tp_mro
+ NULL, // tp_cache
+ NULL, // tp_subclasses
+ NULL, // tp_weaklist
+ NULL, // tp_del
+ 0 // tp_version_tag
+};
// Module Initialization, all statics are initialized here
bool
@@ -428,4 +429,6 @@ initModulePart_Rcode(PyObject* mod) {
return (true);
}
-} // end of unnamed namespace
+} // namespace python
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/python/rcode_python.h b/src/lib/dns/python/rcode_python.h
new file mode 100644
index 0000000..9b5e699
--- /dev/null
+++ b/src/lib/dns/python/rcode_python.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __PYTHON_RCODE_H
+#define __PYTHON_RCODE_H 1
+
+#include <Python.h>
+
+namespace isc {
+namespace dns {
+class Rcode;
+
+namespace python {
+
+// The s_* Class simply covers one instantiation of the object.
+//
+// We added a helper variable static_code here
+// Since we can create Rcodes dynamically with Rcode(int), but also
+// use the static globals (Rcode::NOERROR() etc), we use this
+// variable to see if the code came from one of the latter, in which
+// case Rcode_destroy should not free it (the other option is to
+// allocate new Rcodes for every use of the static ones, but this
+// seems more efficient).
+//
+// Follow-up note: we don't have to use the proxy function in the python lib;
+// we can just define class specific constants directly (see TSIGError).
+// We should make this cleanup later.
+class s_Rcode : public PyObject {
+public:
+ s_Rcode();
+ const Rcode* cppobj;
+ bool static_code;
+};
+
+extern PyTypeObject rcode_type;
+
+bool initModulePart_Rcode(PyObject* mod);
+
+} // namespace python
+} // namespace dns
+} // namespace isc
+#endif // __PYTHON_RCODE_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/python/tests/Makefile.am b/src/lib/dns/python/tests/Makefile.am
index 272f1c1..1149a47 100644
--- a/src/lib/dns/python/tests/Makefile.am
+++ b/src/lib/dns/python/tests/Makefile.am
@@ -11,6 +11,8 @@ PYTESTS += rrclass_python_test.py
PYTESTS += rrset_python_test.py
PYTESTS += rrttl_python_test.py
PYTESTS += rrtype_python_test.py
+PYTESTS += tsig_python_test.py
+PYTESTS += tsigerror_python_test.py
PYTESTS += tsigkey_python_test.py
EXTRA_DIST = $(PYTESTS)
@@ -20,7 +22,7 @@ EXTRA_DIST += testutil.py
# required by loadable python modules.
LIBRARY_PATH_PLACEHOLDER =
if SET_ENV_LIBRARY_PATH
-LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
endif
# test using command-line arguments, so use check-local target instead of TESTS
diff --git a/src/lib/dns/python/tests/message_python_test.py b/src/lib/dns/python/tests/message_python_test.py
index bccc596..72807cc 100644
--- a/src/lib/dns/python/tests/message_python_test.py
+++ b/src/lib/dns/python/tests/message_python_test.py
@@ -62,6 +62,12 @@ def create_message():
message_render.add_rrset(Message.SECTION_ANSWER, rrset)
return message_render
+def strip_mutable_tsig_data(data):
+ # Unfortunately we cannot easily compare TSIG RR because we can't tweak
+ # current time. As a work around this helper function strips off the time
+ # dependent part of TSIG RDATA, i.e., the MAC (assuming HMAC-MD5) and
+ # Time Signed.
+ return data[0:-32] + data[-26:-22] + data[-6:]
class MessageTest(unittest.TestCase):
@@ -81,6 +87,8 @@ class MessageTest(unittest.TestCase):
self.bogus_section = Message.SECTION_ADDITIONAL + 1
self.bogus_below_section = Message.SECTION_QUESTION - 1
+ self.tsig_key = TSIGKey("www.example.com:SFuWd/q99SzF8Yzd1QbB9g==")
+ self.tsig_ctx = TSIGContext(self.tsig_key)
def test_init(self):
self.assertRaises(TypeError, Message, -1)
@@ -277,12 +285,39 @@ class MessageTest(unittest.TestCase):
self.assertRaises(InvalidMessageOperation, self.r.to_wire,
MessageRenderer())
+ def __common_tsigquery_setup(self):
+ self.r.set_opcode(Opcode.QUERY())
+ self.r.set_rcode(Rcode.NOERROR())
+ self.r.set_header_flag(Message.HEADERFLAG_RD)
+ self.r.add_question(Question(Name("www.example.com"),
+ RRClass("IN"), RRType("A")))
+
+ def __common_tsig_checks(self, expected_file):
+ renderer = MessageRenderer()
+ self.r.to_wire(renderer, self.tsig_ctx)
+ actual_wire = strip_mutable_tsig_data(renderer.get_data())
+ expected_wire = strip_mutable_tsig_data(read_wire_data(expected_file))
+ self.assertEqual(expected_wire, actual_wire)
+
+ def test_to_wire_with_tsig(self):
+ self.r.set_qid(0x2d65)
+ self.__common_tsigquery_setup()
+ self.__common_tsig_checks("message_toWire2.wire")
+
+ def test_to_wire_with_edns_tsig(self):
+ self.r.set_qid(0x6cd)
+ self.__common_tsigquery_setup()
+ edns = EDNS()
+ edns.set_udp_size(4096)
+ self.r.set_edns(edns)
+ self.__common_tsig_checks("message_toWire3.wire")
+
def test_to_text(self):
message_render = create_message()
msg_str =\
""";; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4149
-;; flags: qr aa rd ; QUESTION: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0
+;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;test.example.com. IN A
diff --git a/src/lib/dns/python/tests/tsig_python_test.py b/src/lib/dns/python/tests/tsig_python_test.py
new file mode 100644
index 0000000..bffa0cf
--- /dev/null
+++ b/src/lib/dns/python/tests/tsig_python_test.py
@@ -0,0 +1,29 @@
+# Copyright (C) 2010 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import unittest
+from pydnspp import *
+
+class TSIGContextTest(unittest.TestCase):
+ tsig_key = TSIGKey('www.example.com:SFuWd/q99SzF8Yzd1QbB9g==')
+
+ def setUp(self):
+ # In the minimal implementation, we simply check constructing a
+ # TSIGContext doesn't cause any disruption. We can add more tests
+ # later.
+ self.tsig_ctx = TSIGContext(self.tsig_key)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/src/lib/dns/python/tests/tsigerror_python_test.py b/src/lib/dns/python/tests/tsigerror_python_test.py
new file mode 100644
index 0000000..a968b6b
--- /dev/null
+++ b/src/lib/dns/python/tests/tsigerror_python_test.py
@@ -0,0 +1,97 @@
+# Copyright (C) 2011 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import unittest
+import sys
+from pydnspp import *
+
+class TSIGErrorTest(unittest.TestCase):
+ def test_from_code(self):
+ self.assertEqual(0, TSIGError(0).get_code())
+ self.assertEqual(18, TSIGError(18).get_code())
+ self.assertEqual(65535, TSIGError(65535).get_code())
+ self.assertRaises(ValueError, TSIGError, 65536)
+ self.assertRaises(ValueError, TSIGError, -1)
+ self.assertRaises(TypeError, TSIGError, "not yet supported")
+
+ def test_from_rcode(self):
+ # We use RCODE for code values from 0-15.
+ self.assertEqual(0, TSIGError(Rcode.NOERROR()).get_code())
+ self.assertEqual(15, TSIGError(Rcode(15)).get_code())
+
+ # From error code 16 TSIG errors define a separate space, so passing
+ # corresponding RCODE for such code values should be prohibited.
+ self.assertRaises(ValueError, TSIGError, Rcode(16))
+
+ def test_constants(self):
+ # We'll only test arbitrarily chosen subsets of the codes.
+ # This class is quite simple, so it should be suffice.
+ self.assertEqual(TSIGError.BAD_SIG_CODE, TSIGError(16).get_code())
+ self.assertEqual(TSIGError.BAD_KEY_CODE, TSIGError(17).get_code())
+ self.assertEqual(TSIGError.BAD_TIME_CODE, TSIGError(18).get_code())
+
+ self.assertEqual(0, TSIGError.NOERROR.get_code())
+ self.assertEqual(9, TSIGError.NOTAUTH.get_code())
+ self.assertEqual(14, TSIGError.RESERVED14.get_code())
+ self.assertEqual(TSIGError.BAD_SIG_CODE, TSIGError.BAD_SIG.get_code())
+ self.assertEqual(TSIGError.BAD_KEY_CODE, TSIGError.BAD_KEY.get_code())
+ self.assertEqual(TSIGError.BAD_TIME_CODE, TSIGError.BAD_TIME.get_code())
+
+ def test_equal(self):
+ self.assertTrue(TSIGError.NOERROR == TSIGError(Rcode.NOERROR()))
+ self.assertTrue(TSIGError(Rcode.NOERROR()) == TSIGError.NOERROR)
+
+ self.assertTrue(TSIGError.BAD_SIG == TSIGError(16))
+ self.assertTrue(TSIGError(16) == TSIGError.BAD_SIG)
+
+ def test_nequal(self):
+ self.assertTrue(TSIGError.BAD_KEY != TSIGError(Rcode.NOERROR()))
+ self.assertTrue(TSIGError(Rcode.NOERROR()) != TSIGError.BAD_KEY)
+
+ def test_to_text(self):
+ # TSIGError derived from the standard Rcode
+ self.assertEqual("NOERROR", TSIGError(Rcode.NOERROR()).to_text())
+
+ # Well known TSIG errors
+ self.assertEqual("BADSIG", TSIGError.BAD_SIG.to_text())
+ self.assertEqual("BADKEY", TSIGError.BAD_KEY.to_text())
+ self.assertEqual("BADTIME", TSIGError.BAD_TIME.to_text())
+
+ # Unknown (or not yet supported) codes. Simply converted as numeric.
+ self.assertEqual("19", TSIGError(19).to_text());
+ self.assertEqual("65535", TSIGError(65535).to_text());
+
+ # also check str() works same way
+ self.assertEqual("NOERROR", str(TSIGError(Rcode.NOERROR())))
+ self.assertEqual("BADSIG", str(TSIGError.BAD_SIG))
+
+ def test_to_rcode(self):
+ # TSIGError derived from the standard Rcode
+ self.assertEqual(Rcode.NOERROR(), TSIGError(Rcode.NOERROR()).to_rcode())
+
+ # Well known TSIG errors
+ self.assertEqual(Rcode.NOTAUTH(), TSIGError.BAD_SIG.to_rcode())
+ self.assertEqual(Rcode.NOTAUTH(), TSIGError.BAD_KEY.to_rcode())
+ self.assertEqual(Rcode.NOTAUTH(), TSIGError.BAD_TIME.to_rcode())
+
+ # Unknown (or not yet supported) codes are treated as SERVFAIL.
+ self.assertEqual(Rcode.SERVFAIL(), TSIGError(19).to_rcode())
+ self.assertEqual(Rcode.SERVFAIL(), TSIGError(65535).to_rcode())
+
+ # Check there's no redundant refcount (which would cause leak)
+ self.assertEqual(1, sys.getrefcount(TSIGError.BAD_SIG.to_rcode()))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/src/lib/dns/python/tests/tsigkey_python_test.py b/src/lib/dns/python/tests/tsigkey_python_test.py
index 06e6868..305c8dd 100644
--- a/src/lib/dns/python/tests/tsigkey_python_test.py
+++ b/src/lib/dns/python/tests/tsigkey_python_test.py
@@ -44,8 +44,33 @@ class TSIGKeyTest(unittest.TestCase):
TSIGKey.HMACMD5_NAME,
'should be binary') # signature mismatch
+ def test_str(self):
+ k1 = TSIGKey('test.example:CwsLCwsLCwsLCwsLCwsLCw==:hmac-md5.sig-alg.reg.int')
+ self.assertEqual(Name('test.example.'), k1.get_key_name())
+ self.assertEqual(Name('hmac-md5.sig-alg.reg.int.'), k1.get_algorithm_name())
+ self.assertEqual(b'\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b',
+ k1.get_secret())
+ self.assertEqual('test.example.:CwsLCwsLCwsLCwsLCwsLCw==:hmac-md5.sig-alg.reg.int.',
+ k1.to_text())
+
+ self.assertRaises(InvalidParameter, TSIGKey,
+ 'test.example:CwsLCwsLCwsLCwsLCwsLCw==:unsupported')
+ self.assertRaises(InvalidParameter, TSIGKey,
+ '::')
+ self.assertRaises(InvalidParameter, TSIGKey,
+ 'test.example:')
+ self.assertRaises(InvalidParameter, TSIGKey,
+ 'test.example:%bad_base_64%')
+ self.assertRaises(InvalidParameter, TSIGKey,
+ 'test.example:CwsLCwsLCwsLCwsLCwsLCw==:')
+ self.assertRaises(InvalidParameter, TSIGKey,
+ 'test.:example:CwsLCwsLCwsLCwsLCwsLCw==')
+
class TSIGKeyRingTest(unittest.TestCase):
key_name = Name('example.com')
+ md5_name = Name('hmac-md5.sig-alg.reg.int')
+ sha1_name = Name('hmac-sha1')
+ sha256_name = Name('hmac-sha256')
secret = b'someRandomData'
def setUp(self):
@@ -130,18 +155,26 @@ class TSIGKeyRingTest(unittest.TestCase):
def test_find(self):
self.assertEqual((TSIGKeyRing.NOTFOUND, None),
- self.keyring.find(self.key_name))
+ self.keyring.find(self.key_name, self.md5_name))
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.add(TSIGKey(self.key_name,
- TSIGKey.HMACSHA256_NAME,
+ self.sha256_name,
self.secret)))
- (code, key) = self.keyring.find(self.key_name)
+ (code, key) = self.keyring.find(self.key_name, self.sha256_name)
self.assertEqual(TSIGKeyRing.SUCCESS, code)
self.assertEqual(self.key_name, key.get_key_name())
self.assertEqual(TSIGKey.HMACSHA256_NAME, key.get_algorithm_name())
self.assertEqual(self.secret, key.get_secret())
+ (code, key) = self.keyring.find(Name('different-key.example'),
+ self.sha256_name)
+ self.assertEqual(TSIGKeyRing.NOTFOUND, code)
+ self.assertEqual(None, key)
+ (code, key) = self.keyring.find(self.key_name, self.md5_name)
+ self.assertEqual(TSIGKeyRing.NOTFOUND, code)
+ self.assertEqual(None, key)
+
self.assertRaises(TypeError, self.keyring.find, 1)
self.assertRaises(TypeError, self.keyring.find, 'should be a name')
self.assertRaises(TypeError, self.keyring.find, self.key_name, 0)
@@ -149,24 +182,28 @@ class TSIGKeyRingTest(unittest.TestCase):
def test_find_from_some(self):
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.add(TSIGKey(self.key_name,
- TSIGKey.HMACSHA256_NAME,
+ self.sha256_name,
self.secret)))
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.add(TSIGKey(Name('another.example'),
- TSIGKey.HMACMD5_NAME,
+ self.md5_name,
self.secret)))
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.add(TSIGKey(Name('more.example'),
- TSIGKey.HMACSHA1_NAME,
+ self.sha1_name,
self.secret)))
- (code, key) = self.keyring.find(Name('another.example'))
+ (code, key) = self.keyring.find(Name('another.example'), self.md5_name)
self.assertEqual(TSIGKeyRing.SUCCESS, code)
self.assertEqual(Name('another.example'), key.get_key_name())
self.assertEqual(TSIGKey.HMACMD5_NAME, key.get_algorithm_name())
self.assertEqual((TSIGKeyRing.NOTFOUND, None),
- self.keyring.find(Name('noexist.example')))
+ self.keyring.find(Name('noexist.example'),
+ self.sha1_name))
+ self.assertEqual((TSIGKeyRing.NOTFOUND, None),
+ self.keyring.find(Name('another.example'),
+ self.sha1_name))
if __name__ == '__main__':
unittest.main()
diff --git a/src/lib/dns/python/tsig_python.cc b/src/lib/dns/python/tsig_python.cc
new file mode 100644
index 0000000..7b6ba01
--- /dev/null
+++ b/src/lib/dns/python/tsig_python.cc
@@ -0,0 +1,156 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dns/tsig.h>
+
+using namespace isc::dns;
+
+//
+// Definition of the classes
+//
+
+// For each class, we need a struct, a helper functions (init, destroy,
+// and static wrappers around the methods we export), a list of methods,
+// and a type description
+
+namespace {
+// The s_* Class simply covers one instantiation of the object
+class s_TSIGContext : public PyObject {
+public:
+ TSIGContext* tsig_ctx;
+};
+
+//
+// We declare the functions here, the definitions are below
+// the type definition of the object, since both can use the other
+//
+
+// General creation and destruction
+int TSIGContext_init(s_TSIGContext* self, PyObject* args);
+void TSIGContext_destroy(s_TSIGContext* self);
+
+// These are the functions we export
+// For a minimal support, we don't need them.
+
+// This list contains the actual set of functions we have in
+// python. Each entry has
+// 1. Python method name
+// 2. Our static function here
+// 3. Argument type
+// 4. Documentation
+PyMethodDef TSIGContext_methods[] = {
+ { NULL, NULL, 0, NULL }
+};
+
+// This defines the complete type for reflection in python and
+// parsing of PyObject* to s_EDNS
+// Most of the functions are not actually implemented and NULL here.
+PyTypeObject tsig_context_type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "libdns_python.TSIGContext",
+ sizeof(s_TSIGContext), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)TSIGContext_destroy, // tp_dealloc
+ NULL, // tp_print
+ NULL, // tp_getattr
+ NULL, // tp_setattr
+ NULL, // tp_reserved
+ NULL, // tp_repr
+ NULL, // tp_as_number
+ NULL, // tp_as_sequence
+ NULL, // tp_as_mapping
+ NULL, // tp_hash
+ NULL, // tp_call
+ NULL, // tp_str
+ NULL, // tp_getattro
+ NULL, // tp_setattro
+ NULL, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT, // tp_flags
+ "The TSIGContext class maintains a context of a signed session of "
+ "DNS transactions by TSIG.",
+ NULL, // tp_traverse
+ NULL, // tp_clear
+ NULL, // tp_richcompare
+ 0, // tp_weaklistoffset
+ NULL, // tp_iter
+ NULL, // tp_iternext
+ TSIGContext_methods, // tp_methods
+ NULL, // tp_members
+ NULL, // tp_getset
+ NULL, // tp_base
+ NULL, // tp_dict
+ NULL, // tp_descr_get
+ NULL, // tp_descr_set
+ 0, // tp_dictoffset
+ (initproc)TSIGContext_init, // tp_init
+ NULL, // tp_alloc
+ PyType_GenericNew, // tp_new
+ NULL, // tp_free
+ NULL, // tp_is_gc
+ NULL, // tp_bases
+ NULL, // tp_mro
+ NULL, // tp_cache
+ NULL, // tp_subclasses
+ NULL, // tp_weaklist
+ NULL, // tp_del
+ 0 // tp_version_tag
+};
+
+int
+TSIGContext_init(s_TSIGContext* self, PyObject* args) {
+ const s_TSIGKey* tsigkey_obj;
+
+ try {
+ if (PyArg_ParseTuple(args, "O!", &tsigkey_type, &tsigkey_obj)) {
+ self->tsig_ctx = new TSIGContext(*tsigkey_obj->tsigkey);
+ return (0);
+ }
+ } catch (...) {
+ PyErr_SetString(po_IscException, "Unexpected exception");
+ return (-1);
+ }
+
+ PyErr_Clear();
+ PyErr_SetString(PyExc_TypeError,
+ "Invalid arguments to TSIGContext constructor");
+
+ return (-1);
+}
+
+void
+TSIGContext_destroy(s_TSIGContext* const self) {
+ delete self->tsig_ctx;
+ self->tsig_ctx = NULL;
+ Py_TYPE(self)->tp_free(self);
+}
+
+// Module Initialization, all statics are initialized here
+bool
+initModulePart_TSIGContext(PyObject* mod) {
+ // We initialize the static description object with PyType_Ready(),
+ // then add it to the module. This is not just a check! (leaving
+ // this out results in segmentation faults)
+ if (PyType_Ready(&tsig_context_type) < 0) {
+ return (false);
+ }
+ Py_INCREF(&tsig_context_type);
+ void* p = &tsig_context_type;
+ PyModule_AddObject(mod, "TSIGContext", static_cast<PyObject*>(p));
+
+ addClassVariable(tsig_context_type, "DEFAULT_FUDGE",
+ Py_BuildValue("H", TSIGContext::DEFAULT_FUDGE));
+
+ return (true);
+}
+} // end of anonymous namespace
diff --git a/src/lib/dns/python/tsigerror_python.cc b/src/lib/dns/python/tsigerror_python.cc
new file mode 100644
index 0000000..e973772
--- /dev/null
+++ b/src/lib/dns/python/tsigerror_python.cc
@@ -0,0 +1,362 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <Python.h>
+
+#include <string>
+#include <stdexcept>
+
+#include <util/python/pycppwrapper_util.h>
+
+#include <dns/tsigerror.h>
+
+#include "pydnspp_common.h"
+#include "rcode_python.h"
+#include "tsigerror_python.h"
+
+using namespace std;
+using namespace isc::util::python;
+using namespace isc::dns;
+using namespace isc::dns::python;
+
+//
+// Definition of the classes
+//
+
+// For each class, we need a struct, a helper functions (init, destroy,
+// and static wrappers around the methods we export), a list of methods,
+// and a type description
+
+//
+// TSIGError
+//
+
+// Trivial constructor.
+s_TSIGError::s_TSIGError() : cppobj(NULL) {
+}
+
+// Import pydoc text
+#include "tsigerror_python_inc.cc"
+
+namespace {
+// Shortcut type which would be convenient for adding class variables safely.
+typedef CPPPyObjectContainer<s_TSIGError, TSIGError> TSIGErrorContainer;
+
+//
+// We declare the functions here, the definitions are below
+// the type definition of the object, since both can use the other
+//
+
+// General creation and destruction
+int TSIGError_init(s_TSIGError* self, PyObject* args);
+void TSIGError_destroy(s_TSIGError* self);
+
+// These are the functions we export
+PyObject* TSIGError_getCode(const s_TSIGError* const self);
+PyObject* TSIGError_toText(const s_TSIGError* const self);
+PyObject* TSIGError_toRcode(const s_TSIGError* const self);
+PyObject* TSIGError_str(PyObject* self);
+PyObject* TSIGError_richcmp(const s_TSIGError* const self,
+ const s_TSIGError* const other, int op);
+
+// These are the functions we export
+// For a minimal support, we don't need them.
+
+// This list contains the actual set of functions we have in
+// python. Each entry has
+// 1. Python method name
+// 2. Our static function here
+// 3. Argument type
+// 4. Documentation
+PyMethodDef TSIGError_methods[] = {
+ { "get_code", reinterpret_cast<PyCFunction>(TSIGError_getCode),
+ METH_NOARGS,
+ TSIGError_getCode_doc },
+ { "to_text", reinterpret_cast<PyCFunction>(TSIGError_toText), METH_NOARGS,
+ TSIGError_toText_doc },
+ { "to_rcode", reinterpret_cast<PyCFunction>(TSIGError_toRcode),
+ METH_NOARGS,
+ TSIGError_toRcode_doc },
+ { NULL, NULL, 0, NULL }
+};
+
+int
+TSIGError_init(s_TSIGError* self, PyObject* args) {
+ try {
+ // Constructor from the code value
+ long code = 0;
+ if (PyArg_ParseTuple(args, "l", &code)) {
+ if (code < 0 || code > 0xffff) {
+ PyErr_SetString(PyExc_ValueError, "TSIG error out of range");
+ return (-1);
+ }
+ self->cppobj = new TSIGError(code);
+ return (0);
+ }
+
+ // Constructor from Rcode
+ s_Rcode* py_rcode;
+ if (PyArg_ParseTuple(args, "O!", &rcode_type, &py_rcode)) {
+ self->cppobj = new TSIGError(*py_rcode->cppobj);
+ return (0);
+ }
+ } catch (const isc::OutOfRange& ex) {
+ const string ex_what = "Failed to construct TSIGError object: " +
+ string(ex.what());
+ PyErr_SetString(PyExc_ValueError, ex_what.c_str());
+ return (-1);
+ } catch (const exception& ex) {
+ const string ex_what = "Failed to construct TSIGError object: " +
+ string(ex.what());
+ PyErr_SetString(po_IscException, ex_what.c_str());
+ return (-1);
+ } catch (...) {
+ PyErr_SetString(po_IscException,
+ "Unexpected exception in constructing TSIGError");
+ return (-1);
+ }
+
+ PyErr_SetString(PyExc_TypeError,
+ "Invalid arguments to TSIGError constructor");
+
+ return (-1);
+}
+
+void
+TSIGError_destroy(s_TSIGError* const self) {
+ delete self->cppobj;
+ self->cppobj = NULL;
+ Py_TYPE(self)->tp_free(self);
+}
+
+PyObject*
+TSIGError_getCode(const s_TSIGError* const self) {
+ return (Py_BuildValue("I", self->cppobj->getCode()));
+}
+
+PyObject*
+TSIGError_toText(const s_TSIGError* const self) {
+ try {
+ // toText() could throw, so we need to catch any exceptions below.
+ return (Py_BuildValue("s", self->cppobj->toText().c_str()));
+ } catch (const exception& ex) {
+ const string ex_what =
+ "Failed to convert TSIGError object to text: " +
+ string(ex.what());
+ PyErr_SetString(po_IscException, ex_what.c_str());
+ } catch (...) {
+ PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
+ "converting TSIGError object to text");
+ }
+ return (NULL);
+}
+
+PyObject*
+TSIGError_str(PyObject* self) {
+ // Simply call the to_text method we already defined
+ return (PyObject_CallMethod(self, const_cast<char*>("to_text"),
+ const_cast<char*>("")));
+}
+
+PyObject*
+TSIGError_toRcode(const s_TSIGError* const self) {
+ typedef CPPPyObjectContainer<s_Rcode, Rcode> RcodePyObjectContainer;
+
+ try {
+ RcodePyObjectContainer rcode_container(PyObject_New(s_Rcode,
+ &rcode_type));
+ rcode_container.set(new Rcode(self->cppobj->toRcode()));
+ return (rcode_container.release());
+ } catch (const exception& ex) {
+ const string ex_what =
+ "Failed to convert TSIGError to Rcode: " + string(ex.what());
+ PyErr_SetString(po_IscException, ex_what.c_str());
+ } catch (...) {
+ PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
+ "converting TSIGError to Rcode");
+ }
+ return (NULL);
+}
+
+PyObject*
+TSIGError_richcmp(const s_TSIGError* const self,
+ const s_TSIGError* const other,
+ const int op)
+{
+ bool c = false;
+
+ // Check for null and if the types match. If different type,
+ // simply return False
+ if (other == NULL || (self->ob_type != other->ob_type)) {
+ Py_RETURN_FALSE;
+ }
+
+ // Only equals and not equals here, unorderable type
+ switch (op) {
+ case Py_LT:
+ PyErr_SetString(PyExc_TypeError, "Unorderable type; TSIGError");
+ return (NULL);
+ case Py_LE:
+ PyErr_SetString(PyExc_TypeError, "Unorderable type; TSIGError");
+ return (NULL);
+ case Py_EQ:
+ c = (*self->cppobj == *other->cppobj);
+ break;
+ case Py_NE:
+ c = (*self->cppobj != *other->cppobj);
+ break;
+ case Py_GT:
+ PyErr_SetString(PyExc_TypeError, "Unorderable type; TSIGError");
+ return (NULL);
+ case Py_GE:
+ PyErr_SetString(PyExc_TypeError, "Unorderable type; TSIGError");
+ return (NULL);
+ }
+ if (c) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+} // end of unnamed namespace
+
+namespace isc {
+namespace dns {
+namespace python {
+// This defines the complete type for reflection in python and
+// parsing of PyObject* to s_TSIGError
+// Most of the functions are not actually implemented and NULL here.
+PyTypeObject tsigerror_type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "libdns_python.TSIGError",
+ sizeof(s_TSIGError), // tp_basicsize
+ 0, // tp_itemsize
+ reinterpret_cast<destructor>(TSIGError_destroy), // tp_dealloc
+ NULL, // tp_print
+ NULL, // tp_getattr
+ NULL, // tp_setattr
+ NULL, // tp_reserved
+ NULL, // tp_repr
+ NULL, // tp_as_number
+ NULL, // tp_as_sequence
+ NULL, // tp_as_mapping
+ NULL, // tp_hash
+ NULL, // tp_call
+ // THIS MAY HAVE TO BE CHANGED TO NULL:
+ TSIGError_str, // tp_str
+ NULL, // tp_getattro
+ NULL, // tp_setattro
+ NULL, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT, // tp_flags
+ TSIGError_doc,
+ NULL, // tp_traverse
+ NULL, // tp_clear
+ // THIS MAY HAVE TO BE CHANGED TO NULL:
+ reinterpret_cast<richcmpfunc>(TSIGError_richcmp), // tp_richcompare
+ 0, // tp_weaklistoffset
+ NULL, // tp_iter
+ NULL, // tp_iternext
+ TSIGError_methods, // tp_methods
+ NULL, // tp_members
+ NULL, // tp_getset
+ NULL, // tp_base
+ NULL, // tp_dict
+ NULL, // tp_descr_get
+ NULL, // tp_descr_set
+ 0, // tp_dictoffset
+ reinterpret_cast<initproc>(TSIGError_init), // tp_init
+ NULL, // tp_alloc
+ PyType_GenericNew, // tp_new
+ NULL, // tp_free
+ NULL, // tp_is_gc
+ NULL, // tp_bases
+ NULL, // tp_mro
+ NULL, // tp_cache
+ NULL, // tp_subclasses
+ NULL, // tp_weaklist
+ NULL, // tp_del
+ 0 // tp_version_tag
+};
+
+namespace {
+// Trivial shortcut to create and install TSIGError constants.
+inline void
+installTSIGErrorConstant(const char* name, const TSIGError& val) {
+ TSIGErrorContainer container(PyObject_New(s_TSIGError, &tsigerror_type));
+ container.installAsClassVariable(tsigerror_type, name, new TSIGError(val));
+}
+}
+
+// Module Initialization, all statics are initialized here
+bool
+initModulePart_TSIGError(PyObject* mod) {
+ // We initialize the static description object with PyType_Ready(),
+ // then add it to the module. This is not just a check! (leaving
+ // this out results in segmentation faults)
+ if (PyType_Ready(&tsigerror_type) < 0) {
+ return (false);
+ }
+ void* p = &tsigerror_type;
+ if (PyModule_AddObject(mod, "TSIGError", static_cast<PyObject*>(p)) < 0) {
+ return (false);
+ }
+ Py_INCREF(&tsigerror_type);
+
+ try {
+ // Constant class variables
+ // Error codes (bare values)
+ installClassVariable(tsigerror_type, "BAD_SIG_CODE",
+ Py_BuildValue("H", TSIGError::BAD_SIG_CODE));
+ installClassVariable(tsigerror_type, "BAD_KEY_CODE",
+ Py_BuildValue("H", TSIGError::BAD_KEY_CODE));
+ installClassVariable(tsigerror_type, "BAD_TIME_CODE",
+ Py_BuildValue("H", TSIGError::BAD_TIME_CODE));
+
+ // Error codes (constant objects)
+ installTSIGErrorConstant("NOERROR", TSIGError::NOERROR());
+ installTSIGErrorConstant("FORMERR", TSIGError::FORMERR());
+ installTSIGErrorConstant("SERVFAIL", TSIGError::SERVFAIL());
+ installTSIGErrorConstant("NXDOMAIN", TSIGError::NXDOMAIN());
+ installTSIGErrorConstant("NOTIMP", TSIGError::NOTIMP());
+ installTSIGErrorConstant("REFUSED", TSIGError::REFUSED());
+ installTSIGErrorConstant("YXDOMAIN", TSIGError::YXDOMAIN());
+ installTSIGErrorConstant("YXRRSET", TSIGError::YXRRSET());
+ installTSIGErrorConstant("NXRRSET", TSIGError::NXRRSET());
+ installTSIGErrorConstant("NOTAUTH", TSIGError::NOTAUTH());
+ installTSIGErrorConstant("NOTZONE", TSIGError::NOTZONE());
+ installTSIGErrorConstant("RESERVED11", TSIGError::RESERVED11());
+ installTSIGErrorConstant("RESERVED12", TSIGError::RESERVED12());
+ installTSIGErrorConstant("RESERVED13", TSIGError::RESERVED13());
+ installTSIGErrorConstant("RESERVED14", TSIGError::RESERVED14());
+ installTSIGErrorConstant("RESERVED15", TSIGError::RESERVED15());
+ installTSIGErrorConstant("BAD_SIG", TSIGError::BAD_SIG());
+ installTSIGErrorConstant("BAD_KEY", TSIGError::BAD_KEY());
+ installTSIGErrorConstant("BAD_TIME", TSIGError::BAD_TIME());
+ } catch (const exception& ex) {
+ const string ex_what =
+ "Unexpected failure in TSIGError initialization: " +
+ string(ex.what());
+ PyErr_SetString(po_IscException, ex_what.c_str());
+ return (false);
+ } catch (...) {
+ PyErr_SetString(PyExc_SystemError,
+ "Unexpected failure in TSIGError initialization");
+ return (false);
+ }
+
+ return (true);
+}
+} // namespace python
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/python/tsigerror_python.h b/src/lib/dns/python/tsigerror_python.h
new file mode 100644
index 0000000..f0c66cc
--- /dev/null
+++ b/src/lib/dns/python/tsigerror_python.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __PYTHON_TSIGERROR_H
+#define __PYTHON_TSIGERROR_H 1
+
+#include <Python.h>
+
+namespace isc {
+namespace dns {
+class TSIGError;
+
+namespace python {
+
+// The s_* Class simply covers one instantiation of the object
+class s_TSIGError : public PyObject {
+public:
+ s_TSIGError();
+ const TSIGError* cppobj;
+};
+
+extern PyTypeObject tsigerror_type;
+
+bool initModulePart_TSIGError(PyObject* mod);
+
+} // namespace python
+} // namespace dns
+} // namespace isc
+#endif // __PYTHON_TSIGERROR_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/python/tsigerror_python_inc.cc b/src/lib/dns/python/tsigerror_python_inc.cc
new file mode 100644
index 0000000..ed3b605
--- /dev/null
+++ b/src/lib/dns/python/tsigerror_python_inc.cc
@@ -0,0 +1,83 @@
+namespace {
+const char* const TSIGError_doc = "\n\
+TSIG errors.\n\
+\n\
+\n\
+The TSIGError class objects represent standard errors related to TSIG\n\
+protocol operations as defined in related specifications, mainly in\n\
+RFC2845.\n\
+\n\
+TSIGError(error_code)\n\
+\n\
+Constructor from the code value.\n\
+\n\
+Exceptions:\n\
+ None: \n\
+\n\
+Parameters:\n\
+ error_code: The underlying 16-bit error code value of the TSIGError.\n\
+\n\
+TSIGError(rcode)\n\
+\n\
+Constructor from Rcode.\n\
+\n\
+As defined in RFC2845, error code values from 0 to 15 (inclusive) are\n\
+derived from the DNS RCODEs, which are represented via the Rcode class\n\
+in this library. This constructor works as a converter from these\n\
+RCODEs to corresponding TSIGError objects.\n\
+\n\
+Exceptions:\n\
+ ValueError: Given rcode is not convertible to TSIGErrors.\n\
+\n\
+Parameters:\n\
+ rcode: the Rcode from which the TSIGError should be derived.\n\
+\n\
+";
+const char* const TSIGError_getCode_doc = "get_code() -> integer\n\
+\n\
+Returns the TSIGCode error code value.\n\
+\n\
+Exceptions:\n\
+ None: \n\
+\n\
+Return Value(s):\n\
+ The underlying code value corresponding to the TSIGError.\n\
+";
+const char* const TSIGError_toText_doc = "to_text() -> string\n\
+\n\
+Convert the TSIGError to a string.\n\
+\n\
+For codes derived from RCODEs up to 15, this method returns the same\n\
+string as Rcode.to_text() for the corresponding code. For other pre-\n\
+defined code values (see TSIGError.CodeValue), this method returns a\n\
+string representation of the \"mnemonic' used for the enum and\n\
+constant objects as defined in RFC2845. For example, the string for\n\
+code value 16 is \"BADSIG\", etc. For other code values it returns a\n\
+string representation of the decimal number of the value, e.g. \"32\",\n\
+\"100\", etc.\n\
+\n\
+Exceptions:\n\
+ None\n\
+\n\
+Return Value(s):\n\
+ A string representation of the TSIGError.\n\
+";
+const char* const TSIGError_toRcode_doc = "to_rcode() -> Rcode\n\
+\n\
+Convert the TSIGError to a Rcode.\n\
+\n\
+This method returns an Rcode object that is corresponding to the TSIG\n\
+error. The returned Rcode is expected to be used by a verifying server\n\
+to specify the RCODE of a response when TSIG verification fails.\n\
+\n\
+Specifically, this method returns Rcode.NOTAUTH() for the TSIG\n\
+specific errors, BADSIG, BADKEY, BADTIME, as described in RFC2845. For\n\
+errors derived from the standard Rcode (code 0-15), it returns the\n\
+corresponding Rcode. For others, this method returns Rcode.SERVFAIL()\n\
+as a last resort.\n\
+\n\
+Exceptions:\n\
+ None: \n\
+\n\
+";
+}
diff --git a/src/lib/dns/python/tsigkey_python.cc b/src/lib/dns/python/tsigkey_python.cc
index aa87909..4ca7bcd 100644
--- a/src/lib/dns/python/tsigkey_python.cc
+++ b/src/lib/dns/python/tsigkey_python.cc
@@ -55,6 +55,7 @@ void TSIGKey_destroy(s_TSIGKey* self);
PyObject* TSIGKey_getKeyName(const s_TSIGKey* self);
PyObject* TSIGKey_getAlgorithmName(const s_TSIGKey* self);
PyObject* TSIGKey_getSecret(const s_TSIGKey* self);
+PyObject* TSIGKey_toText(const s_TSIGKey* self);
// This list contains the actual set of functions we have in
// python. Each entry has
@@ -72,6 +73,8 @@ PyMethodDef TSIGKey_methods[] = {
{ "get_secret",
reinterpret_cast<PyCFunction>(TSIGKey_getSecret), METH_NOARGS,
"Return the value of the TSIG secret." },
+ { "to_text", reinterpret_cast<PyCFunction>(TSIGKey_toText), METH_NOARGS,
+ "Returns the string representation (name:secret:algorithm)" },
{ NULL, NULL, 0, NULL }
};
@@ -148,27 +151,33 @@ createNameObject(const Name& source) {
int
TSIGKey_init(s_TSIGKey* self, PyObject* args) {
+ const char* str;
+
const s_Name* key_name;
const s_Name* algorithm_name;
PyObject* bytes_obj;
const char* secret;
Py_ssize_t secret_len;
- if (PyArg_ParseTuple(args, "O!O!O", &name_type, &key_name,
+
+ try {
+ if (PyArg_ParseTuple(args, "s", &str)) {
+ self->tsigkey = new TSIGKey(str);
+ return (0);
+ } else if (PyArg_ParseTuple(args, "O!O!O", &name_type, &key_name,
&name_type, &algorithm_name, &bytes_obj) &&
- PyObject_AsCharBuffer(bytes_obj, &secret, &secret_len) != -1) {
- try {
- self->tsigkey = new TSIGKey(*key_name->name,
- *algorithm_name->name,
- secret, secret_len);
- } catch (const isc::InvalidParameter& ex) {
- PyErr_SetString(po_InvalidParameter, ex.what());
- return (-1);
- } catch (...) {
- PyErr_SetString(po_IscException, "Unexpected exception");
- return (-1);
+ PyObject_AsCharBuffer(bytes_obj, &secret, &secret_len) != -1) {
+ self->tsigkey = new TSIGKey(*key_name->name,
+ *algorithm_name->name,
+ secret, secret_len);
+ return (0);
}
- return (0);
+ } catch (const isc::InvalidParameter& ex) {
+ PyErr_SetString(po_InvalidParameter, ex.what());
+ return (-1);
+ } catch (...) {
+ PyErr_SetString(po_IscException, "Unexpected exception");
+ return (-1);
}
PyErr_Clear();
@@ -201,6 +210,11 @@ TSIGKey_getSecret(const s_TSIGKey* const self) {
self->tsigkey->getSecretLength()));
}
+PyObject*
+TSIGKey_toText(const s_TSIGKey* self) {
+ return (Py_BuildValue("s", self->tsigkey->toText().c_str()));
+}
+
// Module Initialization, all statics are initialized here
bool
initModulePart_TSIGKey(PyObject* mod) {
@@ -402,10 +416,12 @@ TSIGKeyRing_remove(const s_TSIGKeyRing* self, PyObject* args) {
PyObject*
TSIGKeyRing_find(const s_TSIGKeyRing* self, PyObject* args) {
s_Name* key_name;
+ s_Name* algorithm_name;
- if (PyArg_ParseTuple(args, "O!", &name_type, &key_name)) {
+ if (PyArg_ParseTuple(args, "O!O!", &name_type, &key_name,
+ &name_type, &algorithm_name)) {
const TSIGKeyRing::FindResult result =
- self->keyring->find(*key_name->name);
+ self->keyring->find(*key_name->name, *algorithm_name->name);
if (result.key != NULL) {
s_TSIGKey* key = PyObject_New(s_TSIGKey, &tsigkey_type);
if (key == NULL) {
diff --git a/src/lib/dns/question.cc b/src/lib/dns/question.cc
index 723fc88..96e2a9c 100644
--- a/src/lib/dns/question.cc
+++ b/src/lib/dns/question.cc
@@ -56,7 +56,7 @@ Question::toWire(OutputBuffer& buffer) const {
}
unsigned int
-Question::toWire(MessageRenderer& renderer) const {
+Question::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeName(name_);
rrtype_.toWire(renderer);
rrclass_.toWire(renderer);
diff --git a/src/lib/dns/question.h b/src/lib/dns/question.h
index 3c038b3..b3f3d98 100644
--- a/src/lib/dns/question.h
+++ b/src/lib/dns/question.h
@@ -32,7 +32,7 @@ class OutputBuffer;
namespace dns {
-class MessageRenderer;
+class AbstractMessageRenderer;
class Question;
/// \brief A pointer-like type pointing to an \c Question object.
@@ -218,13 +218,13 @@ public:
/// \param renderer DNS message rendering context that encapsulates the
/// output buffer and name compression information.
/// \return 1
- unsigned int toWire(MessageRenderer& renderer) const;
+ unsigned int toWire(AbstractMessageRenderer& renderer) const;
/// \brief Render the Question in the wire format without name compression.
///
/// This method behaves like the render version except it doesn't compress
/// the owner name.
- /// See \c toWire(MessageRenderer& renderer)const.
+ /// See \c toWire(AbstractMessageRenderer& renderer)const.
///
/// \param buffer An output buffer to store the wire data.
/// \return 1
diff --git a/src/lib/dns/rdata/any_255/tsig_250.cc b/src/lib/dns/rdata/any_255/tsig_250.cc
index f2bd7ad..8211e7f 100644
--- a/src/lib/dns/rdata/any_255/tsig_250.cc
+++ b/src/lib/dns/rdata/any_255/tsig_250.cc
@@ -24,7 +24,7 @@
#include <dns/messagerenderer.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
-
+#include <dns/tsigerror.h>
using namespace std;
using namespace boost;
@@ -313,15 +313,7 @@ TSIG::toText() const {
result += encodeBase64(impl_->mac_) + " ";
}
result += lexical_cast<string>(impl_->original_id_) + " ";
- if (impl_->error_ == 16) { // XXX: we'll soon introduce generic converter.
- result += "BADSIG ";
- } else if (impl_->error_ == 17) {
- result += "BADKEY ";
- } else if (impl_->error_ == 18) {
- result += "BADTIME ";
- } else {
- result += lexical_cast<string>(impl_->error_) + " ";
- }
+ result += TSIGError(impl_->error_).toText() + " ";
result += lexical_cast<string>(impl_->other_data_.size());
if (impl_->other_data_.size() > 0) {
result += " " + encodeBase64(impl_->other_data_);
diff --git a/src/lib/dns/rrclass-placeholder.h b/src/lib/dns/rrclass-placeholder.h
index ae3ff6f..80035d8 100644
--- a/src/lib/dns/rrclass-placeholder.h
+++ b/src/lib/dns/rrclass-placeholder.h
@@ -31,7 +31,7 @@ class OutputBuffer;
namespace dns {
// forward declarations
-class MessageRenderer;
+class AbstractMessageRenderer;
///
/// \brief A standard DNS module exception that is thrown if an RRClass object
@@ -169,7 +169,7 @@ public:
/// standard exception will be thrown.
///
/// \param buffer An output buffer to store the wire data.
- void toWire(MessageRenderer& renderer) const;
+ void toWire(AbstractMessageRenderer& renderer) const;
/// \brief Render the \c RRClass in the wire format.
///
/// This method renders the class code in network byte order into the
diff --git a/src/lib/dns/rrclass.cc b/src/lib/dns/rrclass.cc
index f1bb8d7..a28e5cf 100644
--- a/src/lib/dns/rrclass.cc
+++ b/src/lib/dns/rrclass.cc
@@ -52,7 +52,7 @@ RRClass::toWire(OutputBuffer& buffer) const {
}
void
-RRClass::toWire(MessageRenderer& renderer) const {
+RRClass::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeUint16(classcode_);
}
diff --git a/src/lib/dns/rrset.cc b/src/lib/dns/rrset.cc
index e80afdb..776d49f 100644
--- a/src/lib/dns/rrset.cc
+++ b/src/lib/dns/rrset.cc
@@ -104,8 +104,8 @@ AbstractRRset::toWire(OutputBuffer& buffer) const {
}
unsigned int
-AbstractRRset::toWire(MessageRenderer& renderer) const {
- const unsigned int rrs_written = rrsetToWire<MessageRenderer>(
+AbstractRRset::toWire(AbstractMessageRenderer& renderer) const {
+ const unsigned int rrs_written = rrsetToWire<AbstractMessageRenderer>(
*this, renderer, renderer.getLengthLimit());
if (getRdataCount() > rrs_written) {
renderer.setTruncated();
@@ -202,7 +202,7 @@ BasicRRset::toWire(OutputBuffer& buffer) const {
}
unsigned int
-BasicRRset::toWire(MessageRenderer& renderer) const {
+BasicRRset::toWire(AbstractMessageRenderer& renderer) const {
return (AbstractRRset::toWire(renderer));
}
diff --git a/src/lib/dns/rrset.h b/src/lib/dns/rrset.h
index bf7adc0..6c15b53 100644
--- a/src/lib/dns/rrset.h
+++ b/src/lib/dns/rrset.h
@@ -47,7 +47,7 @@ class Name;
class RRType;
class RRClass;
class RRTTL;
-class MessageRenderer;
+class AbstractMessageRenderer;
class AbstractRRset;
class BasicRRset;
class RdataIterator;
@@ -311,7 +311,7 @@ public:
/// \return The number of RRs rendered. If the truncation is necessary
/// this value may be different from the number of RDATA objects contained
/// in the RRset.
- virtual unsigned int toWire(MessageRenderer& renderer) const = 0;
+ virtual unsigned int toWire(AbstractMessageRenderer& renderer) const = 0;
/// \brief Render the RRset in the wire format without any compression.
///
@@ -617,7 +617,7 @@ public:
///
/// This method simply uses the default implementation.
/// See \c AbstractRRset::toWire(MessageRenderer&)const.
- virtual unsigned int toWire(MessageRenderer& renderer) const;
+ virtual unsigned int toWire(AbstractMessageRenderer& renderer) const;
/// \brief Render the RRset in the wire format without any compression.
///
diff --git a/src/lib/dns/rrttl.cc b/src/lib/dns/rrttl.cc
index a4c4f83..ecd8cc6 100644
--- a/src/lib/dns/rrttl.cc
+++ b/src/lib/dns/rrttl.cc
@@ -63,7 +63,7 @@ RRTTL::toWire(OutputBuffer& buffer) const {
}
void
-RRTTL::toWire(MessageRenderer& renderer) const {
+RRTTL::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeUint32(ttlval_);
}
diff --git a/src/lib/dns/rrttl.h b/src/lib/dns/rrttl.h
index 17ec891..bf23295 100644
--- a/src/lib/dns/rrttl.h
+++ b/src/lib/dns/rrttl.h
@@ -28,7 +28,7 @@ class OutputBuffer;
namespace dns {
// forward declarations
-class MessageRenderer;
+class AbstractMessageRenderer;
///
/// \brief A standard DNS module exception that is thrown if an RRTTL object
@@ -123,7 +123,7 @@ public:
///
/// \param renderer DNS message rendering context that encapsulates the
/// output buffer in which the RRTTL is to be stored.
- void toWire(MessageRenderer& renderer) const;
+ void toWire(AbstractMessageRenderer& renderer) const;
/// \brief Render the \c RRTTL in the wire format.
///
/// This method renders the TTL value in network byte order into the
diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am
index fdd6e1e..9783beb 100644
--- a/src/lib/dns/tests/Makefile.am
+++ b/src/lib/dns/tests/Makefile.am
@@ -20,6 +20,7 @@ TESTS += run_unittests
run_unittests_SOURCES = unittest_util.h unittest_util.cc
run_unittests_SOURCES += edns_unittest.cc
run_unittests_SOURCES += messagerenderer_unittest.cc
+run_unittests_SOURCES += name_unittest.cc
run_unittests_SOURCES += rrclass_unittest.cc rrtype_unittest.cc
run_unittests_SOURCES += rrttl_unittest.cc
run_unittests_SOURCES += opcode_unittest.cc
@@ -46,13 +47,18 @@ run_unittests_SOURCES += question_unittest.cc
run_unittests_SOURCES += rrparamregistry_unittest.cc
run_unittests_SOURCES += masterload_unittest.cc
run_unittests_SOURCES += message_unittest.cc
+run_unittests_SOURCES += tsig_unittest.cc
+run_unittests_SOURCES += tsigerror_unittest.cc
run_unittests_SOURCES += tsigkey_unittest.cc
+run_unittests_SOURCES += tsigrecord_unittest.cc
run_unittests_SOURCES += run_unittests.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/io/libutil_io.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
endif
diff --git a/src/lib/dns/tests/message_unittest.cc b/src/lib/dns/tests/message_unittest.cc
index 4031e4f..c79ea2c 100644
--- a/src/lib/dns/tests/message_unittest.cc
+++ b/src/lib/dns/tests/message_unittest.cc
@@ -12,9 +12,18 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <fstream>
+
+#include <boost/scoped_ptr.hpp>
+
#include <exceptions/exceptions.h>
#include <util/buffer.h>
+#include <util/time_utilities.h>
+
+#include <util/unittests/testdata.h>
+#include <util/unittests/textdata.h>
+
#include <dns/edns.h>
#include <dns/exceptions.h>
#include <dns/message.h>
@@ -26,6 +35,8 @@
#include <dns/rrclass.h>
#include <dns/rrttl.h>
#include <dns/rrtype.h>
+#include <dns/tsig.h>
+#include <dns/tsigkey.h>
#include <gtest/gtest.h>
@@ -53,6 +64,18 @@ using namespace isc::dns::rdata;
const uint16_t Message::DEFAULT_MAX_UDPSIZE;
const Name test_name("test.example.com");
+namespace isc {
+namespace util {
+namespace detail {
+extern int64_t (*gettimeFunction)();
+}
+}
+}
+
+// XXX: this is defined as class static constants, but some compilers
+// seemingly cannot find the symbol when used in the EXPECT_xxx macros.
+const uint16_t TSIGContext::DEFAULT_FUDGE;
+
namespace {
class MessageTest : public ::testing::Test {
protected:
@@ -60,7 +83,9 @@ protected:
message_parse(Message::PARSE),
message_render(Message::RENDER),
bogus_section(static_cast<Message::Section>(
- Message::SECTION_ADDITIONAL + 1))
+ Message::SECTION_ADDITIONAL + 1)),
+ tsig_ctx(TSIGKey("www.example.com:"
+ "SFuWd/q99SzF8Yzd1QbB9g=="))
{
rrset_a = RRsetPtr(new RRset(test_name, RRClass::IN(),
RRType::A(), RRTTL(3600)));
@@ -88,6 +113,9 @@ protected:
RRsetPtr rrset_a; // A RRset with two RDATAs
RRsetPtr rrset_aaaa; // AAAA RRset with one RDATA with RRSIG
RRsetPtr rrset_rrsig; // RRSIG for the AAAA RRset
+ TSIGContext tsig_ctx;
+ vector<unsigned char> expected_data;
+
static void factoryFromFile(Message& message, const char* datafile);
};
@@ -166,6 +194,70 @@ TEST_F(MessageTest, setEDNS) {
EXPECT_EQ(edns, message_render.getEDNS());
}
+TEST_F(MessageTest, fromWireWithTSIG) {
+ // Initially there should be no TSIG
+ EXPECT_EQ(static_cast<void*>(NULL), message_parse.getTSIGRecord());
+
+ // getTSIGRecord() is only valid in the parse mode.
+ EXPECT_THROW(message_render.getTSIGRecord(), InvalidMessageOperation);
+
+ factoryFromFile(message_parse, "message_toWire2.wire");
+ const char expected_mac[] = {
+ 0x22, 0x70, 0x26, 0xad, 0x29, 0x7b, 0xee, 0xe7,
+ 0x21, 0xce, 0x6c, 0x6f, 0xff, 0x1e, 0x9e, 0xf3
+ };
+ const TSIGRecord* tsig_rr = message_parse.getTSIGRecord();
+ ASSERT_NE(static_cast<void*>(NULL), tsig_rr);
+ EXPECT_EQ(Name("www.example.com"), tsig_rr->getName());
+ EXPECT_EQ(85, tsig_rr->getLength()); // see TSIGRecordTest.getLength
+ EXPECT_EQ(TSIGKey::HMACMD5_NAME(), tsig_rr->getRdata().getAlgorithm());
+ EXPECT_EQ(0x4da8877a, tsig_rr->getRdata().getTimeSigned());
+ EXPECT_EQ(TSIGContext::DEFAULT_FUDGE, tsig_rr->getRdata().getFudge());
+ EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+ tsig_rr->getRdata().getMAC(),
+ tsig_rr->getRdata().getMACSize(),
+ expected_mac, sizeof(expected_mac));
+ EXPECT_EQ(0, tsig_rr->getRdata().getError());
+ EXPECT_EQ(0, tsig_rr->getRdata().getOtherLen());
+ EXPECT_EQ(static_cast<void*>(NULL), tsig_rr->getRdata().getOtherData());
+
+ // If we clear the message for reuse, the recorded TSIG will be cleared.
+ message_parse.clear(Message::PARSE);
+ EXPECT_EQ(static_cast<void*>(NULL), message_parse.getTSIGRecord());
+}
+
+TEST_F(MessageTest, fromWireWithTSIGCompressed) {
+ // Mostly same as fromWireWithTSIG, but the TSIG owner name is compressed.
+ factoryFromFile(message_parse, "message_fromWire12.wire");
+ const TSIGRecord* tsig_rr = message_parse.getTSIGRecord();
+ ASSERT_NE(static_cast<void*>(NULL), tsig_rr);
+ EXPECT_EQ(Name("www.example.com"), tsig_rr->getName());
+ // len(www.example.com) = 17, but when fully compressed, the length is
+ // 2 bytes. So the length of the record should be 15 bytes shorter.
+ EXPECT_EQ(70, tsig_rr->getLength());
+}
+
+TEST_F(MessageTest, fromWireWithBadTSIG) {
+ // Multiple TSIG RRs
+ EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire13.wire"),
+ DNSMessageFORMERR);
+ message_parse.clear(Message::PARSE);
+
+ // TSIG in the answer section (must be in additional)
+ EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire14.wire"),
+ DNSMessageFORMERR);
+ message_parse.clear(Message::PARSE);
+
+ // TSIG is not the last record.
+ EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire15.wire"),
+ DNSMessageFORMERR);
+ message_parse.clear(Message::PARSE);
+
+ // Unexpected RR Class (this will fail in constructing TSIGRecord)
+ EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire16.wire"),
+ DNSMessageFORMERR);
+}
+
TEST_F(MessageTest, getRRCount) {
// by default all counters should be 0
EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_QUESTION));
@@ -519,6 +611,65 @@ TEST_F(MessageTest, toWireInParseMode) {
EXPECT_THROW(message_parse.toWire(renderer), InvalidMessageOperation);
}
+// See dnssectime_unittest.cc
+template <int64_t NOW>
+int64_t
+testGetTime() {
+ return (NOW);
+}
+
+void
+commonTSIGToWireCheck(Message& message, MessageRenderer& renderer,
+ TSIGContext& tsig_ctx, const char* const expected_file)
+{
+ message.setOpcode(Opcode::QUERY());
+ message.setRcode(Rcode::NOERROR());
+ message.setHeaderFlag(Message::HEADERFLAG_RD, true);
+ message.addQuestion(Question(Name("www.example.com"), RRClass::IN(),
+ RRType::A()));
+
+ message.toWire(renderer, tsig_ctx);
+ vector<unsigned char> expected_data;
+ UnitTestUtil::readWireData(expected_file, expected_data);
+ EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+ renderer.getLength(),
+ &expected_data[0], expected_data.size());
+}
+
+TEST_F(MessageTest, toWireWithTSIG) {
+ // Rendering a message with TSIG. Various special cases specific to
+ // TSIG are tested in the tsig tests. We only check the message contains
+ // a TSIG at the end and the ARCOUNT of the header is updated.
+
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ message_render.setQid(0x2d65);
+
+ {
+ SCOPED_TRACE("Message sign with TSIG");
+ commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
+ "message_toWire2.wire");
+ }
+}
+
+TEST_F(MessageTest, toWireWithEDNSAndTSIG) {
+ // Similar to the previous test, but with an EDNS before TSIG.
+ // The wire data check will confirm the ordering.
+ isc::util::detail::gettimeFunction = testGetTime<0x4db60d1f>;
+
+ message_render.setQid(0x6cd);
+
+ EDNSPtr edns(new EDNS());
+ edns->setUDPSize(4096);
+ message_render.setEDNS(edns);
+
+ {
+ SCOPED_TRACE("Message sign with TSIG and EDNS");
+ commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
+ "message_toWire3.wire");
+ }
+}
+
TEST_F(MessageTest, toWireWithoutOpcode) {
message_render.setRcode(Rcode::NOERROR());
EXPECT_THROW(message_render.toWire(renderer), InvalidMessageOperation);
@@ -529,6 +680,45 @@ TEST_F(MessageTest, toWireWithoutRcode) {
EXPECT_THROW(message_render.toWire(renderer), InvalidMessageOperation);
}
+TEST_F(MessageTest, toText) {
+ // Check toText() output for a typical DNS response with records in
+ // all sections
+
+ factoryFromFile(message_parse, "message_toText1.wire");
+ {
+ SCOPED_TRACE("Message toText test (basic case)");
+ ifstream ifs;
+ unittests::openTestData("message_toText1.txt", ifs);
+ unittests::matchTextData(ifs, message_parse.toText());
+ }
+
+ // Another example with EDNS. The expected data was slightly modified
+ // from the dig output (other than replacing tabs with a space): adding
+ // a newline after the "OPT PSEUDOSECTION". This is an intentional change
+ // in our version for better readability.
+ message_parse.clear(Message::PARSE);
+ factoryFromFile(message_parse, "message_toText2.wire");
+ {
+ SCOPED_TRACE("Message toText test with EDNS");
+ ifstream ifs;
+ unittests::openTestData("message_toText2.txt", ifs);
+ unittests::matchTextData(ifs, message_parse.toText());
+ }
+
+ // Another example with TSIG. The expected data was slightly modified
+ // from the dig output (other than replacing tabs with a space): removing
+ // a redundant white space at the end of TSIG RDATA. We'd rather consider
+ // it a dig's defect than a feature.
+ message_parse.clear(Message::PARSE);
+ factoryFromFile(message_parse, "message_toText3.wire");
+ {
+ SCOPED_TRACE("Message toText test with TSIG");
+ ifstream ifs;
+ unittests::openTestData("message_toText3.txt", ifs);
+ unittests::matchTextData(ifs, message_parse.toText());
+ }
+}
+
TEST_F(MessageTest, toTextWithoutOpcode) {
message_render.setRcode(Rcode::NOERROR());
EXPECT_THROW(message_render.toText(), InvalidMessageOperation);
diff --git a/src/lib/dns/tests/run_unittests.cc b/src/lib/dns/tests/run_unittests.cc
index 3cdc61d..18eb0a5 100644
--- a/src/lib/dns/tests/run_unittests.cc
+++ b/src/lib/dns/tests/run_unittests.cc
@@ -14,13 +14,16 @@
#include <gtest/gtest.h>
+#include <util/unittests/testdata.h>
#include <dns/tests/unittest_util.h>
int
main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
isc::UnitTestUtil::addDataPath(TEST_DATA_SRCDIR);
+ isc::util::unittests::addTestDataPath(TEST_DATA_SRCDIR);
isc::UnitTestUtil::addDataPath(TEST_DATA_BUILDDIR);
+ isc::util::unittests::addTestDataPath(TEST_DATA_BUILDDIR);
return (RUN_ALL_TESTS());
}
diff --git a/src/lib/dns/tests/testdata/Makefile.am b/src/lib/dns/tests/testdata/Makefile.am
index 31771bb..cb1bb1c 100644
--- a/src/lib/dns/tests/testdata/Makefile.am
+++ b/src/lib/dns/tests/testdata/Makefile.am
@@ -3,6 +3,12 @@ CLEANFILES = *.wire
BUILT_SOURCES = edns_toWire1.wire edns_toWire2.wire edns_toWire3.wire
BUILT_SOURCES += edns_toWire4.wire
BUILT_SOURCES += message_fromWire10.wire message_fromWire11.wire
+BUILT_SOURCES += message_fromWire12.wire message_fromWire13.wire
+BUILT_SOURCES += message_fromWire14.wire message_fromWire15.wire
+BUILT_SOURCES += message_fromWire16.wire
+BUILT_SOURCES += message_toWire2.wire message_toWire3.wire
+BUILT_SOURCES += message_toText1.wire message_toText2.wire
+BUILT_SOURCES += message_toText3.wire
BUILT_SOURCES += name_toWire5.wire name_toWire6.wire
BUILT_SOURCES += rdatafields1.wire rdatafields2.wire rdatafields3.wire
BUILT_SOURCES += rdatafields4.wire rdatafields5.wire rdatafields6.wire
@@ -33,6 +39,11 @@ BUILT_SOURCES += rdata_tsig_fromWire9.wire
BUILT_SOURCES += rdata_tsig_toWire1.wire rdata_tsig_toWire2.wire
BUILT_SOURCES += rdata_tsig_toWire3.wire rdata_tsig_toWire4.wire
BUILT_SOURCES += rdata_tsig_toWire5.wire
+BUILT_SOURCES += tsigrecord_toWire1.wire tsigrecord_toWire2.wire
+BUILT_SOURCES += tsig_verify1.wire tsig_verify2.wire tsig_verify3.wire
+BUILT_SOURCES += tsig_verify4.wire tsig_verify5.wire tsig_verify6.wire
+BUILT_SOURCES += tsig_verify7.wire tsig_verify8.wire tsig_verify9.wire
+BUILT_SOURCES += tsig_verify10.wire
# NOTE: keep this in sync with real file listing
# so is included in tarball
@@ -45,8 +56,13 @@ EXTRA_DIST += message_fromWire3 message_fromWire4
EXTRA_DIST += message_fromWire5 message_fromWire6
EXTRA_DIST += message_fromWire7 message_fromWire8
EXTRA_DIST += message_fromWire9 message_fromWire10.spec
-EXTRA_DIST += message_fromWire11.spec
-EXTRA_DIST += message_toWire1
+EXTRA_DIST += message_fromWire11.spec message_fromWire12.spec
+EXTRA_DIST += message_fromWire13.spec message_fromWire14.spec
+EXTRA_DIST += message_fromWire15.spec message_fromWire16.spec
+EXTRA_DIST += message_toWire1 message_toWire2.spec message_toWire3.spec
+EXTRA_DIST += message_toText1.txt message_toText1.spec
+EXTRA_DIST += message_toText2.txt message_toText2.spec
+EXTRA_DIST += message_toText3.txt message_toText3.spec
EXTRA_DIST += name_fromWire1 name_fromWire2 name_fromWire3_1 name_fromWire3_2
EXTRA_DIST += name_fromWire4 name_fromWire6 name_fromWire7 name_fromWire8
EXTRA_DIST += name_fromWire9 name_fromWire10 name_fromWire11 name_fromWire12
@@ -66,7 +82,8 @@ EXTRA_DIST += rdata_nsec_fromWire6.spec rdata_nsec_fromWire7.spec
EXTRA_DIST += rdata_nsec_fromWire8.spec rdata_nsec_fromWire9.spec
EXTRA_DIST += rdata_nsec_fromWire10.spec
EXTRA_DIST += rdata_nsec3param_fromWire1
-EXTRA_DIST += rdata_nsec3_fromWire1 rdata_nsec3_fromWire3
+EXTRA_DIST += rdata_nsec3_fromWire1
+EXTRA_DIST += rdata_nsec3_fromWire2.spec rdata_nsec3_fromWire3
EXTRA_DIST += rdata_nsec3_fromWire4.spec rdata_nsec3_fromWire5.spec
EXTRA_DIST += rdata_nsec3_fromWire6.spec rdata_nsec3_fromWire7.spec
EXTRA_DIST += rdata_nsec3_fromWire8.spec rdata_nsec3_fromWire9.spec
@@ -94,7 +111,11 @@ EXTRA_DIST += rdata_tsig_fromWire9.spec
EXTRA_DIST += rdata_tsig_toWire1.spec rdata_tsig_toWire2.spec
EXTRA_DIST += rdata_tsig_toWire3.spec rdata_tsig_toWire4.spec
EXTRA_DIST += rdata_tsig_toWire5.spec
-EXTRA_DIST += rdata_nsec3_fromWire2.spec
+EXTRA_DIST += tsigrecord_toWire1.spec tsigrecord_toWire2.spec
+EXTRA_DIST += tsig_verify1.spec tsig_verify2.spec tsig_verify3.spec
+EXTRA_DIST += tsig_verify4.spec tsig_verify5.spec tsig_verify6.spec
+EXTRA_DIST += tsig_verify7.spec tsig_verify8.spec tsig_verify9.spec
+EXTRA_DIST += tsig_verify10.spec
.spec.wire:
./gen-wiredata.py -o $@ $<
diff --git a/src/lib/dns/tests/testdata/gen-wiredata.py.in b/src/lib/dns/tests/testdata/gen-wiredata.py.in
index 72cbdaa..fd98c6e 100755
--- a/src/lib/dns/tests/testdata/gen-wiredata.py.in
+++ b/src/lib/dns/tests/testdata/gen-wiredata.py.in
@@ -15,7 +15,7 @@
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-import configparser, re, time, sys
+import configparser, re, time, socket, sys
from datetime import datetime
from optparse import OptionParser
@@ -215,9 +215,76 @@ class EDNS:
f.write('# RDLEN=%d\n' % self.rdlen)
f.write('%04x\n' % self.rdlen)
-class SOA:
- # this currently doesn't support name compression within the RDATA.
- rdlen = -1 # auto-calculate
+class RR:
+ '''This is a base class for various types of RR test data.
+ For each RR type (A, AAAA, NS, etc), we define a derived class of RR
+ to dump type specific RDATA parameters. This class defines parameters
+ common to all types of RDATA, namely the owner name, RR class and TTL.
+ The dump() method of derived classes are expected to call dump_header(),
+ whose default implementation is provided in this class. This method
+ decides whether to dump the test data as an RR (with name, type, class)
+ or only as RDATA (with its length), and dumps the corresponding data
+ via the specified file object.
+
+ By convention we assume derived classes are named after the common
+ standard mnemonic of the corresponding RR types. For example, the
+ derived class for the RR type SOA should be named "SOA".
+
+ Configurable parameters are as follows:
+ - as_rr (bool): Whether or not the data is to be dumped as an RR. False
+ by default.
+ - rr_class (string): The RR class of the data. Only meaningful when the
+ data is dumped as an RR. Default is 'IN'.
+ - rr_ttl (integer): The TTL value of the RR. Only meaningful when the
+ data is dumped as an RR. Default is 86400 (1 day).
+ '''
+
+ def __init__(self):
+ self.as_rr = False
+ # only when as_rr is True, same for class/TTL:
+ self.rr_name = 'example.com'
+ self.rr_class = 'IN'
+ self.rr_ttl = 86400
+ def dump_header(self, f, rdlen):
+ type_txt = self.__class__.__name__
+ type_code = parse_value(type_txt, dict_rrtype)
+ if self.as_rr:
+ rrclass = parse_value(self.rr_class, dict_rrclass)
+ f.write('\n# %s RR (QNAME=%s Class=%s TTL=%d RDLEN=%d)\n' %
+ (type_txt, self.rr_name,
+ code_totext(rrclass, rdict_rrclass), self.rr_ttl, rdlen))
+ f.write('%s %04x %04x %08x %04x\n' %
+ (encode_name(self.rr_name), type_code, rrclass,
+ self.rr_ttl, rdlen))
+ else:
+ f.write('\n# %s RDATA (RDLEN=%d)\n' % (type_txt, rdlen))
+ f.write('%04x\n' % rdlen)
+
+class A(RR):
+ rdlen = 4 # fixed by default
+ address = '192.0.2.1'
+
+ def dump(self, f):
+ self.dump_header(f, self.rdlen)
+ f.write('# Address=%s\n' % (self.address))
+ bin_address = socket.inet_aton(self.address)
+ f.write('%02x%02x%02x%02x\n' % (bin_address[0], bin_address[1],
+ bin_address[2], bin_address[3]))
+
+class NS(RR):
+ rdlen = None # auto calculate
+ nsname = 'ns.example.com'
+
+ def dump(self, f):
+ nsname_wire = encode_name(self.nsname)
+ if self.rdlen is None:
+ self.rdlen = len(nsname_wire) / 2
+ self.dump_header(f, self.rdlen)
+ f.write('# NS name=%s\n' % (self.nsname))
+ f.write('%s\n' % nsname_wire)
+
+class SOA(RR):
+ rdlen = None # auto-calculate
mname = 'ns.example.com'
rname = 'root.example.com'
serial = 2010012601
@@ -228,11 +295,9 @@ class SOA:
def dump(self, f):
mname_wire = encode_name(self.mname)
rname_wire = encode_name(self.rname)
- rdlen = self.rdlen
- if rdlen < 0:
- rdlen = int(20 + len(mname_wire) / 2 + len(str(rname_wire)) / 2)
- f.write('\n# SOA RDATA (RDLEN=%d)\n' % rdlen)
- f.write('%04x\n' % rdlen);
+ if self.rdlen is None:
+ self.rdlen = int(20 + len(mname_wire) / 2 + len(str(rname_wire)) / 2)
+ self.dump_header(f, self.rdlen)
f.write('# NNAME=%s RNAME=%s\n' % (self.mname, self.rname))
f.write('%s %s\n' % (mname_wire, rname_wire))
f.write('# SERIAL(%d) REFRESH(%d) RETRY(%d) EXPIRE(%d) MINIMUM(%d)\n' %
@@ -432,7 +497,7 @@ class RRSIG:
f.write('# Tag=%d Signer=%s and Signature\n' % (self.tag, self.signer))
f.write('%04x %s %s\n' % (self.tag, name_wire, sig_wire))
-class TSIG:
+class TSIG(RR):
rdlen = None # auto-calculate
algorithm = 'hmac-sha256'
time_signed = 1286978795 # arbitrarily chosen default
@@ -444,12 +509,18 @@ class TSIG:
other_len = None # 6 if error is BADTIME; otherwise 0
other_data = None # use time_signed + fudge + 1 for BADTIME
dict_macsize = { 'hmac-md5' : 16, 'hmac-sha1' : 20, 'hmac-sha256' : 32 }
+
+ # TSIG has some special defaults
+ def __init__(self):
+ super().__init__()
+ self.rr_class = 'ANY'
+ self.rr_ttl = 0
+
def dump(self, f):
if str(self.algorithm) == 'hmac-md5':
name_wire = encode_name('hmac-md5.sig-alg.reg.int')
else:
name_wire = encode_name(self.algorithm)
- rdlen = self.rdlen
mac_size = self.mac_size
if mac_size is None:
if self.algorithm in self.dict_macsize.keys():
@@ -468,11 +539,10 @@ class TSIG:
if self.error == 18 else ''
else:
other_data = encode_string(self.other_data, other_len)
- if rdlen is None:
- rdlen = int(len(name_wire) / 2 + 16 + len(mac) / 2 + \
- len(other_data) / 2)
- f.write('\n# TSIG RDATA (RDLEN=%d)\n' % rdlen)
- f.write('%04x\n' % rdlen);
+ if self.rdlen is None:
+ self.rdlen = int(len(name_wire) / 2 + 16 + len(mac) / 2 + \
+ len(other_data) / 2)
+ self.dump_header(f, self.rdlen)
f.write('# Algorithm=%s Time-Signed=%d Fudge=%d\n' %
(self.algorithm, self.time_signed, self.fudge))
f.write('%s %012x %04x\n' % (name_wire, self.time_signed, self.fudge))
@@ -488,7 +558,8 @@ def get_config_param(section):
config_param = {'name' : (Name, {}),
'header' : (DNSHeader, header_xtables),
'question' : (DNSQuestion, question_xtables),
- 'edns' : (EDNS, {}), 'soa' : (SOA, {}), 'txt' : (TXT, {}),
+ 'edns' : (EDNS, {}), 'a' : (A, {}), 'ns' : (NS, {}),
+ 'soa' : (SOA, {}), 'txt' : (TXT, {}),
'rp' : (RP, {}), 'rrsig' : (RRSIG, {}),
'nsec' : (NSEC, {}), 'nsec3' : (NSEC3, {}),
'tsig' : (TSIG, {}) }
diff --git a/src/lib/dns/tests/testdata/message_fromWire12.spec b/src/lib/dns/tests/testdata/message_fromWire12.spec
new file mode 100644
index 0000000..4eadeed
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_fromWire12.spec
@@ -0,0 +1,21 @@
+#
+# A simple DNS response message with TSIG signed, but the owner name of TSIG
+# is compressed
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+rr_name: ptr=12
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/message_fromWire13.spec b/src/lib/dns/tests/testdata/message_fromWire13.spec
new file mode 100644
index 0000000..e81ec4c
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_fromWire13.spec
@@ -0,0 +1,20 @@
+#
+# Invalid TSIG: containing 2 TSIG RRs.
+#
+
+[custom]
+sections: header:question:tsig:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 2
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/message_fromWire14.spec b/src/lib/dns/tests/testdata/message_fromWire14.spec
new file mode 100644
index 0000000..bf68a93
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_fromWire14.spec
@@ -0,0 +1,21 @@
+#
+# Invalid TSIG: not in the additional section.
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+# TSIG goes to the answer section
+ancount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/message_fromWire15.spec b/src/lib/dns/tests/testdata/message_fromWire15.spec
new file mode 100644
index 0000000..25d810f
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_fromWire15.spec
@@ -0,0 +1,22 @@
+#
+# Invalid TSIG: not at the end of the message
+#
+
+[custom]
+sections: header:question:tsig:edns
+[header]
+id: 0x2d65
+rd: 1
+arcount: 2
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
+[edns]
+# (all default)
diff --git a/src/lib/dns/tests/testdata/message_fromWire16.spec b/src/lib/dns/tests/testdata/message_fromWire16.spec
new file mode 100644
index 0000000..be0abc3
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_fromWire16.spec
@@ -0,0 +1,21 @@
+#
+# Invalid TSIG: not in the additional section.
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+rr_class: IN
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/message_toText1.spec b/src/lib/dns/tests/testdata/message_toText1.spec
new file mode 100644
index 0000000..b31310e
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toText1.spec
@@ -0,0 +1,24 @@
+#
+# A standard DNS message (taken from an invocation of dig)
+#
+
+[custom]
+sections: header:question:a/1:ns:a/2
+[header]
+id: 29174
+qr: 1
+aa: 1
+ancount: 1
+nscount: 1
+arcount: 1
+[question]
+name: www.example.com
+[a/1]
+as_rr: True
+rr_name: www.example.com
+address: 192.0.2.80
+[ns]
+as_rr: True
+[a/2]
+as_rr: True
+rr_name: ns.example.com
diff --git a/src/lib/dns/tests/testdata/message_toText1.txt b/src/lib/dns/tests/testdata/message_toText1.txt
new file mode 100644
index 0000000..58c7239
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toText1.txt
@@ -0,0 +1,14 @@
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29174
+;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
+
+;; QUESTION SECTION:
+;www.example.com. IN A
+
+;; ANSWER SECTION:
+www.example.com. 86400 IN A 192.0.2.80
+
+;; AUTHORITY SECTION:
+example.com. 86400 IN NS ns.example.com.
+
+;; ADDITIONAL SECTION:
+ns.example.com. 86400 IN A 192.0.2.1
diff --git a/src/lib/dns/tests/testdata/message_toText2.spec b/src/lib/dns/tests/testdata/message_toText2.spec
new file mode 100644
index 0000000..978aab3
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toText2.spec
@@ -0,0 +1,14 @@
+#
+# A standard DNS message with EDNS (taken from an invocation of dig)
+#
+
+[custom]
+sections: header:question:edns
+[header]
+id: 45981
+qr: 1
+rcode: refused
+arcount: 1
+[question]
+[edns]
+do: 1
diff --git a/src/lib/dns/tests/testdata/message_toText2.txt b/src/lib/dns/tests/testdata/message_toText2.txt
new file mode 100644
index 0000000..42cc2c1
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toText2.txt
@@ -0,0 +1,8 @@
+;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 45981
+;; flags: qr; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
+
+;; OPT PSEUDOSECTION:
+; EDNS: version: 0, flags: do; udp: 4096
+
+;; QUESTION SECTION:
+;example.com. IN A
diff --git a/src/lib/dns/tests/testdata/message_toText3.spec b/src/lib/dns/tests/testdata/message_toText3.spec
new file mode 100644
index 0000000..a74ea1b
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toText3.spec
@@ -0,0 +1,31 @@
+#
+# A standard DNS message with TSIG (taken from an invocation of dig)
+#
+
+[custom]
+sections: header:question:a/1:ns:a/2:tsig
+[header]
+id: 10140
+qr: 1
+aa: 1
+ancount: 1
+nscount: 1
+arcount: 2
+[question]
+name: www.example.com
+[a/1]
+as_rr: True
+rr_name: www.example.com
+address: 192.0.2.80
+[ns]
+as_rr: True
+[a/2]
+as_rr: True
+rr_name: ns.example.com
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 1304384318
+original_id: 10140
+mac: 0x5257c80396f2fa95b20c77ae9a652fb2
diff --git a/src/lib/dns/tests/testdata/message_toText3.txt b/src/lib/dns/tests/testdata/message_toText3.txt
new file mode 100644
index 0000000..359b9c5
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toText3.txt
@@ -0,0 +1,17 @@
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10140
+;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2
+
+;; QUESTION SECTION:
+;www.example.com. IN A
+
+;; ANSWER SECTION:
+www.example.com. 86400 IN A 192.0.2.80
+
+;; AUTHORITY SECTION:
+example.com. 86400 IN NS ns.example.com.
+
+;; ADDITIONAL SECTION:
+ns.example.com. 86400 IN A 192.0.2.1
+
+;; TSIG PSEUDOSECTION:
+www.example.com. 0 ANY TSIG hmac-md5.sig-alg.reg.int. 1304384318 300 16 UlfIA5by+pWyDHeummUvsg== 10140 NOERROR 0
diff --git a/src/lib/dns/tests/testdata/message_toWire2.spec b/src/lib/dns/tests/testdata/message_toWire2.spec
new file mode 100644
index 0000000..d256052
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toWire2.spec
@@ -0,0 +1,21 @@
+#
+# A simple DNS query message with TSIG signed
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/message_toWire3.spec b/src/lib/dns/tests/testdata/message_toWire3.spec
new file mode 100644
index 0000000..c8e9453
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toWire3.spec
@@ -0,0 +1,22 @@
+#
+# A simple DNS query message with EDNS and TSIG
+#
+
+[custom]
+sections: header:question:edns:tsig
+[header]
+id: 0x06cd
+rd: 1
+arcount: 2
+[question]
+name: www.example.com
+[edns]
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4db60d1f
+mac_size: 16
+mac: 0x93444053881c83d7eb120e86f25b369e
+original_id: 0x06cd
diff --git a/src/lib/dns/tests/testdata/tsig_verify1.spec b/src/lib/dns/tests/testdata/tsig_verify1.spec
new file mode 100644
index 0000000..687013a
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify1.spec
@@ -0,0 +1,19 @@
+#
+# An example of signed AXFR request
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x3410
+arcount: 1
+[question]
+rrtype: AXFR
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8e951
+mac_size: 16
+mac: 0x35b2fd08268781634400c7c8a5533b13
+original_id: 0x3410
diff --git a/src/lib/dns/tests/testdata/tsig_verify10.spec b/src/lib/dns/tests/testdata/tsig_verify10.spec
new file mode 100644
index 0000000..33ce83e
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify10.spec
@@ -0,0 +1,22 @@
+#
+# A simple DNS query message with TSIG signed whose MAC is too short
+# (only 1 byte)
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 1
+mac: 0x22
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsig_verify2.spec b/src/lib/dns/tests/testdata/tsig_verify2.spec
new file mode 100644
index 0000000..ff98ca3
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify2.spec
@@ -0,0 +1,32 @@
+#
+# An example of signed AXFR response
+#
+
+[custom]
+sections: header:question:soa:tsig
+[header]
+id: 0x3410
+aa: 1
+qr: 1
+ancount: 1
+arcount: 1
+[question]
+rrtype: AXFR
+[soa]
+# note that names are compressed in this RR
+as_rr: True
+rr_name: ptr=12
+mname: ns.ptr=12
+rname: root.ptr=12
+serial: 2011041503
+refresh: 7200
+retry: 3600
+expire: 2592000
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8e951
+mac_size: 16
+mac: 0xbdd612cd2c7f9e0648bd6dc23713e83c
+original_id: 0x3410
diff --git a/src/lib/dns/tests/testdata/tsig_verify3.spec b/src/lib/dns/tests/testdata/tsig_verify3.spec
new file mode 100644
index 0000000..7e2f797
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify3.spec
@@ -0,0 +1,26 @@
+#
+# An example of signed AXFR response (continued)
+#
+
+[custom]
+sections: header:ns:tsig
+[header]
+id: 0x3410
+aa: 1
+qr: 1
+qdcount: 0
+ancount: 1
+arcount: 1
+[ns]
+# note that names are compressed in this RR
+as_rr: True
+rr_name: example.com.
+nsname: ns.ptr=12
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8e951
+mac_size: 16
+mac: 0x102458f7f62ddd7d638d746034130968
+original_id: 0x3410
diff --git a/src/lib/dns/tests/testdata/tsig_verify4.spec b/src/lib/dns/tests/testdata/tsig_verify4.spec
new file mode 100644
index 0000000..4ffbbcf
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify4.spec
@@ -0,0 +1,27 @@
+#
+# An example of signed DNS response with bogus MAC
+#
+
+[custom]
+sections: header:question:a:tsig
+[header]
+id: 0x2d65
+aa: 1
+qr: 1
+rd: 1
+ancount: 1
+arcount: 1
+[question]
+name: www.example.com
+[a]
+as_rr: True
+rr_name: ptr=12
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+# bogus MAC
+mac: 0xdeadbeefdeadbeefdeadbeefdeadbeef
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsig_verify5.spec b/src/lib/dns/tests/testdata/tsig_verify5.spec
new file mode 100644
index 0000000..a6cc643
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify5.spec
@@ -0,0 +1,26 @@
+#
+# An example of signed DNS response
+#
+
+[custom]
+sections: header:question:a:tsig
+[header]
+id: 0x2d65
+aa: 1
+qr: 1
+rd: 1
+ancount: 1
+arcount: 1
+[question]
+name: www.example.com
+[a]
+as_rr: True
+rr_name: ptr=12
+[tsig]
+as_rr: True
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x8fcda66a7cd1a3b9948eb1869d384a9f
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsig_verify6.spec b/src/lib/dns/tests/testdata/tsig_verify6.spec
new file mode 100644
index 0000000..32e0818
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify6.spec
@@ -0,0 +1,21 @@
+#
+# Forwarded DNS query message with TSIG signed (header ID != orig ID)
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x1035
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsig_verify7.spec b/src/lib/dns/tests/testdata/tsig_verify7.spec
new file mode 100644
index 0000000..377578e
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify7.spec
@@ -0,0 +1,21 @@
+#
+# DNS query message with TSIG that has empty MAC (invalidly)
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 0
+mac: ''
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsig_verify8.spec b/src/lib/dns/tests/testdata/tsig_verify8.spec
new file mode 100644
index 0000000..5432d4a
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify8.spec
@@ -0,0 +1,23 @@
+#
+# DNS query message with TSIG that has empty MAC + BADKEY error
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 0
+mac: ''
+# 17: BADKEY
+error: 17
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsig_verify9.spec b/src/lib/dns/tests/testdata/tsig_verify9.spec
new file mode 100644
index 0000000..5888455
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsig_verify9.spec
@@ -0,0 +1,21 @@
+#
+# A simple DNS query message with TSIG signed, but TSIG key and algorithm
+# names have upper case characters (unusual)
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+rr_name: WWW.EXAMPLE.COM
+algorithm: HMAC-MD5.SIG-ALG.REG.INT
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsigrecord_toWire1.spec b/src/lib/dns/tests/testdata/tsigrecord_toWire1.spec
new file mode 100644
index 0000000..a25dc46
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsigrecord_toWire1.spec
@@ -0,0 +1,16 @@
+#
+# A simple TSIG RR (some of the parameters are taken from a live example
+# and don't have a specific meaning)
+#
+
+[custom]
+sections: tsig
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0xdadadadadadadadadadadadadadadada
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsigrecord_toWire2.spec b/src/lib/dns/tests/testdata/tsigrecord_toWire2.spec
new file mode 100644
index 0000000..f667e4c
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsigrecord_toWire2.spec
@@ -0,0 +1,19 @@
+#
+# TSIG RR after some names that could (unexpectedly) cause name compression
+#
+
+[custom]
+sections: name/1:name/2:tsig
+[name/1]
+name: hmac-md5.sig-alg.reg.int
+[name/2]
+name: foo.example.com
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0xdadadadadadadadadadadadadadadada
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/tsig_unittest.cc b/src/lib/dns/tests/tsig_unittest.cc
new file mode 100644
index 0000000..55c3ac2
--- /dev/null
+++ b/src/lib/dns/tests/tsig_unittest.cc
@@ -0,0 +1,907 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <time.h>
+#include <string>
+#include <stdexcept>
+#include <vector>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <gtest/gtest.h>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <util/encode/base64.h>
+#include <util/unittests/newhook.h>
+#include <util/time_utilities.h>
+
+#include <dns/message.h>
+#include <dns/messagerenderer.h>
+#include <dns/question.h>
+#include <dns/opcode.h>
+#include <dns/rcode.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/tsig.h>
+#include <dns/tsigkey.h>
+#include <dns/tsigrecord.h>
+
+#include <dns/tests/unittest_util.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::util::encode;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+
+// See dnssectime.cc
+namespace isc {
+namespace util {
+namespace detail {
+extern int64_t (*gettimeFunction)();
+}
+}
+}
+
+namespace {
+// See dnssectime_unittest.cc
+template <int64_t NOW>
+int64_t
+testGetTime() {
+ return (NOW);
+}
+
+class TSIGTest : public ::testing::Test {
+protected:
+ TSIGTest() :
+ tsig_ctx(NULL), qid(0x2d65), test_name("www.example.com"),
+ badkey_name("badkey.example.com"), test_class(RRClass::IN()),
+ test_ttl(86400), message(Message::RENDER), buffer(0), renderer(buffer),
+ dummy_data(1024, 0xdd), // should be sufficiently large for all tests
+ dummy_record(badkey_name, any::TSIG(TSIGKey::HMACMD5_NAME(),
+ 0x4da8877a,
+ TSIGContext::DEFAULT_FUDGE,
+ 0, NULL, qid, 0, 0, NULL))
+ {
+ // Make sure we use the system time by default so that we won't be
+ // confused due to other tests that tweak the time.
+ isc::util::detail::gettimeFunction = NULL;
+
+ decodeBase64("SFuWd/q99SzF8Yzd1QbB9g==", secret);
+ tsig_ctx.reset(new TSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACMD5_NAME(),
+ &secret[0], secret.size())));
+ tsig_verify_ctx.reset(new TSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACMD5_NAME(),
+ &secret[0],
+ secret.size())));
+ }
+ ~TSIGTest() {
+ isc::util::detail::gettimeFunction = NULL;
+ }
+
+ // Many of the tests below create some DNS message and sign it under
+ // some specific TSIG context. This helper method unifies the common
+ // logic with slightly different parameters.
+ ConstTSIGRecordPtr createMessageAndSign(uint16_t qid, const Name& qname,
+ TSIGContext* ctx,
+ unsigned int message_flags =
+ RD_FLAG,
+ RRType qtype = RRType::A(),
+ const char* answer_data = NULL,
+ const RRType* answer_type = NULL,
+ bool add_question = true,
+ Rcode rcode = Rcode::NOERROR());
+
+ void createMessageFromFile(const char* datafile);
+
+ // bit-wise constant flags to configure DNS header flags for test
+ // messages.
+ static const unsigned int QR_FLAG = 0x1;
+ static const unsigned int AA_FLAG = 0x2;
+ static const unsigned int RD_FLAG = 0x4;
+
+ boost::scoped_ptr<TSIGContext> tsig_ctx;
+ boost::scoped_ptr<TSIGContext> tsig_verify_ctx;
+ TSIGKeyRing keyring;
+ const uint16_t qid;
+ const Name test_name;
+ const Name badkey_name;
+ const RRClass test_class;
+ const RRTTL test_ttl;
+ Message message;
+ OutputBuffer buffer;
+ MessageRenderer renderer;
+ vector<uint8_t> secret;
+ vector<uint8_t> dummy_data;
+ const TSIGRecord dummy_record;
+ vector<uint8_t> received_data;
+};
+
+ConstTSIGRecordPtr
+TSIGTest::createMessageAndSign(uint16_t id, const Name& qname,
+ TSIGContext* ctx, unsigned int message_flags,
+ RRType qtype, const char* answer_data,
+ const RRType* answer_type, bool add_question,
+ Rcode rcode)
+{
+ message.clear(Message::RENDER);
+ message.setQid(id);
+ message.setOpcode(Opcode::QUERY());
+ message.setRcode(rcode);
+ if ((message_flags & QR_FLAG) != 0) {
+ message.setHeaderFlag(Message::HEADERFLAG_QR);
+ }
+ if ((message_flags & AA_FLAG) != 0) {
+ message.setHeaderFlag(Message::HEADERFLAG_AA);
+ }
+ if ((message_flags & RD_FLAG) != 0) {
+ message.setHeaderFlag(Message::HEADERFLAG_RD);
+ }
+ if (add_question) {
+ message.addQuestion(Question(qname, test_class, qtype));
+ }
+ if (answer_data != NULL) {
+ if (answer_type == NULL) {
+ answer_type = &qtype;
+ }
+ RRsetPtr answer_rrset(new RRset(qname, test_class, *answer_type,
+ test_ttl));
+ answer_rrset->addRdata(createRdata(*answer_type, test_class,
+ answer_data));
+ message.addRRset(Message::SECTION_ANSWER, answer_rrset);
+ }
+ renderer.clear();
+ message.toWire(renderer);
+
+ TSIGContext::State expected_new_state =
+ (ctx->getState() == TSIGContext::INIT) ?
+ TSIGContext::SENT_REQUEST : TSIGContext::SENT_RESPONSE;
+ ConstTSIGRecordPtr tsig = ctx->sign(id, renderer.getData(),
+ renderer.getLength());
+ EXPECT_EQ(expected_new_state, ctx->getState());
+
+ return (tsig);
+}
+
+void
+TSIGTest::createMessageFromFile(const char* datafile) {
+ message.clear(Message::PARSE);
+ received_data.clear();
+ UnitTestUtil::readWireData(datafile, received_data);
+ InputBuffer buffer(&received_data[0], received_data.size());
+ message.fromWire(buffer);
+}
+
+void
+commonSignChecks(ConstTSIGRecordPtr tsig, uint16_t expected_qid,
+ uint64_t expected_timesigned,
+ const uint8_t* expected_mac, size_t expected_maclen,
+ uint16_t expected_error = 0,
+ uint16_t expected_otherlen = 0,
+ const uint8_t* expected_otherdata = NULL,
+ const Name& expected_algorithm = TSIGKey::HMACMD5_NAME())
+{
+ ASSERT_TRUE(tsig != NULL);
+ const any::TSIG& tsig_rdata = tsig->getRdata();
+
+ EXPECT_EQ(expected_algorithm, tsig_rdata.getAlgorithm());
+ EXPECT_EQ(expected_timesigned, tsig_rdata.getTimeSigned());
+ EXPECT_EQ(300, tsig_rdata.getFudge());
+ EXPECT_EQ(expected_maclen, tsig_rdata.getMACSize());
+ EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+ tsig_rdata.getMAC(), tsig_rdata.getMACSize(),
+ expected_mac, expected_maclen);
+ EXPECT_EQ(expected_qid, tsig_rdata.getOriginalID());
+ EXPECT_EQ(expected_error, tsig_rdata.getError());
+ EXPECT_EQ(expected_otherlen, tsig_rdata.getOtherLen());
+ EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+ tsig_rdata.getOtherData(), tsig_rdata.getOtherLen(),
+ expected_otherdata, expected_otherlen);
+}
+
+void
+commonVerifyChecks(TSIGContext& ctx, const TSIGRecord* record,
+ const void* data, size_t data_len, TSIGError expected_error,
+ TSIGContext::State expected_new_state =
+ TSIGContext::VERIFIED_RESPONSE)
+{
+ EXPECT_EQ(expected_error, ctx.verify(record, data, data_len));
+ EXPECT_EQ(expected_error, ctx.getError());
+ EXPECT_EQ(expected_new_state, ctx.getState());
+}
+
+TEST_F(TSIGTest, initialState) {
+ // Until signing or verifying, the state should be INIT
+ EXPECT_EQ(TSIGContext::INIT, tsig_ctx->getState());
+
+ // And there should be no error code.
+ EXPECT_EQ(TSIGError(Rcode::NOERROR()), tsig_ctx->getError());
+}
+
+TEST_F(TSIGTest, constructFromKeyRing) {
+ // Construct a TSIG context with an empty key ring. Key shouldn't be
+ // found, and the BAD_KEY error should be recorded.
+ TSIGContext ctx1(test_name, TSIGKey::HMACMD5_NAME(), keyring);
+ EXPECT_EQ(TSIGContext::INIT, ctx1.getState());
+ EXPECT_EQ(TSIGError::BAD_KEY(), ctx1.getError());
+
+ // Add a matching key (we don't use the secret so leave it empty), and
+ // construct it again. This time it should be constructed with a valid
+ // key.
+ keyring.add(TSIGKey(test_name, TSIGKey::HMACMD5_NAME(), NULL, 0));
+ TSIGContext ctx2(test_name, TSIGKey::HMACMD5_NAME(), keyring);
+ EXPECT_EQ(TSIGContext::INIT, ctx2.getState());
+ EXPECT_EQ(TSIGError::NOERROR(), ctx2.getError());
+
+ // Similar to the first case except that the key ring isn't empty but
+ // it doesn't contain a matching key.
+ TSIGContext ctx3(test_name, TSIGKey::HMACSHA1_NAME(), keyring);
+ EXPECT_EQ(TSIGContext::INIT, ctx3.getState());
+ EXPECT_EQ(TSIGError::BAD_KEY(), ctx3.getError());
+
+ TSIGContext ctx4(Name("different-key.example"), TSIGKey::HMACMD5_NAME(),
+ keyring);
+ EXPECT_EQ(TSIGContext::INIT, ctx4.getState());
+ EXPECT_EQ(TSIGError::BAD_KEY(), ctx4.getError());
+
+ // "Unknown" algorithm name will result in BADKEY, too.
+ TSIGContext ctx5(test_name, Name("unknown.algorithm"), keyring);
+ EXPECT_EQ(TSIGContext::INIT, ctx5.getState());
+ EXPECT_EQ(TSIGError::BAD_KEY(), ctx5.getError());
+}
+
+// Example output generated by
+// "dig -y www.example.com:SFuWd/q99SzF8Yzd1QbB9g== www.example.com
+// QID: 0x2d65
+// Time Signed: 0x00004da8877a
+// MAC: 227026ad297beee721ce6c6fff1e9ef3
+const uint8_t common_expected_mac[] = {
+ 0x22, 0x70, 0x26, 0xad, 0x29, 0x7b, 0xee, 0xe7,
+ 0x21, 0xce, 0x6c, 0x6f, 0xff, 0x1e, 0x9e, 0xf3
+};
+TEST_F(TSIGTest, sign) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ {
+ SCOPED_TRACE("Sign test for query");
+ commonSignChecks(createMessageAndSign(qid, test_name, tsig_ctx.get()),
+ qid, 0x4da8877a, common_expected_mac,
+ sizeof(common_expected_mac));
+ }
+}
+
+// Same test as sign, but specifying the key name with upper-case (i.e.
+// non canonical) characters. The digest must be the same. It should actually
+// be ensured at the level of TSIGKey, but we confirm that at this level, too.
+TEST_F(TSIGTest, signUsingUpperCasedKeyName) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ TSIGContext cap_ctx(TSIGKey(Name("WWW.EXAMPLE.COM"),
+ TSIGKey::HMACMD5_NAME(),
+ &secret[0], secret.size()));
+
+ {
+ SCOPED_TRACE("Sign test for query using non canonical key name");
+ commonSignChecks(createMessageAndSign(qid, test_name, &cap_ctx), qid,
+ 0x4da8877a, common_expected_mac,
+ sizeof(common_expected_mac));
+ }
+}
+
+// Same as the previous test, but for the algorithm name.
+TEST_F(TSIGTest, signUsingUpperCasedAlgorithmName) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ TSIGContext cap_ctx(TSIGKey(test_name,
+ Name("HMAC-md5.SIG-alg.REG.int"),
+ &secret[0], secret.size()));
+
+ {
+ SCOPED_TRACE("Sign test for query using non canonical algorithm name");
+ commonSignChecks(createMessageAndSign(qid, test_name, &cap_ctx), qid,
+ 0x4da8877a, common_expected_mac,
+ sizeof(common_expected_mac));
+ }
+}
+
+TEST_F(TSIGTest, signAtActualTime) {
+ // Sign the message using the actual time, and check the accuracy of it.
+ // We cannot reasonably predict the expected MAC, so don't bother to
+ // check it.
+ const uint64_t now = static_cast<uint64_t>(time(NULL));
+
+ {
+ SCOPED_TRACE("Sign test for query at actual time");
+ ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+ tsig_ctx.get());
+ const any::TSIG& tsig_rdata = tsig->getRdata();
+
+ // Check the resulted time signed is in the range of [now, now + 5]
+ // (5 is an arbitrary choice). Note that due to the order of the call
+ // to time() and sign(), time signed must not be smaller than the
+ // current time.
+ EXPECT_LE(now, tsig_rdata.getTimeSigned());
+ EXPECT_GE(now + 5, tsig_rdata.getTimeSigned());
+ }
+}
+
+TEST_F(TSIGTest, signBadData) {
+ // some specific bad data should be rejected proactively.
+ const unsigned char dummy_data = 0;
+ EXPECT_THROW(tsig_ctx->sign(0, NULL, 10), InvalidParameter);
+ EXPECT_THROW(tsig_ctx->sign(0, &dummy_data, 0), InvalidParameter);
+}
+
+TEST_F(TSIGTest, verifyBadData) {
+ // the data must at least hold the DNS message header and the specified
+ // TSIG.
+ EXPECT_THROW(tsig_ctx->verify(&dummy_record, &dummy_data[0],
+ 12 + dummy_record.getLength() - 1),
+ InvalidParameter);
+
+ // And the data must not be NULL.
+ EXPECT_THROW(tsig_ctx->verify(&dummy_record, NULL,
+ 12 + dummy_record.getLength()),
+ InvalidParameter);
+}
+
+#ifdef ENABLE_CUSTOM_OPERATOR_NEW
+// We enable this test only when we enable custom new/delete at build time
+// We could enable/disable the test runtime using the gtest filter, but
+// we'd basically like to minimize the number of disabled tests (they
+// should generally be considered tests that temporarily fail and should
+// be fixed).
+TEST_F(TSIGTest, signExceptionSafety) {
+ // Check sign() provides the strong exception guarantee for the simpler
+ // case (with a key error and empty MAC). The general case is more
+ // complicated and involves more memory allocation, so the test result
+ // won't be reliable.
+
+ commonVerifyChecks(*tsig_verify_ctx, &dummy_record, &dummy_data[0],
+ dummy_data.size(), TSIGError::BAD_KEY(),
+ TSIGContext::RECEIVED_REQUEST);
+
+ try {
+ int dummydata;
+ isc::util::unittests::force_throw_on_new = true;
+ isc::util::unittests::throw_size_on_new = sizeof(TSIGRecord);
+ tsig_verify_ctx->sign(0, &dummydata, sizeof(dummydata));
+ isc::util::unittests::force_throw_on_new = false;
+ ASSERT_FALSE(true) << "Expected throw on new, but it didn't happen";
+ } catch (const std::bad_alloc&) {
+ isc::util::unittests::force_throw_on_new = false;
+
+ // sign() threw, so the state should still be RECEIVED_REQUEST
+ EXPECT_EQ(TSIGContext::RECEIVED_REQUEST, tsig_verify_ctx->getState());
+ }
+ isc::util::unittests::force_throw_on_new = false;
+}
+#endif // ENABLE_CUSTOM_OPERATOR_NEW
+
+// Same test as "sign" but use a different algorithm just to confirm we don't
+// naively hardcode constants specific to a particular algorithm.
+// Test data generated by
+// "dig -y hmac-sha1:www.example.com:MA+QDhXbyqUak+qnMFyTyEirzng= www.example.com"
+// QID: 0x0967, RDflag
+// Current Time: 00004da8be86
+// Time Signed: 00004dae7d5f
+// HMAC Size: 20
+// HMAC: 415340c7daf824ed684ee586f7b5a67a2febc0d3
+TEST_F(TSIGTest, signUsingHMACSHA1) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4dae7d5f>;
+
+ secret.clear();
+ decodeBase64("MA+QDhXbyqUak+qnMFyTyEirzng=", secret);
+ TSIGContext sha1_ctx(TSIGKey(test_name, TSIGKey::HMACSHA1_NAME(),
+ &secret[0], secret.size()));
+
+ const uint16_t sha1_qid = 0x0967;
+ const uint8_t expected_mac[] = {
+ 0x41, 0x53, 0x40, 0xc7, 0xda, 0xf8, 0x24, 0xed, 0x68, 0x4e,
+ 0xe5, 0x86, 0xf7, 0xb5, 0xa6, 0x7a, 0x2f, 0xeb, 0xc0, 0xd3
+ };
+ {
+ SCOPED_TRACE("Sign test using HMAC-SHA1");
+ commonSignChecks(createMessageAndSign(sha1_qid, test_name, &sha1_ctx),
+ sha1_qid, 0x4dae7d5f, expected_mac,
+ sizeof(expected_mac), 0, 0, NULL,
+ TSIGKey::HMACSHA1_NAME());
+ }
+}
+
+// The first part of this test checks verifying the signed query used for
+// the "sign" test.
+// The second part of this test generates a signed response to the signed
+// query as follows:
+// Answer: www.example.com. 86400 IN A 192.0.2.1
+// MAC: 8fcda66a7cd1a3b9948eb1869d384a9f
+TEST_F(TSIGTest, verifyThenSignResponse) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ // This test data for the message test has the same wire format data
+ // as the message used in the "sign" test.
+ createMessageFromFile("message_toWire2.wire");
+ {
+ SCOPED_TRACE("Verify test for request");
+ commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::NOERROR(), TSIGContext::RECEIVED_REQUEST);
+ }
+
+ // Transform the original message to a response, then sign the response
+ // with the context of "verified state".
+ ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+ tsig_verify_ctx.get(),
+ QR_FLAG|AA_FLAG|RD_FLAG,
+ RRType::A(), "192.0.2.1");
+ const uint8_t expected_mac[] = {
+ 0x8f, 0xcd, 0xa6, 0x6a, 0x7c, 0xd1, 0xa3, 0xb9,
+ 0x94, 0x8e, 0xb1, 0x86, 0x9d, 0x38, 0x4a, 0x9f
+ };
+ {
+ SCOPED_TRACE("Sign test for response");
+ commonSignChecks(tsig, qid, 0x4da8877a, expected_mac,
+ sizeof(expected_mac));
+ }
+}
+
+TEST_F(TSIGTest, verifyUpperCaseNames) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ // This test data for the message test has the same wire format data
+ // as the message used in the "sign" test.
+ createMessageFromFile("tsig_verify9.wire");
+ {
+ SCOPED_TRACE("Verify test for request");
+ commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::NOERROR(), TSIGContext::RECEIVED_REQUEST);
+ }
+}
+
+TEST_F(TSIGTest, verifyForwardedMessage) {
+ // Similar to the first part of the previous test, but this test emulates
+ // the "forward" case, where the ID of the Header and the original ID in
+ // TSIG is different.
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ createMessageFromFile("tsig_verify6.wire");
+ {
+ SCOPED_TRACE("Verify test for forwarded request");
+ commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::NOERROR(), TSIGContext::RECEIVED_REQUEST);
+ }
+}
+
+// Example of signing multiple messages in a single TCP stream,
+// taken from data using BIND 9's "one-answer" transfer-format.
+// Request:
+// QID: 0x3410, flags (none)
+// Question: example.com/IN/AXFR
+// Time Signed: 0x4da8e951
+// MAC: 35b2fd08268781634400c7c8a5533b13
+// First message:
+// QID: 0x3410, flags QR, AA
+// Question: example.com/IN/AXFR
+// Answer: example.com. 86400 IN SOA ns.example.com. root.example.com. (
+// 2011041503 7200 3600 2592000 1200)
+// MAC: bdd612cd2c7f9e0648bd6dc23713e83c
+// Second message:
+// Answer: example.com. 86400 IN NS ns.example.com.
+// MAC: 102458f7f62ddd7d638d746034130968
+TEST_F(TSIGTest, signContinuation) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8e951>;
+
+ const uint16_t axfr_qid = 0x3410;
+ const Name zone_name("example.com");
+
+ // Create and sign the AXFR request
+ ConstTSIGRecordPtr tsig = createMessageAndSign(axfr_qid, zone_name,
+ tsig_ctx.get(), 0,
+ RRType::AXFR());
+ // Then verify it (the wire format test data should contain the same
+ // message data, and verification should succeed).
+ received_data.clear();
+ UnitTestUtil::readWireData("tsig_verify1.wire", received_data);
+ {
+ SCOPED_TRACE("Verify AXFR query");
+ commonVerifyChecks(*tsig_verify_ctx, tsig.get(), &received_data[0],
+ received_data.size(), TSIGError::NOERROR(),
+ TSIGContext::RECEIVED_REQUEST);
+ }
+
+ // Create and sign the first response message
+ tsig = createMessageAndSign(axfr_qid, zone_name, tsig_verify_ctx.get(),
+ AA_FLAG|QR_FLAG, RRType::AXFR(),
+ "ns.example.com. root.example.com. "
+ "2011041503 7200 3600 2592000 1200",
+ &RRType::SOA());
+
+ // Then verify it at the requester side.
+ received_data.clear();
+ UnitTestUtil::readWireData("tsig_verify2.wire", received_data);
+ {
+ SCOPED_TRACE("Verify first AXFR response");
+ commonVerifyChecks(*tsig_ctx, tsig.get(), &received_data[0],
+ received_data.size(), TSIGError::NOERROR());
+ }
+
+ // Create and sign the second response message
+ const uint8_t expected_mac[] = {
+ 0x10, 0x24, 0x58, 0xf7, 0xf6, 0x2d, 0xdd, 0x7d,
+ 0x63, 0x8d, 0x74, 0x60, 0x34, 0x13, 0x09, 0x68
+ };
+ {
+ SCOPED_TRACE("Sign test for continued response in TCP stream");
+ tsig = createMessageAndSign(axfr_qid, zone_name, tsig_verify_ctx.get(),
+ AA_FLAG|QR_FLAG, RRType::AXFR(),
+ "ns.example.com.", &RRType::NS(), false);
+ commonSignChecks(tsig, axfr_qid, 0x4da8e951, expected_mac,
+ sizeof(expected_mac));
+ }
+
+ // Then verify it at the requester side.
+ received_data.clear();
+ UnitTestUtil::readWireData("tsig_verify3.wire", received_data);
+ {
+ SCOPED_TRACE("Verify second AXFR response");
+ commonVerifyChecks(*tsig_ctx, tsig.get(), &received_data[0],
+ received_data.size(), TSIGError::NOERROR());
+ }
+}
+
+// BADTIME example, taken from data using specially hacked BIND 9's nsupdate
+// Query:
+// QID: 0x1830, RD flag
+// Current Time: 00004da8be86
+// Time Signed: 00004da8b9d6
+// Question: www.example.com/IN/SOA
+//(mac) 8406 7d50 b8e7 d054 3d50 5bd9 de2a bb68
+// Response:
+// QRbit, RCODE=9(NOTAUTH)
+// Time Signed: 00004da8b9d6 (the one in the query)
+// MAC: d4b043f6f44495ec8a01260e39159d76
+// Error: 0x12 (BADTIME), Other Len: 6
+// Other data: 00004da8be86
+TEST_F(TSIGTest, badtimeResponse) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6>;
+
+ const uint16_t test_qid = 0x7fc4;
+ ConstTSIGRecordPtr tsig = createMessageAndSign(test_qid, test_name,
+ tsig_ctx.get(), 0,
+ RRType::SOA());
+
+ // "advance the clock" and try validating, which should fail due to BADTIME
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8be86>;
+ {
+ SCOPED_TRACE("Verify resulting in BADTIME due to expired SIG");
+ commonVerifyChecks(*tsig_verify_ctx, tsig.get(), &dummy_data[0],
+ dummy_data.size(), TSIGError::BAD_TIME(),
+ TSIGContext::RECEIVED_REQUEST);
+ }
+
+ // make and sign a response in the context of TSIG error.
+ tsig = createMessageAndSign(test_qid, test_name, tsig_verify_ctx.get(),
+ QR_FLAG, RRType::SOA(), NULL, NULL,
+ true, Rcode::NOTAUTH());
+ const uint8_t expected_otherdata[] = { 0, 0, 0x4d, 0xa8, 0xbe, 0x86 };
+ const uint8_t expected_mac[] = {
+ 0xd4, 0xb0, 0x43, 0xf6, 0xf4, 0x44, 0x95, 0xec,
+ 0x8a, 0x01, 0x26, 0x0e, 0x39, 0x15, 0x9d, 0x76
+ };
+ {
+ SCOPED_TRACE("Sign test for response with BADTIME");
+ commonSignChecks(tsig, message.getQid(), 0x4da8b9d6,
+ expected_mac, sizeof(expected_mac),
+ 18, // error: BADTIME
+ sizeof(expected_otherdata),
+ expected_otherdata);
+ }
+}
+
+TEST_F(TSIGTest, badtimeResponse2) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6>;
+
+ ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+ tsig_ctx.get(), 0,
+ RRType::SOA());
+
+ // "rewind the clock" and try validating, which should fail due to BADTIME
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6 - 600>;
+ {
+ SCOPED_TRACE("Verify resulting in BADTIME due to too future SIG");
+ commonVerifyChecks(*tsig_verify_ctx, tsig.get(), &dummy_data[0],
+ dummy_data.size(), TSIGError::BAD_TIME(),
+ TSIGContext::RECEIVED_REQUEST);
+ }
+}
+
+TEST_F(TSIGTest, badtimeBoundaries) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6>;
+
+ // Test various boundary conditions. We intentionally use the magic
+ // number of 300 instead of the constant variable for testing.
+ // In the okay cases, signature is not correct, but it's sufficient to
+ // check the error code isn't BADTIME for the purpose of this test.
+ ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+ tsig_ctx.get(), 0,
+ RRType::SOA());
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6 + 301>;
+ EXPECT_EQ(TSIGError::BAD_TIME(),
+ tsig_verify_ctx->verify(tsig.get(), &dummy_data[0],
+ dummy_data.size()));
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6 + 300>;
+ EXPECT_NE(TSIGError::BAD_TIME(),
+ tsig_verify_ctx->verify(tsig.get(), &dummy_data[0],
+ dummy_data.size()));
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6 - 301>;
+ EXPECT_EQ(TSIGError::BAD_TIME(),
+ tsig_verify_ctx->verify(tsig.get(), &dummy_data[0],
+ dummy_data.size()));
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6 - 300>;
+ EXPECT_NE(TSIGError::BAD_TIME(),
+ tsig_verify_ctx->verify(tsig.get(), &dummy_data[0],
+ dummy_data.size()));
+}
+
+TEST_F(TSIGTest, badtimeOverflow) {
+ isc::util::detail::gettimeFunction = testGetTime<200>;
+ ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+ tsig_ctx.get(), 0,
+ RRType::SOA());
+
+ // This should be in the okay range, but since "200 - fudge" overflows
+ // and we compare them as 64-bit unsigned integers, it results in a false
+ // positive (we intentionally accept that).
+ isc::util::detail::gettimeFunction = testGetTime<100>;
+ EXPECT_EQ(TSIGError::BAD_TIME(),
+ tsig_verify_ctx->verify(tsig.get(), &dummy_data[0],
+ dummy_data.size()));
+}
+
+TEST_F(TSIGTest, badsigResponse) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ // Try to sign a simple message with bogus secret. It should fail
+ // with BADSIG.
+ createMessageFromFile("message_toWire2.wire");
+ TSIGContext bad_ctx(TSIGKey(test_name, TSIGKey::HMACMD5_NAME(),
+ &dummy_data[0], dummy_data.size()));
+ {
+ SCOPED_TRACE("Verify resulting in BADSIG");
+ commonVerifyChecks(bad_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::BAD_SIG(), TSIGContext::RECEIVED_REQUEST);
+ }
+
+ // Sign the same message (which doesn't matter for this test) with the
+ // context of "checked state".
+ {
+ SCOPED_TRACE("Sign test for response with BADSIG error");
+ commonSignChecks(createMessageAndSign(qid, test_name, &bad_ctx),
+ message.getQid(), 0x4da8877a, NULL, 0,
+ 16); // 16: BADSIG
+ }
+}
+
+TEST_F(TSIGTest, badkeyResponse) {
+ // A similar test as badsigResponse but for BADKEY
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ tsig_ctx.reset(new TSIGContext(badkey_name, TSIGKey::HMACMD5_NAME(),
+ keyring));
+ {
+ SCOPED_TRACE("Verify resulting in BADKEY");
+ commonVerifyChecks(*tsig_ctx, &dummy_record, &dummy_data[0],
+ dummy_data.size(), TSIGError::BAD_KEY(),
+ TSIGContext::RECEIVED_REQUEST);
+ }
+
+ {
+ SCOPED_TRACE("Sign test for response with BADKEY error");
+ ConstTSIGRecordPtr sig = createMessageAndSign(qid, test_name,
+ tsig_ctx.get());
+ EXPECT_EQ(badkey_name, sig->getName());
+ commonSignChecks(sig, qid, 0x4da8877a, NULL, 0, 17); // 17: BADKEY
+ }
+}
+
+TEST_F(TSIGTest, badkeyForResponse) {
+ // "BADKEY" case for a response to a signed message
+ createMessageAndSign(qid, test_name, tsig_ctx.get());
+ {
+ SCOPED_TRACE("Verify a response resulting in BADKEY");
+ commonVerifyChecks(*tsig_ctx, &dummy_record, &dummy_data[0],
+ dummy_data.size(), TSIGError::BAD_KEY(),
+ TSIGContext::SENT_REQUEST);
+ }
+
+ // A similar case with a different algorithm
+ const TSIGRecord dummy_record2(test_name,
+ any::TSIG(TSIGKey::HMACSHA1_NAME(),
+ 0x4da8877a,
+ TSIGContext::DEFAULT_FUDGE,
+ 0, NULL, qid, 0, 0, NULL));
+ {
+ SCOPED_TRACE("Verify a response resulting in BADKEY due to bad alg");
+ commonVerifyChecks(*tsig_ctx, &dummy_record2, &dummy_data[0],
+ dummy_data.size(), TSIGError::BAD_KEY(),
+ TSIGContext::SENT_REQUEST);
+ }
+}
+
+TEST_F(TSIGTest, badsigThenValidate) {
+ // According to RFC2845 4.6, if TSIG verification fails the client
+ // should discard that message and wait for another signed response.
+ // This test emulates that situation.
+
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ createMessageAndSign(qid, test_name, tsig_ctx.get());
+
+ createMessageFromFile("tsig_verify4.wire");
+ {
+ SCOPED_TRACE("Verify a response that should fail due to BADSIG");
+ commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::BAD_SIG(), TSIGContext::SENT_REQUEST);
+ }
+
+ createMessageFromFile("tsig_verify5.wire");
+ {
+ SCOPED_TRACE("Verify a response after a BADSIG failure");
+ commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::NOERROR(),
+ TSIGContext::VERIFIED_RESPONSE);
+ }
+}
+
+TEST_F(TSIGTest, nosigThenValidate) {
+ // Similar to the previous test, but the first response doesn't contain
+ // TSIG.
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ createMessageAndSign(qid, test_name, tsig_ctx.get());
+
+ {
+ SCOPED_TRACE("Verify a response without TSIG that should exist");
+ commonVerifyChecks(*tsig_ctx, NULL, &dummy_data[0],
+ dummy_data.size(), TSIGError::FORMERR(),
+ TSIGContext::SENT_REQUEST);
+ }
+
+ createMessageFromFile("tsig_verify5.wire");
+ {
+ SCOPED_TRACE("Verify a response after a FORMERR failure");
+ commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::NOERROR(),
+ TSIGContext::VERIFIED_RESPONSE);
+ }
+}
+
+TEST_F(TSIGTest, badtimeThenValidate) {
+ // Similar to the previous test, but the first response results in BADTIME.
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+ tsig_ctx.get());
+
+ // "advance the clock" and try validating, which should fail due to BADTIME
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a + 600>;
+ {
+ SCOPED_TRACE("Verify resulting in BADTIME due to expired SIG");
+ commonVerifyChecks(*tsig_ctx, tsig.get(), &dummy_data[0],
+ dummy_data.size(), TSIGError::BAD_TIME(),
+ TSIGContext::SENT_REQUEST);
+ }
+
+ // revert the clock again.
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ createMessageFromFile("tsig_verify5.wire");
+ {
+ SCOPED_TRACE("Verify a response after a BADTIME failure");
+ commonVerifyChecks(*tsig_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::NOERROR(),
+ TSIGContext::VERIFIED_RESPONSE);
+ }
+}
+
+TEST_F(TSIGTest, emptyMAC) {
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ // We don't allow empty MAC unless the TSIG error is BADSIG or BADKEY.
+ createMessageFromFile("tsig_verify7.wire");
+ {
+ SCOPED_TRACE("Verify test for request");
+ commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::BAD_SIG(), TSIGContext::RECEIVED_REQUEST);
+ }
+
+ // If the empty MAC comes with a BADKEY error, the error is passed
+ // transparently.
+ createMessageFromFile("tsig_verify8.wire");
+ {
+ SCOPED_TRACE("Verify test for request");
+ commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::BAD_KEY(), TSIGContext::RECEIVED_REQUEST);
+ }
+}
+
+TEST_F(TSIGTest, verifyAfterSendResponse) {
+ // Once the context is used for sending a signed response, it shouldn't
+ // be used for further verification.
+
+ // The following are essentially the same as what verifyThenSignResponse
+ // does with simplification.
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ createMessageFromFile("message_toWire2.wire");
+ tsig_verify_ctx->verify(message.getTSIGRecord(), &received_data[0],
+ received_data.size());
+ EXPECT_EQ(TSIGContext::RECEIVED_REQUEST, tsig_verify_ctx->getState());
+ createMessageAndSign(qid, test_name, tsig_verify_ctx.get(),
+ QR_FLAG|AA_FLAG|RD_FLAG, RRType::A(), "192.0.2.1");
+ EXPECT_EQ(TSIGContext::SENT_RESPONSE, tsig_verify_ctx->getState());
+
+ // Now trying further verification.
+ createMessageFromFile("message_toWire2.wire");
+ EXPECT_THROW(tsig_verify_ctx->verify(message.getTSIGRecord(),
+ &received_data[0],
+ received_data.size()),
+ TSIGContextError);
+}
+
+TEST_F(TSIGTest, signAfterVerified) {
+ // Likewise, once the context verifies a response, it shouldn't for
+ // signing any more.
+
+ // The following are borrowed from badsigThenValidate (without the
+ // intermediate failure)
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ createMessageAndSign(qid, test_name, tsig_ctx.get());
+ createMessageFromFile("tsig_verify5.wire");
+ tsig_ctx->verify(message.getTSIGRecord(), &received_data[0],
+ received_data.size());
+ EXPECT_EQ(TSIGContext::VERIFIED_RESPONSE, tsig_ctx->getState());
+
+ // Now trying further signing.
+ EXPECT_THROW(createMessageAndSign(qid, test_name, tsig_ctx.get()),
+ TSIGContextError);
+}
+
+TEST_F(TSIGTest, tooShortMAC) {
+ // Too short MAC should be rejected.
+ // Note: when we implement RFC4635-based checks, the error code will
+ // (probably) be FORMERR.
+
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ createMessageFromFile("tsig_verify10.wire");
+ {
+ SCOPED_TRACE("Verify test for request");
+ commonVerifyChecks(*tsig_verify_ctx, message.getTSIGRecord(),
+ &received_data[0], received_data.size(),
+ TSIGError::BAD_SIG(), TSIGContext::RECEIVED_REQUEST);
+ }
+}
+
+} // end namespace
diff --git a/src/lib/dns/tests/tsigerror_unittest.cc b/src/lib/dns/tests/tsigerror_unittest.cc
new file mode 100644
index 0000000..bb08aef
--- /dev/null
+++ b/src/lib/dns/tests/tsigerror_unittest.cc
@@ -0,0 +1,116 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string>
+#include <ostream>
+
+#include <gtest/gtest.h>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/rcode.h>
+#include <dns/tsigerror.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+
+namespace {
+TEST(TSIGErrorTest, constructFromErrorCode) {
+ // These are pretty trivial, and also test getCode();
+ EXPECT_EQ(0, TSIGError(0).getCode());
+ EXPECT_EQ(18, TSIGError(18).getCode());
+ EXPECT_EQ(65535, TSIGError(65535).getCode());
+}
+
+TEST(TSIGErrorTest, constructFromRcode) {
+ // We use RCODE for code values from 0-15.
+ EXPECT_EQ(0, TSIGError(Rcode::NOERROR()).getCode());
+ EXPECT_EQ(15, TSIGError(Rcode(15)).getCode());
+
+ // From error code 16 TSIG errors define a separate space, so passing
+ // corresponding RCODE for such code values should be prohibited.
+ EXPECT_THROW(TSIGError(Rcode(16)).getCode(), OutOfRange);
+}
+
+TEST(TSIGErrorTest, constants) {
+ // We'll only test arbitrarily chosen subsets of the codes.
+ // This class is quite simple, so it should be suffice.
+
+ EXPECT_EQ(TSIGError::BAD_SIG_CODE, TSIGError(16).getCode());
+ EXPECT_EQ(TSIGError::BAD_KEY_CODE, TSIGError(17).getCode());
+ EXPECT_EQ(TSIGError::BAD_TIME_CODE, TSIGError(18).getCode());
+
+ EXPECT_EQ(0, TSIGError::NOERROR().getCode());
+ EXPECT_EQ(9, TSIGError::NOTAUTH().getCode());
+ EXPECT_EQ(14, TSIGError::RESERVED14().getCode());
+ EXPECT_EQ(TSIGError::BAD_SIG_CODE, TSIGError::BAD_SIG().getCode());
+ EXPECT_EQ(TSIGError::BAD_KEY_CODE, TSIGError::BAD_KEY().getCode());
+ EXPECT_EQ(TSIGError::BAD_TIME_CODE, TSIGError::BAD_TIME().getCode());
+}
+
+TEST(TSIGErrorTest, equal) {
+ EXPECT_TRUE(TSIGError::NOERROR() == TSIGError(Rcode::NOERROR()));
+ EXPECT_TRUE(TSIGError(Rcode::NOERROR()) == TSIGError::NOERROR());
+ EXPECT_TRUE(TSIGError::NOERROR().equals(TSIGError(Rcode::NOERROR())));
+ EXPECT_TRUE(TSIGError::NOERROR().equals(TSIGError(Rcode::NOERROR())));
+
+ EXPECT_TRUE(TSIGError::BAD_SIG() == TSIGError(16));
+ EXPECT_TRUE(TSIGError(16) == TSIGError::BAD_SIG());
+ EXPECT_TRUE(TSIGError::BAD_SIG().equals(TSIGError(16)));
+ EXPECT_TRUE(TSIGError(16).equals(TSIGError::BAD_SIG()));
+}
+
+TEST(TSIGErrorTest, nequal) {
+ EXPECT_TRUE(TSIGError::BAD_KEY() != TSIGError(Rcode::NOERROR()));
+ EXPECT_TRUE(TSIGError(Rcode::NOERROR()) != TSIGError::BAD_KEY());
+ EXPECT_TRUE(TSIGError::BAD_KEY().nequals(TSIGError(Rcode::NOERROR())));
+ EXPECT_TRUE(TSIGError(Rcode::NOERROR()).nequals(TSIGError::BAD_KEY()));
+}
+
+TEST(TSIGErrorTest, toText) {
+ // TSIGError derived from the standard Rcode
+ EXPECT_EQ("NOERROR", TSIGError(Rcode::NOERROR()).toText());
+
+ // Well known TSIG errors
+ EXPECT_EQ("BADSIG", TSIGError::BAD_SIG().toText());
+ EXPECT_EQ("BADKEY", TSIGError::BAD_KEY().toText());
+ EXPECT_EQ("BADTIME", TSIGError::BAD_TIME().toText());
+
+ // Unknown (or not yet supported) codes. Simply converted as numeric.
+ EXPECT_EQ("19", TSIGError(19).toText());
+ EXPECT_EQ("65535", TSIGError(65535).toText());
+}
+
+TEST(TSIGErrorTest, toRcode) {
+ // TSIGError derived from the standard Rcode
+ EXPECT_EQ(Rcode::NOERROR(), TSIGError(Rcode::NOERROR()).toRcode());
+
+ // Well known TSIG errors
+ EXPECT_EQ(Rcode::NOTAUTH(), TSIGError::BAD_SIG().toRcode());
+ EXPECT_EQ(Rcode::NOTAUTH(), TSIGError::BAD_KEY().toRcode());
+ EXPECT_EQ(Rcode::NOTAUTH(), TSIGError::BAD_TIME().toRcode());
+
+ // Unknown (or not yet supported) codes are treated as SERVFAIL.
+ EXPECT_EQ(Rcode::SERVFAIL(), TSIGError(19).toRcode());
+ EXPECT_EQ(Rcode::SERVFAIL(), TSIGError(65535).toRcode());
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST(TSIGErrorTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << TSIGError::BAD_KEY();
+ EXPECT_EQ(TSIGError::BAD_KEY().toText(), oss.str());
+}
+} // end namespace
diff --git a/src/lib/dns/tests/tsigkey_unittest.cc b/src/lib/dns/tests/tsigkey_unittest.cc
index 6b2b8c5..dac3c49 100644
--- a/src/lib/dns/tests/tsigkey_unittest.cc
+++ b/src/lib/dns/tests/tsigkey_unittest.cc
@@ -18,6 +18,8 @@
#include <exceptions/exceptions.h>
+#include <cryptolink/cryptolink.h>
+
#include <dns/tsigkey.h>
#include <dns/tests/unittest_util.h>
@@ -31,13 +33,22 @@ class TSIGKeyTest : public ::testing::Test {
protected:
TSIGKeyTest() : secret("someRandomData"), key_name("example.com") {}
string secret;
- Name key_name;
+ const Name key_name;
};
TEST_F(TSIGKeyTest, algorithmNames) {
EXPECT_EQ(Name("hmac-md5.sig-alg.reg.int"), TSIGKey::HMACMD5_NAME());
EXPECT_EQ(Name("hmac-sha1"), TSIGKey::HMACSHA1_NAME());
EXPECT_EQ(Name("hmac-sha256"), TSIGKey::HMACSHA256_NAME());
+
+ // Also check conversion to cryptolink definitions
+ EXPECT_EQ(isc::cryptolink::MD5, TSIGKey(key_name, TSIGKey::HMACMD5_NAME(),
+ NULL, 0).getAlgorithm());
+ EXPECT_EQ(isc::cryptolink::SHA1, TSIGKey(key_name, TSIGKey::HMACSHA1_NAME(),
+ NULL, 0).getAlgorithm());
+ EXPECT_EQ(isc::cryptolink::SHA256, TSIGKey(key_name,
+ TSIGKey::HMACSHA256_NAME(),
+ NULL, 0).getAlgorithm());
}
TEST_F(TSIGKeyTest, construct) {
@@ -48,9 +59,13 @@ TEST_F(TSIGKeyTest, construct) {
EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, secret.c_str(),
secret.size(), key.getSecret(), key.getSecretLength());
+ // "unknown" algorithm is only accepted with empty secret.
EXPECT_THROW(TSIGKey(key_name, Name("unknown-alg"),
secret.c_str(), secret.size()),
isc::InvalidParameter);
+ TSIGKey key2(key_name, Name("unknown-alg"), NULL, 0);
+ EXPECT_EQ(key_name, key2.getKeyName());
+ EXPECT_EQ(Name("unknown-alg"), key2.getAlgorithmName());
// The algorithm name should be converted to the canonical form.
EXPECT_EQ("hmac-sha1.",
@@ -58,6 +73,12 @@ TEST_F(TSIGKeyTest, construct) {
secret.c_str(),
secret.size()).getAlgorithmName().toText());
+ // Same for key name
+ EXPECT_EQ("example.com.",
+ TSIGKey(Name("EXAMPLE.CoM."), TSIGKey::HMACSHA256_NAME(),
+ secret.c_str(),
+ secret.size()).getKeyName().toText());
+
// Invalid combinations of secret and secret_len:
EXPECT_THROW(TSIGKey(key_name, TSIGKey::HMACSHA1_NAME(), secret.c_str(), 0),
isc::InvalidParameter);
@@ -109,12 +130,18 @@ class TSIGKeyRingTest : public ::testing::Test {
protected:
TSIGKeyRingTest() :
key_name("example.com"),
+ md5_name("hmac-md5.sig-alg.reg.int"),
+ sha1_name("hmac-sha1"),
+ sha256_name("hmac-sha256"),
secretstring("anotherRandomData"),
secret(secretstring.c_str()),
secret_len(secretstring.size())
{}
TSIGKeyRing keyring;
- Name key_name;
+ const Name key_name;
+ const Name md5_name;
+ const Name sha1_name;
+ const Name sha256_name;
private:
const string secretstring;
protected:
@@ -134,8 +161,8 @@ TEST_F(TSIGKeyRingTest, add) {
EXPECT_EQ(TSIGKeyRing::EXIST, keyring.add(
TSIGKey(key_name, TSIGKey::HMACSHA256_NAME(),
secret, secret_len)));
- // keys are identified their names, the same name of key with a different
- // algorithm would be considered a duplicate.
+ // keys are identified by their names, the same name of key with a
+ // different algorithm would be considered a duplicate.
EXPECT_EQ(TSIGKeyRing::EXIST, keyring.add(
TSIGKey(Name("example.com"), TSIGKey::HMACSHA1_NAME(),
secret, secret_len)));
@@ -187,44 +214,90 @@ TEST_F(TSIGKeyRingTest, removeFromSome) {
}
TEST_F(TSIGKeyRingTest, find) {
- EXPECT_EQ(TSIGKeyRing::NOTFOUND, keyring.find(key_name).code);
- EXPECT_EQ(static_cast<const TSIGKey*>(NULL), keyring.find(key_name).key);
-
- EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(
- TSIGKey(key_name, TSIGKey::HMACSHA256_NAME(),
- secret, secret_len)));
- const TSIGKeyRing::FindResult result(keyring.find(key_name));
- EXPECT_EQ(TSIGKeyRing::SUCCESS, result.code);
- EXPECT_EQ(key_name, result.key->getKeyName());
- EXPECT_EQ(TSIGKey::HMACSHA256_NAME(), result.key->getAlgorithmName());
+ // If the keyring is empty the search should fail.
+ EXPECT_EQ(TSIGKeyRing::NOTFOUND, keyring.find(key_name, md5_name).code);
+ EXPECT_EQ(static_cast<const TSIGKey*>(NULL),
+ keyring.find(key_name, md5_name).key);
+
+ // Add a key and try to find it. Should succeed.
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(TSIGKey(key_name, sha256_name,
+ secret, secret_len)));
+ const TSIGKeyRing::FindResult result1(keyring.find(key_name, sha256_name));
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, result1.code);
+ EXPECT_EQ(key_name, result1.key->getKeyName());
+ EXPECT_EQ(TSIGKey::HMACSHA256_NAME(), result1.key->getAlgorithmName());
EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, secret, secret_len,
- result.key->getSecret(),
- result.key->getSecretLength());
+ result1.key->getSecret(),
+ result1.key->getSecretLength());
+
+ // If either key name or algorithm doesn't match, search should fail.
+ const TSIGKeyRing::FindResult result2 =
+ keyring.find(Name("different-key.example"), sha256_name);
+ EXPECT_EQ(TSIGKeyRing::NOTFOUND, result2.code);
+ EXPECT_EQ(static_cast<const TSIGKey*>(NULL), result2.key);
+
+ const TSIGKeyRing::FindResult result3 = keyring.find(key_name, md5_name);
+ EXPECT_EQ(TSIGKeyRing::NOTFOUND, result3.code);
+ EXPECT_EQ(static_cast<const TSIGKey*>(NULL), result3.key);
}
TEST_F(TSIGKeyRingTest, findFromSome) {
// essentially the same test, but search a larger set
- EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(
- TSIGKey(key_name, TSIGKey::HMACSHA256_NAME(),
- secret, secret_len)));
- EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(
- TSIGKey(Name("another.example"), TSIGKey::HMACMD5_NAME(),
- secret, secret_len)));
- EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(
- TSIGKey(Name("more.example"), TSIGKey::HMACSHA1_NAME(),
- secret, secret_len)));
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(TSIGKey(key_name, sha256_name,
+ secret, secret_len)));
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(TSIGKey(Name("another.example"),
+ md5_name,
+ secret, secret_len)));
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, keyring.add(TSIGKey(Name("more.example"),
+ sha1_name,
+ secret, secret_len)));
const TSIGKeyRing::FindResult result(
- keyring.find(Name("another.example")));
+ keyring.find(Name("another.example"), md5_name));
EXPECT_EQ(TSIGKeyRing::SUCCESS, result.code);
EXPECT_EQ(Name("another.example"), result.key->getKeyName());
EXPECT_EQ(TSIGKey::HMACMD5_NAME(), result.key->getAlgorithmName());
EXPECT_EQ(TSIGKeyRing::NOTFOUND,
- keyring.find(Name("noexist.example")).code);
+ keyring.find(Name("noexist.example"), sha1_name).code);
EXPECT_EQ(static_cast<const TSIGKey*>(NULL),
- keyring.find(Name("noexist.example")).key);
+ keyring.find(Name("noexist.example"), sha256_name).key);
+
+ EXPECT_EQ(TSIGKeyRing::NOTFOUND,
+ keyring.find(Name("another.example"), sha1_name).code);
+ EXPECT_EQ(static_cast<const TSIGKey*>(NULL),
+ keyring.find(Name("another.example"), sha256_name).key);
}
+TEST(TSIGStringTest, TSIGKeyFromToString) {
+ TSIGKey k1 = TSIGKey("test.example:MSG6Ng==:hmac-md5.sig-alg.reg.int");
+ TSIGKey k2 = TSIGKey("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.");
+ TSIGKey k3 = TSIGKey("test.example:MSG6Ng==");
+ TSIGKey k4 = TSIGKey(Name("test.example."), Name("hmac-sha1."), NULL, 0);
+ // "Unknown" key with empty secret is okay
+ TSIGKey k5 = TSIGKey("test.example.::unknown");
+
+ EXPECT_EQ("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.",
+ k1.toText());
+ EXPECT_EQ("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.",
+ k2.toText());
+ EXPECT_EQ("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.",
+ k3.toText());
+ EXPECT_EQ("test.example.::hmac-sha1.", k4.toText());
+ EXPECT_EQ(Name("test.example."), k5.getKeyName());
+ EXPECT_EQ(Name("unknown"), k5.getAlgorithmName());
+
+ EXPECT_THROW(TSIGKey(""), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey(":"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("::"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("..:aa:"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example:xxxx:"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example.::"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example.:"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example.:MSG6Ng==:"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example.:MSG6Ng==:unknown"), isc::InvalidParameter);
+}
+
+
} // end namespace
diff --git a/src/lib/dns/tests/tsigrecord_unittest.cc b/src/lib/dns/tests/tsigrecord_unittest.cc
new file mode 100644
index 0000000..e1b3e93
--- /dev/null
+++ b/src/lib/dns/tests/tsigrecord_unittest.cc
@@ -0,0 +1,159 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <vector>
+#include <sstream>
+
+#include <gtest/gtest.h>
+
+#include <util/buffer.h>
+
+#include <dns/exceptions.h>
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/tsig.h>
+#include <dns/tsigkey.h>
+#include <dns/tsigrecord.h>
+
+#include <dns/tests/unittest_util.h>
+
+using namespace std;
+using namespace isc::util;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+
+namespace {
+class TSIGRecordTest : public ::testing::Test {
+protected:
+ TSIGRecordTest() :
+ test_name("www.example.com"), test_mac(16, 0xda),
+ test_rdata(any::TSIG(TSIGKey::HMACMD5_NAME(), 0x4da8877a,
+ TSIGContext::DEFAULT_FUDGE,
+ test_mac.size(), &test_mac[0],
+ 0x2d65, 0, 0, NULL)),
+ test_record(test_name, test_rdata),
+ buffer(0), renderer(buffer)
+ {}
+ const Name test_name;
+ vector<unsigned char> test_mac;
+ const any::TSIG test_rdata;
+ const TSIGRecord test_record;
+ OutputBuffer buffer;
+ MessageRenderer renderer;
+ vector<unsigned char> data;
+};
+
+TEST_F(TSIGRecordTest, getName) {
+ EXPECT_EQ(test_name, test_record.getName());
+}
+
+TEST_F(TSIGRecordTest, getLength) {
+ // 85 = 17 + 26 + 16 + 26
+ // len(www.example.com) = 17
+ // len(hmac-md5.sig-alg.reg.int) = 26
+ // len(MAC) = 16
+ // the rest are fixed length fields (26 in total)
+ EXPECT_EQ(85, test_record.getLength());
+}
+
+TEST_F(TSIGRecordTest, fromParams) {
+ // Construct the same TSIG RR as test_record from parameters.
+ // See the getLength test for the magic number of 85 (although it
+ // actually doesn't matter)
+ const TSIGRecord record(test_name, TSIGRecord::getClass(),
+ TSIGRecord::getTTL(), test_rdata, 85);
+ // Perform straight sanity checks
+ EXPECT_EQ(test_name, record.getName());
+ EXPECT_EQ(85, record.getLength());
+ EXPECT_EQ(0, test_rdata.compare(record.getRdata()));
+
+ // The constructor doesn't check the length...
+ EXPECT_NO_THROW(TSIGRecord(test_name, TSIGRecord::getClass(),
+ TSIGRecord::getTTL(), test_rdata, 82));
+ // ...even for impossibly small values...
+ EXPECT_NO_THROW(TSIGRecord(test_name, TSIGRecord::getClass(),
+ TSIGRecord::getTTL(), test_rdata, 1));
+ // ...or too large values.
+ EXPECT_NO_THROW(TSIGRecord(test_name, TSIGRecord::getClass(),
+ TSIGRecord::getTTL(), test_rdata, 65536));
+
+ // RDATA must indeed be TSIG
+ EXPECT_THROW(TSIGRecord(test_name, TSIGRecord::getClass(),
+ TSIGRecord::getTTL(), in::A("192.0.2.1"), 85),
+ DNSMessageFORMERR);
+
+ // Unexpected class
+ EXPECT_THROW(TSIGRecord(test_name, RRClass::IN(), TSIGRecord::getTTL(),
+ test_rdata, 85), DNSMessageFORMERR);
+
+ // Unexpected TTL
+ EXPECT_THROW(TSIGRecord(test_name, TSIGRecord::getClass(),
+ RRTTL(3600), test_rdata, 85), DNSMessageFORMERR);
+}
+
+TEST_F(TSIGRecordTest, recordToWire) {
+ UnitTestUtil::readWireData("tsigrecord_toWire1.wire", data);
+ EXPECT_EQ(1, test_record.toWire(renderer));
+ EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+ renderer.getData(), renderer.getLength(),
+ &data[0], data.size());
+
+ // Same test for a dumb buffer
+ buffer.clear();
+ EXPECT_EQ(1, test_record.toWire(buffer));
+ EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+ buffer.getData(), buffer.getLength(),
+ &data[0], data.size());
+}
+
+TEST_F(TSIGRecordTest, recordToOLongToWire) {
+ // By setting the limit to "record length - 1", it will fail, and the
+ // renderer will be marked as "truncated".
+ renderer.setLengthLimit(test_record.getLength() - 1);
+ EXPECT_FALSE(renderer.isTruncated()); // not marked before render attempt
+ EXPECT_EQ(0, test_record.toWire(renderer));
+ EXPECT_TRUE(renderer.isTruncated());
+}
+
+TEST_F(TSIGRecordTest, recordToWireAfterNames) {
+ // A similar test but the TSIG RR follows some domain names that could
+ // cause name compression inside TSIG. Our implementation shouldn't
+ // compress either owner (key) name or the algorithm name. This test
+ // confirms that.
+
+ UnitTestUtil::readWireData("tsigrecord_toWire2.wire", data);
+ renderer.writeName(TSIGKey::HMACMD5_NAME());
+ renderer.writeName(Name("foo.example.com"));
+ EXPECT_EQ(1, test_record.toWire(renderer));
+ EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+ renderer.getData(), renderer.getLength(),
+ &data[0], data.size());
+}
+
+TEST_F(TSIGRecordTest, toText) {
+ EXPECT_EQ("www.example.com. 0 ANY TSIG hmac-md5.sig-alg.reg.int. "
+ "1302890362 300 16 2tra2tra2tra2tra2tra2g== 11621 NOERROR 0\n",
+ test_record.toText());
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST_F(TSIGRecordTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << test_record;
+ EXPECT_EQ(test_record.toText(), oss.str());
+}
+} // end namespace
diff --git a/src/lib/dns/tsig.cc b/src/lib/dns/tsig.cc
new file mode 100644
index 0000000..714b2a5
--- /dev/null
+++ b/src/lib/dns/tsig.cc
@@ -0,0 +1,453 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <sys/time.h>
+
+#include <stdint.h>
+
+#include <cassert>
+#include <vector>
+
+#include <boost/shared_ptr.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <util/time_utilities.h>
+
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/tsig.h>
+#include <dns/tsigerror.h>
+#include <dns/tsigkey.h>
+
+#include <cryptolink/cryptolink.h>
+#include <cryptolink/crypto_hmac.h>
+
+using namespace std;
+using namespace isc::util;
+using namespace isc::cryptolink;
+using namespace isc::dns::rdata;
+
+namespace isc {
+namespace dns {
+namespace {
+typedef boost::shared_ptr<HMAC> HMACPtr;
+
+// TSIG uses 48-bit unsigned integer to represent time signed.
+// Since gettimeWrapper() returns a 64-bit *signed* integer, we
+// make sure it's stored in an unsigned 64-bit integer variable and
+// represents a value in the expected range. (In reality, however,
+// gettimeWrapper() will return a positive integer that will fit
+// in 48 bits)
+uint64_t
+getTSIGTime() {
+ return (detail::gettimeWrapper() & 0x0000ffffffffffffULL);
+}
+}
+
+struct TSIGContext::TSIGContextImpl {
+ TSIGContextImpl(const TSIGKey& key) :
+ state_(INIT), key_(key), error_(Rcode::NOERROR()),
+ previous_timesigned_(0)
+ {}
+
+ // This helper method is used from verify(). It's expected to be called
+ // just before verify() returns. It updates internal state based on
+ // the verification result and return the TSIGError to be returned to
+ // the caller of verify(), so that verify() can call this method within
+ // its 'return' statement.
+ TSIGError postVerifyUpdate(TSIGError error, const void* digest,
+ uint16_t digest_len)
+ {
+ if (state_ == INIT) {
+ state_ = RECEIVED_REQUEST;
+ } else if (state_ == SENT_REQUEST && error == TSIGError::NOERROR()) {
+ state_ = VERIFIED_RESPONSE;
+ }
+ if (digest != NULL) {
+ previous_digest_.assign(static_cast<const uint8_t*>(digest),
+ static_cast<const uint8_t*>(digest) +
+ digest_len);
+ }
+ error_ = error;
+ return (error);
+ }
+
+ // The following three are helper methods to compute the digest for
+ // TSIG sign/verify in order to unify the common code logic for sign()
+ // and verify() and to keep these callers concise.
+ // These methods take an HMAC object, which will be updated with the
+ // calculated digest.
+ // Note: All methods construct a local OutputBuffer as a work space with a
+ // fixed initial buffer size to avoid intermediate buffer extension.
+ // This should be efficient enough, especially for fundamentally expensive
+ // operation like cryptographic sign/verify, but if the creation of the
+ // buffer in each helper method is still identified to be a severe
+ // performance bottleneck, we could have this class a buffer as a member
+ // variable and reuse it throughout the object's lifetime. Right now,
+ // we prefer keeping the scope for local things as small as possible.
+ void digestPreviousMAC(HMACPtr hmac) const;
+ void digestTSIGVariables(HMACPtr hmac, uint16_t rrclass, uint32_t rrttl,
+ uint64_t time_signed, uint16_t fudge,
+ uint16_t error, uint16_t otherlen,
+ const void* otherdata,
+ bool time_variables_only) const;
+ void digestDNSMessage(HMACPtr hmac, uint16_t qid, const void* data,
+ size_t data_len) const;
+ State state_;
+ const TSIGKey key_;
+ vector<uint8_t> previous_digest_;
+ TSIGError error_;
+ uint64_t previous_timesigned_; // only meaningful for response with BADTIME
+};
+
+void
+TSIGContext::TSIGContextImpl::digestPreviousMAC(HMACPtr hmac) const {
+ // We should have ensured the digest size fits 16 bits within this class
+ // implementation.
+ assert(previous_digest_.size() <= 0xffff);
+
+ OutputBuffer buffer(sizeof(uint16_t) + previous_digest_.size());
+ const uint16_t previous_digest_len(previous_digest_.size());
+ buffer.writeUint16(previous_digest_len);
+ if (previous_digest_len != 0) {
+ buffer.writeData(&previous_digest_[0], previous_digest_len);
+ }
+ hmac->update(buffer.getData(), buffer.getLength());
+}
+
+void
+TSIGContext::TSIGContextImpl::digestTSIGVariables(
+ HMACPtr hmac, uint16_t rrclass, uint32_t rrttl, uint64_t time_signed,
+ uint16_t fudge, uint16_t error, uint16_t otherlen, const void* otherdata,
+ bool time_variables_only) const
+{
+ // It's bit complicated, but we can still predict the necessary size of
+ // the data to be digested. So we precompute it to avoid possible
+ // reallocation inside OutputBuffer (not absolutely necessary, but this
+ // is a bit more efficient)
+ size_t data_size = 8;
+ if (!time_variables_only) {
+ data_size += 10 + key_.getKeyName().getLength() +
+ key_.getAlgorithmName().getLength();
+ }
+ OutputBuffer buffer(data_size);
+
+ if (!time_variables_only) {
+ key_.getKeyName().toWire(buffer);
+ buffer.writeUint16(rrclass);
+ buffer.writeUint32(rrttl);
+ key_.getAlgorithmName().toWire(buffer);
+ }
+ buffer.writeUint16(time_signed >> 32);
+ buffer.writeUint32(time_signed & 0xffffffff);
+ buffer.writeUint16(fudge);
+
+ if (!time_variables_only) {
+ buffer.writeUint16(error);
+ buffer.writeUint16(otherlen);
+ }
+
+ hmac->update(buffer.getData(), buffer.getLength());
+ if (!time_variables_only && otherlen > 0) {
+ hmac->update(otherdata, otherlen);
+ }
+}
+
+// In digestDNSMessage, we exploit some minimum knowledge of DNS message
+// format:
+// - the header section has a fixed length of 12 octets (MESSAGE_HEADER_LEN)
+// - the offset in the header section to the ID field is 0
+// - the offset in the header section to the ARCOUNT field is 10 (and the field
+// length is 2 octets)
+// We could construct a separate Message object from the given data, adjust
+// fields via the Message interfaces and then render it back to a separate
+// buffer, but that would be overkilling. The DNS message header has a
+// fixed length and necessary modifications are quite straightforward, so
+// we do the job using lower level interfaces.
+namespace {
+const size_t MESSAGE_HEADER_LEN = 12;
+}
+void
+TSIGContext::TSIGContextImpl::digestDNSMessage(HMACPtr hmac,
+ uint16_t qid, const void* data,
+ size_t data_len) const
+{
+ OutputBuffer buffer(MESSAGE_HEADER_LEN);
+ const uint8_t* msgptr = static_cast<const uint8_t*>(data);
+
+ // Install the original ID
+ buffer.writeUint16(qid);
+ msgptr += sizeof(uint16_t);
+
+ // Copy the rest of the header except the ARCOUNT field.
+ buffer.writeData(msgptr, 8);
+ msgptr += 8;
+
+ // Install the adjusted ARCOUNT (we don't care even if the value is bogus
+ // and it underflows; it would simply result in verification failure)
+ buffer.writeUint16(InputBuffer(msgptr, sizeof(uint16_t)).readUint16() - 1);
+ msgptr += 2;
+
+ // Digest the header and the rest of the DNS message
+ hmac->update(buffer.getData(), buffer.getLength());
+ hmac->update(msgptr, data_len - MESSAGE_HEADER_LEN);
+}
+
+TSIGContext::TSIGContext(const TSIGKey& key) : impl_(new TSIGContextImpl(key))
+{
+}
+
+TSIGContext::TSIGContext(const Name& key_name, const Name& algorithm_name,
+ const TSIGKeyRing& keyring) : impl_(NULL)
+{
+ const TSIGKeyRing::FindResult result(keyring.find(key_name,
+ algorithm_name));
+ if (result.code == TSIGKeyRing::NOTFOUND) {
+ // If not key is found, create a dummy key with the specified key
+ // parameters and empty secret. In the common scenario this will
+ // be used in subsequent response with a TSIG indicating a BADKEY
+ // error.
+ impl_ = new TSIGContextImpl(TSIGKey(key_name, algorithm_name,
+ NULL, 0));
+ impl_->error_ = TSIGError::BAD_KEY();
+ } else {
+ impl_ = new TSIGContextImpl(*result.key);
+ }
+}
+
+TSIGContext::~TSIGContext() {
+ delete impl_;
+}
+
+TSIGContext::State
+TSIGContext::getState() const {
+ return (impl_->state_);
+}
+
+TSIGError
+TSIGContext::getError() const {
+ return (impl_->error_);
+}
+
+ConstTSIGRecordPtr
+TSIGContext::sign(const uint16_t qid, const void* const data,
+ const size_t data_len)
+{
+ if (impl_->state_ == VERIFIED_RESPONSE) {
+ isc_throw(TSIGContextError,
+ "TSIG sign attempt after verifying a response");
+ }
+
+ if (data == NULL || data_len == 0) {
+ isc_throw(InvalidParameter, "TSIG sign error: empty data is given");
+ }
+
+ TSIGError error(TSIGError::NOERROR());
+ const uint64_t now = getTSIGTime();
+
+ // For responses adjust the error code.
+ if (impl_->state_ == RECEIVED_REQUEST) {
+ error = impl_->error_;
+ }
+
+ // For errors related to key or MAC, return an unsigned response as
+ // specified in Section 4.3 of RFC2845.
+ if (error == TSIGError::BAD_SIG() || error == TSIGError::BAD_KEY()) {
+ ConstTSIGRecordPtr tsig(new TSIGRecord(
+ impl_->key_.getKeyName(),
+ any::TSIG(impl_->key_.getAlgorithmName(),
+ now, DEFAULT_FUDGE, 0, NULL,
+ qid, error.getCode(), 0, NULL)));
+ impl_->previous_digest_.clear();
+ impl_->state_ = SENT_RESPONSE;
+ return (tsig);
+ }
+
+ HMACPtr hmac(CryptoLink::getCryptoLink().createHMAC(
+ impl_->key_.getSecret(),
+ impl_->key_.getSecretLength(),
+ impl_->key_.getAlgorithm()),
+ deleteHMAC);
+
+ // If the context has previous MAC (either the Request MAC or its own
+ // previous MAC), digest it.
+ if (impl_->state_ != INIT) {
+ impl_->digestPreviousMAC(hmac);
+ }
+
+ // Digest the message (without TSIG)
+ hmac->update(data, data_len);
+
+ // Digest TSIG variables.
+ // First, prepare some non constant variables.
+ const uint64_t time_signed = (error == TSIGError::BAD_TIME()) ?
+ impl_->previous_timesigned_ : now;
+ // For BADTIME error, we include 6 bytes of other data.
+ // (6 bytes = size of time signed value)
+ const uint16_t otherlen = (error == TSIGError::BAD_TIME()) ? 6 : 0;
+ OutputBuffer otherdatabuf(otherlen);
+ if (error == TSIGError::BAD_TIME()) {
+ otherdatabuf.writeUint16(now >> 32);
+ otherdatabuf.writeUint32(now & 0xffffffff);
+ }
+ const void* const otherdata =
+ (otherlen == 0) ? NULL : otherdatabuf.getData();
+ // Then calculate the digest. If state_ is SENT_RESPONSE we are sending
+ // a continued message in the same TCP stream so skip digesting
+ // variables except for time related variables (RFC2845 4.4).
+ impl_->digestTSIGVariables(hmac, TSIGRecord::getClass().getCode(),
+ TSIGRecord::TSIG_TTL, time_signed,
+ DEFAULT_FUDGE, error.getCode(),
+ otherlen, otherdata,
+ impl_->state_ == SENT_RESPONSE);
+
+ // Get the final digest, update internal state, then finish.
+ vector<uint8_t> digest = hmac->sign();
+ assert(digest.size() <= 0xffff); // cryptolink API should have ensured it.
+ ConstTSIGRecordPtr tsig(new TSIGRecord(
+ impl_->key_.getKeyName(),
+ any::TSIG(impl_->key_.getAlgorithmName(),
+ time_signed, DEFAULT_FUDGE,
+ digest.size(), &digest[0],
+ qid, error.getCode(), otherlen,
+ otherdata)));
+ // Exception free from now on.
+ impl_->previous_digest_.swap(digest);
+ impl_->state_ = (impl_->state_ == INIT) ? SENT_REQUEST : SENT_RESPONSE;
+ return (tsig);
+}
+
+TSIGError
+TSIGContext::verify(const TSIGRecord* const record, const void* const data,
+ const size_t data_len)
+{
+ if (impl_->state_ == SENT_RESPONSE) {
+ isc_throw(TSIGContextError,
+ "TSIG verify attempt after sending a response");
+ }
+
+ // This case happens when we sent a signed request and have received an
+ // unsigned response. According to RFC2845 Section 4.6 this case should be
+ // considered a "format error" (although the specific error code
+ // wouldn't matter much for the caller).
+ if (record == NULL) {
+ return (impl_->postVerifyUpdate(TSIGError::FORMERR(), NULL, 0));
+ }
+
+ const any::TSIG& tsig_rdata = record->getRdata();
+
+ // Reject some obviously invalid data
+ if (data_len < MESSAGE_HEADER_LEN + record->getLength()) {
+ isc_throw(InvalidParameter,
+ "TSIG verify: data length is invalid: " << data_len);
+ }
+ if (data == NULL) {
+ isc_throw(InvalidParameter, "TSIG verify: empty data is invalid");
+ }
+
+ // Check key: whether we first verify it with a known key or we verify
+ // it using the consistent key in the context. If the check fails we are
+ // done with BADKEY.
+ if (impl_->state_ == INIT && impl_->error_ == TSIGError::BAD_KEY()) {
+ return (impl_->postVerifyUpdate(TSIGError::BAD_KEY(), NULL, 0));
+ }
+ if (impl_->key_.getKeyName() != record->getName() ||
+ impl_->key_.getAlgorithmName() != tsig_rdata.getAlgorithm()) {
+ return (impl_->postVerifyUpdate(TSIGError::BAD_KEY(), NULL, 0));
+ }
+
+ // Check time: the current time must be in the range of
+ // [time signed - fudge, time signed + fudge]. Otherwise verification
+ // fails with BADTIME. (RFC2845 Section 4.6.2)
+ // Note: for simplicity we don't explicitly catch the case of too small
+ // current time causing underflow. With the fact that fudge is quite
+ // small and (for now) non configurable, it shouldn't be a real concern
+ // in practice.
+ const uint64_t now = getTSIGTime();
+ if (tsig_rdata.getTimeSigned() + DEFAULT_FUDGE < now ||
+ tsig_rdata.getTimeSigned() - DEFAULT_FUDGE > now) {
+ const void* digest = NULL;
+ size_t digest_len = 0;
+ if (impl_->state_ == INIT) {
+ digest = tsig_rdata.getMAC();
+ digest_len = tsig_rdata.getMACSize();
+ impl_->previous_timesigned_ = tsig_rdata.getTimeSigned();
+ }
+ return (impl_->postVerifyUpdate(TSIGError::BAD_TIME(), digest,
+ digest_len));
+ }
+
+ // TODO: signature length check based on RFC4635
+ // (Right now we enforce the standard signature length in libcryptolink)
+
+ // Handling empty MAC. While RFC2845 doesn't explicitly prohibit other
+ // cases, it can only reasonably happen in a response with BADSIG or
+ // BADKEY. We reject other cases as if it were BADSIG to avoid unexpected
+ // acceptance of a bogus signature. This behavior follows the BIND 9
+ // implementation.
+ if (tsig_rdata.getMACSize() == 0) {
+ TSIGError error = TSIGError(tsig_rdata.getError());
+ if (error != TSIGError::BAD_SIG() && error != TSIGError::BAD_KEY()) {
+ error = TSIGError::BAD_SIG();
+ }
+ return (impl_->postVerifyUpdate(error, NULL, 0));
+ }
+
+ HMACPtr hmac(CryptoLink::getCryptoLink().createHMAC(
+ impl_->key_.getSecret(),
+ impl_->key_.getSecretLength(),
+ impl_->key_.getAlgorithm()),
+ deleteHMAC);
+
+ // If the context has previous MAC (either the Request MAC or its own
+ // previous MAC), digest it.
+ if (impl_->state_ != INIT) {
+ impl_->digestPreviousMAC(hmac);
+ }
+
+ //
+ // Digest DNS message (excluding the trailing TSIG RR and adjusting the
+ // QID and ARCOUNT header fields)
+ //
+ impl_->digestDNSMessage(hmac, tsig_rdata.getOriginalID(),
+ data, data_len - record->getLength());
+
+ // Digest TSIG variables. If state_ is VERIFIED_RESPONSE, it's a
+ // continuation of the same TCP stream and skip digesting them except
+ // for time related variables (RFC2845 4.4).
+ // Note: we use the constant values for RR class and TTL specified
+ // in RFC2845, not received values (we reject other values in constructing
+ // the TSIGRecord).
+ impl_->digestTSIGVariables(hmac, TSIGRecord::getClass().getCode(),
+ TSIGRecord::TSIG_TTL,
+ tsig_rdata.getTimeSigned(),
+ tsig_rdata.getFudge(), tsig_rdata.getError(),
+ tsig_rdata.getOtherLen(),
+ tsig_rdata.getOtherData(),
+ impl_->state_ == VERIFIED_RESPONSE);
+
+ // Verify the digest with the received signature.
+ if (hmac->verify(tsig_rdata.getMAC(), tsig_rdata.getMACSize())) {
+ return (impl_->postVerifyUpdate(TSIGError::NOERROR(),
+ tsig_rdata.getMAC(),
+ tsig_rdata.getMACSize()));
+ }
+
+ return (impl_->postVerifyUpdate(TSIGError::BAD_SIG(), NULL, 0));
+}
+
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/tsig.h b/src/lib/dns/tsig.h
new file mode 100644
index 0000000..bceec25
--- /dev/null
+++ b/src/lib/dns/tsig.h
@@ -0,0 +1,394 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __TSIG_H
+#define __TSIG_H 1
+
+#include <boost/noncopyable.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/tsigerror.h>
+#include <dns/tsigkey.h>
+#include <dns/tsigrecord.h>
+
+namespace isc {
+namespace dns {
+
+/// An exception that is thrown for logic errors identified in TSIG
+/// sign/verify operations.
+///
+/// Note that this exception is not thrown for TSIG protocol errors such as
+/// verification failures. In general, this exception indicates an internal
+/// program bug.
+class TSIGContextError : public isc::Exception {
+public:
+ TSIGContextError(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+/// TSIG session context.
+///
+/// The \c TSIGContext class maintains a context of a signed session of
+/// DNS transactions by TSIG. In many cases a TSIG signed session consists
+/// of a single set of request (e.g. normal query) and reply (e.g. normal
+/// response), where the request is initially signed by the client, and the
+/// reply is signed by the server using the initial signature. As mentioned
+/// in RFC2845, a session can consist of multiple exchanges in a TCP
+/// connection. As also mentioned in the RFC, an AXFR response often contains
+/// multiple DNS messages, which can belong to the same TSIG session.
+/// This class supports all these cases.
+///
+/// A \c TSIGContext object is generally constructed with a TSIG key to be
+/// used for the session, and keeps track of various kinds of session specific
+/// information, such as the original digest while waiting for a response or
+/// verification error information that is to be used for a subsequent
+/// response.
+///
+/// This class has two main methods, \c sign() and \c verify().
+/// The \c sign() method signs given data (which is supposed to be a complete
+/// DNS message without the TSIG itself) using the TSIG key and other
+/// related information associated with the \c TSIGContext object.
+/// The \c verify() method verifies a given DNS message that contains a TSIG
+/// RR using the key and other internal information.
+///
+/// In general, a DNS client that wants to send a signed query will construct
+/// a \c TSIGContext object with the TSIG key that the client is intending to
+/// use, and sign the query with the context. The client will keeps the
+/// context, and verify the response with it.
+///
+/// On the other hand, a DNS server will construct a \c TSIGContext object
+/// with the information of the TSIG RR included in a query with a set of
+/// possible keys (in the form of a \c TSIGKeyRing object). The constructor
+/// in this mode will identify the appropriate TSIG key (or internally record
+/// an error if it doesn't find a key). The server will then verify the
+/// query with the context, and generate a signed response using the same
+/// same context.
+///
+/// When multiple messages belong to the same TSIG session, either side
+/// (signer or verifier) will keep using the same context. It records
+/// the latest session state (such as the previous digest) so that repeated
+/// calls to \c sign() or \c verify() work correctly in terms of the TSIG
+/// protocol.
+///
+/// \b Examples
+///
+/// This is a typical client application that sends a TSIG signed query
+/// and verifies the response.
+///
+/// \code
+/// // "renderer" is of MessageRenderer to render the message.
+/// // (TSIGKey would be configured from config or command line in real app)
+/// TSIGContext ctx(TSIGKey("key.example:MSG6Ng=="));
+/// Message message(Message::RENDER);
+/// message.addQuestion(Question(Name("www.example.com"), RRClass::IN(),
+/// RRType::A()));
+/// message.toWire(renderer, ctx);
+///
+/// // sendto, then recvfrom. received result in (data, data_len)
+///
+/// message.clear(Message::PARSE);
+/// InputBuffer buffer(data, data_len);
+/// message.fromWire(buffer);
+/// TSIGError tsig_error = ctx.verify(message.getTSIGRecord(),
+/// data, data_len);
+/// if (tsig_error == TSIGError::NOERROR()) {
+/// // okay. ctx can be continuously used if it's receiving subsequent
+/// // signed responses from a TCP stream.
+/// } else if (message.getRcode() == Rcode::NOTAUTH()) {
+/// // hard error. give up this transaction per RFC2845 4.6.
+/// } else {
+/// // Other error: discard response keep waiting with the same ctx
+/// // for another (again, RFC2845 4.6).
+/// } \endcode
+///
+/// And this is a typical server application that authenticates a signed
+/// query and returns a response according to the result.
+///
+/// \code
+/// // Assume "message" is of type Message for query handling and
+/// // "renderer" is of MessageRenderer to render responses.
+/// Message message(Message::RENDER);
+///
+/// TSIGKeyRing keyring; // this must be configured with keys somewhere
+///
+/// // Receive a query and store it in (data, data_len)
+/// InputBuffer buffer(data, data_len);
+/// message.clear(Message::PARSE);
+/// message.fromWire(buffer);
+///
+/// const TSIGRecord* tsig = message.getTSIGRecord();
+/// if (tsig != NULL) {
+/// TSIGContext ctx(tsig->getName(), tsig->getRdata().getAlgorithm(),
+/// keyring);
+/// ctx.verify(tsig, data, data_len);
+///
+/// // prepare response
+/// message.makeResponse();
+/// //...
+/// message.toWire(renderer, ctx);
+///
+/// // send the response data back to the client.
+/// // If this is a beginning of a signed session over a TCP and
+/// // server has more data to send to the client, this ctx
+/// // will be used to sign subsequent messages.
+/// } \endcode
+///
+/// <b>TCP Consideration</b>
+///
+/// RFC2845 describes the case where a single TSIG session is used for
+/// multiple DNS messages (Section 4.4). This class supports signing and
+/// verifying the messages in this scenario, but does not care if the messages
+/// were delivered over a TCP connection or not. If, for example, the
+/// same \c TSIGContext object is used to sign two independent DNS queries
+/// sent over UDP, they will be considered to belong to the same TSIG
+/// session, and, as a result, verification will be likely to fail.
+///
+/// \b Copyability
+///
+/// This class is currently non copyable based on the observation of the
+/// typical usage as described above. But there is no strong technical
+/// reason why this class cannot be copyable. If we see the need for it
+/// in future we may change the implementation on this point.
+///
+/// <b>Note to developers:</b>
+/// One basic design choice is to make the \c TSIGContext class is as
+/// independent from the \c Message class. This is because the latter is
+/// much more complicated, depending on many other classes, while TSIG is
+/// a very specific part of the entire DNS protocol set. If the \c TSIGContext
+/// class depends on \c \c Message, it will be more vulnerable to changes
+/// to other classes, and will be more difficult to test due to the
+/// direct or indirect dependencies. The interface of \c sign() that takes
+/// opaque data (instead of, e.g., a \c Message or \c MessageRenderer object)
+/// is therefore a deliberate design decision.
+class TSIGContext : boost::noncopyable {
+public:
+ /// Internal state of context
+ ///
+ /// The constants of this enum type define a specific state of
+ /// \c TSIGContext to adjust the behavior. The definition is public
+ /// and the state can be seen via the \c getState() method, but this is
+ /// mostly private information. It's publicly visible mainly for testing
+ /// purposes; there is no API for the application to change the state
+ /// directly.
+ enum State {
+ INIT, ///< Initial state
+ SENT_REQUEST, ///< Client sent a signed request, waiting response
+ RECEIVED_REQUEST, ///< Server received a signed request
+ SENT_RESPONSE, ///< Server sent a signed response
+ VERIFIED_RESPONSE ///< Client successfully verified a response
+ };
+
+ /// \name Constructors and destructor
+ ///
+ //@{
+ /// Constructor from a TSIG key.
+ ///
+ /// \exception std::bad_alloc Resource allocation for internal data fails
+ ///
+ /// \param key The TSIG key to be used for TSIG sessions with this context.
+ explicit TSIGContext(const TSIGKey& key);
+
+ /// Constructor from key parameters and key ring.
+ TSIGContext(const Name& key_name, const Name& algorithm_name,
+ const TSIGKeyRing& keyring);
+
+ /// The destructor.
+ ~TSIGContext();
+ //@}
+
+ /// Sign a DNS message.
+ ///
+ /// This method computes the TSIG MAC for the given data, which is
+ /// generally expected to be a complete, wire-format DNS message
+ /// that doesn't contain a TSIG RR, based on the TSIG key and
+ /// other context information of \c TSIGContext, and returns a
+ /// result in the form of a (pointer object pointing to)
+ /// \c TSIGRecord object.
+ ///
+ /// The caller of this method will use the returned value to render a
+ /// complete TSIG RR into the message that has been signed so that it
+ /// will become a complete TSIG-signed message.
+ ///
+ /// In general, this method is called once by a client to send a
+ /// signed request or one more times by a server to sign
+ /// response(s) to a signed request. To avoid allowing accidental
+ /// misuse, if this method is called after a "client" validates a
+ /// response, an exception of class \c TSIGContextError will be
+ /// thrown.
+ ///
+ /// \note Normal applications are not expected to call this method
+ /// directly; they will usually use the \c Message::toWire() method
+ /// with a \c TSIGContext object being a parameter and have the
+ /// \c Message class create a complete signed message.
+ ///
+ /// This method treats the given data as opaque, even though it's generally
+ /// expected to represent a wire-format DNS message (see also the class
+ /// description), and doesn't inspect it in any way. For example, it
+ /// doesn't check whether the data length is sane for a valid DNS message.
+ /// This is also the reason why this method takes the \c qid parameter,
+ /// which will be used as the original ID of the resulting
+ /// \c TSIGRecordx object, even though this value should be stored in the
+ /// first two octets (in wire format) of the given data.
+ ///
+ /// \note This method still checks and rejects empty data (\c NULL pointer
+ /// data or the specified data length is 0) in order to avoid catastrophic
+ /// effect such as program crash. Empty data is not necessarily invalid
+ /// for HMAC computation, but obviously it doesn't make sense for a DNS
+ /// message.
+ ///
+ /// This method provides the strong exception guarantee; unless the method
+ /// returns (without an exception being thrown), the internal state of
+ /// the \c TSIGContext won't be modified.
+ ///
+ /// \exception TSIGContextError Context already verified a response.
+ /// \exception InvalidParameter \c data is NULL or \c data_len is 0
+ /// \exception cryptolink::LibraryError Some unexpected error in the
+ /// underlying crypto operation
+ /// \exception std::bad_alloc Temporary resource allocation failure
+ ///
+ /// \param qid The QID to be as the value of the original ID field of
+ /// the resulting TSIG record
+ /// \param data Points to the wire-format data to be signed
+ /// \param data_len The length of \c data in bytes
+ ///
+ /// \return A TSIG record for the given data along with the context.
+ ConstTSIGRecordPtr sign(const uint16_t qid, const void* const data,
+ const size_t data_len);
+
+ /// Verify a DNS message.
+ ///
+ /// This method verifies given data along with the context and a given
+ /// TSIG in the form of a \c TSIGRecord object. The data to be verified
+ /// is generally expected to be a complete, wire-format DNS message,
+ /// exactly as received by the host, and ending with a TSIG RR.
+ /// After verification process this method updates its internal state,
+ /// and returns the result in the form of a \c TSIGError object.
+ /// Possible return values are (see the \c TSIGError class description
+ /// for the mnemonics):
+ ///
+ /// - \c NOERROR: The data has been verified correctly.
+ /// - \c FORMERR: \c TSIGRecord is not given (see below).
+ /// - \c BAD_KEY: Appropriate key is not found or specified key doesn't
+ /// match for the data.
+ /// - \c BAD_TIME: The current time doesn't fall in the range specified
+ /// in the TSIG.
+ /// - \c BAD_SIG: The signature given in the TSIG doesn't match against
+ /// the locally computed digest or is the signature is
+ /// invalid in other way.
+ ///
+ /// If this method is called by a DNS client waiting for a signed
+ /// response and the result is not \c NOERROR, the context can be used
+ /// to try validating another signed message as described in RFC2845
+ /// Section 4.6.
+ ///
+ /// If this method is called by a DNS server that tries to authenticate
+ /// a signed request, and if the result is not \c NOERROR, the
+ /// corresponding error condition is recorded in the context so that
+ /// the server can return a response indicating what was wrong by calling
+ /// \c sign() with the updated context.
+ ///
+ /// In general, this method is called once by a server for
+ /// authenticating a signed request or one more times by a client to
+ /// validate signed response(s) to a signed request. To avoid allowing
+ /// accidental misuse, if this method is called after a "server" signs
+ /// a response, an exception of class \c TSIGContextError will be thrown.
+ ///
+ /// The \c record parameter can be NULL; in that case this method simply
+ /// returns \c FORMERR as the case described in Section 4.6 of RFC2845,
+ /// i.e., receiving an unsigned response to a signed request. This way
+ /// a client can transparently pass the result of
+ /// \c Message::getTSIGRecord() without checking whether it's non NULL
+ /// and take an appropriate action based on the result of this method.
+ ///
+ /// This method handles the given data mostly as opaque. It digests
+ /// the data assuming it begins with a DNS header and ends with a TSIG
+ /// RR whose length is given by calling \c TSIGRecord::getLength() on
+ /// \c record, but otherwise it doesn't parse the data to confirm the
+ /// assumption. It's caller's responsibility to ensure the data is
+ /// valid and consistent with \c record. To avoid disruption, this
+ /// method performs minimal validation on the given \c data and \c record:
+ /// \c data must not be NULL; \c data_len must not be smaller than the
+ /// sum of the DNS header length (fixed, 12 octets) and the length of
+ /// the TSIG RR. If this check fails it throws an \c InvalidParameter
+ /// exception.
+ ///
+ /// One unexpected case that is not covered by this method is that a
+ /// client receives a signed response to an unsigned request. RFC2845 is
+ /// silent about such cases; BIND 9 explicitly identifies the case and
+ /// rejects it. With this implementation, the client can know that the
+ /// response contains a TSIG via the result of
+ /// \c Message::getTSIGRecord() and that it is an unexpected TSIG due to
+ /// the fact that it doesn't have a corresponding \c TSIGContext.
+ /// It's up to the client implementation whether to react to such a case
+ /// explicitly (for example, it could either ignore the TSIG and accept
+ /// the response or drop it).
+ ///
+ /// This method provides the strong exception guarantee; unless the method
+ /// returns (without an exception being thrown), the internal state of
+ /// the \c TSIGContext won't be modified.
+ ///
+ /// \todo Support intermediate TCP DNS messages without TSIG (RFC2845 4.4)
+ /// \todo Signature truncation support based on RFC4635
+ ///
+ /// \exception TSIGContextError Context already signed a response.
+ /// \exception InvalidParameter \c data is NULL or \c data_len is too small.
+ ///
+ /// \param record The \c TSIGRecord to be verified with \c data
+ /// \param data Points to the wire-format data (exactly as received) to
+ /// be verified
+ /// \param data_len The length of \c data in bytes
+ /// \return The \c TSIGError that indicates verification result
+ TSIGError verify(const TSIGRecord* const record, const void* const data,
+ const size_t data_len);
+
+ /// Return the current state of the context
+ ///
+ /// \note
+ /// The states are visible in public mainly for testing purposes.
+ /// Normal applications won't have to deal with them.
+ ///
+ /// \exception None
+ State getState() const;
+
+ /// Return the TSIG error as a result of the latest verification
+ ///
+ /// This method can be called even before verifying anything, but the
+ /// returned value is meaningless in that case.
+ ///
+ /// \exception None
+ TSIGError getError() const;
+
+ /// \name Protocol constants and defaults
+ ///
+ //@{
+ /// The recommended fudge value (in seconds) by RFC2845.
+ ///
+ /// Right now fudge is not tunable, and all TSIGs generated by this API
+ /// will have this value of fudge.
+ static const uint16_t DEFAULT_FUDGE = 300;
+ //@}
+
+private:
+ struct TSIGContextImpl;
+ TSIGContextImpl* impl_;
+};
+}
+}
+
+#endif // __TSIG_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/tsigerror.cc b/src/lib/dns/tsigerror.cc
new file mode 100644
index 0000000..36ef47d
--- /dev/null
+++ b/src/lib/dns/tsigerror.cc
@@ -0,0 +1,68 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <ostream>
+#include <string>
+
+#include <boost/lexical_cast.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/rcode.h>
+#include <dns/tsigerror.h>
+
+namespace isc {
+namespace dns {
+namespace {
+const char* const tsigerror_text[] = {
+ "BADSIG",
+ "BADKEY",
+ "BADTIME"
+};
+}
+
+TSIGError::TSIGError(Rcode rcode) : code_(rcode.getCode()) {
+ if (code_ > MAX_RCODE_FOR_TSIGERROR) {
+ isc_throw(OutOfRange, "Invalid RCODE for TSIG Error: " << rcode);
+ }
+}
+
+std::string
+TSIGError::toText() const {
+ if (code_ <= MAX_RCODE_FOR_TSIGERROR) {
+ return (Rcode(code_).toText());
+ } else if (code_ <= BAD_TIME_CODE) {
+ return (tsigerror_text[code_ - (MAX_RCODE_FOR_TSIGERROR + 1)]);
+ } else {
+ return (boost::lexical_cast<std::string>(code_));
+ }
+}
+
+Rcode
+TSIGError::toRcode() const {
+ if (code_ <= MAX_RCODE_FOR_TSIGERROR) {
+ return (Rcode(code_));
+ }
+ if (code_ > BAD_TIME_CODE) {
+ return (Rcode::SERVFAIL());
+ }
+ return (Rcode::NOTAUTH());
+}
+
+std::ostream&
+operator<<(std::ostream& os, const TSIGError& error) {
+ return (os << error.toText());
+}
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/tsigerror.h b/src/lib/dns/tsigerror.h
new file mode 100644
index 0000000..8efd3ae
--- /dev/null
+++ b/src/lib/dns/tsigerror.h
@@ -0,0 +1,338 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __TSIGERROR_H
+#define __TSIGERROR_H 1
+
+#include <ostream>
+#include <string>
+
+#include <dns/rcode.h>
+
+namespace isc {
+namespace dns {
+/// TSIG errors
+///
+/// The \c TSIGError class objects represent standard errors related to
+/// TSIG protocol operations as defined in related specifications, mainly
+/// in RFC2845.
+class TSIGError {
+public:
+ /// Constants for pre-defined TSIG error values.
+ ///
+ /// Code values from 0 through 15 (inclusive) are derived from those of
+ /// RCODE and are not defined here. See the \c Rcode class.
+ ///
+ /// \note Unfortunately some systems define "BADSIG" as a macro in a public
+ /// header file. To avoid conflict with it we add an underscore to our
+ /// definitions.
+ enum CodeValue {
+ BAD_SIG_CODE = 16, ///< 16: TSIG verification failure
+ BAD_KEY_CODE = 17, ///< 17: TSIG key is not recognized
+ BAD_TIME_CODE = 18 ///< 18: Current time and time signed are too different
+ };
+
+ /// \name Constructors
+ ///
+ /// We use the default versions of destructor, copy constructor,
+ /// and assignment operator.
+ //@{
+ /// Constructor from the code value.
+ ///
+ /// \exception None
+ ///
+ /// \param error_code The underlying 16-bit error code value of the \c TSIGError.
+ explicit TSIGError(uint16_t error_code) : code_(error_code) {}
+
+ /// Constructor from \c Rcode.
+ ///
+ /// As defined in RFC2845, error code values from 0 to 15 (inclusive) are
+ /// derived from the DNS RCODEs, which are represented via the \c Rcode
+ /// class in this library. This constructor works as a converter from
+ /// these RCODEs to corresponding TSIGError objects.
+ ///
+ /// \exception isc::OutOfRange Given rcode is not convertible to
+ /// TSIGErrors.
+ ///
+ /// \param rcode the \c Rcode from which the TSIGError should be derived.
+ explicit TSIGError(Rcode rcode);
+ //@}
+
+ /// \brief Returns the \c TSIGCode error code value.
+ ///
+ /// \exception None
+ ///
+ /// \return The underlying code value corresponding to the \c TSIGError.
+ uint16_t getCode() const { return (code_); }
+
+ /// \brief Return true iff two \c TSIGError objects are equal.
+ ///
+ /// Two TSIGError objects are equal iff their error codes are equal.
+ ///
+ /// \exception None
+ ///
+ /// \param other the \c TSIGError object to compare against.
+ /// \return true if the two TSIGError are equal; otherwise false.
+ bool equals(const TSIGError& other) const
+ { return (code_ == other.code_); }
+
+ /// \brief Same as \c equals().
+ bool operator==(const TSIGError& other) const { return (equals(other)); }
+
+ /// \brief Return true iff two \c TSIGError objects are not equal.
+ ///
+ /// \exception None
+ ///
+ /// \param other the \c TSIGError object to compare against.
+ /// \return true if the two TSIGError objects are not equal;
+ /// otherwise false.
+ bool nequals(const TSIGError& other) const
+ { return (code_ != other.code_); }
+
+ /// \brief Same as \c nequals().
+ bool operator!=(const TSIGError& other) const { return (nequals(other)); }
+
+ /// \brief Convert the \c TSIGError to a string.
+ ///
+ /// For codes derived from RCODEs up to 15, this method returns the
+ /// same string as \c Rcode::toText() for the corresponding code.
+ /// For other pre-defined code values (see TSIGError::CodeValue),
+ /// this method returns a string representation of the "mnemonic' used
+ /// for the enum and constant objects as defined in RFC2845.
+ /// For example, the string for code value 16 is "BADSIG", etc.
+ /// For other code values it returns a string representation of the decimal
+ /// number of the value, e.g. "32", "100", etc.
+ ///
+ /// \exception std::bad_alloc Resource allocation for the string fails
+ ///
+ /// \return A string representation of the \c TSIGError.
+ std::string toText() const;
+
+ /// \brief Convert the \c TSIGError to a \c Rcode
+ ///
+ /// This method returns an \c Rcode object that is corresponding to
+ /// the TSIG error. The returned \c Rcode is expected to be used
+ /// by a verifying server to specify the RCODE of a response when
+ /// TSIG verification fails.
+ ///
+ /// Specifically, this method returns \c Rcode::NOTAUTH() for the
+ /// TSIG specific errors, BADSIG, BADKEY, BADTIME, as described in
+ /// RFC2845. For errors derived from the standard Rcode (code 0-15),
+ /// it returns the corresponding \c Rcode. For others, this method
+ /// returns \c Rcode::SERVFAIL() as a last resort.
+ ///
+ /// \exception None
+ Rcode toRcode() const;
+
+ /// A constant TSIG error object derived from \c Rcode::NOERROR()
+ static const TSIGError& NOERROR();
+
+ /// A constant TSIG error object derived from \c Rcode::FORMERR()
+ static const TSIGError& FORMERR();
+
+ /// A constant TSIG error object derived from \c Rcode::SERVFAIL()
+ static const TSIGError& SERVFAIL();
+
+ /// A constant TSIG error object derived from \c Rcode::NXDOMAIN()
+ static const TSIGError& NXDOMAIN();
+
+ /// A constant TSIG error object derived from \c Rcode::NOTIMP()
+ static const TSIGError& NOTIMP();
+
+ /// A constant TSIG error object derived from \c Rcode::REFUSED()
+ static const TSIGError& REFUSED();
+
+ /// A constant TSIG error object derived from \c Rcode::YXDOMAIN()
+ static const TSIGError& YXDOMAIN();
+
+ /// A constant TSIG error object derived from \c Rcode::YXRRSET()
+ static const TSIGError& YXRRSET();
+
+ /// A constant TSIG error object derived from \c Rcode::NXRRSET()
+ static const TSIGError& NXRRSET();
+
+ /// A constant TSIG error object derived from \c Rcode::NOTAUTH()
+ static const TSIGError& NOTAUTH();
+
+ /// A constant TSIG error object derived from \c Rcode::NOTZONE()
+ static const TSIGError& NOTZONE();
+
+ /// A constant TSIG error object derived from \c Rcode::RESERVED11()
+ static const TSIGError& RESERVED11();
+
+ /// A constant TSIG error object derived from \c Rcode::RESERVED12()
+ static const TSIGError& RESERVED12();
+
+ /// A constant TSIG error object derived from \c Rcode::RESERVED13()
+ static const TSIGError& RESERVED13();
+
+ /// A constant TSIG error object derived from \c Rcode::RESERVED14()
+ static const TSIGError& RESERVED14();
+
+ /// A constant TSIG error object derived from \c Rcode::RESERVED15()
+ static const TSIGError& RESERVED15();
+
+ /// A constant TSIG error object for the BADSIG code
+ /// (see \c TSIGError::BAD_SIG_CODE).
+ static const TSIGError& BAD_SIG();
+
+ /// A constant TSIG error object for the BADKEY code
+ /// (see \c TSIGError::BAD_KEY_CODE).
+ static const TSIGError& BAD_KEY();
+
+ /// A constant TSIG error object for the BADTIME code
+ /// (see \c TSIGError::BAD_TIME_CODE).
+ static const TSIGError& BAD_TIME();
+
+private:
+ // This is internally used to specify the maximum possible RCODE value
+ // that can be convertible to TSIGErrors.
+ static const int MAX_RCODE_FOR_TSIGERROR = 15;
+
+ uint16_t code_;
+};
+
+inline const TSIGError&
+TSIGError::NOERROR() {
+ static TSIGError e(Rcode::NOERROR());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::FORMERR() {
+ static TSIGError e(Rcode::FORMERR());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::SERVFAIL() {
+ static TSIGError e(Rcode::SERVFAIL());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::NXDOMAIN() {
+ static TSIGError e(Rcode::NXDOMAIN());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::NOTIMP() {
+ static TSIGError e(Rcode::NOTIMP());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::REFUSED() {
+ static TSIGError e(Rcode::REFUSED());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::YXDOMAIN() {
+ static TSIGError e(Rcode::YXDOMAIN());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::YXRRSET() {
+ static TSIGError e(Rcode::YXRRSET());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::NXRRSET() {
+ static TSIGError e(Rcode::NXRRSET());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::NOTAUTH() {
+ static TSIGError e(Rcode::NOTAUTH());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::NOTZONE() {
+ static TSIGError e(Rcode::NOTZONE());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::RESERVED11() {
+ static TSIGError e(Rcode::RESERVED11());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::RESERVED12() {
+ static TSIGError e(Rcode::RESERVED12());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::RESERVED13() {
+ static TSIGError e(Rcode::RESERVED13());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::RESERVED14() {
+ static TSIGError e(Rcode::RESERVED14());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::RESERVED15() {
+ static TSIGError e(Rcode::RESERVED15());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::BAD_SIG() {
+ static TSIGError e(BAD_SIG_CODE);
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::BAD_KEY() {
+ static TSIGError e(BAD_KEY_CODE);
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::BAD_TIME() {
+ static TSIGError e(BAD_TIME_CODE);
+ return (e);
+}
+
+/// Insert the \c TSIGError as a string into stream.
+///
+/// This method convert \c tsig_error into a string and inserts it into the
+/// output stream \c os.
+///
+/// \param os A \c std::ostream object on which the insertion operation is
+/// performed.
+/// \param tsig_error An \c TSIGError object output by the operation.
+/// \return A reference to the same \c std::ostream object referenced by
+/// parameter \c os after the insertion operation.
+std::ostream& operator<<(std::ostream& os, const TSIGError& tsig_error);
+}
+}
+
+#endif // __TSIGERROR_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/tsigkey.cc b/src/lib/dns/tsigkey.cc
index 057191d..4082fbe 100644
--- a/src/lib/dns/tsigkey.cc
+++ b/src/lib/dns/tsigkey.cc
@@ -15,50 +15,124 @@
#include <map>
#include <utility>
#include <vector>
+#include <sstream>
#include <exceptions/exceptions.h>
+#include <cryptolink/cryptolink.h>
+
#include <dns/name.h>
+#include <util/encode/base64.h>
#include <dns/tsigkey.h>
using namespace std;
+using namespace isc::cryptolink;
namespace isc {
namespace dns {
+namespace {
+ HashAlgorithm
+ convertAlgorithmName(const isc::dns::Name& name) {
+ if (name == TSIGKey::HMACMD5_NAME()) {
+ return (isc::cryptolink::MD5);
+ }
+ if (name == TSIGKey::HMACSHA1_NAME()) {
+ return (isc::cryptolink::SHA1);
+ }
+ if (name == TSIGKey::HMACSHA256_NAME()) {
+ return (isc::cryptolink::SHA256);
+ }
+ return (isc::cryptolink::UNKNOWN_HASH);
+ }
+}
+
struct
TSIGKey::TSIGKeyImpl {
TSIGKeyImpl(const Name& key_name, const Name& algorithm_name,
+ isc::cryptolink::HashAlgorithm algorithm,
const void* secret, size_t secret_len) :
key_name_(key_name), algorithm_name_(algorithm_name),
+ algorithm_(algorithm),
secret_(static_cast<const uint8_t*>(secret),
static_cast<const uint8_t*>(secret) + secret_len)
{
- // Convert the name to the canonical form.
+ // Convert the key and algorithm names to the canonical form.
+ key_name_.downcase();
algorithm_name_.downcase();
}
- const Name key_name_;
+ Name key_name_;
Name algorithm_name_;
+ const isc::cryptolink::HashAlgorithm algorithm_;
const vector<uint8_t> secret_;
};
TSIGKey::TSIGKey(const Name& key_name, const Name& algorithm_name,
const void* secret, size_t secret_len) : impl_(NULL)
{
- if (algorithm_name != HMACMD5_NAME() &&
- algorithm_name != HMACSHA1_NAME() &&
- algorithm_name != HMACSHA256_NAME()) {
- isc_throw(InvalidParameter, "Unknown TSIG algorithm is specified: " <<
- algorithm_name);
- }
+ const HashAlgorithm algorithm = convertAlgorithmName(algorithm_name);
if ((secret != NULL && secret_len == 0) ||
(secret == NULL && secret_len != 0)) {
isc_throw(InvalidParameter,
- "TSIGKey secret and its length are inconsistent");
+ "TSIGKey secret and its length are inconsistent: " <<
+ key_name << ":" << algorithm_name);
}
+ if (algorithm == isc::cryptolink::UNKNOWN_HASH && secret_len != 0) {
+ isc_throw(InvalidParameter,
+ "TSIGKey with unknown algorithm has non empty secret: " <<
+ key_name << ":" << algorithm_name);
+ }
+ impl_ = new TSIGKeyImpl(key_name, algorithm_name, algorithm, secret,
+ secret_len);
+}
+
+TSIGKey::TSIGKey(const std::string& str) : impl_(NULL) {
+ try {
+ istringstream iss(str);
+
+ string keyname_str;
+ getline(iss, keyname_str, ':');
+ if (iss.fail() || iss.bad() || iss.eof()) {
+ isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
+ }
+
+ string secret_str;
+ getline(iss, secret_str, ':');
+ if (iss.fail() || iss.bad()) {
+ isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
+ }
- impl_ = new TSIGKeyImpl(key_name, algorithm_name, secret, secret_len);
+ string algo_str;
+ if (!iss.eof()) {
+ getline(iss, algo_str);
+ }
+ if (iss.fail() || iss.bad()) {
+ isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
+ }
+
+ const Name algo_name(algo_str.empty() ? "hmac-md5.sig-alg.reg.int" :
+ algo_str);
+ const HashAlgorithm algorithm = convertAlgorithmName(algo_name);
+
+ vector<uint8_t> secret;
+ isc::util::encode::decodeBase64(secret_str, secret);
+
+ if (algorithm == isc::cryptolink::UNKNOWN_HASH && !secret.empty()) {
+ isc_throw(InvalidParameter,
+ "TSIG key with unknown algorithm has non empty secret: "
+ << str);
+ }
+
+ impl_ = new TSIGKeyImpl(Name(keyname_str), algo_name, algorithm,
+ secret.empty() ? NULL : &secret[0],
+ secret.size());
+ } catch (const Exception& e) {
+ // 'reduce' the several types of exceptions name parsing and
+ // Base64 decoding can throw to just the InvalidParameter
+ isc_throw(InvalidParameter, e.what());
+ }
}
+
TSIGKey::TSIGKey(const TSIGKey& source) : impl_(new TSIGKeyImpl(*source.impl_))
{}
@@ -89,6 +163,11 @@ TSIGKey::getAlgorithmName() const {
return (impl_->algorithm_name_);
}
+isc::cryptolink::HashAlgorithm
+TSIGKey::getAlgorithm() const {
+ return (impl_->algorithm_);
+}
+
const void*
TSIGKey::getSecret() const {
return ((impl_->secret_.size() > 0) ? &impl_->secret_[0] : NULL);
@@ -99,6 +178,17 @@ TSIGKey::getSecretLength() const {
return (impl_->secret_.size());
}
+std::string
+TSIGKey::toText() const {
+ const vector<uint8_t> secret_v(static_cast<const uint8_t*>(getSecret()),
+ static_cast<const uint8_t*>(getSecret()) +
+ getSecretLength());
+ std::string secret_str = isc::util::encode::encodeBase64(secret_v);
+
+ return (getKeyName().toText() + ":" + secret_str + ":" +
+ getAlgorithmName().toText());
+}
+
const
Name& TSIGKey::HMACMD5_NAME() {
static Name alg_name("hmac-md5.sig-alg.reg.int");
@@ -152,10 +242,11 @@ TSIGKeyRing::remove(const Name& key_name) {
}
TSIGKeyRing::FindResult
-TSIGKeyRing::find(const Name& key_name) {
+TSIGKeyRing::find(const Name& key_name, const Name& algorithm_name) const {
TSIGKeyRingImpl::TSIGKeyMap::const_iterator found =
impl_->keys.find(key_name);
- if (found == impl_->keys.end()) {
+ if (found == impl_->keys.end() ||
+ (*found).second.getAlgorithmName() != algorithm_name) {
return (FindResult(NOTFOUND, NULL));
}
return (FindResult(SUCCESS, &((*found).second)));
diff --git a/src/lib/dns/tsigkey.h b/src/lib/dns/tsigkey.h
index e56fa88..f0df709 100644
--- a/src/lib/dns/tsigkey.h
+++ b/src/lib/dns/tsigkey.h
@@ -15,6 +15,8 @@
#ifndef __TSIGKEY_H
#define __TSIGKEY_H 1
+#include <cryptolink/cryptolink.h>
+
namespace isc {
namespace dns {
@@ -66,12 +68,30 @@ public:
//@{
/// \brief Constructor from key parameters
///
- /// In the current implementation, \c algorithm_name must be a known
- /// algorithm to this implementation, which are defined via the
- /// <code>static const</code> member functions. For other names
- /// an exception of class \c InvalidParameter will be thrown.
- /// Note: This restriction may be too strict, and we may revisit it
- /// later.
+ /// \c algorithm_name should generally be a known algorithm to this
+ /// implementation, which are defined via the
+ /// <code>static const</code> member functions.
+ ///
+ /// Other names are still accepted as long as the secret is empty
+ /// (\c secret is \c NULL and \c secret_len is 0), however; in some cases
+ /// we might want to treat just the pair of key name and algorithm name
+ /// opaquely, e.g., when generating a response TSIG with a BADKEY error
+ /// because the algorithm is unknown as specified in Section 3.2 of
+ /// RFC2845 (in which case the algorithm name would be copied from the
+ /// request to the response, and for that purpose it would be convenient
+ /// if a \c TSIGKey object can hold a name for an "unknown" algorithm).
+ ///
+ /// \note RFC2845 does not specify which algorithm name should be used
+ /// in such a BADKEY response. The behavior of using the same algorithm
+ /// is derived from the BIND 9 implementation.
+ ///
+ /// It is unlikely that a TSIG key with an unknown algorithm is of any
+ /// use with actual crypto operation, so care must be taken when dealing
+ /// with such keys. (The restriction for the secret will prevent
+ /// accidental creation of such a dangerous key, e.g., due to misspelling
+ /// in a configuration file).
+ /// If the given algorithm name is unknown and non empty secret is
+ /// specified, an exception of type \c InvalidParameter will be thrown.
///
/// \c secret and \c secret_len must be consistent in that the latter
/// is 0 if and only if the former is \c NULL;
@@ -90,6 +110,28 @@ public:
TSIGKey(const Name& key_name, const Name& algorithm_name,
const void* secret, size_t secret_len);
+ /// \brief Constructor from an input string
+ ///
+ /// The string must be of the form:
+ /// <name>:<secret>[:<algorithm>]
+ /// Where <name> is a domain name for the key, <secret> is a
+ /// base64 representation of the key secret, and the optional
+ /// algorithm is an algorithm identifier as specified in RFC4635.
+ /// The default algorithm is hmac-md5.sig-alg.reg.int.
+ ///
+ /// The same restriction about the algorithm name (and secret) as that
+ /// for the other constructor applies.
+ ///
+ /// Since ':' is used as a separator here, it is not possible to
+ /// use this constructor to create keys with a ':' character in
+ /// their name.
+ ///
+ /// \exception InvalidParameter exception if the input string is
+ /// invalid.
+ ///
+ /// \param str The string to make a TSIGKey from
+ explicit TSIGKey(const std::string& str);
+
/// \brief The copy constructor.
///
/// It internally allocates a resource, and if it fails a corresponding
@@ -123,6 +165,9 @@ public:
/// Return the algorithm name.
const Name& getAlgorithmName() const;
+ /// Return the hash algorithm name in the form of cryptolink::HashAlgorithm
+ isc::cryptolink::HashAlgorithm getAlgorithm() const;
+
/// Return the length of the TSIG secret in bytes.
size_t getSecretLength() const;
@@ -139,6 +184,18 @@ public:
const void* getSecret() const;
//@}
+ /// \brief Converts the TSIGKey to a string value
+ ///
+ /// The resulting string will be of the form
+ /// name:secret:algorithm
+ /// Where <name> is a domain name for the key, <secret> is a
+ /// base64 representation of the key secret, and algorithm is
+ /// an algorithm identifier as specified in RFC4635
+ ///
+ /// \param key the TSIG key to convert
+ /// \return The string representation of the given TSIGKey.
+ std::string toText() const;
+
///
/// \name Well known algorithm names as defined in RFC2845 and RFC4635.
///
@@ -268,7 +325,9 @@ public:
/// Find a \c TSIGKey for the given name in the \c TSIGKeyRing.
///
/// It searches the internal storage for a \c TSIGKey whose name is
- /// \c key_name, and returns the result in the form of a \c FindResult
+ /// \c key_name and that uses the hash algorithm identified by
+ /// \c algorithm_name.
+ /// It returns the result in the form of a \c FindResult
/// object as follows:
/// - \c code: \c SUCCESS if a key is found; otherwise \c NOTFOUND.
/// - \c key: A pointer to the found \c TSIGKey object if one is found;
@@ -282,8 +341,9 @@ public:
/// This method never throws an exception.
///
/// \param key_name The name of the key to be found.
+ /// \param algorithm_name The name of the algorithm of the found key.
/// \return A \c FindResult object enclosing the search result (see above).
- FindResult find(const Name& key_name);
+ FindResult find(const Name& key_name, const Name& algorithm_name) const;
private:
struct TSIGKeyRingImpl;
TSIGKeyRingImpl* impl_;
diff --git a/src/lib/dns/tsigrecord.cc b/src/lib/dns/tsigrecord.cc
new file mode 100644
index 0000000..9dd3f78
--- /dev/null
+++ b/src/lib/dns/tsigrecord.cc
@@ -0,0 +1,147 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <ostream>
+#include <string>
+
+#include <util/buffer.h>
+
+#include <dns/exceptions.h>
+#include <dns/messagerenderer.h>
+#include <dns/rrclass.h>
+#include <dns/rrttl.h>
+#include <dns/tsigrecord.h>
+
+using namespace isc::util;
+using namespace isc::dns::rdata;
+
+namespace {
+// Internally used constants:
+
+// Size in octets for the RR type, class TTL, RDLEN fields.
+const size_t RR_COMMON_LEN = 10;
+
+// Size in octets for the fixed part of TSIG RDATAs.
+// - Time Signed (6)
+// - Fudge (2)
+// - MAC Size (2)
+// - Original ID (2)
+// - Error (2)
+// - Other Len (2)
+const size_t RDATA_COMMON_LEN = 16;
+}
+
+namespace isc {
+namespace dns {
+TSIGRecord::TSIGRecord(const Name& key_name,
+ const rdata::any::TSIG& tsig_rdata) :
+ key_name_(key_name), rdata_(tsig_rdata),
+ length_(RR_COMMON_LEN + RDATA_COMMON_LEN + key_name_.getLength() +
+ rdata_.getAlgorithm().getLength() +
+ rdata_.getMACSize() + rdata_.getOtherLen())
+{}
+
+namespace {
+// This is a straightforward wrapper of dynamic_cast<const any::TSIG&>.
+// We use this so that we can throw the DNSMessageFORMERR exception when
+// unexpected type of RDATA is detected in the member initialization list
+// of the constructor below.
+const any::TSIG&
+castToTSIGRdata(const rdata::Rdata& rdata) {
+ try {
+ return (dynamic_cast<const any::TSIG&>(rdata));
+ } catch (std::bad_cast&) {
+ isc_throw(DNSMessageFORMERR,
+ "TSIG record is being constructed from "
+ "incompatible RDATA:" << rdata.toText());
+ }
+}
+}
+
+TSIGRecord::TSIGRecord(const Name& name, const RRClass& rrclass,
+ const RRTTL& ttl, const rdata::Rdata& rdata,
+ size_t length) :
+ key_name_(name), rdata_(castToTSIGRdata(rdata)), length_(length)
+{
+ if (rrclass != getClass()) {
+ isc_throw(DNSMessageFORMERR, "Unexpected TSIG RR class: " << rrclass);
+ }
+ if (ttl != RRTTL(TSIG_TTL)) {
+ isc_throw(DNSMessageFORMERR, "Unexpected TSIG TTL: " << ttl);
+ }
+}
+
+const RRClass&
+TSIGRecord::getClass() {
+ return (RRClass::ANY());
+}
+
+const RRTTL&
+TSIGRecord::getTTL() {
+ static RRTTL ttl(TSIG_TTL);
+ return (ttl);
+}
+
+namespace {
+template <typename OUTPUT>
+void
+toWireCommon(OUTPUT& output, const rdata::any::TSIG& rdata) {
+ // RR type, class, TTL are fixed constants.
+ RRType::TSIG().toWire(output);
+ TSIGRecord::getClass().toWire(output);
+ output.writeUint32(TSIGRecord::TSIG_TTL);
+
+ // RDLEN
+ output.writeUint16(RDATA_COMMON_LEN + rdata.getAlgorithm().getLength() +
+ rdata.getMACSize() + rdata.getOtherLen());
+
+ // TSIG RDATA
+ rdata.toWire(output);
+}
+}
+
+int
+TSIGRecord::toWire(AbstractMessageRenderer& renderer) const {
+ // If adding the TSIG would exceed the size limit, don't do it.
+ if (renderer.getLength() + length_ > renderer.getLengthLimit()) {
+ renderer.setTruncated();
+ return (0);
+ }
+
+ // key name = owner. note that we disable compression.
+ renderer.writeName(key_name_, false);
+ toWireCommon(renderer, rdata_);
+ return (1);
+}
+
+int
+TSIGRecord::toWire(OutputBuffer& buffer) const {
+ key_name_.toWire(buffer);
+ toWireCommon(buffer, rdata_);
+ return (1);
+}
+
+std::string
+TSIGRecord::toText() const {
+ return (key_name_.toText() + " " + RRTTL(TSIG_TTL).toText() + " " +
+ getClass().toText() + " " + RRType::TSIG().toText() + " " +
+ rdata_.toText() + "\n");
+}
+
+std::ostream&
+operator<<(std::ostream& os, const TSIGRecord& record) {
+ return (os << record.toText());
+}
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/tsigrecord.h b/src/lib/dns/tsigrecord.h
new file mode 100644
index 0000000..03de746
--- /dev/null
+++ b/src/lib/dns/tsigrecord.h
@@ -0,0 +1,308 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __TSIGRECORD_H
+#define __TSIGRECORD_H 1
+
+#include <ostream>
+#include <string>
+
+#include <boost/shared_ptr.hpp>
+
+#include <util/buffer.h>
+
+#include <dns/name.h>
+#include <dns/rdataclass.h>
+
+namespace isc {
+namespace util {
+class OutputBuffer;
+}
+namespace dns {
+class AbstractMessageRenderer;
+
+/// TSIG resource record.
+///
+/// A \c TSIGRecord class object represents a TSIG resource record and is
+/// responsible for conversion to and from wire format TSIG record based on
+/// the protocol specification (RFC2845).
+/// This class is provided so that other classes and applications can handle
+/// TSIG without knowing protocol details of TSIG, such as that it uses a
+/// fixed constant of TTL.
+///
+/// \todo So the plan is to eventually provide the "from wire" constructor.
+/// It's not yet provided in the current phase of development.
+///
+/// \note
+/// This class could be a derived class of \c AbstractRRset. That way
+/// it would be able to be used in a polymorphic way; for example,
+/// an application can construct a TSIG RR by itself and insert it to a
+/// \c Message object as a generic RRset. On the other hand, it would mean
+/// this class would have to implement an \c RdataIterator (even though it
+/// can be done via straightforward forwarding) while the iterator is mostly
+/// redundant since there should be one and only one RDATA for a valid TSIG
+/// RR. Likewise, some methods such as \c setTTL() method wouldn't be well
+/// defined due to such special rules for TSIG as using a fixed TTL.
+/// Overall, TSIG is a very special RR type that simply uses the compatible
+/// resource record format, and it will be unlikely that a user wants to
+/// handle it through a generic interface in a polymorphic way.
+/// We therefore chose to define it as a separate class. This is also
+/// similar to why \c EDNS is a separate class.
+class TSIGRecord {
+public:
+ ///
+ /// \name Constructors
+ ///
+ /// We use the default copy constructor, default copy assignment operator,
+ /// (and default destructor) intentionally.
+ //@{
+ /// Constructor from TSIG key name and RDATA
+ ///
+ /// \exception std::bad_alloc Resource allocation for copying the name or
+ /// RDATA fails
+ TSIGRecord(const Name& key_name, const rdata::any::TSIG& tsig_rdata);
+
+ /// Constructor from resource record (RR) parameters.
+ ///
+ /// This constructor is intended to be used in the context of parsing
+ /// an incoming DNS message that contains a TSIG. The parser would
+ /// first extract the owner name, RR type (which is TSIG) class, TTL and
+ /// the TSIG RDATA from the message. This constructor is expected to
+ /// be given these RR parameters (except the RR type, because it must be
+ /// TSIG).
+ ///
+ /// According to RFC2845, a TSIG RR uses fixed RR class (ANY) and TTL (0).
+ /// If the RR class or TTL is different from the expected one, this
+ /// implementation considers it an invalid record and throws an exception
+ /// of class \c DNSMessageFORMERR.
+ ///
+ /// \note This behavior is not specified in the protocol specification,
+ /// but this implementation rejects unexpected values for the following
+ /// reasons (but in any case, this won't matter much in practice as
+ /// RFC2848 clearly states these fields always have the fixed values and
+ /// any sane implementation of TSIG signer will follow that):
+ /// According to the RFC editor (in a private communication), the intended
+ /// use of the TSIG TTL field is to signal protocol extensions (currently
+ /// no such extension is defined), so this field may actually be
+ /// validly non 0 in future. However, until the implementation supports
+ /// that extension it may not always be able to handle the extended
+ /// TSIG as intended; the extension may even affect digest computation.
+ /// There's a related issue on this point. Different implementations
+ /// interpret the RFC in different ways on the received TTL when
+ /// digesting the message: BIND 9 uses the received value (even if
+ /// it's not 0) as part of the TSIG variables; NLnet Labs' LDNS and NSD
+ /// always use a fixed constant of 0 regardless of the received TTL value.
+ /// This means if and when an extension with non 0 TTL is introduced
+ /// there will be interoperability problems in the form of verification
+ /// failure. By explicitly rejecting it (and subsequently returning
+ /// a response with a format error) we can indicate the source of the
+ /// problem more clearly than a "bad signature" TSIG error, which can
+ /// happen for various reasons. On the other hand, rejecting unexpected
+ /// RR classes is mostly for consistency; the RFC lists these two fields
+ /// in the same way, so it makes more sense to handle them equally.
+ /// (BIND 9 rejects unexpected RR classes for TSIG, but that is part of
+ /// general check on RR classes on received RRs; it generally requests
+ /// all classes are the same, and if the protocol specifies the use of
+ /// a particular class for a particular type of RR, it requests that
+ /// class be used).
+ ///
+ /// Likewise, if \c rdata is not of type \c any::TSIG, an exception of
+ /// class DNSMessageFORMERR will be thrown. When the caller is a
+ /// DNS message parser and builds \c rdata from incoming wire format
+ /// data as described above, this case happens when the RR class is
+ /// different from ANY (in the implementation, the type check takes place
+ /// before the explicit check against the RR class explained in the
+ /// previous paragraph).
+ ///
+ /// The \c length parameter is intended to be the length of the TSIG RR
+ /// (from the beginning of the owner name to the end of the RDATA) when
+ /// the caller is a DNS message parser. Note that it is the actual length
+ /// for the RR in the format; if the owner name or the algorithm name
+ /// (in the RDATA) is compressed (although the latter should not be
+ /// compressed according to RFC3597), the length must be the size of the
+ /// compressed data. The length is recorded inside the class and will
+ /// be returned via subsequent calls to \c getLength(). It's intended to
+ /// be used in the context TSIG verification; in the verify process
+ /// the MAC computation must be performed for the original data without
+ /// TSIG, so, to avoid parsing the entire data in the verify process
+ /// again, it's necessary to record information that can identify the
+ /// length to be digested for the MAC. This parameter serves for that
+ /// purpose.
+ ///
+ /// \note Since the constructor doesn't take the wire format data per se,
+ /// it doesn't (and cannot) check the validity of \c length, and simply
+ /// accepts any given value. It even accepts obviously invalid values
+ /// such as 0. It's caller's responsibility to provide a valid value of
+ /// length, and, the verifier's responsibility to use the length safely.
+ ///
+ /// <b>DISCUSSION:</b> this design is fragile in that it introduces
+ /// a tight coupling between message parsing and TSIG verification via
+ /// the \c TSIGRecord class. In terms of responsibility decoupling,
+ /// the ideal way to have \c TSIGRecord remember the entire wire data
+ /// along with the length of the TSIG. Then in the TSIG verification
+ /// we could refer to the necessary potion of data solely from a
+ /// \c TSIGRecord object. However, this approach would require expensive
+ /// heavy copy of the original data or introduce another kind of coupling
+ /// between the data holder and this class (if the original data is freed
+ /// while a \c TSIGRecord object referencing the data still exists, the
+ /// result will be catastrophic). As a "best current compromise", we
+ /// use the current design. We may reconsider it if it turns out to
+ /// cause a big problem or we come up with a better idea.
+ ///
+ /// \exception DNSMessageFORMERR Given RR parameters are invalid for TSIG.
+ /// \exception std::bad_alloc Internal resource allocation fails.
+ ///
+ /// \param name The owner name of the TSIG RR
+ /// \param rrclass The RR class of the RR. Must be \c RRClass::ANY()
+ /// (see above)
+ /// \param ttl The TTL of the RR. Must be 0 (see above)
+ /// \param rdata The RDATA of the RR. Must be of type \c any::TSIG.
+ /// \param length The size of the RR (see above)
+ TSIGRecord(const Name& name, const RRClass& rrclass, const RRTTL& ttl,
+ const rdata::Rdata& rdata, size_t length);
+ //@}
+
+ /// Return the owner name of the TSIG RR, which is the TSIG key name
+ ///
+ /// \exception None
+ const Name& getName() const { return (key_name_); }
+
+ /// Return the RDATA of the TSIG RR
+ ///
+ /// \exception None
+ const rdata::any::TSIG& getRdata() const { return (rdata_); }
+
+ /// \name Protocol constants and defaults
+ ///
+ //@{
+ /// Return the RR class of TSIG
+ ///
+ /// TSIG always uses the ANY RR class. This static method returns it,
+ /// when, though unlikely, an application wants to know which class TSIG
+ /// is supposed to use.
+ ///
+ /// \exception None
+ static const RRClass& getClass();
+
+ /// Return the TTL value of TSIG
+ ///
+ /// TSIG always uses 0 TTL. This static method returns it,
+ /// when, though unlikely, an application wants to know the TTL TSIG
+ /// is supposed to use.
+ ///
+ /// \exception None
+ static const RRTTL& getTTL();
+ //@}
+
+ /// Return the length of the TSIG record
+ ///
+ /// When constructed from the key name and RDATA, it is the length of
+ /// the record when it is rendered by the \c toWire() method.
+ ///
+ /// \note When constructed "from wire", that will mean the length of
+ /// the wire format data for the TSIG RR. The length will be necessary
+ /// to verify the message once parse is completed.
+ ///
+ /// \exception None
+ size_t getLength() const { return (length_); }
+
+ /// \brief Render the \c TSIG RR in the wire format.
+ ///
+ /// This method renders the TSIG record as a form of a DNS TSIG RR
+ /// via \c renderer, which encapsulates output buffer and other rendering
+ /// contexts.
+ ///
+ /// Normally this version of \c toWire() method tries to compress the
+ /// owner name of the RR whenever possible, but this method intentionally
+ /// skips owner name compression. This is due to a report that some
+ /// Windows clients refuse a TSIG if its owner name is compressed
+ /// (See http://marc.info/?l=bind-workers&m=126637138430819&w=2).
+ /// Reportedly this seemed to be specific to GSS-TSIG, but this
+ /// implementation skip compression regardless of the algorithm.
+ ///
+ /// If by adding the TSIG RR the message size would exceed the limit
+ /// maintained in \c renderer, this method skips rendering the RR
+ /// and returns 0 and mark \c renderer as "truncated" (so that a
+ /// subsequent call to \c isTruncated() on \c renderer will result in
+ /// \c true); otherwise it returns 1, which is the number of RR
+ /// rendered.
+ ///
+ /// \note If the caller follows the specification of adding TSIG
+ /// as described in RFC2845, this should not happen; the caller is
+ /// generally expected to leave a sufficient room in the message for
+ /// the TSIG. But this method checks the unexpected case nevertheless.
+ ///
+ /// \exception std::bad_alloc Internal resource allocation fails (this
+ /// should be rare).
+ ///
+ /// \param renderer DNS message rendering context that encapsulates the
+ /// output buffer and name compression information.
+ /// \return 1 if the TSIG RR fits in the message size limit; otherwise 0.
+ int toWire(AbstractMessageRenderer& renderer) const;
+
+ /// \brief Render the \c TSIG RR in the wire format.
+ ///
+ /// This method is same as \c toWire(AbstractMessageRenderer&)const
+ /// except it renders the RR in an \c OutputBuffer and therefore
+ /// does not care about message size limit.
+ /// As a consequence it always returns 1.
+ int toWire(isc::util::OutputBuffer& buffer) const;
+
+ /// Convert the TSIG record to a string.
+ ///
+ /// The output format is the same as the result of \c toText() for
+ /// other normal types of RRsets (with always using the same RR class
+ /// and TTL). It also ends with a newline.
+ ///
+ /// \exception std::bad_alloc Internal resource allocation fails (this
+ /// should be rare).
+ ///
+ /// \return A string representation of \c TSIG record
+ std::string toText() const;
+
+ /// The TTL value to be used in TSIG RRs.
+ static const uint32_t TSIG_TTL = 0;
+ //@}
+
+private:
+ const Name key_name_;
+ const rdata::any::TSIG rdata_;
+ const size_t length_;
+};
+
+/// A pointer-like type pointing to a \c TSIGRecord object.
+typedef boost::shared_ptr<TSIGRecord> TSIGRecordPtr;
+
+/// A pointer-like type pointing to an immutable \c TSIGRecord object.
+typedef boost::shared_ptr<const TSIGRecord> ConstTSIGRecordPtr;
+
+/// Insert the \c TSIGRecord as a string into stream.
+///
+/// This method convert \c record into a string and inserts it into the
+/// output stream \c os.
+///
+/// \param os A \c std::ostream object on which the insertion operation is
+/// performed.
+/// \param record A \c TSIGRecord object output by the operation.
+/// \return A reference to the same \c std::ostream object referenced by
+/// parameter \c os after the insertion operation.
+std::ostream& operator<<(std::ostream& os, const TSIGRecord& record);
+}
+}
+
+#endif // __TSIGRECORD_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/log/Makefile.am b/src/lib/log/Makefile.am
index 5770564..c27b3e4 100644
--- a/src/lib/log/Makefile.am
+++ b/src/lib/log/Makefile.am
@@ -16,11 +16,13 @@ liblog_la_SOURCES += logger_impl.cc logger_impl.h
liblog_la_SOURCES += logger_support.cc logger_support.h
liblog_la_SOURCES += messagedef.cc messagedef.h
liblog_la_SOURCES += message_dictionary.cc message_dictionary.h
-liblog_la_SOURCES += message_exception.h message_exception.cc
+liblog_la_SOURCES += message_exception.h
liblog_la_SOURCES += message_initializer.cc message_initializer.h
liblog_la_SOURCES += message_reader.cc message_reader.h
liblog_la_SOURCES += message_types.h
liblog_la_SOURCES += root_logger_name.cc root_logger_name.h
+liblog_la_SOURCES += log_formatter.h log_formatter.cc
+liblog_la_SOURCES += macros.h
EXTRA_DIST = README
EXTRA_DIST += messagedef.mes
diff --git a/src/lib/log/README b/src/lib/log/README
index ed11b5b..529eefc 100644
--- a/src/lib/log/README
+++ b/src/lib/log/README
@@ -44,7 +44,7 @@ stored definitions; this updated text is logged. However, to aid support,
the message identifier so in the example above, the message finally logged
would be something like:
- OPENIN, unable to open a.txt for input
+ FAC_OPENIN, unable to open a.txt for input
Using The System
@@ -55,17 +55,15 @@ The steps in using the system are:
mnemonic for the message, typically 6-12 characters long - and a message.
The file is described in more detail below.
- Ideally the file should have a file type of ".msg".
+ Ideally the file should have a file type of ".mes".
-2. Run it through the message compiler to produce the .h and .cc files. It
- is intended that this step be included in the build process. However,
- for now run the compiler (found in the "compiler" subdirectory) manually.
- The only argument is the name of the message file: it will produce as
- output two files, having the same name as the input file but with file
- types of ".h" and ".cc".
-
- The compiler is built in the "compiler" subdirectory of the "src/lib/log"
- directory.
+2. Run it through the message compiler to produce the .h and .cc files. This
+ step should be included in the build process. (For an example of how to
+ do this, see src/lib/nsas/Makefile.am.) During development though, the
+ message compiler (found in the "src/lib/log/compiler" directory) will need
+ to be run manually. The only argument is the name of the message file: it
+ will produce as output two files in the default directory, having the same
+ name as the input file but with file types of ".h" and ".cc".
3. Include the .h file in your source code to define message symbols, and
make sure that the .cc file is compiled and linked into your program -
@@ -96,11 +94,12 @@ An example file could be:
$PREFIX TEST_
$NAMESPACE isc::log
-TEST1 message %s is much too large
-+ This message is a test for the general message code
-UNKNOWN unknown message
-+ Issued when the message is unknown.
+% TEST1 message %1 is much too large
+This message is a test for the general message code
+
+% UNKNOWN unknown message
+Issued when the message is unknown.
-- END --
@@ -117,23 +116,31 @@ Points to note:
* Lines starting $ are directives. At present, two directives are recognised:
- * $PREFIX, which has one argument: the string used to prefix symbols. If
- absent, there is no prefix to the symbols. (Prefixes are explained below.)
+ * $PREFIX, which has one optional argument: the string used to prefix symbols.
+ If absent, there is no prefix to the symbols. (Prefixes are explained below.)
+
* $NAMESPACE, which has one argument: the namespace in which the symbols are
- created. In the absence of a $NAMESPACE directive, symbols will be put
- in the global namespace.
+ created. In the absence of a $NAMESPACE directive, symbols will be put in
+ the anonymous namespace.
-* Lines starting + indicate an explanation for the preceding message. These
- are intended to be processed by a separate program and used to generate
- an error messages manual. However they are treated like comments by the
- message compiler. As with comments, these must be on a line by themselves;
- if inline, the text (including the leading "+") will be interpreted as
- part of the line.
+* Message lines. These start with a "%" and are followed by the message
+ identification and the message text, the latter including zero or more
+ replacement tokens, e.g.
-* Message lines. These comprise a symbol name and a message, which may
- include zero or more printf-style tokens. Symbol names will be upper-cased
- by the compiler.
+ % TEST message %1 is larger than the permitted length of %2
+ * There may be zero or more spaces between the leading "%" and the message
+ identification (which, in the example above, is the word "TEST").
+
+ * The replacement tokens are the strings "%1", "%2" etc. When a message
+ is logged, these are replaced with the arguments passed to the logging
+ call: %1 refers to the first argument, %2 to the second etc. Within the
+ message text, the placeholders can appear in any order, and placeholders
+ can be repeated.
+
+* Remaining lines indicate an explanation for the preceding message. These
+ are intended to be processed by a separate program and used to generate
+ an error messages manual. They are ignored by the message compiler.
Message Compiler
----------------
@@ -153,9 +160,8 @@ the form:
:
}
-The symbols define the keys in the global message dictionary.
-
-The namespace enclosing the symbols is set by the $NAMESPACE directive.
+The symbols define the keys in the global message dictionary, with the
+namespace enclosing the symbols set by the $NAMESPACE directive.
The "PREFIX_" part of the symbol name is the string defined in the $PREFIX
the argument to the directive. So "$PREFIX MSG_" would prefix the identifier
@@ -163,12 +169,20 @@ ABC with "MSG_" to give the symbol MSG_ABC. Similarly "$PREFIX E" would
prefix it with "E" to give the symbol EABC. If no $PREFIX is given, no
prefix appears (so the symbol in this example would be ABC).
+The prefix is "syntactic sugar". Generally all symbols in a given message file
+will be prefixed with the same set of letters. By extracting these into
+a separate prefix, it becomes easier to disambiguate the different symbols.
+
+There may be multiple $PREFIX directives in a file. A $PREFIX directive applies
+to all message definitions between it an the next $PREFIX directive. A $PREFIX
+directive with no arguments clears the current prefix.
+
2) A C++ source file (called <message-file-name>.cc) that holds the definitions
of the global symbols and code to insert the symbols and messages into the map.
Symbols are defined to be equal to strings holding the identifier, e.g.
- extern const isc::log::MessageID MSG_DUPLNS = "DUPLNS";
+ extern const isc::log::MessageID MSG_DUPLNS = "MSG_DUPLNS";
(The implementation allows symbols to be compared. However, use of strings
should not be assumed - a future implementation may change this.)
@@ -243,27 +257,49 @@ To use the current version of the logging:
highest-level debug messages and 99 for the lowest-level (and typically
more verbose) messages.
- c) Name of an external message file. This is the same as a standard message
- file, although it should not include any directives. (A single directive
- of a particular type will be ignored; multiple directives will cause the
- read of the file to fail with an error.) If a message is replaced, the
- message should include the same printf-format directives in the same order
- as the original message.
+ c) The external message file. If present, this is the same as a standard
+ message file, although it should not include any directives. (A single
+ directive of a particular type will be ignored; multiple directives will
+ cause the read of the file to fail with an error.)
4. Issue logging calls using methods on logger, e.g.
- logger.error(DPS_NSTIMEOUT, "isc.org");
+ logger.error(DPS_NSTIMEOUT).arg("isc.org");
(where, in the example above we might have defined the symbol in the message
file with something along the lines of:
$PREFIX DPS_
:
- NSTIMEOUT queries to all nameservers for %s have timed out
+ NSTIMEOUT queries to all nameservers for %1 have timed out
At present, the only logging is to the console.
+Efficiency Considerations
+-------------------------
+A common pattern in logging is a debug call of the form:
+
+ logger.debug(dbglevel, MSGID).arg(expensive_call()).arg(...
+
+... where "expensive_call()" is a function call to obtain logging information
+that may be computationally intensive. Although the cost may be justified
+when debugging is enabled, the cost is still incurred even if debugging is
+disabled and the debug() method returns without outputting anything. (The
+same may be true of other logging levels, although there are likely to be
+fewer calls to logger.info(), logger.error() etc. throughout the code and
+they are less likely to be disabled.)
+
+For this reason, a set of macros is provided and are called using the
+construct:
+
+ LOG_DEBUG(logger, dbglevel, MSGID).arg(expensive_call()).arg(...
+ LOG_INFO(logger, MSGID).arg(expensive_call()...)
+
+If these are used, the arguments passed to the arg() method are not evaluated
+if the relevant logging level is disabled.
+
+
Severity Guidelines
===================
When using logging, the question arises, what severity should a message be
@@ -361,9 +397,6 @@ is only one piece of code that does this functionality.
Outstanding Issues
==================
* Ability to configure system according to configuration database.
-* Update the build procedure to create .cc and .h files from the .msg file
- during the build process. (Requires that the message compiler is built
- first.)
log4cxx Issues
diff --git a/src/lib/log/compiler/message.cc b/src/lib/log/compiler/message.cc
index ef4bafd..457a62e 100644
--- a/src/lib/log/compiler/message.cc
+++ b/src/lib/log/compiler/message.cc
@@ -50,17 +50,13 @@ static const char* VERSION = "1.0-0";
/// \li A .cc file containing code that adds the messages to the program's
/// message dictionary at start-up time.
///
-/// Alternatively, the program can produce a .py file that contains the
-/// message definitions.
-///
-
/// \b Invocation<BR>
/// The program is invoked with the command:
///
/// <tt>message [-v | -h | \<message-file\>]</tt>
///
-/// It reads the message file and writes out two files of the same name but with
-/// extensions of .h and .cc.
+/// It reads the message file and writes out two files of the same name in the
+/// default directory but with extensions of .h and .cc.
///
/// \-v causes it to print the version number and exit. \-h prints a help
/// message (and exits).
@@ -251,17 +247,16 @@ writeClosingNamespace(ostream& output, const vector<string>& ns) {
///
/// \param file Name of the message file. The header file is written to a
/// file of the same name but with a .h suffix.
-/// \param prefix Prefix string to use in symbols
/// \param ns Namespace in which the definitions are to be placed. An empty
/// string indicates no namespace.
/// \param dictionary Dictionary holding the message definitions.
void
-writeHeaderFile(const string& file, const string& prefix,
- const vector<string>& ns_components, MessageDictionary& dictionary)
+writeHeaderFile(const string& file, const vector<string>& ns_components,
+ MessageDictionary& dictionary)
{
Filename message_file(file);
- Filename header_file(message_file.useAsDefault(".h"));
+ Filename header_file(Filename(message_file.name()).useAsDefault(".h"));
// Text to use as the sentinels.
string sentinel_text = sentinel(header_file);
@@ -271,7 +266,7 @@ writeHeaderFile(const string& file, const string& prefix,
try {
if (hfile.fail()) {
- throw MessageException(MSG_OPNMSGOUT, header_file.fullName(),
+ throw MessageException(MSG_OPENOUT, header_file.fullName(),
strerror(errno));
}
@@ -294,7 +289,7 @@ writeHeaderFile(const string& file, const string& prefix,
vector<string> idents = sortedIdentifiers(dictionary);
for (vector<string>::const_iterator j = idents.begin();
j != idents.end(); ++j) {
- hfile << "extern const isc::log::MessageID " << prefix << *j << ";\n";
+ hfile << "extern const isc::log::MessageID " << *j << ";\n";
}
hfile << "\n";
@@ -305,7 +300,7 @@ writeHeaderFile(const string& file, const string& prefix,
// Report errors (if any) and exit
if (hfile.fail()) {
- throw MessageException(MSG_MSGWRTERR, header_file.fullName(),
+ throw MessageException(MSG_WRITERR, header_file.fullName(),
strerror(errno));
}
@@ -354,17 +349,17 @@ replaceNonAlphaNum(char c) {
/// to it. But until BIND-10 is ported to Windows, we won't know.
void
-writeProgramFile(const string& file, const string& prefix,
- const vector<string>& ns_components, MessageDictionary& dictionary)
+writeProgramFile(const string& file, const vector<string>& ns_components,
+ MessageDictionary& dictionary)
{
Filename message_file(file);
- Filename program_file(message_file.useAsDefault(".cc"));
+ Filename program_file(Filename(message_file.name()).useAsDefault(".cc"));
// Open the output file for writing
ofstream ccfile(program_file.fullName().c_str());
try {
if (ccfile.fail()) {
- throw MessageException(MSG_OPNMSGOUT, program_file.fullName(),
+ throw MessageException(MSG_OPENOUT, program_file.fullName(),
strerror(errno));
}
@@ -387,7 +382,7 @@ writeProgramFile(const string& file, const string& prefix,
vector<string> idents = sortedIdentifiers(dictionary);
for (vector<string>::const_iterator j = idents.begin();
j != idents.end(); ++j) {
- ccfile << "extern const isc::log::MessageID " << prefix << *j <<
+ ccfile << "extern const isc::log::MessageID " << *j <<
" = \"" << *j << "\";\n";
}
ccfile << "\n";
@@ -422,7 +417,7 @@ writeProgramFile(const string& file, const string& prefix,
// Report errors (if any) and exit
if (ccfile.fail()) {
- throw MessageException(MSG_MSGWRTERR, program_file.fullName(),
+ throw MessageException(MSG_WRITERR, program_file.fullName(),
strerror(errno));
}
@@ -518,13 +513,10 @@ main(int argc, char* argv[]) {
vector<string> ns_components = splitNamespace(reader.getNamespace());
// Write the header file.
- writeHeaderFile(message_file, reader.getPrefix(), ns_components,
- dictionary);
+ writeHeaderFile(message_file, ns_components, dictionary);
// Write the file that defines the message symbols and text
- writeProgramFile(message_file, reader.getPrefix(), ns_components,
- dictionary);
-
+ writeProgramFile(message_file, ns_components, dictionary);
// Finally, warn of any duplicates encountered.
warnDuplicates(reader);
@@ -535,9 +527,12 @@ main(int argc, char* argv[]) {
string text = e.id();
text += ", ";
text += global.getText(e.id());
-
// Format with arguments
- text = isc::util::str::format(text, e.arguments());
+ vector<string> args(e.arguments());
+ for (size_t i(0); i < args.size(); ++ i) {
+ replacePlaceholder(&text, args[i], i + 1);
+ }
+
cerr << text << "\n";
return 1;
diff --git a/src/lib/log/log_formatter.cc b/src/lib/log/log_formatter.cc
new file mode 100644
index 0000000..18c4741
--- /dev/null
+++ b/src/lib/log/log_formatter.cc
@@ -0,0 +1,42 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <log/log_formatter.h>
+
+using namespace std;
+using namespace boost;
+
+namespace isc {
+namespace log {
+
+void
+replacePlaceholder(string* message, const string& arg,
+ const unsigned placeholder)
+{
+ string mark("%" + lexical_cast<string>(placeholder));
+ size_t pos(message->find(mark));
+ if (pos != string::npos) {
+ do {
+ message->replace(pos, mark.size(), arg);
+ pos = message->find(mark, pos + arg.size());
+ } while (pos != string::npos);
+ } else {
+ // We're missing the placeholder, so add some complain
+ message->append(" @@Missing placeholder " + mark + " for '" + arg +
+ "'@@");
+ }
+}
+
+}
+}
diff --git a/src/lib/log/log_formatter.h b/src/lib/log/log_formatter.h
new file mode 100644
index 0000000..cda1d96
--- /dev/null
+++ b/src/lib/log/log_formatter.h
@@ -0,0 +1,150 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __LOG_FORMATTER_H
+#define __LOG_FORMMATER_H
+
+#include <string>
+#include <boost/lexical_cast.hpp>
+
+namespace isc {
+namespace log {
+
+/// \brief The internal replacement routine
+///
+/// This is used internally by the Formatter. Replaces a placeholder
+/// in the message by replacement. If the placeholder is not found,
+/// it adds a complain at the end.
+void
+replacePlaceholder(std::string* message, const std::string& replacement,
+ const unsigned placeholder);
+
+///
+/// \brief The log message formatter
+///
+/// This class allows us to format logging messages conveniently. We
+/// call something like logger.warn(WARN_MSG).arg(15).arg(dnsMsg). This
+/// outputs some text with placeholders replaced by the arguments, if
+/// the logging verbosity is at WARN level or more.
+///
+/// To make this work, we use the Formatter. The warn (or whatever logging
+/// function) returns a Formatter object. That one holds the string to be
+/// output with the placeholders. It also remembers if there should be any
+/// output at all (eg. if the logging is enabled for this level). When there's
+/// no .arg call on the object, it is destroyed right away and we use the
+/// destructor to output the text (but only in case we should output anything).
+///
+/// If there's an .arg call, we return reference to the same object, so another
+/// .arg can be called on it. After the last .arg call is done, the object is
+/// destroyed and, again, we can produce the output.
+///
+/// Of course, if the logging is turned off, we don't bother with any replacing
+/// and just return.
+///
+/// User of logging code should not really care much about this class, only
+/// call the .arg method to generate the correct output.
+///
+/// The class is a template to allow easy testing. Also, we want everything
+/// here in the header anyway and it doesn't depend on the details of what
+/// Logger really is, so it doesn't hurt anything.
+///
+/// Also, if you are interested in the internals, you might find the copy
+/// constructor a bit strange. It deactivates the original formatter. We don't
+/// really want to support copying of the Formatter by user, but C++ needs a
+/// copy constructor when returning from the logging functions, so we need one.
+/// And if we did not deactivate the original Formatter, that one would get
+/// destroyed before any call to .arg, producing an output, and then the one
+/// the .arg calls are called on would get destroyed as well, producing output
+/// again. So, think of this behaviour as soul moving from one to another.
+template<class Logger> class Formatter {
+private:
+ /// \brief The logger we will use to output the final message.
+ ///
+ /// If NULL, we are not active and should not produce anything.
+ mutable Logger* logger_;
+ /// \brief Prefix (eg. "ERROR", "DEBUG" or like that)
+ const char* prefix_;
+ /// \brief The messages with %1, %2... placeholders
+ std::string* message_;
+ /// \brief Which will be the next placeholder to replace
+ unsigned nextPlaceholder_;
+ Formatter& operator =(const Formatter& other);
+public:
+ /// \brief Constructor of "active" formatter
+ ///
+ /// This will create a formatter. If the arguments are set, it
+ /// will be active (will produce output). If you leave them all as NULL,
+ /// it will create an inactive Formatter -- one that'll produce no output.
+ ///
+ /// It is not expected to be called by user of logging system directly.
+ ///
+ /// \param prefix The severity prefix, like "ERROR" or "DEBUG"
+ /// \param message The message with placeholders. We take ownership of
+ /// it and we will modify the string. Must not be NULL unless
+ /// logger is also NULL, but it's not checked.
+ /// \param logger The logger where the final output will go, or NULL
+ /// if no output is wanted.
+ Formatter(const char* prefix = NULL, std::string* message = NULL,
+ Logger* logger = NULL) :
+ logger_(logger), prefix_(prefix), message_(message),
+ nextPlaceholder_(1)
+ {
+ }
+
+ Formatter(const Formatter& other) :
+ logger_(other.logger_), prefix_(other.prefix_),
+ message_(other.message_), nextPlaceholder_(other.nextPlaceholder_)
+ {
+ other.logger_ = false;
+ }
+ /// \brief Destructor.
+ //
+ /// This is the place where output happens if the formatter is active.
+ ~ Formatter() {
+ if (logger_) {
+ logger_->output(prefix_, *message_);
+ delete message_;
+ }
+ }
+ /// \brief Replaces another placeholder
+ ///
+ /// Replaces another placeholder and returns a new formatter with it.
+ /// Deactivates the current formatter. In case the formatter is not active,
+ /// only produces another inactive formatter.
+ ///
+ /// \param arg The argument to place into the placeholder.
+ template<class Arg> Formatter& arg(const Arg& value) {
+ if (logger_) {
+ return (arg(boost::lexical_cast<std::string>(value)));
+ } else {
+ return (*this);
+ }
+ }
+ /// \brief String version of arg.
+ Formatter& arg(const std::string& arg) {
+ if (logger_) {
+ // FIXME: This logic has a problem. If we had a message like
+ // "%1 %2" and called .arg("%2").arg(42), we would get "42 %2".
+ // But we consider this to be rare enough not to complicate
+ // matters.
+ replacePlaceholder(message_, arg, nextPlaceholder_ ++);
+ }
+ return (*this);
+ }
+};
+
+}
+}
+
+#endif
diff --git a/src/lib/log/logger.cc b/src/lib/log/logger.cc
index 99dc3a1..c340315 100644
--- a/src/lib/log/logger.cc
+++ b/src/lib/log/logger.cc
@@ -112,52 +112,57 @@ Logger::isFatalEnabled() {
// Output methods
void
-Logger::debug(int dbglevel, const isc::log::MessageID& ident, ...) {
+Logger::output(const char* sevText, const string& message) {
+ getLoggerPtr()->outputRaw(sevText, message);
+}
+
+Logger::Formatter
+Logger::debug(int dbglevel, const isc::log::MessageID& ident) {
if (isDebugEnabled(dbglevel)) {
- va_list ap;
- va_start(ap, ident);
- getLoggerPtr()->debug(ident, ap);
- va_end(ap);
+ return (Formatter("DEBUG", getLoggerPtr()->lookupMessage(ident),
+ this));
+ } else {
+ return (Formatter());
}
}
-void
-Logger::info(const isc::log::MessageID& ident, ...) {
+Logger::Formatter
+Logger::info(const isc::log::MessageID& ident) {
if (isInfoEnabled()) {
- va_list ap;
- va_start(ap, ident);
- getLoggerPtr()->info(ident, ap);
- va_end(ap);
+ return (Formatter("INFO ", getLoggerPtr()->lookupMessage(ident),
+ this));
+ } else {
+ return (Formatter());
}
}
-void
-Logger::warn(const isc::log::MessageID& ident, ...) {
+Logger::Formatter
+Logger::warn(const isc::log::MessageID& ident) {
if (isWarnEnabled()) {
- va_list ap;
- va_start(ap, ident);
- getLoggerPtr()->warn(ident, ap);
- va_end(ap);
+ return (Formatter("WARN ", getLoggerPtr()->lookupMessage(ident),
+ this));
+ } else {
+ return (Formatter());
}
}
-void
-Logger::error(const isc::log::MessageID& ident, ...) {
+Logger::Formatter
+Logger::error(const isc::log::MessageID& ident) {
if (isErrorEnabled()) {
- va_list ap;
- va_start(ap, ident);
- getLoggerPtr()->error(ident, ap);
- va_end(ap);
+ return (Formatter("ERROR", getLoggerPtr()->lookupMessage(ident),
+ this));
+ } else {
+ return (Formatter());
}
}
-void
-Logger::fatal(const isc::log::MessageID& ident, ...) {
+Logger::Formatter
+Logger::fatal(const isc::log::MessageID& ident) {
if (isFatalEnabled()) {
- va_list ap;
- va_start(ap, ident);
- getLoggerPtr()->fatal(ident, ap);
- va_end(ap);
+ return (Formatter("FATAL", getLoggerPtr()->lookupMessage(ident),
+ this));
+ } else {
+ return (Formatter());
}
}
diff --git a/src/lib/log/logger.h b/src/lib/log/logger.h
index 88e88e2..6bd8924 100644
--- a/src/lib/log/logger.h
+++ b/src/lib/log/logger.h
@@ -21,6 +21,7 @@
#include <log/debug_levels.h>
#include <log/logger_levels.h>
#include <log/message_types.h>
+#include <log/log_formatter.h>
namespace isc {
namespace log {
@@ -83,10 +84,11 @@ public:
loggerptr_(NULL), name_(name), infunc_(infunc)
{}
-
/// \brief Destructor
virtual ~Logger();
+ /// \brief The formatter used to replace placeholders
+ typedef isc::log::Formatter<Logger> Formatter;
/// \brief Get Name of Logger
///
@@ -157,36 +159,31 @@ public:
/// \param dbglevel Debug level, ranging between 0 and 99. Higher numbers
/// are used for more verbose output.
/// \param ident Message identification.
- /// \param ... Optional arguments for the message.
- void debug(int dbglevel, const MessageID& ident, ...);
+ Formatter debug(int dbglevel, const MessageID& ident);
/// \brief Output Informational Message
///
/// \param ident Message identification.
- /// \param ... Optional arguments for the message.
- void info(const MessageID& ident, ...);
+ Formatter info(const MessageID& ident);
/// \brief Output Warning Message
///
/// \param ident Message identification.
- /// \param ... Optional arguments for the message.
- void warn(const MessageID& ident, ...);
+ Formatter warn(const MessageID& ident);
/// \brief Output Error Message
///
/// \param ident Message identification.
- /// \param ... Optional arguments for the message.
- void error(const MessageID& ident, ...);
+ Formatter error(const MessageID& ident);
/// \brief Output Fatal Message
///
/// \param ident Message identification.
- /// \param ... Optional arguments for the message.
- void fatal(const MessageID& ident, ...);
+ Formatter fatal(const MessageID& ident);
/// \brief Equality
///
@@ -205,6 +202,12 @@ protected:
static void reset();
private:
+ friend class isc::log::Formatter<Logger>;
+ /// \brief Raw output function
+ ///
+ /// This is used by the formatter to output formatted output.
+ void output(const char* sevText, const std::string& message);
+
/// \brief Copy Constructor
///
/// Disabled (marked private) as it makes no sense to copy the logger -
diff --git a/src/lib/log/logger_impl.cc b/src/lib/log/logger_impl.cc
index 41153e9..b30f835 100644
--- a/src/lib/log/logger_impl.cc
+++ b/src/lib/log/logger_impl.cc
@@ -13,6 +13,7 @@
// PERFORMANCE OF THIS SOFTWARE
#include <iostream>
+#include <iomanip>
#include <algorithm>
#include <stdarg.h>
@@ -194,17 +195,14 @@ LoggerImpl::isDebugEnabled(int dbglevel) {
}
// Output a general message
+string*
+LoggerImpl::lookupMessage(const MessageID& ident) {
+ return (new string(string(ident) + ", " +
+ MessageDictionary::globalDictionary().getText(ident)));
+}
void
-LoggerImpl::output(const char* sev_text, const MessageID& ident,
- va_list ap)
-{
- char message[512]; // Should be large enough for any message
-
- // Obtain text of the message and substitute arguments.
- const string format = MessageDictionary::globalDictionary().getText(ident);
- vsnprintf(message, sizeof(message), format.c_str(), ap);
-
+LoggerImpl::outputRaw(const char* sevText, const string& message) {
// Get the time in a struct tm format, and convert to text
time_t t_time;
time(&t_time);
@@ -214,8 +212,8 @@ LoggerImpl::output(const char* sev_text, const MessageID& ident,
(void) strftime(chr_time, sizeof(chr_time), "%Y-%m-%d %H:%M:%S", tm_time);
// Now output.
- std::cout << chr_time << " " << sev_text << " [" << getName() << "] " <<
- ident << ", " << message << "\n";
+ cout << chr_time << " " << sevText << " [" << getName() << "] " <<
+ message << endl;
}
} // namespace log
diff --git a/src/lib/log/logger_impl.h b/src/lib/log/logger_impl.h
index 9fc9cf9..187e478 100644
--- a/src/lib/log/logger_impl.h
+++ b/src/lib/log/logger_impl.h
@@ -167,64 +167,16 @@ public:
}
}
-
- /// \brief Output General Message
- ///
- /// The message is formatted to include the date and time, the severity
- /// and the logger generating the message.
+ /// \brief Raw output
///
- /// \param sev_text Severity level as a text string
- /// \param ident Message identification
- /// \param ap Variable argument list holding message arguments
- void output(const char* sev_text, const MessageID& ident,
- va_list ap);
-
+ /// Writes the message with time into the log. Used by the Formatter
+ /// to produce output.
+ void outputRaw(const char* sev_text, const std::string& message);
- /// \brief Output Debug Message
+ /// \brief Look up message text in dictionary
///
- /// \param ident Message identification.
- /// \param text Text to log
- /// \param ap Variable argument list holding message arguments
- void debug(const MessageID& ident, va_list ap) {
- output("DEBUG", ident, ap);
- }
-
-
- /// \brief Output Informational Message
- ///
- /// \param ident Message identification.
- /// \param text Text to log
- /// \param ap Variable argument list holding message arguments
- void info(const MessageID& ident, va_list ap) {
- output("INFO ", ident, ap);
- }
-
- /// \brief Output Warning Message
- ///
- /// \param ident Message identification.
- /// \param text Text to log
- /// \param ap Variable argument list holding message arguments
- void warn(const MessageID& ident, va_list ap) {
- output("WARN ", ident, ap);
- }
-
- /// \brief Output Error Message
- ///
- /// \param ident Message identification.
- /// \param text Text to log
- /// \param ap Variable argument list holding message arguments
- void error(const MessageID& ident, va_list ap) {
- output("ERROR", ident, ap);
- }
-
- /// \brief Output Fatal Message
- ///
- /// \param ident Message identification.
- /// \param text Text to log
- /// \param ap Variable argument list holding message arguments
- void fatal(const MessageID& ident, va_list ap) {
- output("FATAL", ident, ap);
- }
+ /// This gets you the unformatted text of message for given ID.
+ std::string* lookupMessage(const MessageID& id);
/// \brief Equality
///
diff --git a/src/lib/log/logger_support.cc b/src/lib/log/logger_support.cc
index f8bf075..e17c47d 100644
--- a/src/lib/log/logger_support.cc
+++ b/src/lib/log/logger_support.cc
@@ -24,7 +24,9 @@
/// These functions will be replaced once the code has been written to obtain
/// the logging parameters from the configuration database.
+#include <iostream>
#include <algorithm>
+#include <iostream>
#include <string>
#include <vector>
#include <boost/lexical_cast.hpp>
@@ -62,7 +64,7 @@ readLocalMessageFile(const char* file) {
MessageDictionary& dictionary = MessageDictionary::globalDictionary();
MessageReader reader(&dictionary);
try {
- logger.info(MSG_RDLOCMES, file);
+ logger.info(MSG_RDLOCMES).arg(file);
reader.readFile(file, MessageReader::REPLACE);
// File successfully read, list the duplicates
@@ -70,7 +72,7 @@ readLocalMessageFile(const char* file) {
for (MessageReader::MessageIDCollection::const_iterator
i = unknown.begin(); i != unknown.end(); ++i) {
string message_id = boost::lexical_cast<string>(*i);
- logger.warn(MSG_IDNOTFND, message_id.c_str());
+ logger.warn(MSG_IDNOTFND).arg(message_id);
}
}
catch (MessageException& e) {
@@ -82,11 +84,15 @@ readLocalMessageFile(const char* file) {
break;
case 1:
- logger.error(ident, args[0].c_str());
+ logger.error(ident).arg(args[0]);
break;
- default: // 2 or more (2 should be the maximum)
- logger.error(ident, args[0].c_str(), args[1].c_str());
+ case 2:
+ logger.error(ident).arg(args[0]).arg(args[1]);
+ break;
+
+ default: // 3 or more (3 should be the maximum)
+ logger.error(ident).arg(args[0]).arg(args[1]).arg(args[2]);
}
}
}
@@ -117,7 +123,7 @@ initLogger(const string& root, isc::log::Severity severity, int dbglevel,
vector<string>::iterator new_end =
unique(duplicates.begin(), duplicates.end());
for (vector<string>::iterator i = duplicates.begin(); i != new_end; ++i) {
- logger.warn(MSG_DUPMSGID, i->c_str());
+ logger.warn(MSG_DUPMSGID).arg(*i);
}
}
@@ -128,5 +134,76 @@ initLogger(const string& root, isc::log::Severity severity, int dbglevel,
}
}
+/// Logger Run-Time Initialization via Environment Variables
+void initLogger() {
+
+ // Root logger name is defined by the environment variable B10_LOGGER_ROOT.
+ // If not present, the name is "b10root".
+ const char* DEFAULT_ROOT = "b10root";
+ const char* root = getenv("B10_LOGGER_ROOT");
+ if (! root) {
+ root = DEFAULT_ROOT;
+ }
+
+ // Set the logging severity. The environment variable is
+ // B10_LOGGER_SEVERITY, and can be one of "DEBUG", "INFO", "WARN", "ERROR"
+ // of "FATAL". Note that the string must be in upper case with no leading
+ // of trailing blanks.
+ isc::log::Severity severity = isc::log::DEFAULT;
+ const char* sev_char = getenv("B10_LOGGER_SEVERITY");
+ if (sev_char) {
+ string sev_string(sev_char);
+ if (sev_string == "DEBUG") {
+ severity = isc::log::DEBUG;
+ } else if (sev_string == "INFO") {
+ severity = isc::log::INFO;
+ } else if (sev_string == "WARN") {
+ severity = isc::log::WARN;
+ } else if (sev_string == "ERROR") {
+ severity = isc::log::ERROR;
+ } else if (sev_string == "FATAL") {
+ severity = isc::log::FATAL;
+ } else {
+ std::cerr << "**ERROR** unrecognised logger severity of '"
+ << sev_string << "' - default severity will be used\n";
+ }
+ }
+
+ // If the severity is debug, get the debug level (environment variable
+ // B10_LOGGER_DBGLEVEL), which should be in the range 0 to 99.
+ int dbglevel = 0;
+ if (severity == isc::log::DEBUG) {
+ const char* dbg_char = getenv("B10_LOGGER_DBGLEVEL");
+ if (dbg_char) {
+ int level = 0;
+ try {
+ level = boost::lexical_cast<int>(dbg_char);
+ if (level < MIN_DEBUG_LEVEL) {
+ std::cerr << "**ERROR** debug level of " << level
+ << " is invalid - a value of " << MIN_DEBUG_LEVEL
+ << " will be used\n";
+ level = MIN_DEBUG_LEVEL;
+ } else if (level > MAX_DEBUG_LEVEL) {
+ std::cerr << "**ERROR** debug level of " << level
+ << " is invalid - a value of " << MAX_DEBUG_LEVEL
+ << " will be used\n";
+ level = MAX_DEBUG_LEVEL;
+ }
+ } catch (...) {
+ // Error, but not fatal to the test
+ std::cerr << "**ERROR** Unable to translate "
+ "B10_LOGGER_DBGLEVEL - a value of 0 will be used\n";
+ }
+ dbglevel = level;
+ }
+ }
+
+ /// Set the local message file
+ const char* localfile = getenv("B10_LOGGER_LOCALMSG");
+
+ // Initialize logging
+ initLogger(root, severity, dbglevel, localfile);
+}
+
} // namespace log
} // namespace isc
diff --git a/src/lib/log/logger_support.h b/src/lib/log/logger_support.h
index 6b5fdec..f4861b2 100644
--- a/src/lib/log/logger_support.h
+++ b/src/lib/log/logger_support.h
@@ -39,6 +39,37 @@ namespace log {
void initLogger(const std::string& root, isc::log::Severity severity,
int dbglevel, const char* file);
+
+/// \brief Run-Time Initialization from Environment
+///
+/// Performs run-time initialization of the logger via the setting of
+/// environment variables. These are:
+///
+/// B10_LOGGER_ROOT
+/// Name of the root logger. If not given, the string "b10root" will be used.
+///
+/// B10_LOGGER_SEVERITY
+/// Severity of messages that will be logged. This must be one of the strings
+/// "DEBUG", "INFO", "WARN", "ERROR", "FATAL". (Must be upper case and must
+/// not contain leading or trailing spaces.) If not specified (or if
+/// specified but incorrect), the default for the logging system will be used
+/// (currently INFO).
+///
+/// B10_LOGGER_DBGLEVEL
+/// Ignored if the level is not DEBUG, this should be a number between 0 and
+/// 99 indicating the logging severity. The default is 0. If outside these
+/// limits or if not a number, a value of 0 is used.
+///
+/// B10_LOGGER_LOCALMSG
+/// If defined, the path specification of a file that contains message
+/// definitions replacing ones in the default dictionary.
+///
+/// Any errors in the settings cause messages to be output to stderr.
+///
+/// This function is most likely to be called from unit test programs.
+
+void initLogger();
+
} // namespace log
} // namespace isc
diff --git a/src/lib/log/macros.h b/src/lib/log/macros.h
new file mode 100644
index 0000000..3128131
--- /dev/null
+++ b/src/lib/log/macros.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __LOG_MACROS_H
+#define __LOG_MACROS_H
+
+#include <log/logger.h>
+
+/// \brief Macro to conveniently test debug output and log it
+#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE) \
+ if (!(LOGGER).isDebugEnabled((LEVEL))) { \
+ } else \
+ (LOGGER).debug((LEVEL), (MESSAGE))
+
+/// \brief Macro to conveniently test info output and log it
+#define LOG_INFO(LOGGER, MESSAGE) \
+ if (!(LOGGER).isInfoEnabled()) { \
+ } else \
+ (LOGGER).info((MESSAGE))
+
+/// \brief Macro to conveniently test warn output and log it
+#define LOG_WARN(LOGGER, MESSAGE) \
+ if (!(LOGGER).isWarnEnabled()) { \
+ } else \
+ (LOGGER).warn((MESSAGE))
+
+/// \brief Macro to conveniently test error output and log it
+#define LOG_ERROR(LOGGER, MESSAGE) \
+ if (!(LOGGER).isErrorEnabled()) { \
+ } else \
+ (LOGGER).error((MESSAGE))
+
+/// \brief Macro to conveniently test fatal output and log it
+#define LOG_FATAL(LOGGER, MESSAGE) \
+ if (!(LOGGER).isFatalEnabled()) { \
+ } else \
+ (LOGGER).fatal((MESSAGE))
+
+#endif
diff --git a/src/lib/log/message_exception.cc b/src/lib/log/message_exception.cc
deleted file mode 100644
index 1a69ca5..0000000
--- a/src/lib/log/message_exception.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-/// \brief Body of Virtual Destructor
-
-#include <log/message_exception.h>
-
-namespace isc {
-namespace log {
-
-MessageException::~MessageException() throw() {
-}
-
-} // namespace log
-} // namespace isc
diff --git a/src/lib/log/message_exception.h b/src/lib/log/message_exception.h
index 30c6618..eebee89 100644
--- a/src/lib/log/message_exception.h
+++ b/src/lib/log/message_exception.h
@@ -19,6 +19,7 @@
#include <string>
#include <vector>
+#include <boost/lexical_cast.hpp>
#include <log/message_types.h>
namespace isc {
@@ -35,33 +36,47 @@ public:
/// \brief Constructor
///
- /// \param id Message identification
- MessageException(MessageID id) : id_(id)
- {}
+ /// \param id Message identification.
+ /// \param lineno Line number on which error occurred (if > 0).
+ MessageException(MessageID id, int lineno = 0) : id_(id)
+ {
+ if (lineno > 0) {
+ args_.push_back(boost::lexical_cast<std::string>(lineno));
+ }
+ }
/// \brief Constructor
///
- /// \param id Message identification
- /// \param arg1 First message argument
- MessageException(MessageID id, const std::string& arg1) : id_(id)
+ /// \param id Message identification.
+ /// \param arg1 First message argument.
+ /// \param lineno Line number on which error occurred (if > 0).
+ MessageException(MessageID id, const std::string& arg1, int lineno = 0)
+ : id_(id)
{
+ if (lineno > 0) {
+ args_.push_back(boost::lexical_cast<std::string>(lineno));
+ }
args_.push_back(arg1);
}
/// \brief Constructor
///
- /// \param id Message identification
- /// \param arg1 First message argument
- /// \param arg2 Second message argument
+ /// \param id Message identification.
+ /// \param arg1 First message argument.
+ /// \param arg2 Second message argument.
+ /// \param lineno Line number on which error occurred (if > 0).
MessageException(MessageID id, const std::string& arg1,
- const std::string& arg2) : id_(id)
+ const std::string& arg2, int lineno = 0) : id_(id)
{
+ if (lineno > 0) {
+ args_.push_back(boost::lexical_cast<std::string>(lineno));
+ }
args_.push_back(arg1);
args_.push_back(arg2);
}
/// \brief Destructor
- virtual ~MessageException() throw();
+ ~MessageException() throw() {}
/// \brief Return Message ID
///
diff --git a/src/lib/log/message_reader.cc b/src/lib/log/message_reader.cc
index 7281346..1a0b242 100644
--- a/src/lib/log/message_reader.cc
+++ b/src/lib/log/message_reader.cc
@@ -12,8 +12,10 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <cassert>
#include <errno.h>
#include <string.h>
+#include <iostream>
#include <iostream>
#include <fstream>
@@ -25,45 +27,50 @@
using namespace std;
-namespace isc {
-namespace log {
-
-// Virtual destructor.
-MessageReader::~MessageReader() {
+namespace {
+const char DIRECTIVE_FLAG = '$'; // Starts each directive
+const char MESSAGE_FLAG = '%'; // Starts each message
}
+namespace isc {
+namespace log {
+
// Read the file.
void
MessageReader::readFile(const string& file, MessageReader::Mode mode) {
- // Ensure the non-added collection is empty: this object might be
- // being reused.
+ // Ensure the non-added collection is empty: we could be re-using this
+ // object.
not_added_.clear();
- // Open the file
+ // Open the file.
ifstream infile(file.c_str());
if (infile.fail()) {
- throw MessageException(MSG_OPNMSGIN, file, strerror(errno));
+ throw MessageException(MSG_OPENIN, file, strerror(errno));
}
- // Loop round reading it.
+ // Loop round reading it. As we process the file one line at a time,
+ // keep a track of line number of aid diagnosis of problems.
string line;
getline(infile, line);
+ lineno_ = 0;
+
while (infile.good()) {
+ ++lineno_;
processLine(line, mode);
getline(infile, line);
}
// Why did the loop terminate?
if (!infile.eof()) {
- throw MessageException(MSG_MSGRDERR, file, strerror(errno));
+ throw MessageException(MSG_READERR, file, strerror(errno));
}
infile.close();
}
-// Parse a line of the file
+// Parse a line of the file.
void
MessageReader::processLine(const string& line, MessageReader::Mode mode) {
@@ -74,15 +81,16 @@ MessageReader::processLine(const string& line, MessageReader::Mode mode) {
if (text.empty()) {
; // Ignore blank lines
- } else if ((text[0] == '#') || (text[0] == '+')) {
- ; // Ignore comments or descriptions
-
- } else if (text[0] == '$') {
+ } else if (text[0] == DIRECTIVE_FLAG) {
parseDirective(text); // Process directives
- } else {
- parseMessage(text, mode); // Process other lines
+ } else if (text[0] == MESSAGE_FLAG) {
+ parseMessage(text, mode); // Process message definition line
+
+ } else {
+ ; // Other lines are extended message
+ // description so are ignored
}
}
@@ -99,130 +107,162 @@ MessageReader::parseDirective(const std::string& text) {
isc::util::str::uppercase(tokens[0]);
if (tokens[0] == string("$PREFIX")) {
parsePrefix(tokens);
+
} else if (tokens[0] == string("$NAMESPACE")) {
parseNamespace(tokens);
+
} else {
- throw MessageException(MSG_UNRECDIR, tokens[0]);
+
+ // Unrecognised directive
+ throw MessageException(MSG_UNRECDIR, tokens[0], lineno_);
}
}
// Process $PREFIX
-
void
MessageReader::parsePrefix(const vector<string>& tokens) {
- // Check argument count
-
- static string valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
- if (tokens.size() < 2) {
- throw MessageException(MSG_PRFNOARG);
- } else if (tokens.size() > 2) {
- throw MessageException(MSG_PRFEXTRARG);
-
- }
+ // Should not get here unless there is something in the tokens array.
+ assert(tokens.size() > 0);
- // As a style, we are going to have the symbols in uppercase
- string prefix = tokens[1];
- isc::util::str::uppercase(prefix);
+ // Process $PREFIX. With no arguments, the prefix is set to the empty
+ // string. One argument sets the prefix to the to its value and more than
+ // one argument is invalid.
+ if (tokens.size() == 1) {
+ prefix_ = "";
- // Token is potentially valid providing it only contains alphabetic
- // and numeric characters (and underscores) and does not start with a
- // digit.
- if ((prefix.find_first_not_of(valid) != string::npos) ||
- (std::isdigit(prefix[0]))) {
+ } else if (tokens.size() == 2) {
+ prefix_ = tokens[1];
- // Invalid character in string or it starts with a digit.
- throw MessageException(MSG_PRFINVARG, tokens[1]);
- }
+ // Token is potentially valid providing it only contains alphabetic
+ // and numeric characters (and underscores) and does not start with a
+ // digit.
+ if (invalidSymbol(prefix_)) {
+ throw MessageException(MSG_PRFINVARG, prefix_, lineno_);
+ }
- // All OK - unless the prefix has already been set.
+ } else {
- if (prefix_.size() != 0) {
- throw MessageException(MSG_DUPLPRFX);
+ // Too many arguments
+ throw MessageException(MSG_PRFEXTRARG, lineno_);
}
+}
- // Prefix has not been set, so set it and return success.
-
- prefix_ = prefix;
+// Check if string is an invalid C++ symbol. It is valid if comprises only
+// alphanumeric characters and underscores, and does not start with a digit.
+// (Owing to the logic of the rest of the code, we check for its invalidity,
+// not its validity.)
+bool
+MessageReader::invalidSymbol(const string& symbol) {
+ static const string valid_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789_";
+ return ( symbol.empty() ||
+ (symbol.find_first_not_of(valid_chars) != string::npos) ||
+ (std::isdigit(symbol[0])));
}
// Process $NAMESPACE. A lot of the processing is similar to that of $PREFIX,
// except that only limited checks will be done on the namespace (to avoid a
-// lot of parsing and separating out of the namespace components.)
+// lot of parsing and separating out of the namespace components.) Also, unlike
+// $PREFIX, there can only be one $NAMESPACE in a file.
void
MessageReader::parseNamespace(const vector<string>& tokens) {
// Check argument count
-
- static string valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_:"
- "abcdefghijklmnopqrstuvwxyz";
-
if (tokens.size() < 2) {
- throw MessageException(MSG_NSNOARG);
+ throw MessageException(MSG_NSNOARG, lineno_);
} else if (tokens.size() > 2) {
- throw MessageException(MSG_NSEXTRARG);
+ throw MessageException(MSG_NSEXTRARG, lineno_);
}
// Token is potentially valid providing it only contains alphabetic
- // and numeric characters (and underscores and colons).
- if (tokens[1].find_first_not_of(valid) != string::npos) {
-
- // Invalid character in string or it starts with a digit.
- throw MessageException(MSG_NSINVARG, tokens[1]);
+ // and numeric characters (and underscores and colons). As noted above,
+ // we won't be exhaustive - after all, and code containing the resultant
+ // namespace will have to be compiled, and the compiler will catch errors.
+ static const string valid_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789_:";
+ if (tokens[1].find_first_not_of(valid_chars) != string::npos) {
+ throw MessageException(MSG_NSINVARG, tokens[1], lineno_);
}
// All OK - unless the namespace has already been set.
if (ns_.size() != 0) {
- throw MessageException(MSG_DUPLNS);
+ throw MessageException(MSG_DUPLNS, lineno_);
}
// Prefix has not been set, so set it and return success.
-
ns_ = tokens[1];
}
// Process message. By the time this method is called, the line has been
-// stripped of leading and trailing spaces, and we believe that it is a line
-// defining a message. The first token on the line is converted to uppercase
-// and becomes the message ID; the rest of the line is the message text.
+// stripped of leading and trailing spaces. The first character of the string
+// is the message introducer, so we can get rid of that. The remainder is
+// a line defining a message.
+//
+// The first token on the line, when concatenated to the prefix and converted to
+// upper-case, is the message ID. The first of the line from the next token
+// on is the message text.
void
MessageReader::parseMessage(const std::string& text, MessageReader::Mode mode) {
static string delimiters("\t\n "); // Delimiters
+ // The line passed should be at least one character long and start with the
+ // message introducer (else we should not have got here).
+ assert((text.size() >= 1) && (text[0] == MESSAGE_FLAG));
+
+ // A line comprising just the message introducer is not valid.
+ if (text.size() == 1) {
+ throw MessageException(MSG_NOMSGID, text, lineno_);
+ }
+
+ // Strip off the introducer and any leading space after that.
+ string message_line = isc::util::str::trim(text.substr(1));
+
// Look for the first delimiter.
- size_t first_delim = text.find_first_of(delimiters);
+ size_t first_delim = message_line.find_first_of(delimiters);
if (first_delim == string::npos) {
// Just a single token in the line - this is not valid
- throw MessageException(MSG_NOMSGTXT, text);
+ throw MessageException(MSG_NOMSGTXT, message_line, lineno_);
}
- // Extract the first token into the message ID
- string ident = text.substr(0, first_delim);
+ // Extract the first token into the message ID, preceding it with the
+ // current prefix, then convert to upper-case. If the prefix is not set,
+ // perform the valid character check now - the string will become a C++
+ // symbol so we may as well identify problems early.
+ string ident = prefix_ + message_line.substr(0, first_delim);
+ if (prefix_.empty()) {
+ if (invalidSymbol(ident)) {
+ throw MessageException(MSG_INVMSGID, ident, lineno_);
+ }
+ }
+ isc::util::str::uppercase(ident);
// Locate the start of the message text
- size_t first_text = text.find_first_not_of(delimiters, first_delim);
+ size_t first_text = message_line.find_first_not_of(delimiters, first_delim);
if (first_text == string::npos) {
// ?? This happens if there are trailing delimiters, which should not
// occur as we have stripped trailing spaces off the line. Just treat
// this as a single-token error for simplicity's sake.
- throw MessageException(MSG_NOMSGTXT, text);
+ throw MessageException(MSG_NOMSGTXT, message_line, lineno_);
}
// Add the result to the dictionary and to the non-added list if the add to
// the dictionary fails.
bool added;
if (mode == ADD) {
- added = dictionary_->add(ident, text.substr(first_text));
+ added = dictionary_->add(ident, message_line.substr(first_text));
}
else {
- added = dictionary_->replace(ident, text.substr(first_text));
+ added = dictionary_->replace(ident, message_line.substr(first_text));
}
if (!added) {
not_added_.push_back(ident);
diff --git a/src/lib/log/message_reader.h b/src/lib/log/message_reader.h
index d07c7f2..eded9c6 100644
--- a/src/lib/log/message_reader.h
+++ b/src/lib/log/message_reader.h
@@ -64,10 +64,9 @@ public:
dictionary_(dictionary)
{}
-
/// \brief Virtual Destructor
- virtual ~MessageReader();
-
+ virtual ~MessageReader()
+ {}
/// \brief Get Dictionary
///
@@ -188,10 +187,24 @@ private:
/// \param tokens $NAMESPACE line split into tokens
void parseNamespace(const std::vector<std::string>& tokens);
+ /// \brief Check for invalid C++ symbol name
+ ///
+ /// The message ID (or concatenation of prefix and message ID) will be used
+ /// as the name of a symbol in C++ code. This function checks if the name
+ /// is invalid (contains anything other than alphanumeric characters or
+ /// underscores, or starts with a digit).
+ ///
+ /// \param symbol name to check to see if it is an invalid C++ symbol.
+ ///
+ /// \return true if the name is invalid, false if it is valid.
+ bool invalidSymbol(const std::string& symbol);
+
+
/// Attributes
MessageDictionary* dictionary_; ///< Dictionary to add messages to
MessageIDCollection not_added_; ///< List of IDs not added
+ int lineno_; ///< Number of last line read
std::string prefix_; ///< Argument of $PREFIX statement
std::string ns_; ///< Argument of $NAMESPACE statement
};
diff --git a/src/lib/log/messagedef.cc b/src/lib/log/messagedef.cc
index f680a74..5cc89b3 100644
--- a/src/lib/log/messagedef.cc
+++ b/src/lib/log/messagedef.cc
@@ -1,4 +1,4 @@
-// File created from messagedef.mes on Mon Feb 14 11:07:45 2011
+// File created from messagedef.mes on Mon May 9 13:52:54 2011
#include <cstddef>
#include <log/message_types.h>
@@ -7,23 +7,23 @@
namespace isc {
namespace log {
-extern const isc::log::MessageID MSG_DUPLNS = "DUPLNS";
-extern const isc::log::MessageID MSG_DUPLPRFX = "DUPLPRFX";
-extern const isc::log::MessageID MSG_DUPMSGID = "DUPMSGID";
-extern const isc::log::MessageID MSG_IDNOTFND = "IDNOTFND";
-extern const isc::log::MessageID MSG_MSGRDERR = "MSGRDERR";
-extern const isc::log::MessageID MSG_MSGWRTERR = "MSGWRTERR";
-extern const isc::log::MessageID MSG_NOMSGTXT = "NOMSGTXT";
-extern const isc::log::MessageID MSG_NSEXTRARG = "NSEXTRARG";
-extern const isc::log::MessageID MSG_NSINVARG = "NSINVARG";
-extern const isc::log::MessageID MSG_NSNOARG = "NSNOARG";
-extern const isc::log::MessageID MSG_OPNMSGIN = "OPNMSGIN";
-extern const isc::log::MessageID MSG_OPNMSGOUT = "OPNMSGOUT";
-extern const isc::log::MessageID MSG_PRFEXTRARG = "PRFEXTRARG";
-extern const isc::log::MessageID MSG_PRFINVARG = "PRFINVARG";
-extern const isc::log::MessageID MSG_PRFNOARG = "PRFNOARG";
-extern const isc::log::MessageID MSG_RDLOCMES = "RDLOCMES";
-extern const isc::log::MessageID MSG_UNRECDIR = "UNRECDIR";
+extern const isc::log::MessageID MSG_DUPLNS = "MSG_DUPLNS";
+extern const isc::log::MessageID MSG_DUPMSGID = "MSG_DUPMSGID";
+extern const isc::log::MessageID MSG_IDNOTFND = "MSG_IDNOTFND";
+extern const isc::log::MessageID MSG_INVMSGID = "MSG_INVMSGID";
+extern const isc::log::MessageID MSG_NOMSGID = "MSG_NOMSGID";
+extern const isc::log::MessageID MSG_NOMSGTXT = "MSG_NOMSGTXT";
+extern const isc::log::MessageID MSG_NSEXTRARG = "MSG_NSEXTRARG";
+extern const isc::log::MessageID MSG_NSINVARG = "MSG_NSINVARG";
+extern const isc::log::MessageID MSG_NSNOARG = "MSG_NSNOARG";
+extern const isc::log::MessageID MSG_OPENIN = "MSG_OPENIN";
+extern const isc::log::MessageID MSG_OPENOUT = "MSG_OPENOUT";
+extern const isc::log::MessageID MSG_PRFEXTRARG = "MSG_PRFEXTRARG";
+extern const isc::log::MessageID MSG_PRFINVARG = "MSG_PRFINVARG";
+extern const isc::log::MessageID MSG_RDLOCMES = "MSG_RDLOCMES";
+extern const isc::log::MessageID MSG_READERR = "MSG_READERR";
+extern const isc::log::MessageID MSG_UNRECDIR = "MSG_UNRECDIR";
+extern const isc::log::MessageID MSG_WRITERR = "MSG_WRITERR";
} // namespace log
} // namespace isc
@@ -31,23 +31,23 @@ extern const isc::log::MessageID MSG_UNRECDIR = "UNRECDIR";
namespace {
const char* values[] = {
- "DUPLNS", "duplicate $NAMESPACE directive found",
- "DUPLPRFX", "duplicate $PREFIX directive found",
- "DUPMSGID", "duplicate message ID (%s) in compiled code",
- "IDNOTFND", "could not replace message for '%s': no such message identification",
- "MSGRDERR", "error reading from message file %s: %s",
- "MSGWRTERR", "error writing to %s: %s",
- "NOMSGTXT", "a line containing a message ID ('%s') and nothing else was found",
- "NSEXTRARG", "$NAMESPACE directive has too many arguments",
- "NSINVARG", "$NAMESPACE directive has an invalid argument ('%s')",
- "NSNOARG", "no arguments were given to the $NAMESPACE directive",
- "OPNMSGIN", "unable to open message file %s for input: %s",
- "OPNMSGOUT", "unable to open %s for output: %s",
- "PRFEXTRARG", "$PREFIX directive has too many arguments",
- "PRFINVARG", "$PREFIX directive has an invalid argument ('%s')",
- "PRFNOARG", "no arguments were given to the $PREFIX directive",
- "RDLOCMES", "reading local message file %s",
- "UNRECDIR", "unrecognised directive '%s'",
+ "MSG_DUPLNS", "line %1: duplicate $NAMESPACE directive found",
+ "MSG_DUPMSGID", "duplicate message ID (%1) in compiled code",
+ "MSG_IDNOTFND", "could not replace message text for '%1': no such message",
+ "MSG_INVMSGID", "line %1: invalid message identification '%2'",
+ "MSG_NOMSGID", "line %1: message definition line found without a message ID",
+ "MSG_NOMSGTXT", "line %1: line found containing a message ID ('%2') and no text",
+ "MSG_NSEXTRARG", "line %1: $NAMESPACE directive has too many arguments",
+ "MSG_NSINVARG", "line %1: $NAMESPACE directive has an invalid argument ('%2')",
+ "MSG_NSNOARG", "line %1: no arguments were given to the $NAMESPACE directive",
+ "MSG_OPENIN", "unable to open message file %1 for input: %2",
+ "MSG_OPENOUT", "unable to open %1 for output: %2",
+ "MSG_PRFEXTRARG", "line %1: $PREFIX directive has too many arguments",
+ "MSG_PRFINVARG", "line %1: $PREFIX directive has an invalid argument ('%2')",
+ "MSG_RDLOCMES", "reading local message file %1",
+ "MSG_READERR", "error reading from message file %1: %2",
+ "MSG_UNRECDIR", "line %1: unrecognised directive '%2'",
+ "MSG_WRITERR", "error writing to %1: %2",
NULL
};
diff --git a/src/lib/log/messagedef.h b/src/lib/log/messagedef.h
index eb8f4ea..79c8bab 100644
--- a/src/lib/log/messagedef.h
+++ b/src/lib/log/messagedef.h
@@ -1,4 +1,4 @@
-// File created from messagedef.mes on Mon Feb 14 11:07:45 2011
+// File created from messagedef.mes on Mon May 9 13:52:54 2011
#ifndef __MESSAGEDEF_H
#define __MESSAGEDEF_H
@@ -9,22 +9,22 @@ namespace isc {
namespace log {
extern const isc::log::MessageID MSG_DUPLNS;
-extern const isc::log::MessageID MSG_DUPLPRFX;
extern const isc::log::MessageID MSG_DUPMSGID;
extern const isc::log::MessageID MSG_IDNOTFND;
-extern const isc::log::MessageID MSG_MSGRDERR;
-extern const isc::log::MessageID MSG_MSGWRTERR;
+extern const isc::log::MessageID MSG_INVMSGID;
+extern const isc::log::MessageID MSG_NOMSGID;
extern const isc::log::MessageID MSG_NOMSGTXT;
extern const isc::log::MessageID MSG_NSEXTRARG;
extern const isc::log::MessageID MSG_NSINVARG;
extern const isc::log::MessageID MSG_NSNOARG;
-extern const isc::log::MessageID MSG_OPNMSGIN;
-extern const isc::log::MessageID MSG_OPNMSGOUT;
+extern const isc::log::MessageID MSG_OPENIN;
+extern const isc::log::MessageID MSG_OPENOUT;
extern const isc::log::MessageID MSG_PRFEXTRARG;
extern const isc::log::MessageID MSG_PRFINVARG;
-extern const isc::log::MessageID MSG_PRFNOARG;
extern const isc::log::MessageID MSG_RDLOCMES;
+extern const isc::log::MessageID MSG_READERR;
extern const isc::log::MessageID MSG_UNRECDIR;
+extern const isc::log::MessageID MSG_WRITERR;
} // namespace log
} // namespace isc
diff --git a/src/lib/log/messagedef.mes b/src/lib/log/messagedef.mes
index 3599388..51c04fa 100644
--- a/src/lib/log/messagedef.mes
+++ b/src/lib/log/messagedef.mes
@@ -12,108 +12,108 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-$PREFIX MSG_
-$NAMESPACE isc::log
-
# \brief Message Utility Message File
#
-# This is the source of the set of messages generated by the message and logging
-# components. The associated .h and .cc files are created by hand from this
-# file though and are not built during the build process; this is to avoid the
-# chicken-and-egg situation where we need the files to build the message
+# This is the source of the set of messages generated by the message and
+# logging components. The associated .h and .cc files are created by hand from
+# this file though and are not built during the build process; this is to avoid
+# the chicken-and-egg situation where we need the files to build the message
# compiler, yet we need the compiler to build the files.
-DUPMSGID duplicate message ID (%s) in compiled code
-+ Indicative of a programming error, when it started up, BIND10 detected that
-+ the given message ID had been registered by one or more modules. (All message
-+ IDs should be unique throughout BIND10.) This has no impact on the operation
-+ of the server other that erroneous messages may be logged. (When BIND10 loads
-+ the message IDs (and their associated text), if a duplicate ID is found it is
-+ discarded. However, when the module that supplied the duplicate ID logs that
-+ particular message, the text supplied by the module that added the original
-+ ID will be output - something that may bear no relation to the condition being
-+ logged.
-
-DUPLNS duplicate $NAMESPACE directive found
-+ When reading a message file, more than one $NAMESPACE directive was found. In
-+ this version of the code, such a condition is regarded as an error and the
-+ read will be abandoned.
-
-DUPLPRFX duplicate $PREFIX directive found
-+ When reading a message file, more than one $PREFIX directive was found. In
-+ this version of the code, such a condition is regarded as an error and the
-+ read will be abandoned.
-
-IDNOTFND could not replace message for '%s': no such message identification
-+ During start-up a local message file was read. A line with the listed
-+ message identification was found in the file, but the identification is not
-+ one contained in the compiled-in message dictionary. Either the message
-+ identification has been mis-spelled in the file, or the local file was used
-+ for an earlier version of the software and the message with that
-+ identification has been removed.
-+
-+ This message may appear a number of times in the file, once for every such
-+ unknown message identification.
-
-MSGRDERR error reading from message file %s: %s
-+ The specified error was encountered reading from the named message file.
-
-MSGWRTERR error writing to %s: %s
-+ The specified error was encountered by the message compiler when writing to
-+ the named output file.
-
-NSEXTRARG $NAMESPACE directive has too many arguments
-+ The $NAMESPACE directive takes a single argument, a namespace in which all the
-+ generated symbol names are placed. This error is generated when the
-+ compiler finds a $NAMESPACE directive with more than one argument.
-
-NSINVARG $NAMESPACE directive has an invalid argument ('%s')
-+ The $NAMESPACE argument should be a valid C++ namespace. The reader does a
-+ cursory check on its validity, checking that the characters in the namespace
-+ are correct. The error is generated when the reader finds an invalid
-+ character. (Valid are alphanumeric characters, underscores and colons.)
-
-NOMSGTXT a line containing a message ID ('%s') and nothing else was found
-+ Message definitions comprise lines starting with a message identification (a
-+ symbolic name for the message) and followed by the text of the message. This
-+ error is generated when a line is found in the message file that contains just
-+ the message identification and no text.
-
-NSNOARG no arguments were given to the $NAMESPACE directive
-+ The $NAMESPACE directive takes a single argument, a namespace in which all the
-+ generated symbol names are placed. This error is generated when the
-+ compiler finds a $NAMESPACE directive with no arguments.
-
-OPNMSGIN unable to open message file %s for input: %s
-+ The program was not able to open the specified input message file for the
-+ reason given.
-
-OPNMSGOUT unable to open %s for output: %s
-+ The program was not able to open the specified output file for the reason
-+ given.
-
-PRFEXTRARG $PREFIX directive has too many arguments
-+ The $PREFIX directive takes a single argument, a prefix to be added to the
-+ symbol names when a C++ .h file is created. This error is generated when the
-+ compiler finds a $PREFIX directive with more than one argument.
-
-PRFINVARG $PREFIX directive has an invalid argument ('%s')
-+ The $PREFIX argument is used in a symbol name in a C++ header file. As such,
-+ it must adhere to restrictions on C++ symbol names (e.g. may only contain
-+ alphanumeric characters or underscores, and may nor start with a digit). A
-+ $PREFIX directive was found with an argument (given in the message) that
-+ violates those restictions.
-
-PRFNOARG no arguments were given to the $PREFIX directive
-+ The $PREFIX directive takes a single argument, a prefix to be added to the
-+ symbol names when a C++ .h file is created. This error is generated when the
-+ compiler finds a $PREFIX directive with no arguments.
-
-RDLOCMES reading local message file %s
-+ This is an informational message output by BIND10 when it starts to read a
-+ local message file. (A local message file may replace the text of one of more
-+ messages; the ID of the message will not be changed though.)
-
-UNRECDIR unrecognised directive '%s'
-+ A line starting with a dollar symbol was found, but the first word on the line
-+ (shown in the message) was not a recognised message compiler directive.
+$PREFIX MSG_
+$NAMESPACE isc::log
+
+% DUPMSGID duplicate message ID (%1) in compiled code
+Indicative of a programming error, when it started up, BIND10 detected that
+the given message ID had been registered by one or more modules. (All message
+IDs should be unique throughout BIND10.) This has no impact on the operation
+of the server other that erroneous messages may be logged. (When BIND10 loads
+the message IDs (and their associated text), if a duplicate ID is found it is
+discarded. However, when the module that supplied the duplicate ID logs that
+particular message, the text supplied by the module that added the original
+ID will be output - something that may bear no relation to the condition being
+logged.
+
+% DUPLNS line %1: duplicate $NAMESPACE directive found
+When reading a message file, more than one $NAMESPACE directive was found. In
+this version of the code, such a condition is regarded as an error and the
+read will be abandoned.
+
+% IDNOTFND could not replace message text for '%1': no such message
+During start-up a local message file was read. A line with the listed
+message identification was found in the file, but the identification is not
+one contained in the compiled-in message dictionary. Either the message
+identification has been mis-spelled in the file, or the local file was used
+for an earlier version of the software and the message with that
+identification has been removed.
+
+This message may appear a number of times in the file, once for every such
+unknown message identification.
+
+% INVMSGID line %1: invalid message identification '%2'
+The concatenation of the prefix and the message identification is used as
+a symbol in the C++ module; as such it may only contain
+
+% NOMSGID line %1: message definition line found without a message ID
+Message definition lines are lines starting with a "%". The rest of the line
+should comprise the message ID and text describing the message. This error
+indicates the message compiler found a line in the message file comprising
+just the "%" and nothing else.
+
+% NOMSGTXT line %1: line found containing a message ID ('%2') and no text
+Message definition lines are lines starting with a "%". The rest of the line
+should comprise the message ID and text describing the message. This error
+is generated when a line is found in the message file that contains the
+leading "%" and the message identification but no text.
+
+% NSEXTRARG line %1: $NAMESPACE directive has too many arguments
+The $NAMESPACE directive takes a single argument, a namespace in which all the
+generated symbol names are placed. This error is generated when the
+compiler finds a $NAMESPACE directive with more than one argument.
+
+% NSINVARG line %1: $NAMESPACE directive has an invalid argument ('%2')
+The $NAMESPACE argument should be a valid C++ namespace. The reader does a
+cursory check on its validity, checking that the characters in the namespace
+are correct. The error is generated when the reader finds an invalid
+character. (Valid are alphanumeric characters, underscores and colons.)
+
+% NSNOARG line %1: no arguments were given to the $NAMESPACE directive
+The $NAMESPACE directive takes a single argument, a namespace in which all the
+generated symbol names are placed. This error is generated when the
+compiler finds a $NAMESPACE directive with no arguments.
+
+% OPENIN unable to open message file %1 for input: %2
+The program was not able to open the specified input message file for the
+reason given.
+
+% OPENOUT unable to open %1 for output: %2
+The program was not able to open the specified output file for the reason
+given.
+
+% PRFEXTRARG line %1: $PREFIX directive has too many arguments
+The $PREFIX directive takes a single argument, a prefix to be added to the
+symbol names when a C++ .h file is created. This error is generated when the
+compiler finds a $PREFIX directive with more than one argument.
+
+% PRFINVARG line %1: $PREFIX directive has an invalid argument ('%2')
+The $PREFIX argument is used in a symbol name in a C++ header file. As such,
+it must adhere to restrictions on C++ symbol names (e.g. may only contain
+alphanumeric characters or underscores, and may nor start with a digit).
+A $PREFIX directive was found with an argument (given in the message) that
+violates those restictions.
+
+% RDLOCMES reading local message file %1
+This is an informational message output by BIND10 when it starts to read a
+local message file. (A local message file may replace the text of one of more
+messages; the ID of the message will not be changed though.)
+
+% READERR error reading from message file %1: %2
+The specified error was encountered reading from the named message file.
+
+% WRITERR error writing to %1: %2
+The specified error was encountered by the message compiler when writing to
+the named output file.
+
+% UNRECDIR line %1: unrecognised directive '%2'
+A line starting with a dollar symbol was found, but the first word on the line
+(shown in the message) was not a recognised message compiler directive.
diff --git a/src/lib/log/tests/Makefile.am b/src/lib/log/tests/Makefile.am
index b9fe150..46065e8 100644
--- a/src/lib/log/tests/Makefile.am
+++ b/src/lib/log/tests/Makefile.am
@@ -22,6 +22,7 @@ run_unittests_SOURCES += message_reader_unittest.cc
run_unittests_SOURCES += message_initializer_unittest.cc
run_unittests_SOURCES += message_initializer_unittest_2.cc
run_unittests_SOURCES += run_unittests.cc
+run_unittests_SOURCES += log_formatter_unittest.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
diff --git a/src/lib/log/tests/log_formatter_unittest.cc b/src/lib/log/tests/log_formatter_unittest.cc
new file mode 100644
index 0000000..b67831a
--- /dev/null
+++ b/src/lib/log/tests/log_formatter_unittest.cc
@@ -0,0 +1,125 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+#include <log/log_formatter.h>
+
+#include <vector>
+#include <string>
+
+using namespace std;
+
+namespace {
+
+class FormatterTest : public ::testing::Test {
+protected:
+ typedef pair<const char*, string> Output;
+ typedef isc::log::Formatter<FormatterTest> Formatter;
+ vector<Output> outputs;
+public:
+ void output(const char* prefix, const string& message) {
+ outputs.push_back(Output(prefix, message));
+ }
+ // Just shortcut for new string
+ string* s(const char* text) {
+ return (new string(text));
+ }
+};
+
+// Create an inactive formatter and check it doesn't produce any output
+TEST_F(FormatterTest, inactive) {
+ Formatter();
+ EXPECT_EQ(0, outputs.size());
+}
+
+// Create an active formatter and check it produces output. Does no arg
+// substitution yet
+TEST_F(FormatterTest, active) {
+ Formatter("TEST", s("Text of message"), this);
+ ASSERT_EQ(1, outputs.size());
+ EXPECT_STREQ("TEST", outputs[0].first);
+ EXPECT_EQ("Text of message", outputs[0].second);
+}
+
+// No output even when we have an arg on the inactive formatter
+TEST_F(FormatterTest, inactiveArg) {
+ Formatter().arg("Hello");
+ EXPECT_EQ(0, outputs.size());
+}
+
+// Create an active formatter and replace a placeholder with string
+TEST_F(FormatterTest, stringArg) {
+ {
+ SCOPED_TRACE("C++ string");
+ Formatter("TEST", s("Hello %1"), this).arg(string("World"));
+ ASSERT_EQ(1, outputs.size());
+ EXPECT_STREQ("TEST", outputs[0].first);
+ EXPECT_EQ("Hello World", outputs[0].second);
+ }
+ {
+ SCOPED_TRACE("C++ string");
+ Formatter("TEST", s("Hello %1"), this).arg(string("Internet"));
+ ASSERT_EQ(2, outputs.size());
+ EXPECT_STREQ("TEST", outputs[1].first);
+ EXPECT_EQ("Hello Internet", outputs[1].second);
+ }
+}
+
+// Can convert to string
+TEST_F(FormatterTest, intArg) {
+ Formatter("TEST", s("The answer is %1"), this).arg(42);
+ ASSERT_EQ(1, outputs.size());
+ EXPECT_STREQ("TEST", outputs[0].first);
+ EXPECT_EQ("The answer is 42", outputs[0].second);
+}
+
+// Can use multiple arguments at different places
+TEST_F(FormatterTest, multiArg) {
+ Formatter("TEST", s("The %2 are %1"), this).arg("switched").
+ arg("arguments");
+ ASSERT_EQ(1, outputs.size());
+ EXPECT_STREQ("TEST", outputs[0].first);
+ EXPECT_EQ("The arguments are switched", outputs[0].second);
+}
+
+// Can survive and complains if placeholder is missing
+TEST_F(FormatterTest, missingPlace) {
+ EXPECT_NO_THROW(Formatter("TEST", s("Missing the first %2"), this).
+ arg("missing").arg("argument"));
+ ASSERT_EQ(1, outputs.size());
+ EXPECT_STREQ("TEST", outputs[0].first);
+ EXPECT_EQ("Missing the first argument "
+ "@@Missing placeholder %1 for 'missing'@@", outputs[0].second);
+}
+
+// Can replace multiple placeholders
+TEST_F(FormatterTest, multiPlaceholder) {
+ Formatter("TEST", s("The %1 is the %1"), this).
+ arg("first rule of tautology club");
+ ASSERT_EQ(1, outputs.size());
+ EXPECT_STREQ("TEST", outputs[0].first);
+ EXPECT_EQ("The first rule of tautology club is "
+ "the first rule of tautology club", outputs[0].second);
+}
+
+// Test we can cope with replacement containing the placeholder
+TEST_F(FormatterTest, noRecurse) {
+ // If we recurse, this will probably eat all the memory and crash
+ Formatter("TEST", s("%1"), this).arg("%1 %1");
+ ASSERT_EQ(1, outputs.size());
+ EXPECT_STREQ("TEST", outputs[0].first);
+ EXPECT_EQ("%1 %1", outputs[0].second);
+}
+
+}
diff --git a/src/lib/log/tests/logger_support_test.cc b/src/lib/log/tests/logger_support_test.cc
index 4d8863e..0a2338b 100644
--- a/src/lib/log/tests/logger_support_test.cc
+++ b/src/lib/log/tests/logger_support_test.cc
@@ -23,6 +23,7 @@
#include <iostream>
#include <log/logger.h>
+#include <log/macros.h>
#include <log/logger_support.h>
#include <log/root_logger_name.h>
@@ -92,13 +93,14 @@ int main(int argc, char** argv) {
initLogger("alpha", severity, dbglevel, localfile);
// Log a few messages
- logger_ex.fatal(MSG_MSGWRTERR, "test1", "42");
- logger_ex.error(MSG_UNRECDIR, "false");
- logger_dlm.warn(MSG_MSGRDERR, "a.txt", "dummy test");
- logger_dlm.info(MSG_OPNMSGIN, "example.msg", "dummy test");
- logger_ex.debug(0, MSG_UNRECDIR, "[abc]");
- logger_ex.debug(24, MSG_UNRECDIR, "[24]");
- logger_ex.debug(25, MSG_UNRECDIR, "[25]");
- logger_ex.debug(26, MSG_UNRECDIR, "[26]");
+ LOG_FATAL(logger_ex, MSG_WRITERR).arg("test1").arg("42");
+ LOG_ERROR(logger_ex, MSG_RDLOCMES).arg("dummy/file");
+ LOG_WARN(logger_dlm, MSG_READERR).arg("a.txt").arg("dummy reason");
+ LOG_INFO(logger_dlm, MSG_OPENIN).arg("example.msg").arg("dummy reason");
+ LOG_DEBUG(logger_ex, 0, MSG_RDLOCMES).arg("dummy/0");
+ LOG_DEBUG(logger_ex, 24, MSG_RDLOCMES).arg("dummy/24");
+ LOG_DEBUG(logger_ex, 25, MSG_RDLOCMES).arg("dummy/25");
+ LOG_DEBUG(logger_ex, 26, MSG_RDLOCMES).arg("dummy/26");
+
return (0);
}
diff --git a/src/lib/log/tests/message_dictionary_unittest.cc b/src/lib/log/tests/message_dictionary_unittest.cc
index a92585c..ba33820 100644
--- a/src/lib/log/tests/message_dictionary_unittest.cc
+++ b/src/lib/log/tests/message_dictionary_unittest.cc
@@ -29,7 +29,7 @@ using namespace std;
// and the latter should be present.
static const char* values[] = {
- "DUPLNS", "duplicate $NAMESPACE directive found",
+ "MSG_DUPLNS", "duplicate $NAMESPACE directive found",
"NEWSYM", "new symbol added",
NULL
};
@@ -190,7 +190,7 @@ TEST_F(MessageDictionaryTest, GlobalTest) {
TEST_F(MessageDictionaryTest, GlobalLoadTest) {
vector<string>& duplicates = MessageInitializer::getDuplicates();
ASSERT_EQ(1, duplicates.size());
- EXPECT_EQ(string("DUPLNS"), duplicates[0]);
+ EXPECT_EQ(string("MSG_DUPLNS"), duplicates[0]);
string text = MessageDictionary::globalDictionary().getText("NEWSYM");
EXPECT_EQ(string("new symbol added"), text);
diff --git a/src/lib/log/tests/message_reader_unittest.cc b/src/lib/log/tests/message_reader_unittest.cc
index 36288f2..7b3ba5f 100644
--- a/src/lib/log/tests/message_reader_unittest.cc
+++ b/src/lib/log/tests/message_reader_unittest.cc
@@ -68,8 +68,8 @@ TEST_F(MessageReaderTest, BlanksAndComments) {
EXPECT_NO_THROW(reader_.processLine(" \n "));
EXPECT_NO_THROW(reader_.processLine("# This is a comment"));
EXPECT_NO_THROW(reader_.processLine("\t\t # Another comment"));
- EXPECT_NO_THROW(reader_.processLine(" + A description line"));
- EXPECT_NO_THROW(reader_.processLine("#+ A comment"));
+ EXPECT_NO_THROW(reader_.processLine(" A description line"));
+ EXPECT_NO_THROW(reader_.processLine("# A comment"));
EXPECT_NO_THROW(reader_.processLine(" +# A description line"));
// ... and (b) nothing gets added to either the map or the not-added section.
@@ -97,6 +97,15 @@ processLineException(MessageReader& reader, const char* what,
}
}
+// Check that it recognises invalid directives
+
+TEST_F(MessageReaderTest, InvalidDirectives) {
+
+ // Check that a "$" with nothing else generates an error
+ processLineException(reader_, "$", MSG_UNRECDIR);
+ processLineException(reader_, "$xyz", MSG_UNRECDIR);
+}
+
// Check that it can parse a prefix
TEST_F(MessageReaderTest, Prefix) {
@@ -104,8 +113,8 @@ TEST_F(MessageReaderTest, Prefix) {
// Check that no $PREFIX is present
EXPECT_EQ(string(""), reader_.getPrefix());
- // Check that a $PREFIX directive with no argument generates an error.
- processLineException(reader_, "$PREFIX", MSG_PRFNOARG);
+ // Check that a $PREFIX directive with no argument is OK
+ EXPECT_NO_THROW(reader_.processLine("$PREFIX"));
// Check a $PREFIX with multiple arguments is invalid
processLineException(reader_, "$prefix A B", MSG_PRFEXTRARG);
@@ -118,17 +127,19 @@ TEST_F(MessageReaderTest, Prefix) {
// A valid prefix should be accepted
EXPECT_NO_THROW(reader_.processLine("$PREFIX dlm__"));
- EXPECT_EQ(string("DLM__"), reader_.getPrefix());
+ EXPECT_EQ(string("dlm__"), reader_.getPrefix());
// And check that the parser fails on invalid prefixes...
processLineException(reader_, "$prefix 1ABC", MSG_PRFINVARG);
- // ... and rejects another valid one
- processLineException(reader_, "$PREFIX ABC", MSG_DUPLPRFX);
-
// Check that we can clear the prefix as well
reader_.clearPrefix();
EXPECT_EQ(string(""), reader_.getPrefix());
+
+ EXPECT_NO_THROW(reader_.processLine("$PREFIX dlm__"));
+ EXPECT_EQ(string("dlm__"), reader_.getPrefix());
+ EXPECT_NO_THROW(reader_.processLine("$PREFIX"));
+ EXPECT_EQ(string(""), reader_.getPrefix());
}
// Check that it can parse a namespace
@@ -173,8 +184,8 @@ TEST_F(MessageReaderTest, Namespace) {
TEST_F(MessageReaderTest, ValidMessageAddDefault) {
// Add a couple of valid messages
- reader_.processLine("GLOBAL1\t\tthis is message global one\n");
- reader_.processLine("GLOBAL2 this is message global two");
+ reader_.processLine("% GLOBAL1\t\tthis is message global one\n");
+ reader_.processLine("%GLOBAL2 this is message global two");
// ... and check them
EXPECT_EQ(string("this is message global one"),
@@ -191,9 +202,9 @@ TEST_F(MessageReaderTest, ValidMessageAddDefault) {
TEST_F(MessageReaderTest, ValidMessageAdd) {
// Add a couple of valid messages
- reader_.processLine("GLOBAL1\t\tthis is message global one\n",
+ reader_.processLine("%GLOBAL1\t\tthis is message global one\n",
MessageReader::ADD);
- reader_.processLine("GLOBAL2 this is message global two",
+ reader_.processLine("% GLOBAL2 this is message global two",
MessageReader::ADD);
// ... and check them
@@ -214,9 +225,9 @@ TEST_F(MessageReaderTest, ValidMessageReplace) {
dictionary_->add("GLOBAL2", "original global2 message");
// Replace a couple of valid messages
- reader_.processLine("GLOBAL1\t\tthis is message global one\n",
+ reader_.processLine("% GLOBAL1\t\tthis is message global one\n",
MessageReader::REPLACE);
- reader_.processLine("GLOBAL2 this is message global two",
+ reader_.processLine("% GLOBAL2 this is message global two",
MessageReader::REPLACE);
// ... and check them
@@ -237,14 +248,14 @@ TEST_F(MessageReaderTest, ValidMessageReplace) {
TEST_F(MessageReaderTest, Overflows) {
// Add a couple of valid messages
- reader_.processLine("GLOBAL1\t\tthis is message global one\n");
- reader_.processLine("GLOBAL2 this is message global two");
+ reader_.processLine("% GLOBAL1\t\tthis is message global one\n");
+ reader_.processLine("% GLOBAL2 this is message global two");
// Add a duplicate in ADD mode.
- reader_.processLine("GLOBAL1\t\tthis is a replacement for global one");
+ reader_.processLine("% GLOBAL1\t\tthis is a replacement for global one");
// Replace a non-existent one in REPLACE mode
- reader_.processLine("LOCAL\t\tthis is a new message",
+ reader_.processLine("% LOCAL\t\tthis is a new message",
MessageReader::REPLACE);
// Check what is in the dictionary.
diff --git a/src/lib/log/tests/run_time_init_test.sh.in b/src/lib/log/tests/run_time_init_test.sh.in
index e2bdf6f..e48a781 100755
--- a/src/lib/log/tests/run_time_init_test.sh.in
+++ b/src/lib/log/tests/run_time_init_test.sh.in
@@ -29,48 +29,49 @@ passfail() {
# Create the local message file for testing
cat > $localmes << .
-NOTHERE this message is not in the global dictionary
-MSGRDERR replacement read error, parameters: '%s' and '%s'
-UNRECDIR replacement unrecognised directive message, parameter is '%s'
+\$PREFIX MSG_
+% NOTHERE this message is not in the global dictionary
+% READERR replacement read error, parameters: '%1' and '%2'
+% RDLOCMES replacement read local message file, parameter is '%1'
.
echo -n "1. runInitTest default parameters: "
cat > $tempfile << .
-FATAL [alpha.example] MSGWRTERR, error writing to test1: 42
-ERROR [alpha.example] UNRECDIR, unrecognised directive 'false'
-WARN [alpha.dlm] MSGRDERR, error reading from message file a.txt: dummy test
-INFO [alpha.dlm] OPNMSGIN, unable to open message file example.msg for input: dummy test
+FATAL [alpha.example] MSG_WRITERR, error writing to test1: 42
+ERROR [alpha.example] MSG_RDLOCMES, reading local message file dummy/file
+WARN [alpha.dlm] MSG_READERR, error reading from message file a.txt: dummy reason
+INFO [alpha.dlm] MSG_OPENIN, unable to open message file example.msg for input: dummy reason
.
./logger_support_test | cut -d' ' -f3- | diff $tempfile -
passfail $?
echo -n "2. Severity filter: "
cat > $tempfile << .
-FATAL [alpha.example] MSGWRTERR, error writing to test1: 42
-ERROR [alpha.example] UNRECDIR, unrecognised directive 'false'
+FATAL [alpha.example] MSG_WRITERR, error writing to test1: 42
+ERROR [alpha.example] MSG_RDLOCMES, reading local message file dummy/file
.
./logger_support_test -s error | cut -d' ' -f3- | diff $tempfile -
passfail $?
echo -n "3. Debug level: "
cat > $tempfile << .
-FATAL [alpha.example] MSGWRTERR, error writing to test1: 42
-ERROR [alpha.example] UNRECDIR, unrecognised directive 'false'
-WARN [alpha.dlm] MSGRDERR, error reading from message file a.txt: dummy test
-INFO [alpha.dlm] OPNMSGIN, unable to open message file example.msg for input: dummy test
-DEBUG [alpha.example] UNRECDIR, unrecognised directive '[abc]'
-DEBUG [alpha.example] UNRECDIR, unrecognised directive '[24]'
-DEBUG [alpha.example] UNRECDIR, unrecognised directive '[25]'
+FATAL [alpha.example] MSG_WRITERR, error writing to test1: 42
+ERROR [alpha.example] MSG_RDLOCMES, reading local message file dummy/file
+WARN [alpha.dlm] MSG_READERR, error reading from message file a.txt: dummy reason
+INFO [alpha.dlm] MSG_OPENIN, unable to open message file example.msg for input: dummy reason
+DEBUG [alpha.example] MSG_RDLOCMES, reading local message file dummy/0
+DEBUG [alpha.example] MSG_RDLOCMES, reading local message file dummy/24
+DEBUG [alpha.example] MSG_RDLOCMES, reading local message file dummy/25
.
./logger_support_test -s debug -d 25 | cut -d' ' -f3- | diff $tempfile -
passfail $?
echo -n "4. Local message replacement: "
cat > $tempfile << .
-WARN [alpha.log] IDNOTFND, could not replace message for 'NOTHERE': no such message identification
-FATAL [alpha.example] MSGWRTERR, error writing to test1: 42
-ERROR [alpha.example] UNRECDIR, replacement unrecognised directive message, parameter is 'false'
-WARN [alpha.dlm] MSGRDERR, replacement read error, parameters: 'a.txt' and 'dummy test'
+WARN [alpha.log] MSG_IDNOTFND, could not replace message text for 'MSG_NOTHERE': no such message
+FATAL [alpha.example] MSG_WRITERR, error writing to test1: 42
+ERROR [alpha.example] MSG_RDLOCMES, replacement read local message file, parameter is 'dummy/file'
+WARN [alpha.dlm] MSG_READERR, replacement read error, parameters: 'a.txt' and 'dummy reason'
.
./logger_support_test -s warn $localmes | cut -d' ' -f3- | diff $tempfile -
passfail $?
diff --git a/src/lib/nsas/Makefile.am b/src/lib/nsas/Makefile.am
index 5f05f1b..3ecbca7 100644
--- a/src/lib/nsas/Makefile.am
+++ b/src/lib/nsas/Makefile.am
@@ -4,23 +4,39 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG)
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/log -I$(top_builddir)/src/lib/log
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/nsas -I$(top_builddir)/src/lib/nsas
AM_CPPFLAGS += $(SQLITE_CFLAGS)
AM_CXXFLAGS = $(B10_CXXFLAGS)
-# Some versions of GCC warn about some versions of Boost regarding
-# missing initializer for members in its posix_time.
+# Some versions of GCC warn about some versions of Boost regarding missing
+# initializer for members in its posix_time.
# https://svn.boost.org/trac/boost/ticket/3477
# But older GCC compilers don't have the flag.
AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
-if USE_CLANGPP
# clang++ complains about unused function parameters in some boost header
# files.
+if USE_CLANGPP
AM_CXXFLAGS += -Wno-unused-parameter
endif
+# Define rule to build logging source files from message file
+nsasdef.h nsasdef.cc: nsasdef.mes
+ $(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/nsas/nsasdef.mes
+
+# What is being built.
lib_LTLIBRARIES = libnsas.la
+
+# Tell Automake that the nsasdef.{cc,h} source files are created in the build
+# process, so it must create these before doing anything else. Although they
+# are a dependency of the library (so will be created from the message file
+# anyway), there is no guarantee as to exactly _when_ in the build they will be
+# created. As the .h file is included in other sources file (so must be
+# present when they are compiled), the safest option is to create it first.
+BUILT_SOURCES = nsasdef.h nsasdef.cc
+
+# Library sources. The generated files will not be in the distribution.
libnsas_la_SOURCES = address_entry.h address_entry.cc
libnsas_la_SOURCES += asiolink.h
libnsas_la_SOURCES += hash.cc hash.h
@@ -32,9 +48,16 @@ libnsas_la_SOURCES += nameserver_address.h nameserver_address.cc
libnsas_la_SOURCES += nameserver_entry.cc nameserver_entry.h
libnsas_la_SOURCES += nsas_entry_compare.h
libnsas_la_SOURCES += nsas_entry.h nsas_types.h
+libnsas_la_SOURCES += nsas_log.cc nsas_log.h
libnsas_la_SOURCES += zone_entry.cc zone_entry.h
libnsas_la_SOURCES += fetchable.h
libnsas_la_SOURCES += address_request_callback.h
libnsas_la_SOURCES += glue_hints.h glue_hints.cc
-CLEANFILES = *.gcno *.gcda
+nodist_libnsas_la_SOURCES = nsasdef.h nsasdef.cc
+
+# The message file should be in the distribution.
+EXTRA_DIST = nsasdef.mes
+
+# Make sure that the generated files are got rid of in a clean operation
+CLEANFILES = *.gcno *.gcda nsasdef.h nsasdef.cc
diff --git a/src/lib/nsas/nameserver_address_store.cc b/src/lib/nsas/nameserver_address_store.cc
index 3cef38d..ac55409 100644
--- a/src/lib/nsas/nameserver_address_store.cc
+++ b/src/lib/nsas/nameserver_address_store.cc
@@ -22,6 +22,7 @@
#include <dns/rdataclass.h>
#include <util/locks.h>
#include <util/lru_list.h>
+#include <log/logger.h>
#include "hash_table.h"
#include "hash_deleter.h"
@@ -31,6 +32,8 @@
#include "zone_entry.h"
#include "glue_hints.h"
#include "address_request_callback.h"
+#include "nsasdef.h"
+#include "nsas_log.h"
using namespace isc::dns;
using namespace std;
@@ -84,6 +87,8 @@ NameserverAddressStore::lookup(const string& zone, const RRClass& class_code,
boost::shared_ptr<AddressRequestCallback> callback, AddressFamily family,
const GlueHints& glue_hints)
{
+ LOG_DEBUG(nsas_logger, NSAS_DBG_TRACE, NSAS_LOOKUPZONE).arg(zone);
+
pair<bool, boost::shared_ptr<ZoneEntry> > zone_obj(
zone_hash_->getOrAdd(HashKey(zone, class_code),
boost::bind(newZone, resolver_, &zone, &class_code,
@@ -103,6 +108,8 @@ NameserverAddressStore::cancel(const string& zone,
const boost::shared_ptr<AddressRequestCallback>& callback,
AddressFamily family)
{
+ LOG_DEBUG(nsas_logger, NSAS_DBG_TRACE, NSAS_LOOKUPCANCEL).arg(zone);
+
boost::shared_ptr<ZoneEntry> entry(zone_hash_->get(HashKey(zone,
class_code)));
if (entry) {
diff --git a/src/lib/nsas/nameserver_address_store.h b/src/lib/nsas/nameserver_address_store.h
index 148052d..87845c9 100644
--- a/src/lib/nsas/nameserver_address_store.h
+++ b/src/lib/nsas/nameserver_address_store.h
@@ -38,7 +38,6 @@ template<class T> class LruList;
namespace nsas {
-class ResolverInterface;
template<class T> class HashTable;
class ZoneEntry;
class NameserverEntry;
diff --git a/src/lib/nsas/nameserver_entry.cc b/src/lib/nsas/nameserver_entry.cc
index 4035f79..65b2ec2 100644
--- a/src/lib/nsas/nameserver_entry.cc
+++ b/src/lib/nsas/nameserver_entry.cc
@@ -40,6 +40,7 @@
#include "address_entry.h"
#include "nameserver_address.h"
#include "nameserver_entry.h"
+#include "nsas_log.h"
using namespace isc::asiolink;
using namespace isc::nsas;
@@ -178,6 +179,9 @@ NameserverEntry::updateAddressRTTAtIndex(uint32_t rtt, size_t index,
new_rtt = 1;
}
addresses_[family][index].setRTT(new_rtt);
+ LOG_DEBUG(nsas_logger, NSAS_DBG_RTT, NSAS_SETRTT)
+ .arg(addresses_[family][index].getAddress().toText())
+ .arg(old_rtt).arg(new_rtt);
}
void
@@ -203,7 +207,7 @@ NameserverEntry::setAddressUnreachable(const IOAddress& address) {
* \short A callback into the resolver.
*
* Whenever we ask the resolver something, this is created and the answer is
- * fed back trough this. It holds a shared pointer to the entry so it is not
+ * fed back through this. It holds a shared pointer to the entry so it is not
* destroyed too soon.
*/
class NameserverEntry::ResolverCallback :
@@ -230,6 +234,7 @@ class NameserverEntry::ResolverCallback :
if (!response_message ||
response_message->getRcode() != isc::dns::Rcode::NOERROR() ||
response_message->getRRCount(isc::dns::Message::SECTION_ANSWER) == 0) {
+ LOG_ERROR(nsas_logger, NSAS_INVRESPSTR).arg(entry_->getName());
failureInternal(lock);
return;
}
@@ -243,7 +248,12 @@ class NameserverEntry::ResolverCallback :
if (response->getType() != type_ ||
response->getClass() != RRClass(entry_->getClass()))
{
- // TODO Log we got answer of different type
+ // Invalid response type or class
+ LOG_ERROR(nsas_logger, NSAS_INVRESPTC)
+ .arg(entry_->getName()).arg(type_)
+ .arg(entry_->getClass()).arg(response->getType())
+ .arg(response->getClass());
+
failureInternal(lock);
return;
}
@@ -264,8 +274,10 @@ class NameserverEntry::ResolverCallback :
}
}
// If we found it, use it. If not, create a new one.
- entries.push_back(found ? *found : AddressEntry(IOAddress(
- i->getCurrent().toText()), 1));
+ entries.push_back(found ? *found : AddressEntry(
+ IOAddress(address), 1));
+ LOG_DEBUG(nsas_logger, NSAS_DBG_RESULTS, NSAS_NSLKUPSUCC)
+ .arg(address).arg(entry_->getName());
}
// We no longer need the previous set of addresses, we have
@@ -310,6 +322,8 @@ class NameserverEntry::ResolverCallback :
* So mark the current address family as unreachable.
*/
virtual void failure() {
+ LOG_DEBUG(nsas_logger, NSAS_DBG_RESULTS, NSAS_NSLKUPFAIL)
+ .arg(type_).arg(entry_->getName());
Lock lock(entry_->mutex_);
failureInternal(lock);
}
@@ -422,6 +436,8 @@ NameserverEntry::askIP(isc::resolve::ResolverInterface* resolver,
// Ask for both types of addresses
// We are unlocked here, as the callback from that might want to lock
lock.unlock();
+
+ LOG_DEBUG(nsas_logger, NSAS_DBG_TRACE, NSAS_NSADDR).arg(getName());
askIP(resolver, RRType::A(), V4_ONLY);
askIP(resolver, RRType::AAAA(), V6_ONLY);
// Make sure we end the routine when we are not locked
diff --git a/src/lib/nsas/nsas_log.cc b/src/lib/nsas/nsas_log.cc
new file mode 100644
index 0000000..931b131
--- /dev/null
+++ b/src/lib/nsas/nsas_log.cc
@@ -0,0 +1,26 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+/// Defines the logger used by the NSAS
+
+#include "nsas/nsas_log.h"
+
+namespace isc {
+namespace nsas {
+
+isc::log::Logger nsas_logger("nsas");
+
+} // namespace nsas
+} // namespace isc
+
diff --git a/src/lib/nsas/nsas_log.h b/src/lib/nsas/nsas_log.h
new file mode 100644
index 0000000..9631988
--- /dev/null
+++ b/src/lib/nsas/nsas_log.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __NSAS_LOG__H
+#define __NSAS_LOG__H
+
+#include <log/macros.h>
+#include "nsasdef.h"
+
+namespace isc {
+namespace nsas {
+
+/// \brief NSAS Logging
+///
+/// Defines the levels used to output debug messages in the NSAS. Note that
+/// higher numbers equate to more verbose (and detailed) output.
+
+// The first level traces normal operations - asking the NSAS for an address,
+// and cancelling a lookup. It also records when the NSAS calls back to the
+// resolver to resolve something.
+const int NSAS_DBG_TRACE = 10;
+
+// The next level extends the normal operations and records the results of the
+// lookups.
+const int NSAS_DBG_RESULTS = 20;
+
+// Additional information on the usage of the names - the RTT values obtained
+// when queries were done.
+const int NSAS_DBG_RTT = 30;
+
+
+/// \brief NSAS Logger
+///
+/// Define the logger used to log messages. We could define it in multiple
+/// modules, but defining in a single module and linking to it saves time and
+/// space.
+extern isc::log::Logger nsas_logger; // isc::nsas::logger is the NSAS logger
+
+} // namespace nsas
+} // namespace isc
+
+#endif // __NSAS_LOG__H
diff --git a/src/lib/nsas/nsasdef.mes b/src/lib/nsas/nsasdef.mes
new file mode 100644
index 0000000..0f32d09
--- /dev/null
+++ b/src/lib/nsas/nsasdef.mes
@@ -0,0 +1,61 @@
+# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+$PREFIX NSAS_
+$NAMESPACE isc::nsas
+
+% INVRESPSTR queried for %1 but got invalid response
+This message indicates an internal error in the nameserver address store
+component (NSAS) of the resolver. The NSAS made a query for a RR for the
+specified nameserver but received an invalid response. Either the success
+function was called without a DNS message or the message was invalid on some
+way. (In the latter case, the error should have been picked up elsewhere in
+the processing logic, hence the raising of the error here.)
+
+% INVRESPTC queried for %1 RR of type/class %2/%3, received response %4/%5
+This message indicates an internal error in the nameserver address store
+component (NSAS) of the resolver. The NSAS made a query for the given RR
+type and class, but instead received an answer with the given type and class.
+
+% LOOKUPCANCEL lookup for zone %1 has been cancelled
+A debug message, this is output when a NSAS (nameserver address store -
+part of the resolver) lookup for a zone has been cancelled.
+
+% LOOKUPZONE searching NSAS for nameservers for zone %1
+A debug message, this is output when a call is made to the nameserver address
+store (part of the resolver) to obtain the nameservers for the specified zone.
+
+% NSADDR asking resolver to obtain A and AAAA records for %1
+A debug message, the NSAS (nameserver address store - part of the resolver) is
+making a callback into the resolver to retrieve the address records for the
+specified nameserver.
+
+% NSLKUPFAIL failed to lookup any %1 for %2
+A debug message, the NSAS (nameserver address store - part of the resolver)
+has been unable to retrieve the specified resource record for the specified
+nameserver. This is not necessarily a problem - the nameserver may be
+unreachable, in which case the NSAS will try other nameservers in the zone.
+
+% NSLKUPSUCC found address %1 for %2
+A debug message, the NSAS (nameserver address store - part of the resolver)
+has retrieved the given address for the specified nameserver through an
+external query.
+
+% SETRTT reporting RTT for %1 as %2; new value is now %3
+A NSAS (nameserver address store - part of the resolver) debug message
+reporting the round-trip time (RTT) for a query made to the specified
+nameserver. The RTT has been updated using the value given and the new RTT is
+displayed. (The RTT is subject to a calculation that damps out sudden
+changes. As a result, the new RTT is not necessarily equal to the RTT
+reported.)
diff --git a/src/lib/nsas/tests/Makefile.am b/src/lib/nsas/tests/Makefile.am
index 56f36d1..e9235ba 100644
--- a/src/lib/nsas/tests/Makefile.am
+++ b/src/lib/nsas/tests/Makefile.am
@@ -53,6 +53,7 @@ endif
run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
diff --git a/src/lib/nsas/tests/nameserver_address_unittest.cc b/src/lib/nsas/tests/nameserver_address_unittest.cc
index e3bc5de..1b211e9 100644
--- a/src/lib/nsas/tests/nameserver_address_unittest.cc
+++ b/src/lib/nsas/tests/nameserver_address_unittest.cc
@@ -51,7 +51,8 @@ public:
ns_.reset(new NameserverEntry(name_.toText(), RRClass::IN()));
ns_->askIP(resolver_.get(), boost::shared_ptr<Callback>(new Callback), ANY_OK);
resolver_->asksIPs(name_, 0, 1);
- resolver_->requests[0].second->success(createResponseMessage(rrv4_));
+ resolver_->requests[0].second->success(
+ isc::util::unittests::createResponseMessage(rrv4_));
}
// Return the sample NameserverEntry
diff --git a/src/lib/nsas/tests/nameserver_entry_unittest.cc b/src/lib/nsas/tests/nameserver_entry_unittest.cc
index 7e9f675..3435d26 100644
--- a/src/lib/nsas/tests/nameserver_entry_unittest.cc
+++ b/src/lib/nsas/tests/nameserver_entry_unittest.cc
@@ -72,7 +72,8 @@ private:
RRsetPtr set)
{
if (set) {
- resolver->requests[index].second->success(createResponseMessage(set));
+ resolver->requests[index].second->success(
+ isc::util::unittests::createResponseMessage(set));
} else {
resolver->requests[index].second->failure();
}
diff --git a/src/lib/nsas/tests/nsas_test.h b/src/lib/nsas/tests/nsas_test.h
index 033df81..2dd95ef 100644
--- a/src/lib/nsas/tests/nsas_test.h
+++ b/src/lib/nsas/tests/nsas_test.h
@@ -27,6 +27,7 @@
#include <config.h>
#include <util/buffer.h>
+#include <util/unittests/resolver.h>
#include <dns/message.h>
#include <dns/rdata.h>
#include <dns/rrtype.h>
@@ -35,24 +36,12 @@
#include <dns/rcode.h>
#include <dns/messagerenderer.h>
#include <dns/rdataclass.h>
-#include <resolve/resolver_interface.h>
#include "../nsas_entry.h"
using namespace isc::dns::rdata;
using namespace isc::dns;
using namespace isc::util;
-
-namespace {
- MessagePtr
- createResponseMessage(RRsetPtr answer_rrset)
- {
- MessagePtr response(new Message(Message::RENDER));
- response->setOpcode(Opcode::QUERY());
- response->setRcode(Rcode::NOERROR());
- response->addRRset(Message::SECTION_ANSWER, answer_rrset);
- return response;
- }
-}
+using isc::util::unittests::TestResolver;
namespace isc {
namespace dns {
@@ -223,139 +212,6 @@ private:
static const uint32_t HASHTABLE_DEFAULT_SIZE = 1009; ///< First prime above 1000
-using namespace std;
-
-/*
- * This pretends to be a resolver. It stores the queries and
- * they can be answered.
- */
-class TestResolver : public isc::resolve::ResolverInterface {
- private:
- bool checkIndex(size_t index) {
- return (requests.size() > index);
- }
-
- typedef std::map<isc::dns::Question, RRsetPtr >
- PresetAnswers;
- PresetAnswers answers_;
- public:
- typedef pair<QuestionPtr, CallbackPtr> Request;
- vector<Request> requests;
-
- /// \brief Destructor
- ///
- /// This is important. All callbacks in the requests vector must be
- /// called to remove them from internal loops. Without this, destroying
- /// the NSAS object will leave memory assigned.
- ~TestResolver() {
- for (size_t i = 0; i < requests.size(); ++i) {
- requests[i].second->failure();
- }
- }
-
- virtual void resolve(const QuestionPtr& q, const CallbackPtr& c) {
- PresetAnswers::iterator it(answers_.find(*q));
- if (it == answers_.end()) {
- requests.push_back(Request(q, c));
- } else {
- if (it->second) {
- c->success(createResponseMessage(it->second));
- } else {
- c->failure();
- }
- }
- }
-
- /*
- * Add a preset answer. If shared_ptr() is passed (eg. NULL),
- * it will generate failure. If the question is not preset,
- * it goes to requests and you can answer later.
- */
- void addPresetAnswer(const isc::dns::Question& question,
- RRsetPtr answer)
- {
- answers_[question] = answer;
- }
-
- // Thrown if the query at the given index does not exist.
- class NoSuchRequest : public std::exception { };
-
- // Thrown if the answer does not match the query
- class DifferentRequest : public std::exception { };
-
- QuestionPtr operator[](size_t index) {
- if (index >= requests.size()) {
- throw NoSuchRequest();
- }
- return (requests[index].first);
- }
- /*
- * Looks if the two provided requests in resolver are A and AAAA.
- * Sorts them so index1 is A.
- *
- * Returns false if there aren't enough elements
- */
- bool asksIPs(const Name& name, size_t index1, size_t index2) {
- size_t max = (index1 < index2) ? index2 : index1;
- if (!checkIndex(max)) {
- return false;
- }
- EXPECT_EQ(name, (*this)[index1]->getName());
- EXPECT_EQ(name, (*this)[index2]->getName());
- EXPECT_EQ(RRClass::IN(), (*this)[index1]->getClass());
- EXPECT_EQ(RRClass::IN(), (*this)[index2]->getClass());
- // If they are the other way around, swap
- if ((*this)[index1]->getType() == RRType::AAAA() &&
- (*this)[index2]->getType() == RRType::A())
- {
- TestResolver::Request tmp((*this).requests[index1]);
- (*this).requests[index1] =
- (*this).requests[index2];
- (*this).requests[index2] = tmp;
- }
- // Check the correct addresses
- EXPECT_EQ(RRType::A(), (*this)[index1]->getType());
- EXPECT_EQ(RRType::AAAA(), (*this)[index2]->getType());
- return (true);
- }
-
- /*
- * Sends a simple answer to a query.
- * 1) Provide index of a query and the address(es) to pass.
- * 2) Provide index of query and components of address to pass.
- */
- void answer(size_t index, RRsetPtr& set) {
- if (index >= requests.size()) {
- throw NoSuchRequest();
- }
- requests[index].second->success(createResponseMessage(set));
- }
-
- void answer(size_t index, const Name& name, const RRType& type,
- const rdata::Rdata& rdata, size_t TTL = 100)
- {
- RRsetPtr set(new RRset(name, RRClass::IN(),
- type, RRTTL(TTL)));
- set->addRdata(rdata);
- answer(index, set);
- }
-
-
- void provideNS(size_t index,
- RRsetPtr nameservers)
- {
- if (index >= requests.size()) {
- throw NoSuchRequest();
- }
- if (requests[index].first->getName() != nameservers->getName() ||
- requests[index].first->getType() != RRType::NS())
- {
- throw DifferentRequest();
- }
- requests[index].second->success(createResponseMessage(nameservers));
- }
-};
-
// String constants. These should end in a dot.
static const std::string EXAMPLE_CO_UK("example.co.uk.");
static const std::string EXAMPLE_NET("example.net.");
diff --git a/src/lib/nsas/tests/run_unittests.cc b/src/lib/nsas/tests/run_unittests.cc
index d1277ad..bc672d0 100644
--- a/src/lib/nsas/tests/run_unittests.cc
+++ b/src/lib/nsas/tests/run_unittests.cc
@@ -13,14 +13,23 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
+#include <stdlib.h>
+
+#include <string>
+#include <boost/lexical_cast.hpp>
#include <gtest/gtest.h>
#include <dns/tests/unittest_util.h>
+#include <log/logger_support.h>
+
+using namespace std;
int
main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
+ isc::log::initLogger();
+
return (RUN_ALL_TESTS());
}
diff --git a/src/lib/python/bind10_config.py.in b/src/lib/python/bind10_config.py.in
index 3f2947d..4a38903 100644
--- a/src/lib/python/bind10_config.py.in
+++ b/src/lib/python/bind10_config.py.in
@@ -17,7 +17,37 @@
# variables to python scripts and libraries.
import os
-BIND10_MSGQ_SOCKET_FILE = os.path.join("@localstatedir@",
- "@PACKAGE_NAME@",
- "msgq_socket").replace("${prefix}",
- "@prefix@")
+def reload():
+ # In a function, for testing purposes
+ global BIND10_MSGQ_SOCKET_FILE
+ global DATA_PATH
+ global PLUGIN_PATHS
+ global PREFIX
+ BIND10_MSGQ_SOCKET_FILE = os.path.join("@localstatedir@",
+ "@PACKAGE_NAME@",
+ "msgq_socket").replace("${prefix}",
+ "@prefix@")
+ PREFIX = "@prefix@"
+
+ # If B10_FROM_SOURCE is set in the environment, we use data files
+ # from a directory relative to the value of that variable, or, if defined,
+ # relative to the value of B10_FROM_SOURCE_LOCALSTATEDIR. Otherwise
+ # we use the ones installed on the system.
+ # B10_FROM_SOURCE_LOCALSTATEDIR is specifically intended to be used for
+ # tests where we want to use variuos types of configuration within the test
+ # environment. (We may want to make it even more generic so that the path is
+ # passed from the boss process)
+ if "B10_FROM_SOURCE" in os.environ:
+ if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
+ DATA_PATH = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"]
+ else:
+ DATA_PATH = os.environ["B10_FROM_SOURCE"]
+ PLUGIN_PATHS = [DATA_PATH + '/src/bin/cfgmgr/plugins']
+ else:
+ DATA_PATH = "@localstatedir@/@PACKAGE@".replace("${prefix}", PREFIX)
+ PLUGIN_PATHS = ["@prefix@/share/@PACKAGE@/config_plugins"]
+ # For testing the plugins so they can find their own spec files
+ if "B10_TEST_PLUGIN_DIR" in os.environ:
+ PLUGIN_PATHS = os.environ["B10_TEST_PLUGIN_DIR"].split(':')
+
+reload()
diff --git a/src/lib/python/isc/notify/notify_out.py b/src/lib/python/isc/notify/notify_out.py
index db80c33..178a983 100644
--- a/src/lib/python/isc/notify/notify_out.py
+++ b/src/lib/python/isc/notify/notify_out.py
@@ -304,7 +304,7 @@ class NotifyOut:
try:
r_fds, w, e = select.select(valid_socks, [], [], block_timeout)
except select.error as err:
- if err.args[0] != EINTR:
+ if err.args[0] != errno.EINTR:
return {}, {}
if self._read_sock in r_fds: # user has called shutdown()
diff --git a/src/lib/python/isc/notify/tests/Makefile.am b/src/lib/python/isc/notify/tests/Makefile.am
index 07129ec..a83ff86 100644
--- a/src/lib/python/isc/notify/tests/Makefile.am
+++ b/src/lib/python/isc/notify/tests/Makefile.am
@@ -6,7 +6,7 @@ EXTRA_DIST = $(PYTESTS)
# required by loadable python modules.
LIBRARY_PATH_PLACEHOLDER =
if SET_ENV_LIBRARY_PATH
-LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
endif
# test using command-line arguments, so use check-local target instead of TESTS
diff --git a/src/lib/python/isc/util/Makefile.am b/src/lib/python/isc/util/Makefile.am
index 7ab8048..f6cbb78 100644
--- a/src/lib/python/isc/util/Makefile.am
+++ b/src/lib/python/isc/util/Makefile.am
@@ -1,5 +1,5 @@
SUBDIRS = . tests
-python_PYTHON = __init__.py process.py socketserver_mixin.py
+python_PYTHON = __init__.py process.py socketserver_mixin.py file.py
pythondir = $(pyexecdir)/isc/util
diff --git a/src/lib/python/isc/util/file.py b/src/lib/python/isc/util/file.py
new file mode 100644
index 0000000..faef9a8
--- /dev/null
+++ b/src/lib/python/isc/util/file.py
@@ -0,0 +1,29 @@
+# Copyright (C) 2011 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""Various functions for working with files and directories."""
+
+from os.path import exists, join
+
+def path_search(filename, paths):
+ """
+ Searches list of paths to find filename in one of them. The found one will
+ be returned or IOError will be returned if it isn't found.
+ """
+ for p in paths:
+ f = join(p, filename)
+ if exists(f):
+ return f
+ raise IOError("'" + filename + "' not found in " + str(paths))
diff --git a/src/lib/python/isc/util/tests/Makefile.am b/src/lib/python/isc/util/tests/Makefile.am
index f32fda0..0ce96de 100644
--- a/src/lib/python/isc/util/tests/Makefile.am
+++ b/src/lib/python/isc/util/tests/Makefile.am
@@ -1,5 +1,5 @@
PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
-PYTESTS = process_test.py socketserver_mixin_test.py
+PYTESTS = process_test.py socketserver_mixin_test.py file_test.py
EXTRA_DIST = $(PYTESTS)
# test using command-line arguments, so use check-local target instead of TESTS
diff --git a/src/lib/python/isc/util/tests/file_test.py b/src/lib/python/isc/util/tests/file_test.py
new file mode 100644
index 0000000..fb765d7
--- /dev/null
+++ b/src/lib/python/isc/util/tests/file_test.py
@@ -0,0 +1,32 @@
+# Copyright (C) 2011 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import isc.util.file
+import unittest
+
+class FileTest(unittest.TestCase):
+ def test_search_path_find(self):
+ """Test it returns the first occurence of the file"""
+ self.assertEqual('./Makefile',
+ isc.util.file.path_search('Makefile',
+ ['/no/such/directory/', '.',
+ '../tests/']))
+
+ def test_search_path_notfound(self):
+ """Test it throws an exception when the file can't be found"""
+ self.assertRaises(IOError, isc.util.file.path_search, 'no file', ['/no/such/directory'])
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/src/lib/resolve/recursive_query.cc b/src/lib/resolve/recursive_query.cc
index c0d5ee6..b753cc9 100644
--- a/src/lib/resolve/recursive_query.cc
+++ b/src/lib/resolve/recursive_query.cc
@@ -28,6 +28,7 @@
#include <dns/message.h>
#include <dns/opcode.h>
#include <dns/exceptions.h>
+#include <dns/rdataclass.h>
#include <resolve/resolve.h>
#include <cache/resolver_cache.h>
@@ -48,6 +49,65 @@ using namespace isc::asiolink;
namespace isc {
namespace asiodns {
+namespace {
+// Function to check if the given name/class has any address in the cache
+bool
+hasAddress(const Name& name, const RRClass& rrClass,
+ const isc::cache::ResolverCache& cache)
+{
+ // FIXME: If we are single-stack and we get only the other type of
+ // address, what should we do? In that case, it will be considered
+ // unreachable, which is most probably true, because A and AAAA will
+ // usually have the same RTT, so we should have both or none from the
+ // glue.
+ return (cache.lookup(name, RRType::A(), rrClass) != RRsetPtr() ||
+ cache.lookup(name, RRType::AAAA(), rrClass) != RRsetPtr());
+}
+
+}
+
+/// \brief Find deepest usable delegation in the cache
+///
+/// This finds the deepest delegation we have in cache and is safe to use.
+/// It is not public function, therefore it's not in header. But it's not
+/// in anonymous namespace, so we can call it from unittests.
+/// \param name The name we want to delegate to.
+/// \param cache The place too look for known delegations.
+std::string
+deepestDelegation(Name name, RRClass rrclass,
+ isc::cache::ResolverCache& cache)
+{
+ RRsetPtr cachedNS;
+ // Look for delegation point from bottom, until we find one with
+ // IP address or get to root.
+ //
+ // We need delegation with IP address so we can ask it right away.
+ // If we don't have the IP address, we would need to ask above it
+ // anyway in the best case, and the NS could be inside the zone,
+ // and we could get all loopy with the NSAS in the worst case.
+ while (name.getLabelCount() > 1 &&
+ (cachedNS = cache.lookupDeepestNS(name, rrclass)) != RRsetPtr()) {
+ // Look if we have an IP address for the NS
+ for (RdataIteratorPtr ns(cachedNS->getRdataIterator());
+ !ns->isLast(); ns->next()) {
+ // Do we have IP for this specific NS?
+ if (hasAddress(dynamic_cast<const rdata::generic::NS&>(
+ ns->getCurrent()).getNSName(), rrclass,
+ cache)) {
+ // Found one, stop checking and use this zone
+ // (there may be more addresses, that's only better)
+ return (cachedNS->getName().toText());
+ }
+ }
+ // We don't have anything for this one, so try something higher
+ if (name.getLabelCount() > 1) {
+ name = name.split(1);
+ }
+ }
+ // Fallback, nothing found, start at root
+ return (".");
+}
+
typedef std::vector<std::pair<std::string, uint16_t> > AddressVector;
// Here we do not use the typedef above, as the SunStudio compiler
@@ -131,13 +191,12 @@ private:
// Info for (re)sending the query (the question and destination)
Question question_;
+ // This is the query message got from client
+ ConstMessagePtr query_message_;
+
// This is where we build and store our final answer
MessagePtr answer_message_;
- // currently we use upstream as the current list of NS records
- // we should differentiate between forwarding and resolving
- boost::shared_ptr<AddressVector> upstream_;
-
// Test server - only used for testing. This takes precedence over all
// other servers if the port is non-zero.
std::pair<std::string, uint16_t> test_server_;
@@ -239,7 +298,6 @@ private:
// if we have a response for our query stored already. if
// so, call handlerecursiveresponse(), if not, we call send()
void doLookup() {
- cur_zone_ = ".";
dlog("doLookup: try cache");
Message cached_message(Message::RENDER);
isc::resolve::initResponseMessage(question_, cached_message);
@@ -255,9 +313,12 @@ private:
stop();
}
} else {
+ dlog("doLookup: get lowest usable delegation from cache");
+ cur_zone_ = deepestDelegation(question_.getName(),
+ question_.getClass(), cache_);
send();
}
-
+
}
// Send the current question to the given nameserver address
@@ -282,13 +343,8 @@ private:
}
}
- // 'general' send; if we are in forwarder mode, send a query to
- // a random nameserver in our forwarders list. If we are in
- // recursive mode, ask the NSAS to give us an address.
+ // 'general' send, ask the NSAS to give us an address.
void send(IOFetch::Protocol protocol = IOFetch::UDP) {
- // If are in forwarder mode, send it to a random
- // forwarder. If not, ask the NSAS for an address
- const int uc = upstream_->size();
protocol_ = protocol; // Store protocol being used for this
if (test_server_.second != 0) {
dlog("Sending upstream query (" + question_.toText() +
@@ -300,18 +356,6 @@ private:
test_server_.second, buffer_, this,
query_timeout_);
io_.get_io_service().post(query);
- } else if (uc > 0) {
- // TODO: use boost, or rand()-utility function we provide
- int serverIndex = rand() % uc;
- dlog("Sending upstream query (" + question_.toText() +
- ") to " + upstream_->at(serverIndex).first);
- ++outstanding_events_;
- gettimeofday(¤t_ns_qsent_time, NULL);
- IOFetch query(protocol, io_, question_,
- upstream_->at(serverIndex).first,
- upstream_->at(serverIndex).second, buffer_, this,
- query_timeout_);
- io_.get_io_service().post(query);
} else {
// Ask the NSAS for an address for the current zone,
// the callback will call the actual sendTo()
@@ -486,7 +530,6 @@ public:
RunningQuery(IOService& io,
const Question& question,
MessagePtr answer_message,
- boost::shared_ptr<AddressVector> upstream,
std::pair<std::string, uint16_t>& test_server,
OutputBufferPtr buffer,
isc::resolve::ResolverInterface::CallbackPtr cb,
@@ -498,8 +541,8 @@ public:
:
io_(io),
question_(question),
+ query_message_(),
answer_message_(answer_message),
- upstream_(upstream),
test_server_(test_server),
buffer_(buffer),
resolvercallback_(cb),
@@ -647,8 +690,7 @@ public:
incoming.fromWire(ibuf);
buffer_->clear();
- if (recursive_mode() &&
- incoming.getRcode() == Rcode::NOERROR()) {
+ if (incoming.getRcode() == Rcode::NOERROR()) {
done_ = handleRecursiveAnswer(incoming);
} else {
isc::resolve::copyResponseMessage(incoming, answer_message_);
@@ -682,13 +724,11 @@ public:
} else if (!done_ && retries_--) {
// Query timed out, but we have some retries, so send again
dlog("Timeout for " + question_.toText() + " to " + current_ns_address.getAddress().toText() + ", resending query");
- if (recursive_mode()) {
- current_ns_address.updateRTT(isc::nsas::AddressEntry::UNREACHABLE);
- }
+ current_ns_address.updateRTT(isc::nsas::AddressEntry::UNREACHABLE);
send();
} else {
// We are either already done, or out of retries
- if (recursive_mode() && result == IOFetch::TIME_OUT) {
+ if (result == IOFetch::TIME_OUT) {
dlog("Timeout for " + question_.toText() + " to " + current_ns_address.getAddress().toText() + ", giving up");
current_ns_address.updateRTT(isc::nsas::AddressEntry::UNREACHABLE);
}
@@ -705,12 +745,179 @@ public:
void makeSERVFAIL() {
isc::resolve::makeErrorMessage(answer_message_, Rcode::SERVFAIL());
}
-
- // Returns true if we are in 'recursive' mode
- // Returns false if we are in 'forwarding' mode
- // (i.e. if we have anything in upstream_)
- bool recursive_mode() const {
- return upstream_->empty();
+};
+
+class ForwardQuery : public IOFetch::Callback {
+private:
+ // The io service to handle async calls
+ IOService& io_;
+
+ // This is the query message got from client
+ ConstMessagePtr query_message_;
+
+ // This is where we build and store our final answer
+ MessagePtr answer_message_;
+
+ // List of nameservers to forward to
+ boost::shared_ptr<AddressVector> upstream_;
+
+ // Buffer to store the result.
+ OutputBufferPtr buffer_;
+
+ // This will be notified when we succeed or fail
+ isc::resolve::ResolverInterface::CallbackPtr resolvercallback_;
+
+ /*
+ * TODO Do something more clever with timeouts. In the long term, some
+ * computation of average RTT, increase with each retry, etc.
+ */
+ // Timeout information
+ int query_timeout_;
+
+ // TODO: replace by our wrapper
+ asio::deadline_timer client_timer;
+ asio::deadline_timer lookup_timer;
+
+ // Make FowardQuery deletes itself safely. for more information see
+ // the comments of outstanding_events in RunningQuery.
+ size_t outstanding_events_;
+
+ // If we have a client timeout, we call back with a failure message,
+ // but we do not stop yet. We use this variable to make sure we
+ // don't call back a second time later
+ bool callback_called_;
+
+ // send the query to the server.
+ void send(IOFetch::Protocol protocol = IOFetch::UDP) {
+ const int uc = upstream_->size();
+ buffer_->clear();
+ int serverIndex = rand() % uc;
+ ConstQuestionPtr question = *(query_message_->beginQuestion());
+ dlog("Sending upstream query (" + question->toText() +
+ ") to " + upstream_->at(serverIndex).first);
+ ++outstanding_events_;
+ // Forward the query, create the IOFetch with
+ // query message, so that query flags can be forwarded
+ // together.
+ IOFetch query(protocol, io_, query_message_,
+ upstream_->at(serverIndex).first,
+ upstream_->at(serverIndex).second,
+ buffer_, this, query_timeout_);
+
+ io_.get_io_service().post(query);
+ }
+
+public:
+ ForwardQuery(IOService& io,
+ ConstMessagePtr query_message,
+ MessagePtr answer_message,
+ boost::shared_ptr<AddressVector> upstream,
+ OutputBufferPtr buffer,
+ isc::resolve::ResolverInterface::CallbackPtr cb,
+ int query_timeout, int client_timeout, int lookup_timeout) :
+ io_(io),
+ query_message_(query_message),
+ answer_message_(answer_message),
+ upstream_(upstream),
+ buffer_(buffer),
+ resolvercallback_(cb),
+ query_timeout_(query_timeout),
+ client_timer(io.get_io_service()),
+ lookup_timer(io.get_io_service()),
+ outstanding_events_(0),
+ callback_called_(false)
+ {
+ // Setup the timer to stop trying (lookup_timeout)
+ if (lookup_timeout >= 0) {
+ lookup_timer.expires_from_now(
+ boost::posix_time::milliseconds(lookup_timeout));
+ ++outstanding_events_;
+ lookup_timer.async_wait(boost::bind(&ForwardQuery::lookupTimeout, this));
+ }
+
+ // Setup the timer to send an answer (client_timeout)
+ if (client_timeout >= 0) {
+ client_timer.expires_from_now(
+ boost::posix_time::milliseconds(client_timeout));
+ ++outstanding_events_;
+ client_timer.async_wait(boost::bind(&ForwardQuery::clientTimeout, this));
+ }
+
+ send();
+ }
+
+ virtual void lookupTimeout() {
+ if (!callback_called_) {
+ makeSERVFAIL();
+ callCallback(false);
+ }
+ assert(outstanding_events_ > 0);
+ --outstanding_events_;
+ stop();
+ }
+
+ virtual void clientTimeout() {
+ if (!callback_called_) {
+ makeSERVFAIL();
+ callCallback(false);
+ }
+ assert(outstanding_events_ > 0);
+ --outstanding_events_;
+ stop();
+ }
+
+ // If the callback has not been called yet, call it now
+ // If success is true, we call 'success' with our answer_message
+ // If it is false, we call failure()
+ void callCallback(bool success) {
+ if (!callback_called_) {
+ callback_called_ = true;
+ if (success) {
+ resolvercallback_->success(answer_message_);
+ } else {
+ resolvercallback_->failure();
+ }
+ }
+ }
+
+ virtual void stop() {
+ // if we cancel our timers, we will still get an event for
+ // that, so we cannot delete ourselves just yet (those events
+ // would be bound to a deleted object)
+ // cancel them one by one, both cancels should get us back
+ // here again.
+ // same goes if we have an outstanding query (can't delete
+ // until that one comes back to us)
+ lookup_timer.cancel();
+ client_timer.cancel();
+ if (outstanding_events_ > 0) {
+ return;
+ } else {
+ delete this;
+ }
+ }
+
+ // This function is used as callback from DNSQuery.
+ virtual void operator()(IOFetch::Result result) {
+ // XXX is this the place for TCP retry?
+ assert(outstanding_events_ > 0);
+ --outstanding_events_;
+ if (result != IOFetch::TIME_OUT) {
+ // we got an answer
+ Message incoming(Message::PARSE);
+ InputBuffer ibuf(buffer_->getData(), buffer_->getLength());
+ incoming.fromWire(ibuf);
+ isc::resolve::copyResponseMessage(incoming, answer_message_);
+ callCallback(true);
+ }
+
+ stop();
+ }
+
+ // Clear the answer parts of answer_message, and set the rcode
+ // to servfail
+ void makeSERVFAIL() {
+ isc::resolve::makeErrorMessage(answer_message_, Rcode::SERVFAIL());
}
};
@@ -753,7 +960,7 @@ RecursiveQuery::resolve(const QuestionPtr& question,
} else {
dlog("Message not found in cache, starting recursive query");
// It will delete itself when it is done
- new RunningQuery(io, *question, answer_message, upstream_,
+ new RunningQuery(io, *question, answer_message,
test_server_, buffer, callback,
query_timeout_, client_timeout_,
lookup_timeout_, retries_, nsas_,
@@ -807,7 +1014,7 @@ RecursiveQuery::resolve(const Question& question,
} else {
dlog("Message not found in cache, starting recursive query");
// It will delete itself when it is done
- new RunningQuery(io, question, answer_message, upstream_,
+ new RunningQuery(io, question, answer_message,
test_server_, buffer, crs, query_timeout_,
client_timeout_, lookup_timeout_, retries_,
nsas_, cache_, rtt_recorder_);
@@ -815,5 +1022,36 @@ RecursiveQuery::resolve(const Question& question,
}
}
+void
+RecursiveQuery::forward(ConstMessagePtr query_message,
+ MessagePtr answer_message,
+ OutputBufferPtr buffer,
+ DNSServer* server,
+ isc::resolve::ResolverInterface::CallbackPtr callback)
+{
+ // XXX: eventually we will need to be able to determine whether
+ // the message should be sent via TCP or UDP, or sent initially via
+ // UDP and then fall back to TCP on failure, but for the moment
+ // we're only going to handle UDP.
+ IOService& io = dns_service_.getIOService();
+
+ if (!callback) {
+ callback.reset(new isc::resolve::ResolverCallbackServer(server));
+ }
+
+ // TODO: general 'prepareinitialanswer'
+ answer_message->setOpcode(isc::dns::Opcode::QUERY());
+ ConstQuestionPtr question = *query_message->beginQuestion();
+ answer_message->addQuestion(*question);
+
+ // implement the simplest forwarder, which will pass
+ // everything throught without interpretation, except
+ // QID, port number. The response will not be cached.
+ // It will delete itself when it is done
+ new ForwardQuery(io, query_message, answer_message,
+ upstream_, buffer, callback, query_timeout_,
+ client_timeout_, lookup_timeout_);
+}
+
} // namespace asiodns
} // namespace isc
diff --git a/src/lib/resolve/recursive_query.h b/src/lib/resolve/recursive_query.h
index c082426..b9fb80d 100644
--- a/src/lib/resolve/recursive_query.h
+++ b/src/lib/resolve/recursive_query.h
@@ -141,6 +141,20 @@ public:
isc::util::OutputBufferPtr buffer,
DNSServer* server);
+ /// \brief Initiates forwarding for the given query.
+ ///
+ /// Others parameters are same with the parameters of
+ /// function resolve().
+ ///
+ /// \param query_message the full query got from client.
+ /// \param callback callback object
+ void forward(isc::dns::ConstMessagePtr query_message,
+ isc::dns::MessagePtr answer_message,
+ isc::util::OutputBufferPtr buffer,
+ DNSServer* server,
+ isc::resolve::ResolverInterface::CallbackPtr callback =
+ isc::resolve::ResolverInterface::CallbackPtr());
+
/// \brief Set Test Server
///
/// This method is *only* for unit testing the class. If set, it enables
diff --git a/src/lib/resolve/tests/recursive_query_unittest.cc b/src/lib/resolve/tests/recursive_query_unittest.cc
index 3338893..4e939fa 100644
--- a/src/lib/resolve/tests/recursive_query_unittest.cc
+++ b/src/lib/resolve/tests/recursive_query_unittest.cc
@@ -31,10 +31,13 @@
#include <dns/rcode.h>
#include <util/buffer.h>
+#include <util/unittests/resolver.h>
#include <dns/message.h>
+#include <dns/rdataclass.h>
#include <nsas/nameserver_address_store.h>
#include <cache/resolver_cache.h>
+#include <resolve/resolve.h>
// IMPORTANT: We shouldn't directly use ASIO definitions in this test.
// In particular, we must not include asio.hpp in this file.
@@ -59,6 +62,18 @@ using namespace isc::asiolink;
using namespace isc::dns;
using namespace isc::util;
+namespace isc {
+namespace asiodns {
+
+// This is defined in recursive_query.cc, but not in header (it's not public
+// function). So bring it in to be tested.
+std::string
+deepestDelegation(Name name, RRClass rrclass,
+ isc::cache::ResolverCache& cache);
+
+}
+}
+
namespace {
const char* const TEST_SERVER_PORT = "53535";
const char* const TEST_CLIENT_PORT = "53536";
@@ -110,6 +125,9 @@ class RecursiveQueryTest : public ::testing::Test {
protected:
RecursiveQueryTest();
~RecursiveQueryTest() {
+ // It would delete itself, but after the io_service_, which could
+ // segfailt in case there were unhandled requests
+ resolver_.reset();
if (res_ != NULL) {
freeaddrinfo(res_);
}
@@ -348,12 +366,6 @@ protected:
private:
bool* done_;
};
-
- class MockResolver : public isc::resolve::ResolverInterface {
- void resolve(const QuestionPtr& question,
- const ResolverInterface::CallbackPtr& callback) {
- }
- };
// This version of mock server just stops the io_service when it is resumed
// the second time. (Used in the clientTimeout test, where resume
@@ -423,16 +435,17 @@ protected:
vector<uint8_t> callback_data_;
int sock_;
struct addrinfo* res_;
+ boost::shared_ptr<isc::util::unittests::TestResolver> resolver_;
};
RecursiveQueryTest::RecursiveQueryTest() :
dns_service_(NULL), callback_(NULL), callback_protocol_(0),
- callback_native_(-1), sock_(-1), res_(NULL)
+ callback_native_(-1), sock_(-1), res_(NULL),
+ resolver_(new isc::util::unittests::TestResolver())
{
io_service_ = new IOService();
setDNSService(true, true);
- boost::shared_ptr<MockResolver>mock_resolver(new MockResolver());
- nsas_ = new isc::nsas::NameserverAddressStore(mock_resolver);
+ nsas_ = new isc::nsas::NameserverAddressStore(resolver_);
}
TEST_F(RecursiveQueryTest, v6UDPSend) {
@@ -567,9 +580,12 @@ TEST_F(RecursiveQueryTest, forwarderSend) {
singleAddress(TEST_IPV4_ADDR, port));
Question q(Name("example.com"), RRClass::IN(), RRType::TXT());
+ Message query_message(Message::RENDER);
+ isc::resolve::initResponseMessage(q, query_message);
+
OutputBufferPtr buffer(new OutputBuffer(0));
MessagePtr answer(new Message(Message::RENDER));
- rq.resolve(q, answer, buffer, &server);
+ rq.forward(ConstMessagePtr(&query_message), answer, buffer, &server);
char data[4096];
size_t size = sizeof(data);
@@ -634,8 +650,41 @@ bool tryRead(int sock_, int recv_options, size_t max, int* num) {
return true;
}
+// Mock resolver callback for testing forward query.
+class MockResolverCallback : public isc::resolve::ResolverInterface::Callback {
+public:
+ enum ResultValue {
+ DEFAULT = 0,
+ SUCCESS = 1,
+ FAILURE = 2
+ };
+
+ MockResolverCallback(DNSServer* server):
+ result(DEFAULT),
+ server_(server->clone())
+ {}
-// Test it tries the correct amount of times before giving up
+ ~MockResolverCallback() {
+ delete server_;
+ }
+
+ void success(const isc::dns::MessagePtr response) {
+ result = SUCCESS;
+ server_->resume(true);
+ }
+
+ void failure() {
+ result = FAILURE;
+ server_->resume(false);
+ }
+
+ uint32_t result;
+private:
+ DNSServer* server_;
+};
+
+// Test query timeout, set query timeout is lower than client timeout
+// and lookup timeout.
TEST_F(RecursiveQueryTest, forwardQueryTimeout) {
// Prepare the service (we do not use the common setup, we do not answer
setDNSService();
@@ -657,26 +706,20 @@ TEST_F(RecursiveQueryTest, forwardQueryTimeout) {
Question question(Name("example.net"), RRClass::IN(), RRType::A());
OutputBufferPtr buffer(new OutputBuffer(0));
MessagePtr answer(new Message(Message::RENDER));
- query.resolve(question, answer, buffer, &server);
+ Message query_message(Message::RENDER);
+ isc::resolve::initResponseMessage(question, query_message);
+ boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
+ query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
// Run the test
io_service_->run();
-
- // Read up to 3 packets. Use some ad hoc timeout to prevent an infinite
- // block (see also recvUDP()).
- int recv_options = setSocketTimeout(sock_, 10, 0);
- int num = 0;
- bool read_success = tryRead(sock_, recv_options, 3, &num);
-
- // The query should 'succeed' with an error response
- EXPECT_TRUE(done);
- EXPECT_EQ(3, num);
- EXPECT_TRUE(read_success);
+ EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
}
// If we set client timeout to lower than querytimeout, we should
-// get a failure answer, but still see retries
-// (no actual answer is given here yet)
+// get a failure answer
+// (no actual answer is given here yet. TODO the returned error message
+// should be tested)
TEST_F(RecursiveQueryTest, forwardClientTimeout) {
// Prepare the service (we do not use the common setup, we do not answer
setDNSService();
@@ -691,36 +734,25 @@ TEST_F(RecursiveQueryTest, forwardClientTimeout) {
// Do the answer
const uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
- // Set it up to retry twice before client timeout fires
- // Since the lookup timer has not fired, it should retry
- // four times
RecursiveQuery query(*dns_service_,
*nsas_, cache_,
singleAddress(TEST_IPV4_ADDR, port),
singleAddress(TEST_IPV4_ADDR, port),
- 200, 480, 4000, 4);
- Question question(Name("example.net"), RRClass::IN(), RRType::A());
+ 1000, 10, 4000, 4);
+ Question q(Name("example.net"), RRClass::IN(), RRType::A());
OutputBufferPtr buffer(new OutputBuffer(0));
- query.resolve(question, answer, buffer, &server);
+ Message query_message(Message::RENDER);
+ isc::resolve::initResponseMessage(q, query_message);
+ boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
+ query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
// Run the test
io_service_->run();
-
- // we know it'll fail, so make it a shorter timeout
- int recv_options = setSocketTimeout(sock_, 1, 0);
-
- // Try to read 4 times
- int num = 0;
- bool read_success = tryRead(sock_, recv_options, 4, &num);
-
- // The query should fail
- EXPECT_TRUE(done1);
- EXPECT_EQ(3, num);
- EXPECT_FALSE(read_success);
+ EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
}
-// If we set lookup timeout to lower than querytimeout*retries, we should
-// fail before the full amount of retries
+// If we set lookup timeout to lower than querytimeout, the lookup
+// will fail.
TEST_F(RecursiveQueryTest, forwardLookupTimeout) {
// Prepare the service (we do not use the common setup, we do not answer
setDNSService();
@@ -736,30 +768,22 @@ TEST_F(RecursiveQueryTest, forwardLookupTimeout) {
// Do the answer
const uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
- // Set up the test so that it will retry 5 times, but the lookup
- // timeout will fire after only 3 normal timeouts
RecursiveQuery query(*dns_service_,
*nsas_, cache_,
singleAddress(TEST_IPV4_ADDR, port),
singleAddress(TEST_IPV4_ADDR, port),
- 200, 4000, 480, 5);
+ 1000, 4000, 10, 5);
Question question(Name("example.net"), RRClass::IN(), RRType::A());
OutputBufferPtr buffer(new OutputBuffer(0));
- query.resolve(question, answer, buffer, &server);
+ Message query_message(Message::RENDER);
+ isc::resolve::initResponseMessage(question, query_message);
+
+ boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
+ query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
// Run the test
io_service_->run();
-
- int recv_options = setSocketTimeout(sock_, 1, 0);
-
- // Try to read 5 times, should stop after 3 reads
- int num = 0;
- bool read_success = tryRead(sock_, recv_options, 5, &num);
-
- // The query should fail and respond with an error
- EXPECT_TRUE(done);
- EXPECT_EQ(3, num);
- EXPECT_FALSE(read_success);
+ EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
}
// Set everything very low and see if this doesn't cause weird
@@ -779,8 +803,6 @@ TEST_F(RecursiveQueryTest, lowtimeouts) {
// Do the answer
const uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
- // Set up the test so that it will retry 5 times, but the lookup
- // timeout will fire after only 3 normal timeouts
RecursiveQuery query(*dns_service_,
*nsas_, cache_,
singleAddress(TEST_IPV4_ADDR, port),
@@ -788,21 +810,15 @@ TEST_F(RecursiveQueryTest, lowtimeouts) {
1, 1, 1, 1);
Question question(Name("example.net"), RRClass::IN(), RRType::A());
OutputBufferPtr buffer(new OutputBuffer(0));
- query.resolve(question, answer, buffer, &server);
+ Message query_message(Message::RENDER);
+ isc::resolve::initResponseMessage(question, query_message);
+
+ boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
+ query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
// Run the test
io_service_->run();
-
- int recv_options = setSocketTimeout(sock_, 1, 0);
-
- // Try to read 5 times, should stop after 3 reads
- int num = 0;
- bool read_success = tryRead(sock_, recv_options, 5, &num);
-
- // The query should fail and respond with an error
- EXPECT_TRUE(done);
- EXPECT_EQ(1, num);
- EXPECT_FALSE(read_success);
+ EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
}
// as mentioned above, we need a more better framework for this,
@@ -857,7 +873,88 @@ TEST_F(RecursiveQueryTest, DISABLED_recursiveSendNXDOMAIN) {
EXPECT_EQ(0, answer->getRRCount(Message::SECTION_ANSWER));
}
+// Test that we don't start at root when we have a lower NS cached.
+TEST_F(RecursiveQueryTest, CachedNS) {
+ setDNSService(true, true);
+
+ // Check we have a reasonable fallback - if there's nothing of interest
+ // in the cache, start at root.
+ EXPECT_EQ(".", deepestDelegation(Name("www.somewhere.deep.example.org"),
+ RRClass::IN(), cache_));
+
+ // Prefill the cache. There's a zone with a NS and IP address for one
+ // of them (to see that one is enough) and another deeper one, with NS,
+ // but without IP.
+ RRsetPtr nsUpper(new RRset(Name("example.org"), RRClass::IN(),
+ RRType::NS(), RRTTL(300)));
+ nsUpper->addRdata(rdata::generic::NS(Name("ns.example.org")));
+ nsUpper->addRdata(rdata::generic::NS(Name("ns2.example.org")));
+
+ RRsetPtr nsLower(new RRset(Name("somewhere.deep.example.org"),
+ RRClass::IN(), RRType::NS(), RRTTL(300)));
+ nsLower->addRdata(rdata::generic::NS(Name("ns.somewhere.deep.example.org"))
+ );
+
+ RRsetPtr nsIp(new RRset(Name("ns2.example.org"), RRClass::IN(),
+ RRType::A(), RRTTL(300)));
+ nsIp->addRdata(rdata::in::A("192.0.2.1"));
+
+ // Make sure the test runs in the correct environment (we don't test
+ // the cache, but we need it to unswer this way for the test, so we
+ // just make sure)
+ ASSERT_TRUE(cache_.update(nsUpper));
+ ASSERT_TRUE(cache_.update(nsLower));
+ ASSERT_TRUE(cache_.update(nsIp));
+ RRsetPtr deepest(cache_.lookupDeepestNS(Name(
+ "www.somewhere.deep.example.org"), RRClass::IN()));
+ ASSERT_NE(RRsetPtr(), deepest);
+ ASSERT_EQ(nsLower->getName(), deepest->getName());
+
+ // Direct check of the function that chooses the delegation point
+ // It should not use nsLower, because we don't have IP address for
+ // that one. But it can choose nsUpper.
+ EXPECT_EQ("example.org.",
+ deepestDelegation(Name("www.somewhere.deep.example.org"),
+ RRClass::IN(), cache_));
+
+ // Now more complex and indirect test:
+ // We ask it to resolve the name for us. It will pick up a delegation
+ // point and ask NSAS for it. NSAS will in turn ask resolver for NS record
+ // of the delegation point. We then pick it up from the fake resolver
+ // and check it is the correct one. This checks the delegation point
+ // travels safely trough the whole path there (it would be enough to check
+ // it up to NSAS, but replacing NSAS is more complicated, so we just
+ // include in the test as well for simplicity).
+
+ // Prepare the recursive query
+ vector<pair<string, uint16_t> > roots;
+ roots.push_back(pair<string, uint16_t>("192.0.2.2", 53));
+
+ RecursiveQuery rq(*dns_service_, *nsas_, cache_,
+ vector<pair<string, uint16_t> >(), roots);
+ // Ask a question at the bottom. It should not use the lower NS, because
+ // it would lead to a loop in NS. But it can use the nsUpper one, it has
+ // an IP address and we can avoid asking root.
+ Question q(Name("www.somewhere.deep.example.org"), RRClass::IN(),
+ RRType::A());
+ OutputBufferPtr buffer(new OutputBuffer(0));
+ MessagePtr answer(new Message(Message::RENDER));
+ // The server is here so we have something to pass there
+ MockServer server(*io_service_);
+ rq.resolve(q, answer, buffer, &server);
+ // We don't need to run the service in this test. We are interested only
+ // in the place it starts resolving at
+
+ // Look what is asked by NSAS - it should be our delegation point.
+ EXPECT_NO_THROW(EXPECT_EQ(nsUpper->getName(),
+ (*resolver_)[0]->getName()) <<
+ "It starts resolving at the wrong place") <<
+ "It does not ask NSAS anything, how does it know where to send?";
+}
+
// TODO: add tests that check whether the cache is updated on succesfull
// responses, and not updated on failures.
+
+
}
diff --git a/src/lib/server_common/portconfig.cc b/src/lib/server_common/portconfig.cc
index 941644e..7b2b3dd 100644
--- a/src/lib/server_common/portconfig.cc
+++ b/src/lib/server_common/portconfig.cc
@@ -96,11 +96,17 @@ installListenAddresses(const AddressList& newAddresses,
}
catch (const exception& e) {
/*
- * We couldn't set it. So return it back. If that fails as well,
- * we have a problem.
+ * If one of the addresses isn't set successfully, we will restore
+ * the old addresses, the behavior is that either all address are
+ * set successuflly or none of them will be used. whether this
+ * behavior is user desired, maybe we need revisited it later. And
+ * if address setting is more smarter, it should check whether some
+ * part of the new address already in used to avoid interuption the
+ * service.
*
- * If that fails, bad luck, but we are useless anyway, so just die
- * and let boss start us again.
+ * If the address setting still failed, we can live with it, since
+ * user will get error info, command control can be used to set new
+ * address. So we just catch the exception without propagating outside
*/
dlog(string("Unable to set new address: ") + e.what(), true);
try {
@@ -109,9 +115,10 @@ installListenAddresses(const AddressList& newAddresses,
catch (const exception& e2) {
dlog("Unable to recover from error;", true);
dlog(string("Rollback failed with: ") + e2.what(), true);
- abort();
}
- throw; // Let it fly a little bit further
+ //Anyway the new configure has problem, we need to notify configure
+ //manager the new configure doesn't work
+ throw;
}
}
diff --git a/src/lib/server_common/tests/portconfig_unittest.cc b/src/lib/server_common/tests/portconfig_unittest.cc
index 5262565..65963eb 100644
--- a/src/lib/server_common/tests/portconfig_unittest.cc
+++ b/src/lib/server_common/tests/portconfig_unittest.cc
@@ -177,7 +177,7 @@ TEST_F(InstallListenAddresses, rollback) {
EXPECT_NO_THROW(installListenAddresses(valid_, store_, dnss_));
checkAddresses(valid_, "Before rollback");
// This should not bind them, but should leave the original addresses
- EXPECT_THROW(installListenAddresses(invalid_, store_, dnss_), IOError);
+ EXPECT_THROW(installListenAddresses(invalid_, store_, dnss_), exception);
checkAddresses(valid_, "After rollback");
}
diff --git a/src/lib/util/Makefile.am b/src/lib/util/Makefile.am
index 77a3e4a..6deec27 100644
--- a/src/lib/util/Makefile.am
+++ b/src/lib/util/Makefile.am
@@ -24,5 +24,7 @@ libutil_la_SOURCES += encode/binary_from_base16.h
libutil_la_SOURCES += random/qid_gen.h random/qid_gen.cc
libutil_la_SOURCES += random/random_number_generator.h
+EXTRA_DIST = python/pycppwrapper_util.h
+
libutil_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
CLEANFILES = *.gcno *.gcda
diff --git a/src/lib/util/encode/base_n.cc b/src/lib/util/encode/base_n.cc
index e79f11d..406dc77 100644
--- a/src/lib/util/encode/base_n.cc
+++ b/src/lib/util/encode/base_n.cc
@@ -138,7 +138,7 @@ private:
// DecodeNormalizer is an input iterator intended to be used as a filter
// between the encoded baseX stream and binary_from_baseXX.
// A DecodeNormalizer object is configured with three string iterators
-// (base, base_beinpad, and base_beginpad), specifying the head of the string,
+// (base, base_beginpad, and base_end), specifying the head of the string,
// the beginning position of baseX padding (when there's padding), and
// end of the string, respectively. It internally iterators over the original
// stream, and return each character of the encoded string via its dereference
diff --git a/src/lib/util/python/mkpywrapper.py.in b/src/lib/util/python/mkpywrapper.py.in
new file mode 100755
index 0000000..4bf7752
--- /dev/null
+++ b/src/lib/util/python/mkpywrapper.py.in
@@ -0,0 +1,100 @@
+#!@PYTHON@
+
+# Copyright (C) 2011 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""This utility program generates a C++ header and implementation files
+that can be used as a template of C++ python binding for a C++ class.
+
+Usage: ./mkpywrapper.py ClassName
+(the script should be run on this directory)
+
+It will generate two files: classname_python.h and classname_python.cc,
+many of whose definitions are in the namespace isc::MODULE_NAME::python.
+By default MODULE_NAME will be 'dns' (because this tool is originally
+intended to be used for the C++ python binding of the DNS library), but
+can be changed via the -m command line option.
+
+The generated files contain code fragments that are commonly used in
+C++ python binding implementations. It will define a class named
+s_ClassName which is a derived class of PyModule and can meet the
+requirement of the CPPPyObjectContainer template class (see
+pycppwrapper_util.h). It also defines (and declares in the header file)
+"classname_type", which is of PyTypeObject and is intended to be used
+to define details of the python bindings for the ClassName class.
+
+In many cases the header file can be used as a startpoint of the
+binding development without modification. But you may want to make
+ClassName::cppobj a constant variable (and you should if you can).
+Many definitions of classname_python.cc should also be able to be used
+just as defined, but some will need to be changed or removed. In
+particular, you should at least adjust ClassName_init(). You'll
+probably also need to add more definitions to that file to provide
+complete features of the C++ class.
+"""
+
+import datetime, string, sys
+from optparse import OptionParser
+
+# Remember the current year to produce the copyright boilerplate
+YEAR = datetime.date.today().timetuple()[0]
+
+def dump_file(out_file, temp_file, class_name, module):
+ for line in temp_file.readlines():
+ line = line.replace("@YEAR@", str(YEAR))
+ line = line.replace("@CPPCLASS at _H", class_name.upper() + "_H")
+ line = line.replace("@CPPCLASS@", class_name)
+ line = line.replace("@cppclass@", class_name.lower())
+ line = line.replace("@MODULE@", module)
+ out_file.write(line)
+
+def dump_wrappers(class_name, output, module):
+ try:
+ if output == "-":
+ header_file = sys.stdout
+ else:
+ header_file = open(output + "_python.h", "w")
+ header_template_file = open("wrapper_template.h", "r")
+ if output == "-":
+ impl_file = sys.stdout
+ else:
+ impl_file = open(output + "_python.cc", "w")
+ impl_template_file = open("wrapper_template.cc", "r")
+ except:
+ sys.stderr.write('Failed to open C++ file(s)\n')
+ sys.exit(1)
+ dump_file(header_file, header_template_file, class_name, module)
+ dump_file(impl_file, impl_template_file, class_name, module)
+
+usage = '''usage: %prog [options] class_name'''
+
+if __name__ == "__main__":
+ parser = OptionParser(usage=usage)
+ parser.add_option('-o', '--output', action='store', dest='output',
+ default=None, metavar='FILE',
+ help='prefix of output file names [default: derived from the class name]')
+ parser.add_option('-m', '--module', action='store', dest='module',
+ default='dns',
+ help='C++ module name of the wrapper (for namespaces) [default: dns]')
+ (options, args) = parser.parse_args()
+
+ if len(args) == 0:
+ parser.error('input file is missing')
+
+ class_name = args[0]
+ if not options.output:
+ options.output = class_name.lower()
+
+ dump_wrappers(class_name, options.output, options.module)
diff --git a/src/lib/util/python/pycppwrapper_util.h b/src/lib/util/python/pycppwrapper_util.h
new file mode 100644
index 0000000..fd55c19
--- /dev/null
+++ b/src/lib/util/python/pycppwrapper_util.h
@@ -0,0 +1,308 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __PYCPPWRAPPER_UTIL_H
+#define __PYCPPWRAPPER_UTIL_H 1
+
+#include <Python.h>
+
+#include <exceptions/exceptions.h>
+
+/**
+ * @file pycppwrapper_util.h
+ * @short Shared definitions for python/C(++) API
+ *
+ * This utility defines a set of convenient wrappers for the python C API
+ * to use it safely from our C++ bindings. The python C API has many pitfalls
+ * such as not-so-consistent reference count policies. Also, many existing
+ * examples are careless about error handling. It's easy to find on the net
+ * example (even of "production use") python extensions like this:
+ *
+ * \code
+ * new_exception = PyErr_NewException("mymodule.Exception", NULL, NULL);
+ * // new_exception can be NULL, in which case the call to
+ * // PyModule_AddObject will cause a surprising disruption.
+ * PyModule_AddObject(mymodule, "Exception", new_exception); \endcode
+ *
+ * When using the python C API with C++, we should also be careful about
+ * exception safety. The underlying C++ code (including standard C++ libraries
+ * and memory allocation) can throw exceptions, in which case we need to
+ * make sure any intermediate python objects are cleaned up (we also need to
+ * catch the C++ exceptions inside the binding and convert them to python
+ * errors, but that's a different subject). This is not a trivial task
+ * because the python objects are represented as bare C pointers (so there's
+ * no destructor) and we need to address the exception safety along with python
+ * reference counters (so we cannot naively apply standard smart pointers).
+ *
+ * This utility tries to help address these issues.
+ *
+ * Also, it's intentional that this is a header-only utility. This way the
+ * C++ loadable module won't depend on another C++ library (which is not
+ * necessarily wrong, but would increase management cost such as link-time
+ * troubles only for a small utility feature).
+ */
+
+namespace isc {
+namespace util {
+namespace python {
+
+/// This is thrown inside this utility when it finds a NULL pointer is passed
+/// when it should not be NULL.
+class PyCPPWrapperException : public isc::Exception {
+public:
+ PyCPPWrapperException(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+/// This helper class is similar to the standard autoptr and manages PyObject
+/// using some kind of RAII techniques. It is, however, customized for the
+/// python C API.
+///
+/// A PyObjectContainer object is constructed with a pointer to PyObject,
+/// which is often just created dynamically. The caller will eventually
+/// attach the object to a different python object (often a module or class)
+/// via specific methods or directly return it to the python interpreter.
+///
+/// There are two cases in destructing the object: with or without decreasing
+/// a reference to the PyObject. If the object is intended to be an argument
+/// to another python C library that increases the reference to the object for
+/// itself, we should normally release our own reference; otherwise the
+/// reference will leak and the object won't be garbage collected. Also, when
+/// an unexpected error happens in the form of C++ exception, we should
+/// release the reference to prevent resource leak.
+///
+/// In some other cases, we should simply give our reference to the caller.
+/// That is the case when the created object itself is a return value of
+/// an extended python method written in the C++ binding. Likewise, some
+/// python C library functions "steal" the reference. In these cases we
+/// should not decrease the reference; otherwise it would cause duplicate free.
+///
+/// By default, the destructor of this class releases the reference to the
+/// PyObject. If this behavior is desirable, you can extract the original
+/// bare pointer to the PyObject by the \c get() method. If you don't want
+/// the reference to be decreased, the original bare pointer should be
+/// extracted using the \c release() method.
+///
+/// There are two convenience methods for commonly used operations:
+/// \c installAsClassVariable() to add the PyObject as a class variable
+/// and \c installToModule to add the PyObject to a specified python module.
+/// These methods (at least to some extent) take care of the reference to
+/// the object (either release or keep) depending on the usage context so
+/// that the user don't have to worry about it.
+///
+/// On construction, this class expects the pointer can be NULL.
+/// If it happens it immediately throws a \c PyCPPWrapperException exception.
+/// This behavior is to convert failures in the python C API (such as
+/// PyObject_New() returning NULL) to C++ exception so that we can unify
+/// error handling in the style of C++ exceptions.
+///
+/// Examples 1: To create a tuple of two python objects, do this:
+///
+/// \code
+/// try {
+/// PyObjectContainer container0(Py_BuildValue("I", 0));
+/// PyObjectContainer container1(Py_BuildValue("s", cppobj.toText().c_str()));
+/// return (Py_BuildValue("OO", container0.get(), container1.get()));
+/// } catch { ... set python exception, etc ... } \endcode
+///
+/// Commonly deployed buggy implementation to achieve this would be like this:
+/// \code
+/// return (Py_BuildValue("OO", Py_BuildValue("I", 0),
+/// Py_BuildValue("s", cppobj.toText().c_str())));
+/// \endcode
+/// One clear bug of this code is that references to the element objects of
+/// the tuple will leak.
+/// (Assuming \c cppobj.toText() can throw) this code is also not exception
+/// safe; if \c cppobj.toText() throws the reference to the first object
+/// will leak, even if the code tried to do the necessary cleanup in the
+/// successful case.
+/// Further, this code naively passes the result of the first two calls to
+/// \c Py_BuildValue() to the third one even if they can be NULL.
+/// In this specific case, it happens to be okay because \c Py_BuildValue()
+/// accepts NULL and treats it as an indication of error. But not all
+/// python C library works that way (remember, the API is so inconsistent)
+/// and we need to refer to the API manual every time we have to worry about
+/// passing a NULL object to a library function. We'd certainly like to
+/// avoid such development overhead. The code using \c PyObjectContainer
+/// addresses all these problems.
+///
+/// Examples 2: Install a (constant) variable to a class.
+///
+/// \code
+/// try {
+/// // installClassVariable is a wrapper of
+/// // PyObjectContainer::installAsClassVariable. See below.
+/// installClassVariable(myclass_type, "SOME_CONSTANT",
+/// Py_BuildValue("I", 0));
+/// } catch { ... }
+/// \endcode
+///
+/// Examples 3: Install a custom exception to a module.
+///
+/// \code
+/// PyObject* new_exception; // publicly visible
+/// ...
+/// try {
+/// new_exception = PyErr_NewException("mymodule.NewException",
+/// NULL, NULL);
+/// PyObjectContainer(new_exception).installToModule(mymodule,
+/// "NewException");
+/// } catch { ... }
+/// \endcode
+///
+/// Note that \c installToModule() keeps the reference to \c new_exception
+/// by default. This is a common practice when we introduce a custom
+/// exception in a python biding written in C/C++. See the code comment
+/// of the method for more details.
+struct PyObjectContainer {
+ PyObjectContainer(PyObject* obj) : obj_(obj) {
+ if (obj_ == NULL) {
+ isc_throw(PyCPPWrapperException, "Unexpected NULL PyObject, "
+ "probably due to short memory");
+ }
+ }
+ virtual ~PyObjectContainer() {
+ if (obj_ != NULL) {
+ Py_DECREF(obj_);
+ }
+ }
+ PyObject* get() {
+ return (obj_);
+ }
+ PyObject* release() {
+ PyObject* ret = obj_;
+ obj_ = NULL;
+ return (ret);
+ }
+
+ // Install the enclosed PyObject to the specified python class 'pyclass'
+ // as a variable named 'name'.
+ void installAsClassVariable(PyTypeObject& pyclass, const char* name) {
+ if (PyDict_SetItemString(pyclass.tp_dict, name, obj_) < 0) {
+ isc_throw(PyCPPWrapperException, "Failed to set a class variable, "
+ "probably due to short memory");
+ }
+ // Ownership successfully transferred to the class object. We'll let
+ // it be released in the destructor.
+ }
+
+ // Install the enclosed PyObject to the specified module 'mod' as an
+ // object named 'name'.
+ // By default, this method explicitly keeps the reference to the object
+ // even after the module "steals" it. To cancel this behavior and give
+ // the reference to the module completely, the third parameter 'keep_ref'
+ // should be set to false.
+ void installToModule(PyObject* mod, const char* name,
+ bool keep_ref = true)
+ {
+ if (PyModule_AddObject(mod, name, obj_) < 0) {
+ isc_throw(PyCPPWrapperException, "Failed to add an object to "
+ "module, probably due to short memory");
+ }
+ // PyModule_AddObject has "stolen" the reference, so unless we
+ // have to retain it ourselves we don't (shouldn't) decrease it.
+ // However, we actually often need to keep our own reference because
+ // objects added to a module are often referenced via non local
+ // C/C++ variables in various places of the C/C++ code. In order
+ // for the code to run safely even if some buggy/evil python program
+ // performs 'del mod.obj', we need the extra reference. See, e.g.:
+ // http://docs.python.org/py3k/c-api/init.html#Py_Initialize
+ // http://mail.python.org/pipermail/python-dev/2005-June/054238.html
+ if (keep_ref) {
+ Py_INCREF(obj_);
+ }
+ obj_ = NULL;
+ }
+
+protected:
+ PyObject* obj_;
+};
+
+/// This templated class is a derived class of \c PyObjectContainer and
+/// manages C++-class based python objects.
+///
+/// The template parameter \c PYSTRUCT must be a derived class (structure) of
+/// \c PyObject that has a member variable named \c cppobj, which must be a
+/// a pointer to \c CPPCLASS (the second template parameter).
+///
+/// For example, to define a custom python class based on a C++ class, MyClass,
+/// we'd define a class (struct) named \c s_MyClass like this:
+/// \code
+/// class s_MyClass : public PyObject {
+/// public:
+/// s_MyClass() : cppobj(NULL) {}
+/// MyClass* cppobj;
+/// };
+/// \endcode
+///
+/// And, to build and return a python version of MyClass object, write the
+/// following C++ code:
+/// \code
+/// typedef CPPPyObjectContainer<s_MyClass, MyClass> MyContainer;
+/// try {
+/// // below, myclass_type is of \c PyTypeObject that defines
+/// // a python class (type) for MyClass
+/// MyContainer container(PyObject_New(s_MyClass, myclass_type));
+/// container.set(new MyClass());
+/// return (container.release()); // give the reference to the caller
+/// } catch { ... }
+/// \endcode
+///
+/// This code prevents bugs like NULL pointer dereference when \c PyObject_New
+/// fails or resource leaks when new'ing \c MyClass results in an exception.
+/// Note that we use \c release() (derived from the base class) instead of
+/// \c get(); in this case we should simply pass the reference generated in
+/// \c PyObject_New() to the caller.
+template <typename PYSTRUCT, typename CPPCLASS>
+struct CPPPyObjectContainer : public PyObjectContainer {
+ CPPPyObjectContainer(PYSTRUCT* obj) : PyObjectContainer(obj) {}
+
+ // This method associates a C++ object with the corresponding python
+ // object enclosed in this class.
+ void set(CPPCLASS* value) {
+ if (value == NULL) {
+ isc_throw(PyCPPWrapperException, "Unexpected NULL C++ object, "
+ "probably due to short memory");
+ }
+ static_cast<PYSTRUCT*>(obj_)->cppobj = value;
+ }
+
+ // This is a convenience short cut to associate a C++ object with the
+ // python object and install it to the specified python class \c pyclass
+ // as a variable named \c name.
+ void installAsClassVariable(PyTypeObject& pyclass, const char* name,
+ CPPCLASS* value)
+ {
+ set(value);
+ PyObjectContainer::installAsClassVariable(pyclass, name);
+ }
+};
+
+/// A shortcut function to install a python class variable.
+///
+/// It installs a python object \c obj to a specified class \c pyclass
+/// as a variable named \c name.
+inline void
+installClassVariable(PyTypeObject& pyclass, const char* name, PyObject* obj) {
+ PyObjectContainer(obj).installAsClassVariable(pyclass, name);
+}
+
+} // namespace python
+} // namespace util
+} // namespace isc
+#endif // __PYCPPWRAPPER_UTIL_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/python/wrapper_template.cc b/src/lib/util/python/wrapper_template.cc
new file mode 100644
index 0000000..2fe7567
--- /dev/null
+++ b/src/lib/util/python/wrapper_template.cc
@@ -0,0 +1,293 @@
+// Copyright (C) @YEAR@ Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string>
+#include <stdexcept>
+
+#include <util/python/pycppwrapper_util.h>
+
+#include "@cppclass at _python.h"
+
+using namespace std;
+using namespace isc::util::python;
+using namespace isc::@MODULE@;
+using namespace isc::@MODULE@::python;
+
+//
+// Definition of the classes
+//
+
+// For each class, we need a struct, a helper functions (init, destroy,
+// and static wrappers around the methods we export), a list of methods,
+// and a type description
+
+//
+// @CPPCLASS@
+//
+
+// Trivial constructor.
+s_ at CPPCLASS@::s_ at CPPCLASS@() : cppobj(NULL) {
+}
+
+namespace {
+// Shortcut type which would be convenient for adding class variables safely.
+typedef CPPPyObjectContainer<s_ at CPPCLASS@, @CPPCLASS@> @CPPCLASS at Container;
+
+//
+// We declare the functions here, the definitions are below
+// the type definition of the object, since both can use the other
+//
+
+// General creation and destruction
+int @CPPCLASS at _init(s_ at CPPCLASS@* self, PyObject* args);
+void @CPPCLASS at _destroy(s_ at CPPCLASS@* self);
+
+// These are the functions we export
+// ADD/REMOVE/MODIFY THE FOLLOWING AS APPROPRIATE FOR THE ACTUAL CLASS.
+//
+PyObject* @CPPCLASS at _toText(const s_ at CPPCLASS@* const self);
+PyObject* @CPPCLASS at _str(PyObject* self);
+PyObject* @CPPCLASS at _richcmp(const s_ at CPPCLASS@* const self,
+ const s_ at CPPCLASS@* const other, int op);
+
+// This is quite specific pydnspp. For other wrappers this should probably
+// be removed.
+PyObject* @CPPCLASS at _toWire(const s_ at CPPCLASS@* self, PyObject* args);
+
+// These are the functions we export
+// For a minimal support, we don't need them.
+
+// This list contains the actual set of functions we have in
+// python. Each entry has
+// 1. Python method name
+// 2. Our static function here
+// 3. Argument type
+// 4. Documentation
+PyMethodDef @CPPCLASS at _methods[] = {
+ { "to_text", reinterpret_cast<PyCFunction>(@CPPCLASS at _toText), METH_NOARGS,
+ "Returns the text representation" },
+ // This is quite specific pydnspp. For other wrappers this should probably
+ // be removed:
+ { "to_wire", reinterpret_cast<PyCFunction>(@CPPCLASS at _toWire), METH_VARARGS,
+ "Converts the @CPPCLASS@ object to wire format.\n"
+ "The argument can be either a MessageRenderer or an object that "
+ "implements the sequence interface. If the object is mutable "
+ "(for instance a bytearray()), the wire data is added in-place.\n"
+ "If it is not (for instance a bytes() object), a new object is "
+ "returned" },
+ { NULL, NULL, 0, NULL }
+};
+
+// This is a template of typical code logic of python class initialization
+// with C++ backend. You'll need to adjust it according to details of the
+// actual C++ class.
+int
+ at CPPCLASS@_init(s_ at CPPCLASS@* self, PyObject* args) {
+ try {
+ if (PyArg_ParseTuple(args, "REPLACE ME")) {
+ // YOU'LL NEED SOME VALIDATION, PREPARATION, ETC, HERE.
+ self->cppobj = new @CPPCLASS@(/*NECESSARY PARAMS*/);
+ return (0);
+ }
+ } catch (const exception& ex) {
+ const string ex_what = "Failed to construct @CPPCLASS@ object: " +
+ string(ex.what());
+ PyErr_SetString(po_IscException, ex_what.c_str());
+ return (-1);
+ } catch (...) {
+ PyErr_SetString(po_IscException,
+ "Unexpected exception in constructing @CPPCLASS@");
+ return (-1);
+ }
+
+ PyErr_SetString(PyExc_TypeError,
+ "Invalid arguments to @CPPCLASS@ constructor");
+
+ return (-1);
+}
+
+// This is a template of typical code logic of python object destructor.
+// In many cases you can use it without modification, but check that carefully.
+void
+ at CPPCLASS@_destroy(s_ at CPPCLASS@* const self) {
+ delete self->cppobj;
+ self->cppobj = NULL;
+ Py_TYPE(self)->tp_free(self);
+}
+
+// This should be able to be used without modification as long as the
+// underlying C++ class has toText().
+PyObject*
+ at CPPCLASS@_toText(const s_ at CPPCLASS@* const self) {
+ try {
+ // toText() could throw, so we need to catch any exceptions below.
+ return (Py_BuildValue("s", self->cppobj->toText().c_str()));
+ } catch (const exception& ex) {
+ const string ex_what =
+ "Failed to convert @CPPCLASS@ object to text: " +
+ string(ex.what());
+ PyErr_SetString(po_IscException, ex_what.c_str());
+ } catch (...) {
+ PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
+ "converting @CPPCLASS@ object to text");
+ }
+ return (NULL);
+}
+
+PyObject*
+ at CPPCLASS@_str(PyObject* self) {
+ // Simply call the to_text method we already defined
+ return (PyObject_CallMethod(self, const_cast<char*>("to_text"),
+ const_cast<char*>("")));
+}
+
+PyObject*
+ at CPPCLASS@_richcmp(const s_ at CPPCLASS@* const self,
+ const s_ at CPPCLASS@* const other,
+ const int op)
+{
+ bool c = false;
+
+ // Check for null and if the types match. If different type,
+ // simply return False
+ if (other == NULL || (self->ob_type != other->ob_type)) {
+ Py_RETURN_FALSE;
+ }
+
+ // Only equals and not equals here, unorderable type
+ switch (op) {
+ case Py_LT:
+ PyErr_SetString(PyExc_TypeError, "Unorderable type; @CPPCLASS@");
+ return (NULL);
+ case Py_LE:
+ PyErr_SetString(PyExc_TypeError, "Unorderable type; @CPPCLASS@");
+ return (NULL);
+ case Py_EQ:
+ c = (*self->cppobj == *other->cppobj);
+ break;
+ case Py_NE:
+ c = (*self->cppobj != *other->cppobj);
+ break;
+ case Py_GT:
+ PyErr_SetString(PyExc_TypeError, "Unorderable type; @CPPCLASS@");
+ return (NULL);
+ case Py_GE:
+ PyErr_SetString(PyExc_TypeError, "Unorderable type; @CPPCLASS@");
+ return (NULL);
+ }
+ if (c) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+} // end of unnamed namespace
+
+namespace isc {
+namespace @MODULE@ {
+namespace python {
+// This defines the complete type for reflection in python and
+// parsing of PyObject* to s_ at CPPCLASS@
+// Most of the functions are not actually implemented and NULL here.
+PyTypeObject @cppclass at _type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "libdns_python. at CPPCLASS@",
+ sizeof(s_ at CPPCLASS@), // tp_basicsize
+ 0, // tp_itemsize
+ reinterpret_cast<destructor>(@CPPCLASS at _destroy), // tp_dealloc
+ NULL, // tp_print
+ NULL, // tp_getattr
+ NULL, // tp_setattr
+ NULL, // tp_reserved
+ NULL, // tp_repr
+ NULL, // tp_as_number
+ NULL, // tp_as_sequence
+ NULL, // tp_as_mapping
+ NULL, // tp_hash
+ NULL, // tp_call
+ // THIS MAY HAVE TO BE CHANGED TO NULL:
+ @CPPCLASS at _str, // tp_str
+ NULL, // tp_getattro
+ NULL, // tp_setattro
+ NULL, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT, // tp_flags
+ "The @CPPCLASS@ class objects is...(COMPLETE THIS)",
+ NULL, // tp_traverse
+ NULL, // tp_clear
+ // THIS MAY HAVE TO BE CHANGED TO NULL:
+ reinterpret_cast<richcmpfunc>(@CPPCLASS at _richcmp), // tp_richcompare
+ 0, // tp_weaklistoffset
+ NULL, // tp_iter
+ NULL, // tp_iternext
+ @CPPCLASS at _methods, // tp_methods
+ NULL, // tp_members
+ NULL, // tp_getset
+ NULL, // tp_base
+ NULL, // tp_dict
+ NULL, // tp_descr_get
+ NULL, // tp_descr_set
+ 0, // tp_dictoffset
+ reinterpret_cast<initproc>(@CPPCLASS at _init), // tp_init
+ NULL, // tp_alloc
+ PyType_GenericNew, // tp_new
+ NULL, // tp_free
+ NULL, // tp_is_gc
+ NULL, // tp_bases
+ NULL, // tp_mro
+ NULL, // tp_cache
+ NULL, // tp_subclasses
+ NULL, // tp_weaklist
+ NULL, // tp_del
+ 0 // tp_version_tag
+};
+
+// Module Initialization, all statics are initialized here
+bool
+initModulePart_ at CPPCLASS@(PyObject* mod) {
+ // We initialize the static description object with PyType_Ready(),
+ // then add it to the module. This is not just a check! (leaving
+ // this out results in segmentation faults)
+ if (PyType_Ready(&@cppclass at _type) < 0) {
+ return (false);
+ }
+ void* p = &@cppclass at _type;
+ if (PyModule_AddObject(mod, "@CPPCLASS@", static_cast<PyObject*>(p)) < 0) {
+ return (false);
+ }
+ Py_INCREF(&@cppclass at _type);
+
+ // The following template is the typical procedure for installing class
+ // variables. If the class doesn't have a class variable, remove the
+ // entire try-catch clauses.
+ try {
+ // Constant class variables
+ installClassVariable(@cppclass at _type, "REPLACE_ME",
+ Py_BuildValue("REPLACE ME"));
+ } catch (const exception& ex) {
+ const string ex_what =
+ "Unexpected failure in @CPPCLASS@ initialization: " +
+ string(ex.what());
+ PyErr_SetString(po_IscException, ex_what.c_str());
+ return (false);
+ } catch (...) {
+ PyErr_SetString(PyExc_SystemError,
+ "Unexpected failure in @CPPCLASS@ initialization");
+ return (false);
+ }
+
+ return (true);
+}
+} // namespace python
+} // namespace @MODULE@
+} // namespace isc
diff --git a/src/lib/util/python/wrapper_template.h b/src/lib/util/python/wrapper_template.h
new file mode 100644
index 0000000..1f983e4
--- /dev/null
+++ b/src/lib/util/python/wrapper_template.h
@@ -0,0 +1,44 @@
+// Copyright (C) @YEAR@ Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __PYTHON_ at CPPCLASS@_H
+#define __PYTHON_ at CPPCLASS@_H 1
+
+#include <Python.h>
+
+namespace isc {
+namespace @MODULE@ {
+class @CPPCLASS@;
+
+namespace python {
+
+// The s_* Class simply covers one instantiation of the object
+class s_ at CPPCLASS@ : public PyObject {
+public:
+ s_ at CPPCLASS@();
+ @CPPCLASS@* cppobj;
+};
+
+extern PyTypeObject @cppclass at _type;
+
+bool initModulePart_ at CPPCLASS@(PyObject* mod);
+
+} // namespace python
+} // namespace @MODULE@
+} // namespace isc
+#endif // __PYTHON_ at CPPCLASS@_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/time_utilities.cc b/src/lib/util/time_utilities.cc
index 229800d..9303ab5 100644
--- a/src/lib/util/time_utilities.cc
+++ b/src/lib/util/time_utilities.cc
@@ -110,12 +110,9 @@ timeToText64(uint64_t value) {
// library, it's not even declared in a header file.
namespace detail {
int64_t (*gettimeFunction)() = NULL;
-}
-namespace {
int64_t
-gettimeofdayWrapper() {
- using namespace detail;
+gettimeWrapper() {
if (gettimeFunction != NULL) {
return (gettimeFunction());
}
@@ -132,7 +129,7 @@ timeToText32(const uint32_t value) {
// We first adjust the time to the closest epoch based on the current time.
// Note that the following variables must be signed in order to handle
// time until year 2038 correctly.
- const int64_t start = gettimeofdayWrapper() - 0x7fffffff;
+ const int64_t start = detail::gettimeWrapper() - 0x7fffffff;
int64_t base = 0;
int64_t t;
while ((t = (base + value)) < start) {
diff --git a/src/lib/util/time_utilities.h b/src/lib/util/time_utilities.h
index 0558f16..a53089d 100644
--- a/src/lib/util/time_utilities.h
+++ b/src/lib/util/time_utilities.h
@@ -15,6 +15,8 @@
#ifndef __TIME_UTILITIES_H
#define __TIME_UTILITIES_H 1
+#include <string>
+
#include <sys/types.h>
#include <stdint.h>
@@ -39,6 +41,32 @@ public:
isc::Exception(file, line, what) {}
};
+namespace detail {
+/// Return the current time in seconds
+///
+/// This function returns the "current" time in seconds from epoch
+/// (00:00:00 January 1, 1970) as a 64-bit signed integer. The return
+/// value can represent a point of time before epoch as a negative number.
+///
+/// This function is provided to help test time conscious implementations
+/// such as DNSSEC and TSIG signatures. It is difficult to test them with
+/// an unusual or a specifically chosen "current" via system-provided
+/// library functions to get time. This function acts as a straightforward
+/// wrapper of such a library function, but provides test code with a hook
+/// to return an arbitrary time value: if \c isc::util::detail::gettimeFunction
+/// is set to a pointer of function that returns 64-bit signed integer,
+/// \c gettimeWrapper() calls that function instead of the system library.
+///
+/// This hook variable is specifically intended for testing purposes, so,
+/// even if it's visible outside of this library, it's not even declared in a
+/// header file.
+///
+/// If the implementation doesn't need to be tested with faked current time,
+/// it should simply use the system supplied library function instead of
+/// this one.
+int64_t gettimeWrapper();
+}
+
///
/// \name DNSSEC time conversion functions.
///
diff --git a/src/lib/util/unittests/Makefile.am b/src/lib/util/unittests/Makefile.am
index b702647..340cd1f 100644
--- a/src/lib/util/unittests/Makefile.am
+++ b/src/lib/util/unittests/Makefile.am
@@ -2,6 +2,9 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CXXFLAGS = $(B10_CXXFLAGS)
lib_LTLIBRARIES = libutil_unittests.la
-libutil_unittests_la_SOURCES = fork.h fork.cc
+libutil_unittests_la_SOURCES = fork.h fork.cc resolver.h
+libutil_unittests_la_SOURCES += newhook.h newhook.cc
+libutil_unittests_la_SOURCES += testdata.h testdata.cc
+libutil_unittests_la_SOURCES += textdata.h
CLEANFILES = *.gcno *.gcda
diff --git a/src/lib/util/unittests/newhook.cc b/src/lib/util/unittests/newhook.cc
new file mode 100644
index 0000000..9e545a5
--- /dev/null
+++ b/src/lib/util/unittests/newhook.cc
@@ -0,0 +1,51 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <stdlib.h>
+
+#include <new>
+#include <stdexcept>
+
+#include "newhook.h"
+
+#ifdef ENABLE_CUSTOM_OPERATOR_NEW
+void*
+operator new(size_t size) throw(std::bad_alloc) {
+ if (isc::util::unittests::force_throw_on_new &&
+ size == isc::util::unittests::throw_size_on_new) {
+ throw std::bad_alloc();
+ }
+ void* p = malloc(size);
+ if (p == NULL) {
+ throw std::bad_alloc();
+ }
+ return (p);
+}
+
+void
+operator delete(void* p) throw() {
+ if (p != NULL) {
+ free(p);
+ }
+}
+#endif
+
+namespace isc {
+namespace util {
+namespace unittests {
+bool force_throw_on_new = false;
+size_t throw_size_on_new = 0;
+}
+}
+}
diff --git a/src/lib/util/unittests/newhook.h b/src/lib/util/unittests/newhook.h
new file mode 100644
index 0000000..7eb8ade
--- /dev/null
+++ b/src/lib/util/unittests/newhook.h
@@ -0,0 +1,82 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __UTIL_UNITTESTS_NEWHOOK_H
+#define __UTIL_UNITTESTS_NEWHOOK_H 1
+
+/**
+ * @file newhook.h
+ * @short Enable the use of special operator new that throws for testing.
+ *
+ * This small utility allows a test case to force the global operator new
+ * to throw for a given size to test a case where memory allocation fails
+ * (which normally doesn't happen). To enable the feature, everything must
+ * be built with defining ENABLE_CUSTOM_OPERATOR_NEW beforehand, and set
+ * \c force_throw_on_new to \c true and \c throw_size_on_new to the size
+ * of data that should trigger the exception, immediately before starting
+ * the specific test that needs the exception.
+ *
+ * Example:
+ * \code #include <util/unittests/newhook.h>
+ * ...
+ * TEST(SomeTest, newException) {
+ * isc::util::unittests::force_throw_on_new = true;
+ * isc::util::unittests::throw_size_on_new = sizeof(Foo);
+ * try {
+ * // this will do 'new Foo()' internally and should throw
+ * createFoo();
+ * isc::util::unittests::force_throw_on_new = false;
+ * ASSERT_FALSE(true) << "Expected throw on new";
+ * } catch (const std::bad_alloc&) {
+ * isc::util::unittests::force_throw_on_new = false;
+ * // do some integrity check, etc, if necessary
+ * }
+ * } \endcode
+ *
+ * Replacing the global operator new (and delete) is a dangerous technique,
+ * and triggering an exception solely based on the allocation size is not
+ * reliable, so this feature is disabled by default two-fold: The
+ * ENABLE_CUSTOM_OPERATOR_NEW build time variable, and run-time
+ * \c force_throw_on_new.
+ */
+
+namespace isc {
+namespace util {
+namespace unittests {
+/// Switch to enable the use of special operator new
+///
+/// This is set to \c false by default.
+extern bool force_throw_on_new;
+
+/// The allocation size that triggers an exception in the special operator new
+///
+/// This is the exact size that causes an exception to be thrown;
+/// for example, if it is set to 100, an attempt of allocating 100 bytes
+/// will result in an exception, but allocation attempt for 101 bytes won't
+/// (unless, of course, memory is really exhausted and allocation really
+/// fails).
+///
+/// The default value is 0. The value of this variable has no meaning
+/// unless the use of the special operator is enabled at build time and
+/// via \c force_throw_on_new.
+extern size_t throw_size_on_new;
+}
+}
+}
+
+#endif // __UTIL_UNITTESTS_NEWHOOK_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/unittests/resolver.h b/src/lib/util/unittests/resolver.h
new file mode 100644
index 0000000..560a892
--- /dev/null
+++ b/src/lib/util/unittests/resolver.h
@@ -0,0 +1,193 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef UTIL_UNITTEST_RESOLVER_H
+#define UTIL_UNITTEST_RESOLVER_H
+
+/// \file resolver.h
+/// \brief Fake resolver
+
+#include <map>
+#include <dns/rrset.h>
+#include <dns/question.h>
+#include <dns/message.h>
+#include <dns/opcode.h>
+#include <dns/rcode.h>
+#include <dns/rrttl.h>
+#include <resolve/resolver_interface.h>
+#include <gtest/gtest.h>
+
+namespace isc {
+namespace util {
+namespace unittests {
+
+/// \brief Put rrset into a message as an answer
+inline static isc::dns::MessagePtr
+createResponseMessage(isc::dns::RRsetPtr answer_rrset)
+{
+ isc::dns::MessagePtr response(new isc::dns::Message(
+ isc::dns::Message::RENDER));
+ response->setOpcode(isc::dns::Opcode::QUERY());
+ response->setRcode(isc::dns::Rcode::NOERROR());
+ response->addRRset(isc::dns::Message::SECTION_ANSWER, answer_rrset);
+ return response;
+}
+
+/// \brief Mock resolver
+///
+/// This class pretends to be a resolver. However, it only stores the
+/// requests and can answer them right away by prepared answers. It doesn't
+/// do any real work and is intended for testing purposes.
+class TestResolver : public isc::resolve::ResolverInterface {
+ private:
+ bool checkIndex(size_t index) {
+ return (requests.size() > index);
+ }
+
+ typedef std::map<isc::dns::Question, isc::dns::RRsetPtr>
+ PresetAnswers;
+ PresetAnswers answers_;
+ public:
+ typedef std::pair<isc::dns::QuestionPtr, CallbackPtr> Request;
+ /// \brief List of requests the tested class sent trough resolve
+ std::vector<Request> requests;
+
+ /// \brief Destructor
+ ///
+ /// This is important. All callbacks in the requests vector must be
+ /// called to remove them from internal loops. Without this, destroying
+ /// the NSAS object will leave memory assigned.
+ ~TestResolver() {
+ for (size_t i = 0; i < requests.size(); ++i) {
+ requests[i].second->failure();
+ }
+ }
+
+ /// \brief Testing version of resolve
+ ///
+ /// If there's a prepared answer (provided by addPresetAnswer), it
+ /// answers it right away. Otherwise it just stores the request in
+ /// the requests member so it can be examined later.
+ virtual void resolve(const isc::dns::QuestionPtr& q,
+ const CallbackPtr& c)
+ {
+ PresetAnswers::iterator it(answers_.find(*q));
+ if (it == answers_.end()) {
+ requests.push_back(Request(q, c));
+ } else {
+ if (it->second) {
+ c->success(createResponseMessage(it->second));
+ } else {
+ c->failure();
+ }
+ }
+ }
+
+ /// \brief Add a preset answer.
+ ///
+ /// Add a preset answer. If shared_ptr() is passed (eg. NULL),
+ /// it will generate failure. If the question is not preset,
+ /// it goes to requests and you can answer later.
+ void addPresetAnswer(const isc::dns::Question& question,
+ isc::dns::RRsetPtr answer)
+ {
+ answers_[question] = answer;
+ }
+
+ /// \brief Thrown if the query at the given index does not exist.
+ class NoSuchRequest : public std::exception { };
+
+ /// \brief Thrown if the answer does not match the query
+ class DifferentRequest : public std::exception { };
+
+ /// \brief Provides the question of request on given answer
+ isc::dns::QuestionPtr operator[](size_t index) {
+ if (index >= requests.size()) {
+ throw NoSuchRequest();
+ }
+ return (requests[index].first);
+ }
+ /// \brief Test it asks for IP addresses
+ /// Looks if the two provided requests in resolver are A and AAAA.
+ /// Sorts them so index1 is A.
+ ///
+ /// Returns false if there aren't enough elements
+ bool asksIPs(const isc::dns::Name& name, size_t index1,
+ size_t index2)
+ {
+ size_t max = (index1 < index2) ? index2 : index1;
+ if (!checkIndex(max)) {
+ return false;
+ }
+ EXPECT_EQ(name, (*this)[index1]->getName());
+ EXPECT_EQ(name, (*this)[index2]->getName());
+ EXPECT_EQ(isc::dns::RRClass::IN(), (*this)[index1]->getClass());
+ EXPECT_EQ(isc::dns::RRClass::IN(), (*this)[index2]->getClass());
+ // If they are the other way around, swap
+ if ((*this)[index1]->getType() == isc::dns::RRType::AAAA() &&
+ (*this)[index2]->getType() == isc::dns::RRType::A())
+ {
+ TestResolver::Request tmp((*this).requests[index1]);
+ (*this).requests[index1] =
+ (*this).requests[index2];
+ (*this).requests[index2] = tmp;
+ }
+ // Check the correct addresses
+ EXPECT_EQ(isc::dns::RRType::A(), (*this)[index1]->getType());
+ EXPECT_EQ(isc::dns::RRType::AAAA(), (*this)[index2]->getType());
+ return (true);
+ }
+
+ /// \brief Answer a request
+ /// Sends a simple answer to a query.
+ /// 1) Provide index of a query and the address(es) to pass.
+ /// 2) Provide index of query and components of address to pass.
+ void answer(size_t index, isc::dns::RRsetPtr& set) {
+ if (index >= requests.size()) {
+ throw NoSuchRequest();
+ }
+ requests[index].second->success(createResponseMessage(set));
+ }
+
+ void answer(size_t index, const isc::dns::Name& name,
+ const isc::dns::RRType& type,
+ const isc::dns::rdata::Rdata& rdata, size_t TTL = 100)
+ {
+ isc::dns::RRsetPtr set(new isc::dns::RRset(name,
+ isc::dns::RRClass::IN(),
+ type,
+ isc::dns::RRTTL(TTL)));
+ set->addRdata(rdata);
+ answer(index, set);
+ }
+ /// \Answer the query at index by list of nameservers
+ void provideNS(size_t index, isc::dns::RRsetPtr nameservers)
+ {
+ if (index >= requests.size()) {
+ throw NoSuchRequest();
+ }
+ if (requests[index].first->getName() != nameservers->getName() ||
+ requests[index].first->getType() != isc::dns::RRType::NS())
+ {
+ throw DifferentRequest();
+ }
+ requests[index].second->success(createResponseMessage(nameservers));
+ }
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/lib/util/unittests/testdata.cc b/src/lib/util/unittests/testdata.cc
new file mode 100644
index 0000000..2148d31
--- /dev/null
+++ b/src/lib/util/unittests/testdata.cc
@@ -0,0 +1,61 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string>
+#include <stdexcept>
+#include <fstream>
+#include <vector>
+
+#include "testdata.h"
+
+using namespace std;
+
+namespace {
+vector<string>&
+getDataPaths() {
+ static vector<string> data_path;
+ return (data_path);
+}
+}
+
+namespace isc {
+namespace util {
+namespace unittests {
+
+void
+addTestDataPath(const string& path) {
+ getDataPaths().push_back(path);
+}
+
+void
+openTestData(const char* const datafile, ifstream& ifs) {
+ vector<string>::const_iterator it = getDataPaths().begin();
+ for (; it != getDataPaths().end(); ++it) {
+ string data_path = *it;
+ if (data_path.empty() || *data_path.rbegin() != '/') {
+ data_path.push_back('/');
+ }
+ ifs.open((data_path + datafile).c_str(), ios_base::in);
+ if (!ifs.fail()) {
+ return;
+ }
+ }
+
+ throw runtime_error("failed to open data file in data paths: " +
+ string(datafile));
+}
+
+}
+}
+}
diff --git a/src/lib/util/unittests/testdata.h b/src/lib/util/unittests/testdata.h
new file mode 100644
index 0000000..03bd83a
--- /dev/null
+++ b/src/lib/util/unittests/testdata.h
@@ -0,0 +1,54 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __UTIL_UNITTESTS_TESTDATA_H
+#define __UTIL_UNITTESTS_TESTDATA_H 1
+
+/**
+ * @file testdata.h
+ * @short Manipulating test data files.
+ *
+ * This utility defines functions that help test case handle test data
+ * stored in a file.
+ */
+
+namespace isc {
+namespace util {
+namespace unittests {
+/// Add a path (directory) that \c openTestData() will search for test data
+/// files.
+void addTestDataPath(const std::string& path);
+
+/// Open a file specified by 'datafile' using the data paths registered via
+/// addTestDataPath(). On success, ifs will be ready for reading the data
+/// stored in 'datafile'. If the data file cannot be open with any of the
+/// registered paths, a runtime_error exception will be thrown.
+///
+/// \note Care should be taken if you want to reuse the same single \c ifs
+/// for multiple input data. Some standard C++ library implementations retain
+/// the failure bit if the first stream reaches the end of the first file,
+/// and make the second call to \c ifstream::open() fail. The safest way
+/// is to use a different \c ifstream object for a new call to this function;
+/// alternatively make sure you explicitly clear the error bit by calling
+/// \c ifstream::clear() on \c ifs.
+void openTestData(const char* const datafile, std::ifstream& ifs);
+}
+}
+}
+
+#endif // __UTIL_UNITTESTS_TESTDATA_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/unittests/textdata.h b/src/lib/util/unittests/textdata.h
new file mode 100644
index 0000000..3e9b1aa
--- /dev/null
+++ b/src/lib/util/unittests/textdata.h
@@ -0,0 +1,103 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <istream>
+#include <string>
+#include <sstream>
+
+#include <gtest/gtest.h>
+
+#ifndef __UTIL_UNITTESTS_TEXTDATA_H
+#define __UTIL_UNITTESTS_TEXTDATA_H 1
+
+/**
+ * @file textdata.h
+ * @short Utilities for tests with text data.
+ *
+ * This utility provides convenient helper functions for unit tests using
+ * textual data.
+ */
+
+namespace isc {
+namespace util {
+namespace unittests {
+
+/// Line-by-line text comparison.
+///
+/// This templated function takes two standard input streams, extracts
+/// strings from them, and compares the two sets of strings line by line.
+template <typename EXPECTED_STREAM, typename ACTUAL_STREAM>
+void
+matchTextData(EXPECTED_STREAM& expected, ACTUAL_STREAM& actual) {
+ std::string actual_line;
+ std::string expected_line;
+ while (std::getline(actual, actual_line), !actual.eof()) {
+ std::getline(expected, expected_line);
+ if (expected.eof()) {
+ FAIL() << "Redundant line in actual output: " << actual_line;
+ break;
+ }
+ if (actual.bad() || actual.fail() ||
+ expected.bad() || expected.fail()) {
+ throw std::runtime_error("Unexpected error in data streams");
+ }
+ EXPECT_EQ(expected_line, actual_line);
+ }
+ while (std::getline(expected, expected_line), !expected.eof()) {
+ ADD_FAILURE() << "Missing line in actual output: " << expected_line;
+ }
+}
+
+/// Similar to the fully templated version, but takes string for the second
+/// (actual) data.
+///
+/// Due to the nature of textual data, it will often be the case that test
+/// data is given as a string object. This shortcut version helps such cases
+/// so that the test code doesn't have to create a string stream with the
+/// string data just for testing.
+template <typename EXPECTED_STREAM>
+void
+matchTextData(EXPECTED_STREAM& expected, const std::string& actual_text) {
+ std::istringstream iss(actual_text);
+ matchTextData(expected, iss);
+}
+
+/// Same for the previous version, but the first argument is string.
+template <typename ACTUAL_STREAM>
+void
+matchTextData(const std::string& expected_text, ACTUAL_STREAM& actual) {
+ std::istringstream iss(expected_text);
+ matchTextData(iss, actual);
+}
+
+/// Same for the previous two, but takes strings for both expected and
+/// actual data.
+void
+matchTextData(const std::string& expected_text,
+ const std::string& actual_text)
+{
+ std::istringstream expected_is(expected_text);
+ std::istringstream actual_is(actual_text);
+ matchTextData(expected_is, actual_is);
+}
+
+}
+}
+}
+
+#endif // __UTIL_UNITTESTS_TEXTDATA_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/tests/tools/badpacket/scan.cc b/tests/tools/badpacket/scan.cc
index b0c605c..a6e7229 100644
--- a/tests/tools/badpacket/scan.cc
+++ b/tests/tools/badpacket/scan.cc
@@ -21,10 +21,6 @@
#include <config.h>
-// on sunstudio, asio.hpp needs unistd.h for pipe() to be defined
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
#include <asio.hpp>
#include <asiolink/io_address.h>
diff --git a/tests/tools/badpacket/tests/Makefile.am b/tests/tools/badpacket/tests/Makefile.am
index 7cde4aa..e83c3b6 100644
--- a/tests/tools/badpacket/tests/Makefile.am
+++ b/tests/tools/badpacket/tests/Makefile.am
@@ -24,6 +24,7 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDFLAGS += $(top_builddir)/src/lib/log/liblog.la
run_unittests_LDFLAGS += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDFLAGS += $(top_builddir)/src/lib/util/libutil.la
run_unittests_LDADD = $(GTEST_LDADD)
endif
More information about the bind10-changes
mailing list