From 59a121d64b58c9311f447594a4b74bee41a40056 Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Wed, 5 Jun 2013 15:19:00 -0400 Subject: [PATCH] Updating FC with changes from phoenix-int --- CMakeLists.txt | 230 +- CMakeModules/FindVLD.cmake | 123 + README.md | 25 - include/fc/abstract_types.hpp | 92 - include/fc/actor.hpp | 2 +- include/fc/aligned.hpp | 4 +- include/fc/any.hpp | 6 +- include/fc/array.hpp | 30 +- include/fc/asio.hpp | 170 +- include/fc/bigint.hpp | 42 - include/fc/buffer.hpp | 21 - include/fc/crypto/base32.hpp | 10 + include/fc/crypto/base36.hpp | 10 + include/fc/{ => crypto}/base58.hpp | 0 include/fc/crypto/base64.hpp | 8 + include/fc/crypto/bigint.hpp | 70 + include/fc/{ => crypto}/blowfish.hpp | 12 +- include/fc/{ => crypto}/dh.hpp | 17 +- include/fc/crypto/elliptic.hpp | 61 + include/fc/{ => crypto}/hex.hpp | 0 include/fc/crypto/pke.hpp | 113 + include/fc/crypto/sha1.hpp | 67 + include/fc/crypto/sha256.hpp | 72 + include/fc/crypto/sha512.hpp | 72 + include/fc/{ => crypto}/super_fast_hash.hpp | 0 include/fc/error.hpp | 36 - include/fc/error_report.hpp | 76 - include/fc/example.hpp | 12 - include/fc/exception.hpp | 107 - include/fc/exception/exception.hpp | 238 + include/fc/filesystem.hpp | 57 +- include/fc/function.hpp | 112 - include/fc/fwd_impl.hpp | 4 +- include/fc/fwd_reflect.hpp | 21 - include/fc/http/connection.hpp | 64 - include/fc/interprocess/file_mapping.hpp | 2 +- include/fc/interprocess/iprocess.hpp | 66 + include/fc/interprocess/process.hpp | 36 + include/fc/invokeable.hpp | 17 - include/fc/io/base16.hpp | 13 + include/fc/io/base58.hpp | 8 + include/fc/{ => io}/base64.hpp | 0 include/fc/io/buffered_iostream.hpp | 71 + include/fc/io/datastream.hpp | 182 + .../datastream_back.hpp} | 99 +- include/fc/{ => io}/fstream.hpp | 4 +- include/fc/io/iobuffer.hpp | 81 + include/fc/io/iostream.hpp | 98 + include/fc/io/json.hpp | 56 + include/fc/{ => io}/raw.hpp | 203 +- include/fc/io/raw_fwd.hpp | 38 + include/fc/io/raw_unpack_file.hpp | 24 + include/fc/io/sstream.hpp | 31 + include/fc/io/stdio.hpp | 36 + include/fc/{ => io}/varint.hpp | 11 +- include/fc/iostream.hpp | 80 - include/fc/iostream_wrapper.hpp | 118 - include/fc/json.hpp | 54 - include/fc/json_rpc_client.hpp | 74 - include/fc/json_rpc_connection.hpp | 196 - include/fc/json_rpc_error_object.hpp | 27 - include/fc/json_rpc_process_client.hpp | 54 - include/fc/json_rpc_ssh_process_client.hpp | 33 - include/fc/json_rpc_stream_connection.hpp | 40 - include/fc/json_rpc_tcp_connection.hpp | 28 - include/fc/json_rpc_tcp_server.hpp | 42 - include/fc/lexical_cast.hpp | 98 - include/fc/log.hpp | 31 - include/fc/{ => log}/appender.hpp | 8 +- include/fc/{ => log}/console_appender.hpp | 33 +- include/fc/{ => log}/file_appender.hpp | 10 +- include/fc/log/log_message.hpp | 159 + include/fc/log/logger.hpp | 137 + include/fc/{ => log}/logger_config.hpp | 18 +- include/fc/logger.hpp | 144 - include/fc/make_fused.hpp | 10 +- include/fc/map.hpp | 18 - include/fc/{ => network}/endpoint.hpp | 0 include/fc/network/http/connection.hpp | 76 + include/fc/{ => network}/http/server.hpp | 15 +- include/fc/{ => network}/ip.hpp | 9 +- include/fc/{ => network}/tcp_socket.hpp | 13 +- include/fc/{ => network}/udp_socket.hpp | 0 include/fc/network/url.hpp | 106 + include/fc/numeric_cast.hpp | 9 - include/fc/optional.hpp | 47 +- include/fc/pke.hpp | 155 - include/fc/process.hpp | 59 - include/fc/program_options.hpp | 64 - include/fc/{ => reflect}/reflect.hpp | 12 +- include/fc/{ => reflect}/typename.hpp | 0 include/fc/reflect/variant.hpp | 99 + include/fc/rpc/json_connection.hpp | 140 + include/fc/rpc/variant_connection.hpp | 140 + include/fc/rpc/variant_stream.hpp | 36 + include/fc/server.hpp | 27 - include/fc/sha1.hpp | 69 - include/fc/sha256.hpp | 69 - include/fc/shared_impl.cpp | 84 - include/fc/shared_impl.hpp | 163 - include/fc/shared_ptr.hpp | 1 - include/fc/signal.hpp | 29 +- include/fc/signals.hpp | 9 +- include/fc/ssh/client.hpp | 44 +- include/fc/ssh/process.hpp | 53 +- include/fc/sstream.hpp | 45 - include/fc/stream.hpp | 93 - include/fc/string.hpp | 21 +- include/fc/{ => thread}/future.hpp | 47 +- include/fc/{ => thread}/mutex.hpp | 2 +- include/fc/{ => thread}/priority.hpp | 0 include/fc/{ => thread}/scoped_lock.hpp | 0 include/fc/{ => thread}/spin_lock.hpp | 1 + include/fc/{ => thread}/spin_yield_lock.hpp | 0 include/fc/{ => thread}/task.hpp | 8 +- include/fc/{ => thread}/thread.hpp | 11 +- include/fc/{ => thread}/unique_lock.hpp | 13 +- include/fc/thread/wait_condition.hpp | 68 + include/fc/thread_d.hpp | 393 -- include/fc/time.hpp | 24 +- include/fc/time_io.hpp | 18 - include/fc/unique_ptr.hpp | 60 + include/fc/url.hpp | 40 - include/fc/utility.hpp | 19 +- include/fc/value.hpp | 240 - include/fc/value_cast.hpp | 180 - include/fc/value_io.hpp | 332 -- include/fc/variant.hpp | 296 ++ include/fc/variant_object.hpp | 216 + include/fc/vector.hpp | 29 +- include/fc/vector_g.hpp | 140 - include/fc/wait_any.hpp | 6 +- src/asio.cpp | 60 +- src/bigint.cpp | 84 - src/console_appender.cpp | 56 - src/crypto/base32.cpp | 28 + src/crypto/base36.cpp | 50 + src/{ => crypto}/base58.cpp | 11 +- src/{ => crypto}/base64.cpp | 2 +- src/crypto/bigint.cpp | 177 + src/{ => crypto}/blowfish.cpp | 17 +- src/{ => crypto}/dh.cpp | 4 +- src/crypto/elliptic.cpp | 429 ++ src/{ => crypto}/hex.cpp | 6 +- src/crypto/pke.cpp | 365 ++ src/crypto/sha1.cpp | 87 + src/crypto/sha256.cpp | 100 + src/crypto/sha512.cpp | 104 + src/error_report.cpp | 189 - src/exception.cpp | 429 +- src/filesystem.cpp | 162 +- src/{ => interprocess}/file_mapping.cpp | 2 +- src/interprocess/process.cpp | 185 + src/io/buffered_iostream.cpp | 138 + src/io/datastream.cpp | 7 + src/{ => io}/fstream.cpp | 25 +- src/io/iostream.cpp | 354 ++ src/io/json.cpp | 483 ++ src/{ => io}/sstream.cpp | 48 +- src/io/varint.cpp | 10 + src/iostream.cpp | 168 - src/json.cpp | 1055 ----- src/json_rpc_connection.cpp | 167 - src/json_rpc_error_object.cpp | 13 - src/json_rpc_stream_connection.cpp | 130 - src/json_rpc_tcp_connection.cpp | 40 - src/json_rpc_tcp_server.cpp | 58 - src/lexical_cast.cpp | 29 - src/log.cpp | 66 - src/{ => log}/appender.cpp | 26 +- src/log/console_appender.cpp | 82 + {include/fc => src/log}/console_defines.h | 0 src/{ => log}/file_appender.cpp | 25 +- src/log/log_message.cpp | 210 + src/{ => log}/logger.cpp | 60 +- src/{ => log}/logger_config.cpp | 55 +- src/{ => network/http}/http_connection.cpp | 55 +- src/{ => network/http}/http_server.cpp | 52 +- src/{ => network}/ip.cpp | 26 +- src/network/resolve.cpp | 15 + src/network/tcp_socket.cpp | 91 + src/{ => network}/udp_socket.cpp | 13 +- src/network/url.cpp | 199 + src/pke.cpp | 183 - src/process.cpp | 221 - src/program_options.cpp | 72 - src/reflect.cpp | 12 - src/rpc/json_connection.cpp | 464 ++ src/sha1.cpp | 106 - src/sha256.cpp | 105 - src/ssh.cpp | 1060 ----- src/ssh/client.cpp | 717 +++ src/ssh/client_impl.hpp | 280 ++ src/ssh/process.cpp | 334 ++ src/string.cpp | 43 +- src/super_fast_hash.cpp | 84 - src/task.cpp | 29 - src/tcp_socket.cpp | 132 - src/{ => thread}/context.hpp | 72 +- src/{ => thread}/future.cpp | 44 +- src/{ => thread}/mutex.cpp | 19 +- src/{ => thread}/spin_lock.cpp | 2 +- src/{ => thread}/spin_yield_lock.cpp | 2 +- src/thread/task.cpp | 37 + src/{ => thread}/thread.cpp | 63 +- src/{ => thread}/thread_d.hpp | 125 +- src/time.cpp | 12 +- src/url.cpp | 104 - src/value.cpp | 734 --- src/value_cast.cpp | 0 src/variant.cpp | 647 +++ src/variant_object.cpp | 363 ++ src/vector.cpp | 186 - tests/json_rpc_test.cpp | 84 - tests/logger.cpp | 25 - tests/ssh.cpp | 45 - unit_tests | Bin 2012660 -> 0 bytes vendor/CMakeLists.txt | 3 - .../boost_1.51/include}/boost/atomic.hpp | 0 .../include}/boost/atomic/detail/base.hpp | 0 .../include}/boost/atomic/detail/builder.hpp | 0 .../include}/boost/atomic/detail/fallback.hpp | 0 .../boost/atomic/detail/gcc-alpha.hpp | 0 .../boost/atomic/detail/gcc-armv6+.hpp | 0 .../include}/boost/atomic/detail/gcc-ppc.hpp | 0 .../include}/boost/atomic/detail/gcc-x86.hpp | 0 .../boost/atomic/detail/generic-cas.hpp | 0 .../boost/atomic/detail/integral-casts.hpp | 0 .../boost/atomic/detail/interlocked.hpp | 0 .../boost/atomic/detail/linux-arm.hpp | 0 .../atomic/detail/valid_integral_types.hpp | 0 .../include}/boost/atomic/platform.hpp | 0 .../boost_1.51/include/boost/context/all.hpp | 14 + .../include/boost/context/detail/config.hpp | 42 + .../boost/context/detail/fcontext_arm.hpp | 66 + .../boost/context/detail/fcontext_i386.hpp | 68 + .../context/detail/fcontext_i386_win.hpp | 83 + .../boost/context/detail/fcontext_mips.hpp | 68 + .../boost/context/detail/fcontext_ppc.hpp | 70 + .../boost/context/detail/fcontext_x86_64.hpp | 66 + .../context/detail/fcontext_x86_64_win.hpp | 90 + .../include/boost/context/fcontext.hpp | 82 + .../include/boost/context/stack_allocator.hpp | 37 + .../include/boost/context/stack_utils.hpp | 41 + .../boost_1.51/include}/boost/process.hpp | 0 .../boost_1.51/include}/boost/process/all.hpp | 0 .../include}/boost/process/child.hpp | 0 .../include}/boost/process/config.hpp | 0 .../include}/boost/process/context.hpp | 0 .../boost/process/detail/basic_status.hpp | 0 .../process/detail/basic_status_service.hpp | 5 + .../boost/process/detail/posix_helpers.hpp | 0 .../boost/process/detail/status_impl.hpp | 0 .../boost/process/detail/systembuf.hpp | 0 .../boost/process/detail/windows_helpers.hpp | 0 .../include}/boost/process/environment.hpp | 0 .../include}/boost/process/handle.hpp | 0 .../include}/boost/process/operations.hpp | 14 +- .../include}/boost/process/pid_type.hpp | 0 .../include}/boost/process/pipe.hpp | 0 .../include}/boost/process/pistream.hpp | 0 .../include}/boost/process/postream.hpp | 0 .../include}/boost/process/process.hpp | 0 .../include}/boost/process/self.hpp | 0 .../include}/boost/process/status.hpp | 0 .../boost/process/stream_behavior.hpp | 0 .../include}/boost/process/stream_ends.hpp | 0 .../include}/boost/process/stream_id.hpp | 0 .../include}/boost/process/stream_type.hpp | 0 .../context/asm/fcontext_arm_aapcs_elf_gas.S | 101 + .../context/asm/fcontext_i386_ms_pe_masm.asm | 151 + .../context/asm/fcontext_i386_sysv_elf_gas.S | 122 + .../asm/fcontext_i386_sysv_macho_gas.S | 118 + .../context/asm/fcontext_mips32_o32_elf_gas.S | 144 + .../context/asm/fcontext_ppc32_sysv_elf_gas.S | 222 + .../context/asm/fcontext_ppc64_sysv_elf_gas.S | 250 ++ .../asm/fcontext_x86_64_ms_pe_masm.asm | 207 + .../asm/fcontext_x86_64_sysv_elf_gas.S | 116 + .../asm/fcontext_x86_64_sysv_macho_gas.S | 111 + vendor/boost_1.51/libs/context/fcontext.cpp | 36 + vendor/boost_1.51/libs/context/seh.cpp | 83 + .../libs/context/stack_allocator_posix.cpp | 85 + .../libs/context/stack_allocator_windows.cpp | 86 + .../libs/context/stack_utils_posix.cpp | 81 + .../libs/context/stack_utils_windows.cpp | 84 + vendor/libssh2-1.4.2/AUTHORS | 48 - vendor/libssh2-1.4.2/CMakeLists.txt | 28 - vendor/libssh2-1.4.2/COPYING | 42 - vendor/libssh2-1.4.2/ChangeLog | 1 - vendor/libssh2-1.4.2/HACKING | 13 - vendor/libssh2-1.4.2/README | 102 - vendor/libssh2-1.4.2/RELEASE-NOTES | 21 - vendor/libssh2-1.4.2/include/libssh2.h | 1188 ----- .../libssh2-1.4.2/include/libssh2_publickey.h | 118 - vendor/libssh2-1.4.2/include/libssh2_sftp.h | 345 -- vendor/libssh2-1.4.2/src/agent.c | 793 ---- vendor/libssh2-1.4.2/src/channel.c | 2570 ----------- vendor/libssh2-1.4.2/src/channel.h | 141 - vendor/libssh2-1.4.2/src/comp.c | 390 -- vendor/libssh2-1.4.2/src/comp.h | 45 - vendor/libssh2-1.4.2/src/crypt.c | 334 -- vendor/libssh2-1.4.2/src/crypto.h | 118 - vendor/libssh2-1.4.2/src/global.c | 78 - vendor/libssh2-1.4.2/src/hostkey.c | 485 -- vendor/libssh2-1.4.2/src/keepalive.c | 98 - vendor/libssh2-1.4.2/src/kex.c | 2008 --------- vendor/libssh2-1.4.2/src/knownhost.c | 1146 ----- vendor/libssh2-1.4.2/src/libgcrypt.c | 593 --- vendor/libssh2-1.4.2/src/libgcrypt.h | 150 - vendor/libssh2-1.4.2/src/libssh2_config.h | 5 - vendor/libssh2-1.4.2/src/libssh2_config_osx.h | 224 - vendor/libssh2-1.4.2/src/libssh2_config_win.h | 41 - vendor/libssh2-1.4.2/src/libssh2_priv.h | 1038 ----- vendor/libssh2-1.4.2/src/mac.c | 314 -- vendor/libssh2-1.4.2/src/mac.h | 67 - vendor/libssh2-1.4.2/src/misc.c | 612 --- vendor/libssh2-1.4.2/src/misc.h | 94 - vendor/libssh2-1.4.2/src/openssl.c | 804 ---- vendor/libssh2-1.4.2/src/openssl.h | 178 - vendor/libssh2-1.4.2/src/packet.c | 1243 ----- vendor/libssh2-1.4.2/src/packet.h | 76 - vendor/libssh2-1.4.2/src/pem.c | 213 - vendor/libssh2-1.4.2/src/publickey.c | 1058 ----- vendor/libssh2-1.4.2/src/scp.c | 1085 ----- vendor/libssh2-1.4.2/src/session.c | 1751 -------- vendor/libssh2-1.4.2/src/session.h | 93 - vendor/libssh2-1.4.2/src/sftp.c | 3278 -------------- vendor/libssh2-1.4.2/src/sftp.h | 230 - vendor/libssh2-1.4.2/src/transport.c | 873 ---- vendor/libssh2-1.4.2/src/transport.h | 87 - vendor/libssh2-1.4.2/src/userauth.c | 1687 ------- vendor/libssh2-1.4.2/src/userauth.h | 50 - vendor/libssh2-1.4.2/src/version.c | 54 - vendor/sigar/CMakeLists.txt | 33 - vendor/sigar/include/sigar.h | 943 ---- vendor/sigar/include/sigar_fileinfo.h | 157 - vendor/sigar/include/sigar_format.h | 65 - vendor/sigar/include/sigar_getline.h | 18 - vendor/sigar/include/sigar_log.h | 80 - vendor/sigar/include/sigar_private.h | 422 -- vendor/sigar/include/sigar_ptql.h | 53 - vendor/sigar/include/sigar_util.h | 191 - vendor/sigar/src/os/aix/aix_sigar.c | 2151 --------- vendor/sigar/src/os/aix/sigar_os.h | 73 - vendor/sigar/src/os/darwin/darwin_sigar.c | 3711 --------------- vendor/sigar/src/os/darwin/sigar_os.h | 89 - vendor/sigar/src/os/hpux/hpux_sigar.c | 1342 ------ vendor/sigar/src/os/hpux/sigar_os.h | 49 - vendor/sigar/src/os/linux/linux_sigar.c | 2782 ------------ vendor/sigar/src/os/linux/sigar_os.h | 82 - vendor/sigar/src/os/solaris/get_mib2.c | 321 -- vendor/sigar/src/os/solaris/get_mib2.h | 127 - vendor/sigar/src/os/solaris/kstats.c | 181 - vendor/sigar/src/os/solaris/procfs.c | 97 - vendor/sigar/src/os/solaris/sigar_os.h | 224 - vendor/sigar/src/os/solaris/solaris_sigar.c | 2717 ----------- vendor/sigar/src/os/win32/peb.c | 212 - vendor/sigar/src/os/win32/sigar_os.h | 676 --- vendor/sigar/src/os/win32/sigar_pdh.h | 47 - vendor/sigar/src/os/win32/win32_sigar.c | 3992 ----------------- vendor/sigar/src/os/win32/wmi.cpp | 243 - vendor/sigar/src/sigar.c | 2428 ---------- vendor/sigar/src/sigar_cache.c | 179 - vendor/sigar/src/sigar_fileinfo.c | 815 ---- vendor/sigar/src/sigar_format.c | 696 --- vendor/sigar/src/sigar_getline.c | 1849 -------- vendor/sigar/src/sigar_ptql.c | 1967 -------- vendor/sigar/src/sigar_signal.c | 216 - vendor/sigar/src/sigar_util.c | 1060 ----- vendor/sigar/src/sigar_version_autoconf.c | 22 - 370 files changed, 13676 insertions(+), 66345 deletions(-) create mode 100644 CMakeModules/FindVLD.cmake delete mode 100644 README.md delete mode 100644 include/fc/abstract_types.hpp delete mode 100644 include/fc/bigint.hpp delete mode 100644 include/fc/buffer.hpp create mode 100644 include/fc/crypto/base32.hpp create mode 100644 include/fc/crypto/base36.hpp rename include/fc/{ => crypto}/base58.hpp (100%) create mode 100644 include/fc/crypto/base64.hpp create mode 100644 include/fc/crypto/bigint.hpp rename include/fc/{ => crypto}/blowfish.hpp (94%) rename include/fc/{ => crypto}/dh.hpp (55%) create mode 100644 include/fc/crypto/elliptic.hpp rename include/fc/{ => crypto}/hex.hpp (100%) create mode 100644 include/fc/crypto/pke.hpp create mode 100644 include/fc/crypto/sha1.hpp create mode 100644 include/fc/crypto/sha256.hpp create mode 100644 include/fc/crypto/sha512.hpp rename include/fc/{ => crypto}/super_fast_hash.hpp (100%) delete mode 100644 include/fc/error.hpp delete mode 100644 include/fc/error_report.hpp delete mode 100644 include/fc/example.hpp delete mode 100644 include/fc/exception.hpp create mode 100644 include/fc/exception/exception.hpp delete mode 100644 include/fc/function.hpp delete mode 100644 include/fc/fwd_reflect.hpp delete mode 100644 include/fc/http/connection.hpp create mode 100644 include/fc/interprocess/iprocess.hpp create mode 100644 include/fc/interprocess/process.hpp delete mode 100644 include/fc/invokeable.hpp create mode 100644 include/fc/io/base16.hpp create mode 100644 include/fc/io/base58.hpp rename include/fc/{ => io}/base64.hpp (100%) create mode 100644 include/fc/io/buffered_iostream.hpp create mode 100644 include/fc/io/datastream.hpp rename include/fc/{datastream.hpp => io/datastream_back.hpp} (53%) rename include/fc/{ => io}/fstream.hpp (92%) create mode 100644 include/fc/io/iobuffer.hpp create mode 100644 include/fc/io/iostream.hpp create mode 100644 include/fc/io/json.hpp rename include/fc/{ => io}/raw.hpp (62%) create mode 100644 include/fc/io/raw_fwd.hpp create mode 100644 include/fc/io/raw_unpack_file.hpp create mode 100644 include/fc/io/sstream.hpp create mode 100644 include/fc/io/stdio.hpp rename include/fc/{ => io}/varint.hpp (66%) delete mode 100644 include/fc/iostream.hpp delete mode 100644 include/fc/iostream_wrapper.hpp delete mode 100644 include/fc/json.hpp delete mode 100644 include/fc/json_rpc_client.hpp delete mode 100644 include/fc/json_rpc_connection.hpp delete mode 100644 include/fc/json_rpc_error_object.hpp delete mode 100644 include/fc/json_rpc_process_client.hpp delete mode 100644 include/fc/json_rpc_ssh_process_client.hpp delete mode 100644 include/fc/json_rpc_stream_connection.hpp delete mode 100644 include/fc/json_rpc_tcp_connection.hpp delete mode 100644 include/fc/json_rpc_tcp_server.hpp delete mode 100644 include/fc/lexical_cast.hpp delete mode 100644 include/fc/log.hpp rename include/fc/{ => log}/appender.hpp (83%) rename include/fc/{ => log}/console_appender.hpp (69%) rename include/fc/{ => log}/file_appender.hpp (81%) create mode 100644 include/fc/log/log_message.hpp create mode 100644 include/fc/log/logger.hpp rename include/fc/{ => log}/logger_config.hpp (81%) delete mode 100644 include/fc/logger.hpp delete mode 100644 include/fc/map.hpp rename include/fc/{ => network}/endpoint.hpp (100%) create mode 100644 include/fc/network/http/connection.hpp rename include/fc/{ => network}/http/server.hpp (87%) rename include/fc/{ => network}/ip.hpp (83%) rename include/fc/{ => network}/tcp_socket.hpp (80%) rename include/fc/{ => network}/udp_socket.hpp (100%) create mode 100644 include/fc/network/url.hpp delete mode 100644 include/fc/numeric_cast.hpp delete mode 100644 include/fc/pke.hpp delete mode 100644 include/fc/process.hpp delete mode 100644 include/fc/program_options.hpp rename include/fc/{ => reflect}/reflect.hpp (96%) rename include/fc/{ => reflect}/typename.hpp (100%) create mode 100644 include/fc/reflect/variant.hpp create mode 100644 include/fc/rpc/json_connection.hpp create mode 100644 include/fc/rpc/variant_connection.hpp create mode 100644 include/fc/rpc/variant_stream.hpp delete mode 100644 include/fc/server.hpp delete mode 100644 include/fc/sha1.hpp delete mode 100644 include/fc/sha256.hpp delete mode 100644 include/fc/shared_impl.cpp delete mode 100644 include/fc/shared_impl.hpp delete mode 100644 include/fc/sstream.hpp delete mode 100644 include/fc/stream.hpp rename include/fc/{ => thread}/future.hpp (86%) rename include/fc/{ => thread}/mutex.hpp (98%) rename include/fc/{ => thread}/priority.hpp (100%) rename include/fc/{ => thread}/scoped_lock.hpp (100%) rename include/fc/{ => thread}/spin_lock.hpp (98%) rename include/fc/{ => thread}/spin_yield_lock.hpp (100%) rename include/fc/{ => thread}/task.hpp (95%) rename include/fc/{ => thread}/thread.hpp (91%) rename include/fc/{ => thread}/unique_lock.hpp (63%) create mode 100644 include/fc/thread/wait_condition.hpp delete mode 100644 include/fc/thread_d.hpp delete mode 100644 include/fc/time_io.hpp create mode 100644 include/fc/unique_ptr.hpp delete mode 100644 include/fc/url.hpp delete mode 100644 include/fc/value.hpp delete mode 100644 include/fc/value_cast.hpp delete mode 100644 include/fc/value_io.hpp create mode 100644 include/fc/variant.hpp create mode 100644 include/fc/variant_object.hpp delete mode 100644 include/fc/vector_g.hpp delete mode 100644 src/bigint.cpp delete mode 100644 src/console_appender.cpp create mode 100644 src/crypto/base32.cpp create mode 100644 src/crypto/base36.cpp rename src/{ => crypto}/base58.cpp (98%) rename src/{ => crypto}/base64.cpp (99%) create mode 100644 src/crypto/bigint.cpp rename src/{ => crypto}/blowfish.cpp (94%) rename src/{ => crypto}/dh.cpp (96%) create mode 100644 src/crypto/elliptic.cpp rename src/{ => crypto}/hex.cpp (87%) create mode 100644 src/crypto/pke.cpp create mode 100644 src/crypto/sha1.cpp create mode 100644 src/crypto/sha256.cpp create mode 100644 src/crypto/sha512.cpp delete mode 100644 src/error_report.cpp rename src/{ => interprocess}/file_mapping.cpp (96%) create mode 100644 src/interprocess/process.cpp create mode 100644 src/io/buffered_iostream.cpp create mode 100644 src/io/datastream.cpp rename src/{ => io}/fstream.cpp (73%) create mode 100644 src/io/iostream.cpp create mode 100644 src/io/json.cpp rename src/{ => io}/sstream.cpp (73%) create mode 100644 src/io/varint.cpp delete mode 100644 src/iostream.cpp delete mode 100644 src/json.cpp delete mode 100644 src/json_rpc_connection.cpp delete mode 100644 src/json_rpc_error_object.cpp delete mode 100644 src/json_rpc_stream_connection.cpp delete mode 100644 src/json_rpc_tcp_connection.cpp delete mode 100644 src/json_rpc_tcp_server.cpp delete mode 100644 src/lexical_cast.cpp delete mode 100644 src/log.cpp rename src/{ => log}/appender.cpp (59%) create mode 100644 src/log/console_appender.cpp rename {include/fc => src/log}/console_defines.h (100%) rename src/{ => log}/file_appender.cpp (54%) create mode 100644 src/log/log_message.cpp rename src/{ => log}/logger.cpp (59%) rename src/{ => log}/logger_config.cpp (57%) rename src/{ => network/http}/http_connection.cpp (79%) rename src/{ => network/http}/http_server.cpp (77%) rename src/{ => network}/ip.cpp (76%) create mode 100644 src/network/resolve.cpp create mode 100644 src/network/tcp_socket.cpp rename src/{ => network}/udp_socket.cpp (85%) create mode 100644 src/network/url.cpp delete mode 100644 src/pke.cpp delete mode 100644 src/process.cpp delete mode 100644 src/program_options.cpp delete mode 100644 src/reflect.cpp create mode 100644 src/rpc/json_connection.cpp delete mode 100644 src/sha1.cpp delete mode 100644 src/sha256.cpp delete mode 100644 src/ssh.cpp create mode 100644 src/ssh/client.cpp create mode 100644 src/ssh/client_impl.hpp create mode 100644 src/ssh/process.cpp delete mode 100644 src/super_fast_hash.cpp delete mode 100644 src/task.cpp delete mode 100644 src/tcp_socket.cpp rename src/{ => thread}/context.hpp (68%) rename src/{ => thread}/future.cpp (62%) rename src/{ => thread}/mutex.cpp (85%) rename src/{ => thread}/spin_lock.cpp (96%) rename src/{ => thread}/spin_yield_lock.cpp (96%) create mode 100644 src/thread/task.cpp rename src/{ => thread}/thread.cpp (84%) rename src/{ => thread}/thread_d.hpp (80%) delete mode 100644 src/url.cpp delete mode 100644 src/value.cpp delete mode 100644 src/value_cast.cpp create mode 100644 src/variant.cpp create mode 100644 src/variant_object.cpp delete mode 100644 src/vector.cpp delete mode 100644 tests/json_rpc_test.cpp delete mode 100644 tests/logger.cpp delete mode 100644 tests/ssh.cpp delete mode 100755 unit_tests delete mode 100644 vendor/CMakeLists.txt rename {include => vendor/boost_1.51/include}/boost/atomic.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/atomic/detail/base.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/atomic/detail/builder.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/atomic/detail/fallback.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/atomic/detail/gcc-alpha.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/atomic/detail/gcc-armv6+.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/atomic/detail/gcc-ppc.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/atomic/detail/gcc-x86.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/atomic/detail/generic-cas.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/atomic/detail/integral-casts.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/atomic/detail/interlocked.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/atomic/detail/linux-arm.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/atomic/detail/valid_integral_types.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/atomic/platform.hpp (100%) create mode 100644 vendor/boost_1.51/include/boost/context/all.hpp create mode 100644 vendor/boost_1.51/include/boost/context/detail/config.hpp create mode 100644 vendor/boost_1.51/include/boost/context/detail/fcontext_arm.hpp create mode 100644 vendor/boost_1.51/include/boost/context/detail/fcontext_i386.hpp create mode 100644 vendor/boost_1.51/include/boost/context/detail/fcontext_i386_win.hpp create mode 100644 vendor/boost_1.51/include/boost/context/detail/fcontext_mips.hpp create mode 100644 vendor/boost_1.51/include/boost/context/detail/fcontext_ppc.hpp create mode 100644 vendor/boost_1.51/include/boost/context/detail/fcontext_x86_64.hpp create mode 100644 vendor/boost_1.51/include/boost/context/detail/fcontext_x86_64_win.hpp create mode 100644 vendor/boost_1.51/include/boost/context/fcontext.hpp create mode 100644 vendor/boost_1.51/include/boost/context/stack_allocator.hpp create mode 100644 vendor/boost_1.51/include/boost/context/stack_utils.hpp rename {include => vendor/boost_1.51/include}/boost/process.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/all.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/child.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/config.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/context.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/detail/basic_status.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/detail/basic_status_service.hpp (94%) rename {include => vendor/boost_1.51/include}/boost/process/detail/posix_helpers.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/detail/status_impl.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/detail/systembuf.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/detail/windows_helpers.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/environment.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/handle.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/operations.hpp (93%) rename {include => vendor/boost_1.51/include}/boost/process/pid_type.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/pipe.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/pistream.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/postream.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/process.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/self.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/status.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/stream_behavior.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/stream_ends.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/stream_id.hpp (100%) rename {include => vendor/boost_1.51/include}/boost/process/stream_type.hpp (100%) create mode 100644 vendor/boost_1.51/libs/context/asm/fcontext_arm_aapcs_elf_gas.S create mode 100644 vendor/boost_1.51/libs/context/asm/fcontext_i386_ms_pe_masm.asm create mode 100644 vendor/boost_1.51/libs/context/asm/fcontext_i386_sysv_elf_gas.S create mode 100644 vendor/boost_1.51/libs/context/asm/fcontext_i386_sysv_macho_gas.S create mode 100644 vendor/boost_1.51/libs/context/asm/fcontext_mips32_o32_elf_gas.S create mode 100644 vendor/boost_1.51/libs/context/asm/fcontext_ppc32_sysv_elf_gas.S create mode 100644 vendor/boost_1.51/libs/context/asm/fcontext_ppc64_sysv_elf_gas.S create mode 100644 vendor/boost_1.51/libs/context/asm/fcontext_x86_64_ms_pe_masm.asm create mode 100644 vendor/boost_1.51/libs/context/asm/fcontext_x86_64_sysv_elf_gas.S create mode 100644 vendor/boost_1.51/libs/context/asm/fcontext_x86_64_sysv_macho_gas.S create mode 100644 vendor/boost_1.51/libs/context/fcontext.cpp create mode 100644 vendor/boost_1.51/libs/context/seh.cpp create mode 100644 vendor/boost_1.51/libs/context/stack_allocator_posix.cpp create mode 100644 vendor/boost_1.51/libs/context/stack_allocator_windows.cpp create mode 100644 vendor/boost_1.51/libs/context/stack_utils_posix.cpp create mode 100644 vendor/boost_1.51/libs/context/stack_utils_windows.cpp delete mode 100644 vendor/libssh2-1.4.2/AUTHORS delete mode 100644 vendor/libssh2-1.4.2/CMakeLists.txt delete mode 100644 vendor/libssh2-1.4.2/COPYING delete mode 100644 vendor/libssh2-1.4.2/ChangeLog delete mode 100644 vendor/libssh2-1.4.2/HACKING delete mode 100644 vendor/libssh2-1.4.2/README delete mode 100644 vendor/libssh2-1.4.2/RELEASE-NOTES delete mode 100644 vendor/libssh2-1.4.2/include/libssh2.h delete mode 100644 vendor/libssh2-1.4.2/include/libssh2_publickey.h delete mode 100644 vendor/libssh2-1.4.2/include/libssh2_sftp.h delete mode 100644 vendor/libssh2-1.4.2/src/agent.c delete mode 100644 vendor/libssh2-1.4.2/src/channel.c delete mode 100644 vendor/libssh2-1.4.2/src/channel.h delete mode 100644 vendor/libssh2-1.4.2/src/comp.c delete mode 100644 vendor/libssh2-1.4.2/src/comp.h delete mode 100644 vendor/libssh2-1.4.2/src/crypt.c delete mode 100644 vendor/libssh2-1.4.2/src/crypto.h delete mode 100644 vendor/libssh2-1.4.2/src/global.c delete mode 100644 vendor/libssh2-1.4.2/src/hostkey.c delete mode 100644 vendor/libssh2-1.4.2/src/keepalive.c delete mode 100644 vendor/libssh2-1.4.2/src/kex.c delete mode 100644 vendor/libssh2-1.4.2/src/knownhost.c delete mode 100644 vendor/libssh2-1.4.2/src/libgcrypt.c delete mode 100644 vendor/libssh2-1.4.2/src/libgcrypt.h delete mode 100644 vendor/libssh2-1.4.2/src/libssh2_config.h delete mode 100644 vendor/libssh2-1.4.2/src/libssh2_config_osx.h delete mode 100644 vendor/libssh2-1.4.2/src/libssh2_config_win.h delete mode 100644 vendor/libssh2-1.4.2/src/libssh2_priv.h delete mode 100644 vendor/libssh2-1.4.2/src/mac.c delete mode 100644 vendor/libssh2-1.4.2/src/mac.h delete mode 100644 vendor/libssh2-1.4.2/src/misc.c delete mode 100644 vendor/libssh2-1.4.2/src/misc.h delete mode 100644 vendor/libssh2-1.4.2/src/openssl.c delete mode 100644 vendor/libssh2-1.4.2/src/openssl.h delete mode 100644 vendor/libssh2-1.4.2/src/packet.c delete mode 100644 vendor/libssh2-1.4.2/src/packet.h delete mode 100644 vendor/libssh2-1.4.2/src/pem.c delete mode 100644 vendor/libssh2-1.4.2/src/publickey.c delete mode 100644 vendor/libssh2-1.4.2/src/scp.c delete mode 100644 vendor/libssh2-1.4.2/src/session.c delete mode 100644 vendor/libssh2-1.4.2/src/session.h delete mode 100644 vendor/libssh2-1.4.2/src/sftp.c delete mode 100644 vendor/libssh2-1.4.2/src/sftp.h delete mode 100644 vendor/libssh2-1.4.2/src/transport.c delete mode 100644 vendor/libssh2-1.4.2/src/transport.h delete mode 100644 vendor/libssh2-1.4.2/src/userauth.c delete mode 100644 vendor/libssh2-1.4.2/src/userauth.h delete mode 100644 vendor/libssh2-1.4.2/src/version.c delete mode 100644 vendor/sigar/CMakeLists.txt delete mode 100644 vendor/sigar/include/sigar.h delete mode 100644 vendor/sigar/include/sigar_fileinfo.h delete mode 100644 vendor/sigar/include/sigar_format.h delete mode 100644 vendor/sigar/include/sigar_getline.h delete mode 100644 vendor/sigar/include/sigar_log.h delete mode 100644 vendor/sigar/include/sigar_private.h delete mode 100644 vendor/sigar/include/sigar_ptql.h delete mode 100644 vendor/sigar/include/sigar_util.h delete mode 100644 vendor/sigar/src/os/aix/aix_sigar.c delete mode 100644 vendor/sigar/src/os/aix/sigar_os.h delete mode 100644 vendor/sigar/src/os/darwin/darwin_sigar.c delete mode 100644 vendor/sigar/src/os/darwin/sigar_os.h delete mode 100644 vendor/sigar/src/os/hpux/hpux_sigar.c delete mode 100644 vendor/sigar/src/os/hpux/sigar_os.h delete mode 100644 vendor/sigar/src/os/linux/linux_sigar.c delete mode 100644 vendor/sigar/src/os/linux/sigar_os.h delete mode 100644 vendor/sigar/src/os/solaris/get_mib2.c delete mode 100644 vendor/sigar/src/os/solaris/get_mib2.h delete mode 100644 vendor/sigar/src/os/solaris/kstats.c delete mode 100644 vendor/sigar/src/os/solaris/procfs.c delete mode 100644 vendor/sigar/src/os/solaris/sigar_os.h delete mode 100644 vendor/sigar/src/os/solaris/solaris_sigar.c delete mode 100644 vendor/sigar/src/os/win32/peb.c delete mode 100755 vendor/sigar/src/os/win32/sigar_os.h delete mode 100644 vendor/sigar/src/os/win32/sigar_pdh.h delete mode 100755 vendor/sigar/src/os/win32/win32_sigar.c delete mode 100644 vendor/sigar/src/os/win32/wmi.cpp delete mode 100644 vendor/sigar/src/sigar.c delete mode 100644 vendor/sigar/src/sigar_cache.c delete mode 100644 vendor/sigar/src/sigar_fileinfo.c delete mode 100644 vendor/sigar/src/sigar_format.c delete mode 100644 vendor/sigar/src/sigar_getline.c delete mode 100644 vendor/sigar/src/sigar_ptql.c delete mode 100644 vendor/sigar/src/sigar_signal.c delete mode 100644 vendor/sigar/src/sigar_util.c delete mode 100644 vendor/sigar/src/sigar_version_autoconf.c diff --git a/CMakeLists.txt b/CMakeLists.txt index d56f86d..7b0db49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,31 +3,47 @@ PROJECT( fc ) CMAKE_MINIMUM_REQUIRED( VERSION 2.8.0 ) SET( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules;${CMAKE_MODULE_PATH}" ) +SET( CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMakeModules;${CMAKE_MODULE_PATH}" ) INCLUDE( VersionMacros ) INCLUDE( SetupTargetMacros ) +INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR} ) +INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/include ) +INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/vendor/boost_1_51/include ) SET( DEFAULT_HEADER_INSTALL_DIR include/\${target} ) SET( DEFAULT_LIBRARY_INSTALL_DIR lib/ ) SET( DEFAULT_EXECUTABLE_INSTALL_DIR bin/ ) SET( CMAKE_DEBUG_POSTFIX _debug ) -#SET( BUILD_SHARED_LIBS NO ) - +SET( BUILD_SHARED_LIBS NO ) SET(Boost_USE_STATIC_LIBS ON) FIND_PACKAGE(Boost 1.51 COMPONENTS thread date_time system filesystem program_options signals serialization chrono unit_test_framework context ) +if( WIN32 ) + set( RPCRT4 Rpcrt4 ) + set( OPENSSL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/vendor/openssl" ) + if ( NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/vendor/openssl/lib" ) + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/vendor/openssl/out32dll" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/vendor/openssl/cmakefun") + file(RENAME "${CMAKE_CURRENT_SOURCE_DIR}/vendor/openssl/cmakefun/out32dll" "${CMAKE_CURRENT_SOURCE_DIR}/vendor/openssl/lib") + endif( NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/vendor/openssl/lib" ) +endif( WIN32 ) - -INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR} ) LINK_DIRECTORIES( ${Boost_LIBRARY_DIRS} ) IF( WIN32 ) + ADD_DEFINITIONS( -DWIN32 ) ADD_DEFINITIONS( -DBOOST_CONTEXT_NO_LIB ) ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS ) ADD_DEFINITIONS( -D_WIN32_WINNT=0x0501 ) ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) + ADD_DEFINITIONS( -DBOOST_ALL_NO_LIB -DBOOST_THREAD_BUILD_LIB) + ADD_DEFINITIONS( -DWIN32) + # Activate C++ exception handling + IF (NOT CMAKE_CXX_FLAGS MATCHES "/EHsc") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc") + ENDIF() ELSE(WIN32) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -Wno-unused-local-typedefs -fmax-errors=3" ) ENDIF(WIN32) if( UNIX ) @@ -40,82 +56,144 @@ endif() option( UNITY_BUILD OFF ) FIND_PACKAGE( OpenSSL ) -FIND_PACKAGE( ZLIB ) -include_directories( vendor/zlib-1.2.7/) -include_directories( vendor/libssh2-1.4.2/include ) +include_directories( vendor/boost_1.51/include ) include_directories( ${Boost_INCLUDE_DIR} ) include_directories( ${OPENSSL_INCLUDE_DIR} ) -include_directories( include ) -set( sources - src/logger.cpp - src/console_appender.cpp - src/file_appender.cpp - src/appender.cpp - src/logger_config.cpp - src/ssh.cpp - src/url.cpp - src/process.cpp - src/http_connection.cpp - src/http_server.cpp - src/json_rpc_connection.cpp - src/json_rpc_stream_connection.cpp - src/json_rpc_tcp_connection.cpp - src/json_rpc_tcp_server.cpp - src/json_rpc_error_object.cpp - src/error_report.cpp - src/value.cpp - src/lexical_cast.cpp - src/spin_lock.cpp - src/spin_yield_lock.cpp - src/task.cpp - src/future.cpp - src/shared_ptr.cpp - src/string.cpp - src/json.cpp - src/log.cpp - src/time.cpp - src/iostream.cpp - src/fstream.cpp - src/sstream.cpp - src/exception.cpp - src/thread.cpp - src/hex.cpp - src/sha1.cpp - src/sha256.cpp - src/filesystem.cpp - src/ip.cpp - src/bigint.cpp - src/mutex.cpp - src/pke.cpp - src/base64.cpp - src/base58.cpp - src/blowfish.cpp - src/dh.cpp - src/udp_socket.cpp - src/tcp_socket.cpp - src/asio.cpp - src/super_fast_hash.cpp - src/file_mapping.cpp - src/reflect.cpp -# src/program_options.cpp +SET( ALL_OPENSSL_LIBRARIES + ${OPENSSL_LIBRARIES} + ${SSL_EAY_RELEASE} + ${LIB_EAY_RELEASE} + ) + +set( fc_sources + src/variant.cpp + src/exception.cpp + src/variant_object.cpp + src/thread/thread.cpp + src/thread/future.cpp + src/thread/task.cpp + src/thread/spin_lock.cpp + src/thread/spin_yield_lock.cpp + src/thread/mutex.cpp + src/asio.cpp + src/string.cpp + src/shared_ptr.cpp + src/time.cpp + src/io/iostream.cpp + src/io/datastream.cpp + src/io/buffered_iostream.cpp + src/io/fstream.cpp + src/io/sstream.cpp + src/io/json.cpp + src/io/varint.cpp + src/filesystem.cpp + src/interprocess/process.cpp + src/interprocess/file_mapping.cpp + src/rpc/json_connection.cpp + src/log/log_message.cpp + src/log/logger.cpp + src/log/appender.cpp + src/log/console_appender.cpp + src/log/file_appender.cpp + src/log/logger_config.cpp + src/crypto/base36.cpp + src/crypto/bigint.cpp + src/crypto/base64.cpp + src/crypto/base58.cpp + src/crypto/hex.cpp + src/crypto/sha1.cpp + src/crypto/sha256.cpp + src/crypto/dh.cpp + src/crypto/blowfish.cpp + src/network/tcp_socket.cpp + src/network/udp_socket.cpp + src/network/http/http_connection.cpp + src/network/http/http_server.cpp + src/network/ip.cpp + src/network/resolve.cpp + src/network/url.cpp +# src/ssh/client.cpp +# src/ssh/process.cpp + ) + +IF( UNIX ) + IF( ENABLE_ARM ) + SET_PROPERTY( SOURCE + vendor/boost_1.51/libs/context/asm/fcontext_arm_aapcs_elf_gas.S + PROPERTY LANGUAGE C) + SET( boost_context_sources vendor/boost_1.51/libs/context/protected_stack_posix.cpp + vendor/boost_1.51/libs/context/stack_helper_posix.cpp + vendor/boost_1.51/libs/context/asm/fcontext_arm_aapcs_elf_gas.S + ) + ELSE() + + IF( APPLE ) + SET_PROPERTY( SOURCE + vendor/boost_1.51/libs/context/asm/fcontext_x86_64_sysv_macho_gas.S + PROPERTY LANGUAGE C) + SET( boost_context_sources vendor/boost_1.51/libs/context/stack_utils_posix.cpp + vendor/boost_1.51/libs/context/stack_allocator_posix.cpp + vendor/boost_1.51/libs/context/fcontext.cpp + vendor/boost_1.51/libs/context/asm/fcontext_x86_64_sysv_macho_gas.S + ) + ELSE (APPLE) + IF( CMAKE_SIZEOF_VOID_P EQUAL 4 ) + SET_PROPERTY( SOURCE + vendor/boost_1.51/libs/context/asm/fcontext_i386_sysv_elf_gas.S + PROPERTY LANGUAGE C) + SET( fcontext_asm vendor/boost_1.51/libs/context/asm/fcontext_i386_sysv_elf_gas.S ) + ELSE( ) + SET( fcontext_asm vendor/boost_1.51/libs/context/asm/fcontext_x86_64_sysv_elf_gas.S ) + SET_PROPERTY( SOURCE + vendor/boost_1.51/libs/context/asm/fcontext_x86_64_sysv_elf_gas.S + PROPERTY LANGUAGE C) + ENDIF( ) + + SET( boost_context_sources vendor/boost_1.51/libs/context/stack_utils_posix.cpp + vendor/boost_1.51/libs/context/stack_allocator_posix.cpp + vendor/boost_1.51/libs/context/fcontext.cpp + ${fcontext_asm} + ) + ENDIF(APPLE) + + ENDIF() +ENDIF( UNIX ) + +IF( WIN32 ) + ENABLE_LANGUAGE(ASM_MASM) +# SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHa" ) + + SET( boost_context_sources vendor/boost_1.51/libs/context/fcontext.cpp + vendor/boost_1.51/libs/context/seh.cpp + vendor/boost_1.51/libs/context/stack_allocator_windows.cpp + vendor/boost_1.51/libs/context/stack_utils_windows.cpp + vendor/boost_1.51/libs/context/seh.cpp + ) + IF( CMAKE_SIZEOF_VOID_P EQUAL 8 ) + SET( boost_context_sources ${boost_context_sources} + vendor/boost_1.51/libs/context/asm/fcontext_x86_64_ms_pe_masm.asm ) + ELSE() # 32bit + SET( boost_context_sources ${boost_context_sources} + vendor/boost_1.51/libs/context/asm/fcontext_i386_ms_pe_masm.asm ) + SET( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO" ) + message(STATUS "") + message(STATUS "Note for Visual Studio 2012 projects:") + message(STATUS " Each time CMake regenerates your projects, you will need to:") + message(STATUS " Right-click on the 'fc' project and select 'Build Customizations', and") + message(STATUS " check the 'masm' customization.") + message(STATUS " then, go to the 'Properties' for the fcontext*.asm file, and change its ") + message(STATUS " item type from 'Does not participate in build' to 'Microsoft Macro Assembler'") + ENDIF() + +ENDIF(WIN32) + +set( sources + ${fc_sources} + ${boost_context_sources} ) -add_subdirectory(vendor) +setup_library( fc SOURCES ${sources} LIBRARY_TYPE STATIC ) -#add_executable( date t.cpp ) -#target_link_libraries( date fc ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${rt_library} ${Boost_DATE_TIME_LIBRARY}) -setup_library( fc SOURCES ${sources} ) - -#setup_executable( json_rpc_test SOURCES tests/json_rpc_test.cpp LIBRARIES fc ${ZLIB_LIBRARY} ${pthread_library} ${rt_library} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${rt_library} ${Boost_DATE_TIME_LIBRARY}) -setup_executable( ssh_test SOURCES tests/ssh.cpp LIBRARIES fc ${pthread_library} ${rt_library} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${rt_library} ssh2 ${OPENSSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY} ${ZLIB_LIBRARY} ${ALL_OPENSSL_LIBRARIES} ${Boost_DATE_TIME_LIBRARY}) - -setup_executable( logger_test SOURCES tests/logger.cpp LIBRARIES fc ${pthread_library} ${rt_library} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${rt_library} ssh2 ${OPENSSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY} ${ZLIB_LIBRARY} ${ALL_OPENSSL_LIBRARIES} ${Boost_DATE_TIME_LIBRARY}) - -#add_executable( test_vec tests/vector_test.cpp ) -#target_link_libraries( test_vec fc ${Boost_SYSTEM_LIBRARY} ${Boost_CHRONO_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ) - -#add_executable( unit_tests tests/unit.cpp ) -#target_link_libraries( unit_tests fc ${Boost_CHRONO_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ) diff --git a/CMakeModules/FindVLD.cmake b/CMakeModules/FindVLD.cmake new file mode 100644 index 0000000..716625c --- /dev/null +++ b/CMakeModules/FindVLD.cmake @@ -0,0 +1,123 @@ +# Module for locating Visual Leak Detector. +# +# Customizable variables: +# VLD_ROOT_DIR +# This variable points to the Visual Leak Detector root directory. By +# default, the module looks for the installation directory by examining the +# Program Files/Program Files (x86) folders and the VLDROOT environment +# variable. +# +# Read-only variables: +# VLD_FOUND +# Indicates that the library has been found. +# +# VLD_INCLUDE_DIRS +# Points to the Visual Leak Detector include directory. +# +# VLD_LIBRARY_DIRS +# Points to the Visual Leak Detector directory that contains the libraries. +# The content of this variable can be passed to link_directories. +# +# VLD_LIBRARIES +# Points to the Visual Leak Detector libraries that can be passed to +# target_link_libararies. +# +# +# Copyright (c) 2012 Sergiu Dotenco +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +INCLUDE (FindPackageHandleStandardArgs) + +SET (_VLD_POSSIBLE_LIB_SUFFIXES lib) + +# Version 2.0 uses vld_x86 and vld_x64 instead of simply vld as library names +IF (CMAKE_SIZEOF_VOID_P EQUAL 4) + LIST (APPEND _VLD_POSSIBLE_LIB_SUFFIXES lib/Win32) +ELSEIF (CMAKE_SIZEOF_VOID_P EQUAL 8) + LIST (APPEND _VLD_POSSIBLE_LIB_SUFFIXES lib/Win64) +ENDIF (CMAKE_SIZEOF_VOID_P EQUAL 4) + +FIND_PATH (VLD_ROOT_DIR + NAMES include/vld.h + PATHS ENV VLDROOT + "$ENV{PROGRAMFILES}/Visual Leak Detector" + "$ENV{PROGRAMFILES(X86)}/Visual Leak Detector" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Visual Leak Detector;InstallLocation]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Visual Leak Detector;InstallLocation]" + DOC "VLD root directory") + +FIND_PATH (VLD_INCLUDE_DIR + NAMES vld.h + HINTS ${VLD_ROOT_DIR} + PATH_SUFFIXES include + DOC "VLD include directory") + +FIND_LIBRARY (VLD_LIBRARY_DEBUG + NAMES vld + HINTS ${VLD_ROOT_DIR} + PATH_SUFFIXES ${_VLD_POSSIBLE_LIB_SUFFIXES} + DOC "VLD debug library") + +IF (VLD_ROOT_DIR) + SET (_VLD_VERSION_FILE ${VLD_ROOT_DIR}/CHANGES.txt) + + IF (EXISTS ${_VLD_VERSION_FILE}) + SET (_VLD_VERSION_REGEX + "Visual Leak Detector \\(VLD\\) Version (([0-9]+)\\.([0-9]+)([a-z]|(.([0-9]+)))?)") + FILE (STRINGS ${_VLD_VERSION_FILE} _VLD_VERSION_TMP REGEX + ${_VLD_VERSION_REGEX}) + + STRING (REGEX REPLACE ${_VLD_VERSION_REGEX} "\\1" _VLD_VERSION_TMP + "${_VLD_VERSION_TMP}") + + STRING (REGEX REPLACE "([0-9]+).([0-9]+).*" "\\1" VLD_VERSION_MAJOR + "${_VLD_VERSION_TMP}") + STRING (REGEX REPLACE "([0-9]+).([0-9]+).*" "\\2" VLD_VERSION_MINOR + "${_VLD_VERSION_TMP}") + + SET (VLD_VERSION ${VLD_VERSION_MAJOR}.${VLD_VERSION_MINOR}) + + IF ("${_VLD_VERSION_TMP}" MATCHES "^([0-9]+).([0-9]+).([0-9]+)$") + # major.minor.patch version numbering scheme + STRING (REGEX REPLACE "([0-9]+).([0-9]+).([0-9]+)" "\\3" + VLD_VERSION_PATCH "${_VLD_VERSION_TMP}") + SET (VLD_VERSION "${VLD_VERSION}.${VLD_VERSION_PATCH}") + SET (VLD_VERSION_COUNT 3) + ELSE ("${_VLD_VERSION_TMP}" MATCHES "^([0-9]+).([0-9]+).([0-9]+)$") + # major.minor version numbering scheme. The trailing letter is ignored. + SET (VLD_VERSION_COUNT 2) + ENDIF ("${_VLD_VERSION_TMP}" MATCHES "^([0-9]+).([0-9]+).([0-9]+)$") + ENDIF (EXISTS ${_VLD_VERSION_FILE}) +ENDIF (VLD_ROOT_DIR) + +IF (VLD_LIBRARY_DEBUG) + SET (VLD_LIBRARY debug ${VLD_LIBRARY_DEBUG} CACHE DOC "VLD library") + GET_FILENAME_COMPONENT (_VLD_LIBRARY_DIR ${VLD_LIBRARY_DEBUG} PATH) + SET (VLD_LIBRARY_DIR ${_VLD_LIBRARY_DIR} CACHE PATH "VLD library directory") +ENDIF (VLD_LIBRARY_DEBUG) + +SET (VLD_INCLUDE_DIRS ${VLD_INCLUDE_DIR}) +SET (VLD_LIBRARY_DIRS ${VLD_LIBRARY_DIR}) +SET (VLD_LIBRARIES ${VLD_LIBRARY}) + +MARK_AS_ADVANCED (VLD_INCLUDE_DIR VLD_LIBRARY_DIR VLD_LIBRARY_DEBUG VLD_LIBRARY) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS (VLD REQUIRED_VARS VLD_ROOT_DIR + VLD_INCLUDE_DIR VLD_LIBRARY VERSION_VAR VLD_VERSION) diff --git a/README.md b/README.md deleted file mode 100644 index cae31d1..0000000 --- a/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Fast Compiliing C++ Library ------------------------------------------ - -In my prior attempts at developing MACE what I discovered is that compile times -would explode to unreasonable levels that hinder the rate of development more -than what can be saved by reduced typing. So I began a quest to get C++ to compile -as quickly as Java or C# and the result is this library. - -One of the major drawbacks to templates is that they place everything in header and -must be compiled with every run and generate a lot of object code. With Link Time Optimization, -the benefit of inline methods mostly disapears, leaving only static vs dynamic polymorphism. - -For the vast majority of applications, a virtual method call is not the bottleneck and the -increased compile times costs more than is otherwise justified; therefore, the Fast Compiling C++ -library opts for virtual interfaces to handle reflection instead of template interfaces. One could -argue that both types of reflection could be useful. - -Another source of slowness was the standard template library itself. Most standard template library -classes cannot be forward declared and import thousands of lines of code into every compilation unit. - -Another source of slowness is the need to include headers simply because the 'size' of the object must -be known. A new utility class allows you to 'forward declare' the size required for certain types which -allows you to remove their inclusion from the header file. - - diff --git a/include/fc/abstract_types.hpp b/include/fc/abstract_types.hpp deleted file mode 100644 index 0f54e7e..0000000 --- a/include/fc/abstract_types.hpp +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef _FC_ABSTRACT_TYPES_HPP_ -#define _FC_ABSTRACT_TYPES_HPP_ -#include -#include - -namespace fc { - - struct abstract_type { - virtual ~abstract_type(){} - virtual size_t size_of()const = 0; - /* - * @brief Inplace destructor (does not free memory) ((T*)dst)->~T(); - */ - virtual void destructor( void* dst )const = 0; - - /** @brief 'delete T' */ - virtual void destroy( void* dst )const = 0; - }; - - template - struct type : virtual abstract_type { - virtual size_t size_of()const { return sizeof(T); } - virtual void destructor( void* dst )const { ((T*)dst)->~T(); } - virtual void destroy( void* dst )const { delete ((T*)dst); } - }; - - struct abstract_moveable_type : virtual abstract_type { - virtual void move_construct( void* dst, void* src )const = 0; - virtual void move( void* dst, void* src )const = 0; - }; - - template - struct moveable_type : virtual type, virtual abstract_moveable_type { - static abstract_moveable_type& instance() { static moveable_type inst; return inst; } - virtual void destruct( void* dst )const { ((T*)dst)->~T(); } - virtual void move_construct( void* dst, void* src )const { slog( "move construct" ); new ((char*)dst) T( fc::move(*((T*)src)) ); } - virtual void move( void* dst, void* src )const { *((T*)dst) = fc::move(*((T*)src)); } - }; - - struct abstract_value_type : virtual abstract_moveable_type { - virtual void construct( void* dst )const = 0; - virtual void copy_construct( void* dst, const void* src )const = 0; - virtual void assign( void* dst, const void* src )const = 0; - }; - - /** - * Default constructable, moveable, copyable, assignable. - */ - template - struct value_type : virtual moveable_type, virtual abstract_value_type { - static abstract_value_type& instance() { static value_type inst; return inst; } - - virtual void construct( void* dst )const { new ((char*)dst) T(); } - virtual void copy_construct( void* dst, const void* src )const { new ((char*)dst) T( *((const T*)src) ); } - virtual void assign( void* dst, const void* src )const { *((T*)dst) = *((const T*)src); } - }; - - struct abstract_less_than_comparable_type { - virtual bool less_than( const void* left, const void* right )const = 0; - }; - - - template - struct less_than_comparable_type : abstract_less_than_comparable_type { - virtual bool less_than( const void* left, const void* right )const { - return *((const T*)left) < *((const T*)right); - } - }; - - struct abstract_equal_comparable_type { - virtual bool equal( const void* left, const void* right )const = 0; - }; - - template - struct equal_comparable_type : abstract_equal_comparable_type { - virtual bool equal( const void* left, const void* right )const { - return *((const T*)left) == *((const T*)right); - } - }; - - struct abstract_callable_type { - virtual void call( const void* self )const = 0; - }; - - template - struct callable_type : virtual abstract_callable_type, virtual value_type { - virtual void call( const void* self )const { (*((const T*)self))(); } - }; - -} // namespace fc - -#endif diff --git a/include/fc/actor.hpp b/include/fc/actor.hpp index 007b937..3460f48 100644 --- a/include/fc/actor.hpp +++ b/include/fc/actor.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include namespace fc { diff --git a/include/fc/aligned.hpp b/include/fc/aligned.hpp index 7bda080..b107ed1 100644 --- a/include/fc/aligned.hpp +++ b/include/fc/aligned.hpp @@ -1,5 +1,4 @@ -#ifndef _FC_ALIGNED_HPP_ -#define _FC_ALIGNED_HPP_ +#pragma once namespace fc { template @@ -13,4 +12,3 @@ namespace fc { }; } -#endif // _FC_ALIGNED_HPP_ diff --git a/include/fc/any.hpp b/include/fc/any.hpp index 632fdb5..022d29e 100644 --- a/include/fc/any.hpp +++ b/include/fc/any.hpp @@ -1,9 +1,7 @@ -#ifndef _FC_ANY_HPP_ -#define _FC_ANY_HPP_ +#pragma once #include namespace fc { + // TODO: define this without using boost typedef boost::any any; } - -#endif // _FC_ANY_HPP_ diff --git a/include/fc/array.hpp b/include/fc/array.hpp index f97ffe5..9f2b4b7 100644 --- a/include/fc/array.hpp +++ b/include/fc/array.hpp @@ -1,5 +1,6 @@ -#ifndef _FC_ARRAY_HPP_ -#define _FC_ARRAY_HPP_ +#pragma once +#include +#include namespace fc { @@ -9,6 +10,27 @@ namespace fc { T data[N]; }; -} + template + bool operator == ( const array& a, const array& b ) + { return 0 == memcmp( a.data, b.data, N ); } + template + bool operator != ( const array& a, const array& b ) + { return 0 != memcmp( a.data, b.data, N ); } -#endif // _FC_ARRAY_HPP_ + template + void to_variant( const array& bi, variant& v ) + { + v = fc::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ); + } + template + void from_variant( const variant& v, array& bi ) + { + fc::vector ve = v.as< vector >(); + if( ve.size() ) + { + memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); + } + else + memset( &bi, char(0), sizeof(bi) ); + } +} diff --git a/include/fc/asio.hpp b/include/fc/asio.hpp index c63067e..2434d2b 100644 --- a/include/fc/asio.hpp +++ b/include/fc/asio.hpp @@ -5,9 +5,8 @@ #pragma once #include #include -#include -#include -#include +#include +#include namespace fc { /** @@ -53,7 +52,7 @@ namespace asio { * This IO service is automatically running in its own thread to service asynchronous * requests without blocking any other threads. */ - boost::asio::io_service& default_io_service(); + boost::asio::io_service& default_io_service(bool cleanup = false); /** * @brief wraps boost::asio::async_read @@ -62,18 +61,6 @@ namespace asio { */ template size_t read( AsyncReadStream& s, const MutableBufferSequence& buf ) { - detail::non_blocking non_blocking; - - // TODO: determine if non_blocking query results in a system call that - // will slow down every read... - if( non_blocking(s) || non_blocking(s,true) ) { - boost::system::error_code ec; - size_t r = boost::asio::read( s, buf, ec ); - if( !ec ) return r; - if( ec != boost::asio::error::would_block ) - BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); - } - promise::ptr p(new promise("fc::asio::read")); boost::asio::async_read( s, buf, boost::bind( detail::read_write_handler, p, _1, _2 ) ); return p->wait(); @@ -92,39 +79,27 @@ namespace asio { * @return the number of bytes read. */ template - size_t read_some( AsyncReadStream& s, const MutableBufferSequence& buf ) { - detail::non_blocking non_blocking; - - // TODO: determine if non_blocking query results in a system call that - // will slow down every read... - if( non_blocking(s) || non_blocking(s,true) ) { - boost::system::error_code ec; - size_t r = s.read_some( buf, ec ); - if( !ec ) return r; - if( ec != boost::asio::error::would_block ) - BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); - } - - promise::ptr p(new promise("fc::asio::read_some")); + size_t read_some( AsyncReadStream& s, const MutableBufferSequence& buf ) + { + promise::ptr p(new promise("fc::asio::async_read_some")); s.async_read_some( buf, boost::bind( detail::read_write_handler, p, _1, _2 ) ); return p->wait(); } + template + size_t read_some( AsyncReadStream& s, boost::asio::streambuf& buf ) + { + char buffer[1024]; + size_t bytes_read = read_some( s, boost::asio::buffer( buffer, sizeof(buffer) ) ); + buf.sputn( buffer, bytes_read ); + return bytes_read; + } + /** @brief wraps boost::asio::async_write * @return the number of bytes written */ template size_t write( AsyncWriteStream& s, const ConstBufferSequence& buf ) { - detail::non_blocking non_blocking; - - if( non_blocking(s) || non_blocking(s,true) ) { - boost::system::error_code ec; - size_t r = boost::asio::write( s, buf, ec ); - if( !ec ) return r; - if( ec != boost::asio::error::would_block) { - BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); - } - } promise::ptr p(new promise("fc::asio::write")); boost::asio::async_write(s, buf, boost::bind( detail::read_write_handler, p, _1, _2 ) ); return p->wait(); @@ -137,81 +112,11 @@ namespace asio { */ template size_t write_some( AsyncWriteStream& s, const ConstBufferSequence& buf ) { - detail::non_blocking non_blocking; - - if( non_blocking(s) || non_blocking(s,true) ) { - boost::system::error_code ec; - size_t r = s.write_some( buf, ec ); - if( !ec ) return r; - if( ec != boost::asio::error::would_block) { - BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); - } - } promise::ptr p(new promise("fc::asio::write_some")); s.async_write_some( buf, boost::bind( detail::read_write_handler, p, _1, _2 ) ); return p->wait(); } - template - class sink : public boost::iostreams::sink { - public: - // struct category : boost::iostreams::sink::category {}; - typedef char type; - - sink( AsyncWriteStream& p ):m_stream(p){} - - std::streamsize write( const char* s, std::streamsize n ) { - return fc::asio::write( m_stream, boost::asio::const_buffers_1(s,n) ); - } - void close() { m_stream.close(); } - - private: - AsyncWriteStream& m_stream; - }; - - template - class source : public boost::iostreams::source { - public: - // struct category : boost::iostreams::sink::category {}; - typedef char type; - - source( AsyncReadStream& p ):m_stream(p){} - - std::streamsize read( char* s, std::streamsize n ) { - return fc::asio::read_some( m_stream, boost::asio::buffer(s,n) ); - } - void close() { m_stream.close(); } - - private: - AsyncReadStream& m_stream; - }; - template - class io_device { - public: - typedef boost::iostreams::bidirectional_device_tag category; - typedef char char_type; - - io_device( AsyncStream& p ):m_stream(p){} - - std::streamsize write( const char* s, std::streamsize n ) { - return fc::asio::write( m_stream, boost::asio::const_buffers_1(s,static_cast(n)) ); - } - std::streamsize read( char* s, std::streamsize n ) { - try { - return fc::asio::read_some( m_stream, boost::asio::buffer(s,n) ); - } catch ( const boost::system::system_error& e ) { - if( e.code() == boost::asio::error::eof ) - return -1; - throw; - } - } - void close() { m_stream.close(); } - - private: - AsyncStream& m_stream; - }; - - namespace tcp { typedef boost::asio::ip::tcp::endpoint endpoint; typedef boost::asio::ip::tcp::resolver::iterator resolver_iterator; @@ -228,7 +133,6 @@ namespace asio { promise::ptr p( new promise("fc::asio::tcp::accept") ); acc.async_accept( sock, boost::bind( fc::asio::detail::error_handler, p, _1 ) ); auto ec = p->wait(); - if( !ec ) sock.non_blocking(true); if( ec ) BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); } @@ -241,23 +145,53 @@ namespace asio { promise::ptr p(new promise("fc::asio::tcp::connect")); sock.async_connect( ep, boost::bind( fc::asio::detail::error_handler, p, _1 ) ); auto ec = p->wait(); - if( !ec ) sock.non_blocking(true); if( ec ) BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); } - - typedef boost::iostreams::stream > ostream; - typedef boost::iostreams::stream > istream; - typedef boost::iostreams::stream > iostream; - } namespace udp { typedef boost::asio::ip::udp::endpoint endpoint; typedef boost::asio::ip::udp::resolver::iterator resolver_iterator; typedef boost::asio::ip::udp::resolver resolver; /// @brief resolve all udp::endpoints for hostname:port - std::vector resolve( resolver& r, const std::string& hostname, const std::string& port ); + std::vector resolve( resolver& r, const std::string& hostname, + const std::string& port ); } + template + class istream : public virtual fc::istream + { + public: + istream( std::shared_ptr str ) + :_stream( fc::move(str) ){} + + virtual size_t readsome( char* buf, size_t len ) + { + auto r = fc::asio::read_some(*_stream, boost::asio::buffer(buf, len) ); + return r; + } + + private: + std::shared_ptr _stream; + }; + + template + class ostream : public virtual fc::ostream + { + public: + ostream( std::shared_ptr str ) + :_stream( fc::move(str) ){} + + virtual size_t writesome( const char* buf, size_t len ) + { + return fc::asio::write_some(*_stream, boost::asio::const_buffers_1(buf, len) ); + } + + virtual void close(){ _stream->close(); } + virtual void flush() {} + private: + std::shared_ptr _stream; + }; + } } // namespace fc::asio diff --git a/include/fc/bigint.hpp b/include/fc/bigint.hpp deleted file mode 100644 index 7c68f1d..0000000 --- a/include/fc/bigint.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _FC_BIGINT_HPP -#define _FC_BIGINT_HPP -#include -#include - -struct bignum_st; -typedef bignum_st BIGNUM; - -namespace fc { - class bigint { - public: - bigint( const char* bige, uint32_t l ); - bigint( unsigned long i = 0 ); - bigint( const bigint& c ); - bigint( bigint&& c ); - ~bigint(); - - bool is_negative()const; - int64_t to_int64()const; - - int64_t log2()const; - bool operator < ( const bigint& c )const; - bool operator > ( const bigint& c )const; - bool operator >= ( const bigint& c )const; - bool operator == ( const bigint& c )const; - - bigint operator + ( const bigint& a )const; - bigint operator * ( const bigint& a )const; - bigint operator / ( const bigint& a )const; - bigint operator - ( const bigint& a )const; - - bigint& operator = ( const bigint& a ); - bigint& operator = ( bigint&& a ); - - operator fc::string()const; - - private: - BIGNUM* n; - }; -} // namespace fc - -#endif diff --git a/include/fc/buffer.hpp b/include/fc/buffer.hpp deleted file mode 100644 index e6fce6d..0000000 --- a/include/fc/buffer.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _FC_BUFFER_HPP_ -#define _FC_BUFFER_HPP_ -namespace fc { - - struct const_buffer { - const_buffer( const char* const c = 0, size_t l = 0 ) - :data(c),size(l){} - const char* const data; - size_t size; - }; - - struct mutable_buffer { - mutable_buffer( char* c = 0, size_t l = 0 ) - :data(c),size(l){} - char* data; - size_t size; - }; - -} - -#endif // _FC_BUFFER_HPP_ diff --git a/include/fc/crypto/base32.hpp b/include/fc/crypto/base32.hpp new file mode 100644 index 0000000..ed81aae --- /dev/null +++ b/include/fc/crypto/base32.hpp @@ -0,0 +1,10 @@ +#pragma once +#include +#include + +namespace fc +{ + fc::vector from_base32( const fc::string& b32 ); + fc::string to_base32( const fc::vector& vec ); + fc::string to_base32( const char* data, size_t len ); +} diff --git a/include/fc/crypto/base36.hpp b/include/fc/crypto/base36.hpp new file mode 100644 index 0000000..163dabf --- /dev/null +++ b/include/fc/crypto/base36.hpp @@ -0,0 +1,10 @@ +#pragma once +#include +#include + +namespace fc +{ + fc::vector from_base36( const fc::string& b36 ); + fc::string to_base36( const fc::vector& vec ); + fc::string to_base36( const char* data, size_t len ); +} diff --git a/include/fc/base58.hpp b/include/fc/crypto/base58.hpp similarity index 100% rename from include/fc/base58.hpp rename to include/fc/crypto/base58.hpp diff --git a/include/fc/crypto/base64.hpp b/include/fc/crypto/base64.hpp new file mode 100644 index 0000000..ee92618 --- /dev/null +++ b/include/fc/crypto/base64.hpp @@ -0,0 +1,8 @@ +#pragma once +#include + +namespace fc { +std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len); +std::string base64_encode( const std::string& enc ); +std::string base64_decode( const std::string& encoded_string); +} // namespace fc diff --git a/include/fc/crypto/bigint.hpp b/include/fc/crypto/bigint.hpp new file mode 100644 index 0000000..d5e4962 --- /dev/null +++ b/include/fc/crypto/bigint.hpp @@ -0,0 +1,70 @@ +#pragma once +#include +#include +#include + +struct bignum_st; +typedef bignum_st BIGNUM; + +namespace fc { + class bigint { + public: + bigint( const fc::vector& bige ); + bigint( const char* bige, uint32_t l ); + bigint( unsigned long i = 0 ); + bigint( const bigint& c ); + bigint( bigint&& c ); + explicit bigint( BIGNUM* n ); + ~bigint(); + + bigint& operator = ( const bigint& a ); + bigint& operator = ( bigint&& a ); + + operator bool()const; + + bool is_negative()const; + int64_t to_int64()const; + + int64_t log2()const; + bigint exp( const bigint& c )const; + + static bigint random( uint32_t bits, int t, int ); + + bool operator < ( const bigint& c )const; + bool operator > ( const bigint& c )const; + bool operator >= ( const bigint& c )const; + bool operator == ( const bigint& c )const; + bool operator != ( const bigint& c )const; + + bigint operator + ( const bigint& a )const; + bigint operator * ( const bigint& a )const; + bigint operator / ( const bigint& a )const; + bigint operator % ( const bigint& a )const; + bigint operator /= ( const bigint& a ); + bigint operator - ( const bigint& a )const; + + + bigint operator++(int); + bigint& operator++(); + bigint operator--(int); + bigint& operator--(); + + operator fc::string()const; + + // returns bignum as bigendian bytes + operator fc::vector()const; + + BIGNUM* dup()const; + + BIGNUM* get()const { return n; } + private: + BIGNUM* n; + }; + + class variant; + /** encodes the big int as base64 string, or a number */ + void to_variant( const bigint& bi, variant& v ); + /** decodes the big int as base64 string, or a number */ + void from_variant( const variant& v, bigint& bi ); +} // namespace fc + diff --git a/include/fc/blowfish.hpp b/include/fc/crypto/blowfish.hpp similarity index 94% rename from include/fc/blowfish.hpp rename to include/fc/crypto/blowfish.hpp index 3cee331..2ee62b1 100644 --- a/include/fc/blowfish.hpp +++ b/include/fc/crypto/blowfish.hpp @@ -120,8 +120,7 @@ E73214A2822139CA62B343CC5B65587310DD908D0C241B2263C2CF80DA */ -#ifndef __FC_BLOWFISH_HPP__ -#define __FC_BLOWFISH_HPP__ +#pragma once #include namespace fc { @@ -150,12 +149,12 @@ public: void reset_chain() { m_oChain = m_oChain0; } // encrypt/decrypt Buffer in Place - void encrypt(unsigned char* buf, uint64_t n, int iMode=ECB); - void decrypt(unsigned char* buf, uint64_t n, int iMode=ECB); + void encrypt(unsigned char* buf, uint64_t n, int iMode=CBC); + void decrypt(unsigned char* buf, uint64_t n, int iMode=CBC); // encrypt/decrypt from Input Buffer to Output Buffer - void encrypt(const unsigned char* in, unsigned char* out, uint64_t n, int iMode=ECB); - void decrypt(const unsigned char* in, unsigned char* out, uint64_t n, int iMode=ECB); + void encrypt(const unsigned char* in, unsigned char* out, uint64_t n, int iMode=CBC); + void decrypt(const unsigned char* in, unsigned char* out, uint64_t n, int iMode=CBC); //Private Functions private: @@ -176,5 +175,4 @@ private: } // namespace fc -#endif // __BLOWFISH_H__ diff --git a/include/fc/dh.hpp b/include/fc/crypto/dh.hpp similarity index 55% rename from include/fc/dh.hpp rename to include/fc/crypto/dh.hpp index ec9112f..92c63b6 100644 --- a/include/fc/dh.hpp +++ b/include/fc/crypto/dh.hpp @@ -1,7 +1,5 @@ -#ifndef _FC_DH_HPP_ -#define _FC_DH_HPP_ -//#include -#include +#pragma once +#include #include namespace fc { @@ -11,13 +9,13 @@ namespace fc { bool generate_params( int s, uint8_t g ); bool generate_pub_key(); bool compute_shared_key( const char* buf, uint32_t s ); - bool compute_shared_key( const std::vector& pubk); + bool compute_shared_key( const vector& pubk); bool validate(); - std::vector p; - std::vector pub_key; - std::vector priv_key; - std::vector shared_key; + vector p; + vector pub_key; + vector priv_key; + vector shared_key; bool valid; uint8_t g; }; @@ -25,4 +23,3 @@ namespace fc { } // namespace fc -#endif diff --git a/include/fc/crypto/elliptic.hpp b/include/fc/crypto/elliptic.hpp new file mode 100644 index 0000000..167d663 --- /dev/null +++ b/include/fc/crypto/elliptic.hpp @@ -0,0 +1,61 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace fc { namespace ecc { + + namespace detail + { + class public_key_impl; + class private_key_impl; + } + + typedef fc::array signature; + typedef fc::array compact_signature; + + class public_key + { + public: + public_key(); + ~public_key(); + bool verify( const fc::sha256& digest, const signature& sig ); + + std::vector serialize(); + public_key( const std::vector& v ); + public_key( const compact_signature& c, const fc::sha256& digest ); + private: + friend class private_key; + fc::fwd my; + }; + + + class private_key + { + public: + private_key(); + private_key( std::vector k ); + ~private_key(); + + static private_key generate(); + static private_key regenerate( const fc::sha256& secret ); + + fc::sha256 get_secret()const; // get the private key secret + + /** + * Given a public key, calculatse a 512 bit shared secret between that + * key and this private key. + */ + fc::sha512 get_shared_secret( const public_key& pub ); + + signature sign( const fc::sha256& digest ); + compact_signature sign_compact( const fc::sha256& digest ); + bool verify( const fc::sha256& digest, const signature& sig ); + + public_key get_public_key()const; + private: + fc::fwd my; + }; +} } // fc::ecc diff --git a/include/fc/hex.hpp b/include/fc/crypto/hex.hpp similarity index 100% rename from include/fc/hex.hpp rename to include/fc/crypto/hex.hpp diff --git a/include/fc/crypto/pke.hpp b/include/fc/crypto/pke.hpp new file mode 100644 index 0000000..3f1c607 --- /dev/null +++ b/include/fc/crypto/pke.hpp @@ -0,0 +1,113 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace fc { + namespace detail { class pke_impl; } + + class private_key; + class public_key; + void generate_key_pair( public_key&, private_key& ); + + typedef std::vector bytes; + typedef bytes signature; + + class public_key + { + public: + public_key(); + explicit public_key( const bytes& d ); + public_key( const public_key& k ); + public_key( public_key&& k ); + ~public_key(); + + operator bool()const; + + public_key& operator=(const public_key& p ); + public_key& operator=(public_key&& p ); + + bool verify( const sha1& digest, const array& sig )const; + bool verify( const sha1& digest, const signature& sig )const; + bool verify( const sha256& digest, const signature& sig )const; + bytes encrypt( const char* data, size_t len )const; + bytes encrypt( const bytes& )const; + bytes decrypt( const bytes& )const; + + bytes serialize()const; + friend void generate_key_pair( public_key&, private_key& ); + private: + std::shared_ptr my; + }; + + class private_key + { + public: + private_key(); + explicit private_key( const bytes& d ); + private_key( const private_key& k ); + private_key( private_key&& k ); + ~private_key(); + + operator bool()const; + + private_key& operator=(const private_key& p ); + private_key& operator=(private_key&& p ); + + void sign( const sha1& digest, array& sig )const; + signature sign( const sha1& digest )const; + signature sign( const sha256& digest )const; + + bytes decrypt( const char* bytes, size_t len )const; + bytes decrypt( const bytes& )const; + bytes encrypt( const bytes& )const; + + bytes serialize()const; + friend void generate_key_pair( public_key&, private_key& ); + + private: + std::shared_ptr my; + }; + bool operator==( const private_key& a, const private_key& b ); + + namespace raw + { + template + void unpack( Stream& s, fc::public_key& pk) + { + bytes ser; + fc::raw::unpack(s,ser); + pk = fc::public_key( ser ); + } + + template + void pack( Stream& s, const fc::public_key& pk) + { + fc::raw::pack( s, pk.serialize() ); + } + + template + void unpack( Stream& s, fc::private_key& pk) + { + bytes ser; + fc::raw::unpack(s,ser); + pk = fc::private_key( ser ); + } + + template + void pack( Stream& s, const fc::private_key& pk) + { + fc::raw::pack( s, pk.serialize() ); + } + } + class variant; + void to_variant( const public_key& bi, variant& v ); + void from_variant( const variant& v, public_key& bi ); + void to_variant( const private_key& bi, variant& v ); + void from_variant( const variant& v, private_key& bi ); + +} // fc + diff --git a/include/fc/crypto/sha1.hpp b/include/fc/crypto/sha1.hpp new file mode 100644 index 0000000..e91503e --- /dev/null +++ b/include/fc/crypto/sha1.hpp @@ -0,0 +1,67 @@ +#pragma once +#include +#include + +namespace fc{ + +class sha1 +{ + public: + sha1(); + explicit sha1( const string& hex_str ); + + string str()const; + operator string()const; + + char* data()const; + + static sha1 hash( const char* d, uint32_t dlen ); + static sha1 hash( const string& ); + + template + static sha1 hash( const T& t ) + { + sha1::encoder e; + e << t; + return e.result(); + } + + class encoder + { + public: + encoder(); + ~encoder(); + + void write( const char* d, uint32_t dlen ); + void put( char c ) { write( &c, 1 ); } + void reset(); + sha1 result(); + + private: + struct impl; + fc::fwd my; + }; + + template + inline friend T& operator<<( T& ds, const sha1& ep ) { + ds.write( ep.data(), sizeof(ep) ); + return ds; + } + + template + inline friend T& operator>>( T& ds, sha1& ep ) { + ds.read( ep.data(), sizeof(ep) ); + return ds; + } + friend sha1 operator << ( const sha1& h1, uint32_t i ); + friend bool operator == ( const sha1& h1, const sha1& h2 ); + friend bool operator != ( const sha1& h1, const sha1& h2 ); + friend sha1 operator ^ ( const sha1& h1, const sha1& h2 ); + friend bool operator >= ( const sha1& h1, const sha1& h2 ); + friend bool operator > ( const sha1& h1, const sha1& h2 ); + friend bool operator < ( const sha1& h1, const sha1& h2 ); + + uint32_t _hash[5]; +}; + +} // namespace fc diff --git a/include/fc/crypto/sha256.hpp b/include/fc/crypto/sha256.hpp new file mode 100644 index 0000000..85a9868 --- /dev/null +++ b/include/fc/crypto/sha256.hpp @@ -0,0 +1,72 @@ +#pragma once +#include +#include + +namespace fc +{ + +class sha256 +{ + public: + sha256(); + explicit sha256( const string& hex_str ); + + string str()const; + operator string()const; + + char* data()const; + + static sha256 hash( const char* d, uint32_t dlen ); + static sha256 hash( const string& ); + + template + static sha256 hash( const T& t ) + { + sha256::encoder e; + e << t; + return e.result(); + } + + class encoder + { + public: + encoder(); + ~encoder(); + + void write( const char* d, uint32_t dlen ); + void put( char c ) { write( &c, 1 ); } + void reset(); + sha256 result(); + + private: + struct impl; + fc::fwd my; + }; + + template + inline friend T& operator<<( T& ds, const sha256& ep ) { + ds.write( ep.data(), sizeof(ep) ); + return ds; + } + + template + inline friend T& operator>>( T& ds, sha256& ep ) { + ds.read( ep.data(), sizeof(ep) ); + return ds; + } + friend sha256 operator << ( const sha256& h1, uint32_t i ); + friend bool operator == ( const sha256& h1, const sha256& h2 ); + friend bool operator != ( const sha256& h1, const sha256& h2 ); + friend sha256 operator ^ ( const sha256& h1, const sha256& h2 ); + friend bool operator >= ( const sha256& h1, const sha256& h2 ); + friend bool operator > ( const sha256& h1, const sha256& h2 ); + friend bool operator < ( const sha256& h1, const sha256& h2 ); + + uint64_t _hash[4]; +}; + + class variant; + void to_variant( const sha256& bi, variant& v ); + void from_variant( const variant& v, sha256& bi ); + +} // fc diff --git a/include/fc/crypto/sha512.hpp b/include/fc/crypto/sha512.hpp new file mode 100644 index 0000000..f926846 --- /dev/null +++ b/include/fc/crypto/sha512.hpp @@ -0,0 +1,72 @@ +#pragma once +#include +#include + +namespace fc +{ + +class sha512 +{ + public: + sha512(); + explicit sha512( const string& hex_str ); + + string str()const; + operator string()const; + + char* data()const; + + static sha512 hash( const char* d, uint32_t dlen ); + static sha512 hash( const string& ); + + template + static sha512 hash( const T& t ) + { + sha512::encoder e; + e << t; + return e.result(); + } + + class encoder + { + public: + encoder(); + ~encoder(); + + void write( const char* d, uint32_t dlen ); + void put( char c ) { write( &c, 1 ); } + void reset(); + sha512 result(); + + private: + struct impl; + fc::fwd my; + }; + + template + inline friend T& operator<<( T& ds, const sha512& ep ) { + ds.write( ep.data(), sizeof(ep) ); + return ds; + } + + template + inline friend T& operator>>( T& ds, sha512& ep ) { + ds.read( ep.data(), sizeof(ep) ); + return ds; + } + friend sha512 operator << ( const sha512& h1, uint32_t i ); + friend bool operator == ( const sha512& h1, const sha512& h2 ); + friend bool operator != ( const sha512& h1, const sha512& h2 ); + friend sha512 operator ^ ( const sha512& h1, const sha512& h2 ); + friend bool operator >= ( const sha512& h1, const sha512& h2 ); + friend bool operator > ( const sha512& h1, const sha512& h2 ); + friend bool operator < ( const sha512& h1, const sha512& h2 ); + + uint64_t _hash[8]; +}; + + class variant; + void to_variant( const sha512& bi, variant& v ); + void from_variant( const variant& v, sha512& bi ); + +} // fc diff --git a/include/fc/super_fast_hash.hpp b/include/fc/crypto/super_fast_hash.hpp similarity index 100% rename from include/fc/super_fast_hash.hpp rename to include/fc/crypto/super_fast_hash.hpp diff --git a/include/fc/error.hpp b/include/fc/error.hpp deleted file mode 100644 index b08087b..0000000 --- a/include/fc/error.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include - -namespace fc { - struct future_wait_timeout: public std::exception{ - future_wait_timeout( const fc::string& msg = "" ):m_msg(msg){} - ~future_wait_timeout()throw() {} - const char* what()const throw() { return m_msg.c_str(); } - private: - fc::string m_msg; - }; - struct task_canceled: public std::exception{}; - struct thread_quit: public std::exception{}; - struct wait_any_error: public std::exception{}; - - struct pke_exception : public std::exception {}; - struct invalid_buffer_length : public pke_exception {}; - struct invalid_key_length : public pke_exception {}; - - struct generic_exception : public std::exception { - generic_exception( const fc::string& msg = "" ):m_msg(msg){} - ~generic_exception()throw() {} - const char* what()const throw() { return m_msg.c_str(); } - private: - fc::string m_msg; - }; - - - struct bad_cast: public std::exception{ - const char* what()const throw(){ return "bad cast"; } - }; - struct range_error: public std::exception{ - const char* what()const throw(){ return "range error"; } - }; -} - diff --git a/include/fc/error_report.hpp b/include/fc/error_report.hpp deleted file mode 100644 index 726f47d..0000000 --- a/include/fc/error_report.hpp +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - -namespace fc { - - /** - * Represents one stack frame within an error_report. - */ - class error_frame { - public: - error_frame( const fc::string& file, uint64_t line, const fc::string& method, const fc::string& desc, fc::value m ); - error_frame( bool detail, const fc::string& file, uint64_t line, const fc::string& method, const fc::string& desc, fc::value m ); - error_frame():file("unknown-file"),line(0){} - error_frame(const error_frame& ); - error_frame(error_frame&& ); - - error_frame& operator=(const error_frame& ); - error_frame& operator=(error_frame&& ); - - fc::string to_string()const; - fc::string to_detail_string()const; - - fc::string desc; - fc::string file; - int64_t line; - fc::string method; - fc::optional meta; - fc::string time; - bool detail; - }; - typedef fc::vector error_context; - - /** - * This class is used for rich error reporting that captures relevant errors the - * whole way up the stack. By using FC_THROW_REPORT(...) and FC_REPORT_PUSH( e, ...) - * you can capture the file, line, and method where the error was caught / rethrown. - */ - class error_report { - public: - error_report(); - error_report( const fc::string& desc, fc::value meta = fc::value() ); - error_report( const fc::string& file, uint64_t line, const fc::string& method, const fc::string& desc, fc::value meta = fc::value() ); - - error_frame& current(); - error_report& pop_frame(); - error_report& push_frame( const fc::string& file, uint64_t line, const fc::string& method, const fc::string& desc, fc::value meta = fc::value() ); - error_report& push_frame( bool detail, const fc::string& file, uint64_t line, const fc::string& method, const fc::string& desc, fc::value meta = fc::value() ); - error_report& append( const error_report& e ); - - fc::string to_string()const; - fc::string to_detail_string()const; - error_context stack; ///< Human readable stack of what we were atempting to do. - - fc::exception_ptr copy_exception(); - }; - - fc::string substitute( const fc::string& format, const fc::value& keys ); - fc::value recursive_substitute( const value& in, const fc::value& keys ); - -} // namespace fc - -#include -FC_REFLECT( fc::error_frame, (desc)(file)(line)(method)(time)(meta)(detail) ) -FC_REFLECT( fc::error_report, (stack) ) - -#define FC_IDENT(...) __VA_ARGS__ -#define FC_REPORT( X, ... ) fc::error_report X( __FILE__, __LINE__, __func__, __VA_ARGS__ ) -#define FC_THROW_REPORT( ... ) FC_THROW( fc::error_report( __FILE__, __LINE__, __func__, __VA_ARGS__ )) -#define FC_REPORT_CURRENT(ER, ... ) (ER).pop_frame().push_frame( __FILE__, __LINE__, __func__, __VA_ARGS__ ) -#define FC_REPORT_PUSH( ER, ... ) (ER).push_frame( __FILE__, __LINE__, __func__, __VA_ARGS__ ); -#define FC_REPORT_PUSH_DETAIL( ER, ... ) (ER).push_frame( true, __FILE__, __LINE__, __func__, __VA_ARGS__ ) -#define FC_REPORT_POP(ER) (ER).pop_frame() diff --git a/include/fc/example.hpp b/include/fc/example.hpp deleted file mode 100644 index 0feaa7e..0000000 --- a/include/fc/example.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _EXAMPLE_HPP_ -#define _EXAMPLE_HPP_ -#include - - struct example { - int a; - int b; - }; - - FC_REFLECTABLE( example ) - -#endif // _EXAMPLE_HPP_ diff --git a/include/fc/exception.hpp b/include/fc/exception.hpp deleted file mode 100644 index 3b4fc55..0000000 --- a/include/fc/exception.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef _FC_EXCEPTION_HPP_ -#define _FC_EXCEPTION_HPP_ -#include -#include -#include - -// TODO: Remove boost exception dependency here!! -// TODO: Remove boost format dependency here!! - -// provided for easy integration with boost. -namespace boost { class exception_ptr; } - -namespace fc { - /** - * Simply including boost/exception_ptr.hpp is enough to significantly - * lengthen compile times. This header defines an 'opaque' exception - * type that provides the most 'general' exception handling needs without - * requiring a significant amount of code to be included. - */ - class exception_ptr { - public: - exception_ptr(); - exception_ptr( const boost::exception_ptr& c ); - exception_ptr( boost::exception_ptr&& c ); - exception_ptr( const exception_ptr& c ); - exception_ptr( exception_ptr&& c ); - ~exception_ptr(); - - exception_ptr& operator=(const boost::exception_ptr& c); - exception_ptr& operator=(boost::exception_ptr&& c); - - exception_ptr& operator=(const exception_ptr& c); - exception_ptr& operator=(exception_ptr&& c); - - fc::string diagnostic_information()const; - - operator bool()const; - - operator const boost::exception_ptr& ()const; - operator boost::exception_ptr& (); - private: - char my[sizeof(void*)*2]; - }; - - exception_ptr current_exception(); - template - inline exception_ptr copy_exception( T&& e ) { - try { throw e; } catch (...) { return current_exception(); } - return exception_ptr(); - } - void rethrow_exception( const exception_ptr& e ); - - void throw_exception( const char* func, const char* file, int line, const char* msg ); - void throw_exception_( const char* func, const char* file, int line, const char* msg, - const fc::string& a1 ); - void throw_exception_( const char* func, const char* file, int line, const char* msg, - const fc::string& a1, const fc::string& a2 ); - void throw_exception_( const char* func, const char* file, int line, const char* msg, - const fc::string& a1, const fc::string& a2, const fc::string& a3 ); - void throw_exception_( const char* func, const char* file, int line, const char* msg, - const fc::string& a1, const fc::string& a2, const fc::string& a3, const fc::string& a4 ); - - template - fc::string to_string( T&& v ) { return fc::string(fc::forward(v)); } - fc::string to_string( char v ); // { return fc::string(&v,1); } - fc::string to_string( uint64_t v ); - fc::string to_string( int64_t v ); - fc::string to_string( double v ); - fc::string to_string( float v ); - fc::string to_string( int8_t v ); - fc::string to_string( uint8_t v ); - fc::string to_string( int32_t v ); - fc::string to_string( uint32_t v ); - fc::string to_string( int16_t v ); - fc::string to_string( uint16_t v ); -// fc::string to_string( size_t v ); -// fc::string to_string( long int v ); - - template - void throw_exception( const char* func, const char* file, int line, const char* msg, T&& a1 ) { - throw_exception_( func, file, line, msg, to_string(fc::forward(a1) ) ); - } - - template - void throw_exception( const char* func, const char* file, int line, const char* msg, T1&& a1, T2&& a2 ) { - throw_exception_( func, file, line, msg, to_string(fc::forward(a1) ), to_string( fc::forward(a2) ) ); - } - template - void throw_exception( const char* func, const char* file, int line, const char* msg, T1&& a1, T2&& a2, T3&& a3 ) { - throw_exception_( func, file, line, msg, to_string(fc::forward(a1) ), to_string( fc::forward(a2) ), to_string( fc::forward(a3) ) ); - } - template - void throw_exception( const char* func, const char* file, int line, const char* msg, T1&& a1, T2&& a2, T3&& a3, T4&& a4 ) { - throw_exception_( func, file, line, msg, to_string(fc::forward(a1) ), to_string( fc::forward(a2) ), to_string( fc::forward(a3) ), to_string( fc::forward(a4) ) ); - } - - fc::string except_str(); - -} // namespace fc -#define FC_THROW(X) throw X -#define FC_THROW_MSG( ... ) \ - do { \ - fc::throw_exception( BOOST_CURRENT_FUNCTION, __FILE__, __LINE__, __VA_ARGS__ ); \ - } while(0) - - -#endif // _FC_EXCEPTION_HPP_ diff --git a/include/fc/exception/exception.hpp b/include/fc/exception/exception.hpp new file mode 100644 index 0000000..ea181db --- /dev/null +++ b/include/fc/exception/exception.hpp @@ -0,0 +1,238 @@ +#pragma once +/** + * @file exception.hpp + * @brief Defines exception's used by fc + */ +#include +#include +#include + +namespace fc +{ + namespace detail { class exception_impl; } + + /** + * @brief Used to generate a useful error report when an exception is thrown. + * @ingroup serializable + * + * At each level in the stack where the exception is caught and rethrown a + * new log_message is added to the exception. + * + * exception's are designed to be serialized to a variant and + * deserialized from an variant. + * + * @see FC_THROW_EXCEPTION + * @see FC_RETHROW_EXCEPTION + * @see FC_RETHROW_EXCEPTIONS + */ + class exception + { + public: + exception(); + exception( log_message&& ); + exception( const exception& e ); + exception( exception&& e ); + ~exception(); + + virtual const char* what()const throw() { return "exception"; } + + /** + * @return a reference to log messages that have + * been added to this log. + */ + const log_messages& get_log()const; + void append_log( log_message m ); + + /** + * Generates a detailed string including file, line, method, + * and other information that is generally only useful for + * developers. + */ + string to_detail_string( log_level ll = log_level::all )const; + + /** + * Generates a user-friendly error report. + */ + string to_string( log_level ll = log_level::info )const; + + /** + * Throw this exception as its most derived type. + * + * @note does not return. + */ + virtual NO_RETURN void dynamic_rethrow_exception()const; + + /** + * This is equivalent to: + * @code + * try { throwAsDynamic_exception(); } + * catch( ... ) { return std::current_exception(); } + * @endcode + */ + virtual std::shared_ptr dynamic_copy_exception()const; + + protected: + friend void to_variant( const exception& e, variant& v ); + friend void from_variant( const variant& e, exception& ll ); + virtual void from_variant( const variant& ){} + virtual void to_variant( variant& ){} + + std::unique_ptr my; + }; + void to_variant( const exception& e, variant& v ); + void from_variant( const variant& e, exception& ll ); + typedef std::shared_ptr exception_ptr; + + typedef optional oexception; + + + + /** + * @brief re-thrown whenever an unhandled exception is caught. + * @ingroup serializable + * Any exceptions thrown by 3rd party libraries that are not + * caught get wrapped in an unhandled_exception exception. + * + * The original exception is captured as a std::exception_ptr + * which may be rethrown. The std::exception_ptr does not + * propgate across process boundaries. + */ + class unhandled_exception : public exception + { + public: + unhandled_exception( log_message&& m, std::exception_ptr e = std::current_exception() ); + unhandled_exception( log_messages ); + unhandled_exception( const exception& ); + virtual const char* what()const throw() { return "Unhandled _exception"; } + std::exception_ptr get_inner_exception()const; + + virtual NO_RETURN void dynamic_rethrow_exception()const; + virtual std::shared_ptr dynamic_copy_exception()const; + private: + std::exception_ptr _inner; + }; + + template + fc::exception_ptr copy_exception( T&& e ) + { +#if defined(_MSC_VER) && (_MSC_VER < 1700) + return std::make_shared( log_message(), std::copy_exception(fc::forward(e)) ); +#else + return std::make_shared( log_message(), std::make_exception_ptr(fc::forward(e)) ); +#endif + } + + /** + * @brief wraps unhanlded std::exception's + * @ingroup serializable + * + * This exception allows the 'what' field of unhandled std::exceptions + * to be propagated across process boundaries. + */ + class std_exception : public unhandled_exception + { + public: + std_exception( log_message&& m, std::exception_ptr e, const char* w ); + std_exception( log_messages ); + std_exception( const exception& c); + virtual const char* what()const throw() { return _what.c_str(); } + + protected: + void from_variant( const variant& v ); + void to_variant( variant& v ); + private: + string _what; + }; + + +#define FC_DECLARE_EXCEPTION( TYPE, WHAT ) \ + class TYPE : public exception \ + { \ + public: \ + TYPE( log_message&& m ); \ + TYPE( log_messages ); \ + TYPE( const TYPE& c ); \ + TYPE(); \ + virtual const char* what()const throw() { return WHAT; } \ + }; + + FC_DECLARE_EXCEPTION( timeout_exception, "Timeout" ); + FC_DECLARE_EXCEPTION( file_not_found_exception, "File Not Found" ); + /** + * @brief report's parse errors + */ + FC_DECLARE_EXCEPTION( parse_error_exception, "Parse Error" ); + FC_DECLARE_EXCEPTION( invalid_arg_exception, "Invalid Argument" ); + /** + * @brief reports when a key, guid, or other item is not found. + */ + FC_DECLARE_EXCEPTION( key_not_found_exception, "Key Not Found" ); + FC_DECLARE_EXCEPTION( bad_cast_exception, "Bad Cast" ); + FC_DECLARE_EXCEPTION( out_of_range_exception, "Out of Range" ); + + /** @brief if an operation is unsupported or not valid this may be thrown */ + FC_DECLARE_EXCEPTION( invalidOperation_exception, "Invalid Operation" ); + + /** + * @brief used to report a canceled Operation + */ + FC_DECLARE_EXCEPTION( canceled_exception, "Canceled" ); + /** + * @brief used inplace of assert() to report violations of pre conditions. + */ + FC_DECLARE_EXCEPTION( assert_exception, "Assert Exception" ); + FC_DECLARE_EXCEPTION( eof_exception, "End Of File" ); + + fc::string except_str(); + + +} // namespace fc +/** + * @brief Checks a condition and throws an assert_exception if the test is FALSE + */ +#define FC_ASSERT( TEST, ... ) \ +if( !(TEST) ) { FC_THROW_EXCEPTION( assert_exception, #TEST __VA_ARGS__ ); } + +#define FC_THROW( FORMAT, ... ) \ + throw fc::exception( FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ ) ) + +#define FC_EXCEPTION( EXCEPTION_TYPE, FORMAT, ... ) \ + fc::EXCEPTION_TYPE( FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ ) ) +/** + * @def FC_THROW_EXCEPTION( EXCEPTION, FORMAT, ... ) + * @param EXCEPTION a class in the Phoenix::Athena::API namespace that inherits + * @param format - a const char* string with "${keys}" + */ +#define FC_THROW_EXCEPTION( EXCEPTION, FORMAT, ... ) \ + throw fc::EXCEPTION( FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ ) ) + + +/** + * @def FC_RETHROW_EXCEPTION(ER,LOG_LEVEL,FORMAT,...) + * @brief Appends a log_message to the exception ER and rethrows it. + */ +#define FC_RETHROW_EXCEPTION( ER, LOG_LEVEL, FORMAT, ... ) \ + do { \ + er.append_log( FC_LOG_MESSAGE( LOG_LEVEL, FORMAT, __VA_ARGS__ ) ); \ + throw;\ + } while(false) + +/** + * @def FC_RETHROW_EXCEPTIONS(LOG_LEVEL,FORMAT,...) + * @brief Catchs all exception's, std::exceptions, and ... and rethrows them after + * appending the provided log message. + */ +#define FC_RETHROW_EXCEPTIONS( LOG_LEVEL, FORMAT, ... ) \ + catch( fc::exception& er ) { \ + FC_RETHROW_EXCEPTION( er, LOG_LEVEL, FORMAT, __VA_ARGS__ ); \ + } catch( const std::exception& e ) { \ + throw fc::std_exception( \ + FC_LOG_MESSAGE( LOG_LEVEL, FORMAT,__VA_ARGS__), \ + std::current_exception(), \ + e.what() ) ; \ + } catch( ... ) { \ + throw fc::unhandled_exception( \ + FC_LOG_MESSAGE( LOG_LEVEL, FORMAT,__VA_ARGS__), \ + std::current_exception() ); \ + } + diff --git a/include/fc/filesystem.hpp b/include/fc/filesystem.hpp index 5cea39e..988d11c 100644 --- a/include/fc/filesystem.hpp +++ b/include/fc/filesystem.hpp @@ -1,6 +1,8 @@ #pragma once +#include #include -#include +#include +#include #include namespace boost { @@ -60,6 +62,9 @@ namespace fc { bool is_relative()const; bool is_absolute()const; + + static char separator_char; + private: fwd _p; }; @@ -104,20 +109,64 @@ namespace fc { void create_directories( const path& p ); void remove_all( const path& p ); path absolute( const path& p ); + path make_relative(const path& from, const path& to); path canonical( const path& p ); uint64_t file_size( const path& p ); bool remove( const path& p ); void copy( const path& from, const path& to ); void rename( const path& from, const path& to ); + void create_hard_link( const path& from, const path& to ); path unique_path(); path temp_directory_path(); - class value; - void pack( fc::value& , const fc::path& ); - void unpack( const fc::value& , fc::path& ); + class variant; + void to_variant( const fc::path&, fc::variant& ); + void from_variant( const fc::variant& , fc::path& ); template<> struct get_typename { static const char* name() { return "path"; } }; + + /** + * Class which creates a temporary directory inside an existing temporary directory. + */ + class temp_file_base + { + public: + inline ~temp_file_base() { remove(); } + inline operator bool() const { return _path; } + inline bool operator!() const { return !_path; } + const fc::path& path() const; + void remove(); + void release(); + protected: + typedef fc::optional path_t; + inline temp_file_base(const path_t& path) : _path(path) {} + inline temp_file_base(path_t&& path) : _path(std::move(path)) {} + path_t _path; + }; + + /** + * Class which creates a temporary directory inside an existing temporary directory. + */ + class temp_file : public temp_file_base + { + public: + temp_file(temp_file&& other); + temp_file& operator=(temp_file&& other); + temp_file(const fc::path& tempFolder = fc::temp_directory_path(), bool create = false); + }; + + /** + * Class which creates a temporary directory inside an existing temporary directory. + */ + class temp_directory : public temp_file_base + { + public: + temp_directory(temp_directory&& other); + temp_directory& operator=(temp_directory&& other); + temp_directory(const fc::path& tempFolder = fc::temp_directory_path()); + }; + } diff --git a/include/fc/function.hpp b/include/fc/function.hpp deleted file mode 100644 index 6aec96e..0000000 --- a/include/fc/function.hpp +++ /dev/null @@ -1,112 +0,0 @@ -#if 0 -#pragma once -#include -#include -namespace fc { -template -class function { - public: - function(){} - - template - function( Functor&& f ) - :func( new impl( fc::forward(f) ) ){}; - - function( const function& c ):func(c.func){} - function( function&& c ) { fc::swap( func, c.func); } - ~function(){} - - template - function& operator=( Functor&& f ) { - func.reset( new impl( fc::forward(f) ) ); - return *this; - } - - function& operator=( const function& c ) { func = c.func; return *this; } - function& operator=( function&& c ) { fc::swap(func,c.func); return *this; } - - R operator()( Args... args)const { return func->call(args...); } - - bool operator!()const { return !func; } - - protected: - - struct impl_base : public fc::retainable { - virtual ~impl_base(){} - virtual R call(Args...)const = 0; - }; - - template - struct impl : impl_base { - template - impl( U&& u ):func( fc::forward(u) ){} - - virtual R call(Args... args)const { return func(args...); } - - Functor func; - }; - function( const fc::shared_ptr& f ):func(f){} - function( fc::shared_ptr&& f ):func(fc::move(f)){} - - fc::shared_ptr func; -}; - -/** - * Provides functionality similar to boost::function. - * - * Functions have 'reference semantics', meaning that copies will all - * refer to the same underlying function. - * - * TODO: Small functions are allocated on the stack, large functors are - * allocated on the heap. - * - * Simply including boost/function adds an additional 0.6 seconds to every - * object file compared to using fc/function. - * - * Including on the other hand adds a mere 0.05 - * seconds to every object file compared to fc/function. - */ -template -class function : public function { - public: - function(){} - template - function( U&& u ) { *this = fc::forward(u); } - using function::operator=; -}; - -template -class function : public function { - public: - function(){} - function( const function& u ):function(u){} - function( function&& u ):function(u){} - function( const function& u ):function(u.func){} - function( function&& u ):function(fc::move(u.func)){} - - using function::operator=; -}; - -template -class function : public function { - public: - function(){} - template - function( U&& u ):function( fc::forward(u) ){} - function( const function& c ):function(c.func){} - using function::operator=; -}; - -template -class function : public function { - public: - function(){} - template - function( U&& u ):function( fc::forward(u) ){} - function( const function& c ):function(c.func){} - using function::operator=; -}; - -} -#endif - diff --git a/include/fc/fwd_impl.hpp b/include/fc/fwd_impl.hpp index c5862ce..639085a 100644 --- a/include/fc/fwd_impl.hpp +++ b/include/fc/fwd_impl.hpp @@ -1,5 +1,4 @@ -#ifndef _FC_FWD_IMPL_HPP_ -#define _FC_FWD_IMPL_HPP_ +#pragma once #include #include @@ -134,4 +133,3 @@ namespace fc { } // namespace fc -#endif //_FC_FWD_IMPL_HPP_ diff --git a/include/fc/fwd_reflect.hpp b/include/fc/fwd_reflect.hpp deleted file mode 100644 index 62b5bfe..0000000 --- a/include/fc/fwd_reflect.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _FC_FWD_REFLECT_HPP_ -#define _FC_FWD_REFLECT_HPP_ -#include -#include - -namespace fc { - template - class reflector> : public detail::reflector_impl, reflector> >{ - public: - virtual const char* name()const { return instance().name(); } - virtual void visit( void* s, const abstract_visitor& v )const { - instance().visit(s,v); - } - virtual void visit( const void* s, const abstract_const_visitor& v )const { - instance().visit(s,v); - } - - static reflector& instance() { return reflector::instance(); } - }; -} // namespace fc -#endif //_FC_FWD_REFLECT_HPP_ diff --git a/include/fc/http/connection.hpp b/include/fc/http/connection.hpp deleted file mode 100644 index 0f71530..0000000 --- a/include/fc/http/connection.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once -#include -#include -#include - -namespace fc { - namespace ip { class endpoint; } - class tcp_socket; - - namespace http { - - struct header { - header( fc::string k, fc::string v ) - :key(fc::move(k)),val(fc::move(v)){} - header(){} - fc::string key; - fc::string val; - }; - - struct reply { - enum status_code { - OK = 200, - RecordCreated = 201, - NotFound = 404, - Found = 302, - InternalServerError = 500 - }; - reply( status_code c = OK):status(c){} - int status; - fc::vector
headers; - fc::vector body; - }; - - struct request { - fc::string get_header( const fc::string& key )const; - fc::string method; - fc::string domain; - fc::string path; - fc::vector
headers; - fc::vector body; - }; - - fc::vector
parse_urlencoded_params( const fc::string& f ); - - /** - * Connections have reference semantics, all copies refer to the same - * underlying socket. - */ - class connection { - public: - // used for clients - void connect_to( const fc::ip::endpoint& ep ); - http::reply request( const fc::string& method, const fc::string& url, const fc::string& body ); - - // used for servers - fc::tcp_socket& get_socket()const; - - http::request read_request()const; - - FC_REFERENCE_TYPE(connection) - }; - -} } // fc::http - diff --git a/include/fc/interprocess/file_mapping.hpp b/include/fc/interprocess/file_mapping.hpp index 18f9e01..00863e8 100644 --- a/include/fc/interprocess/file_mapping.hpp +++ b/include/fc/interprocess/file_mapping.hpp @@ -25,7 +25,7 @@ namespace fc { }; class mapped_region { public: - mapped_region( const file_mapping& fm, mode_t m, size_t start, size_t size ); + mapped_region( const file_mapping& fm, mode_t m, uint64_t start, size_t size ); mapped_region( const file_mapping& fm, mode_t m ); ~mapped_region(); void flush(); diff --git a/include/fc/interprocess/iprocess.hpp b/include/fc/interprocess/iprocess.hpp new file mode 100644 index 0000000..77d9ce6 --- /dev/null +++ b/include/fc/interprocess/iprocess.hpp @@ -0,0 +1,66 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace fc +{ + /** + * @brief abstract interface for interacting with external processes + * + * At the very least we have ssh::process and direct child processes, and + * there may be other processes that need to implement this protocol. + */ + class iprocess + { + public: + enum exec_opts { + open_none = 0, + open_stdin = 0x01, + open_stdout = 0x02, + open_stderr = 0x04, + open_all = open_stdin|open_stdout|open_stderr, + }; + + virtual ~iprocess(){} + + /** + * + * @return *this + */ + virtual iprocess& exec( const fc::path& exe, vector args, + const fc::path& work_dir = fc::path(), exec_opts opts = open_all ) = 0; + + /** + * @return blocks until the process exits + */ + virtual int result() = 0; + + + /** + * Forcefully kills the process. + */ + virtual void kill() = 0; + + /** + * @brief returns a stream that writes to the process' stdin + */ + virtual fc::buffered_ostream_ptr in_stream() = 0; + + /** + * @brief returns a stream that reads from the process' stdout + */ + virtual fc::buffered_istream_ptr out_stream() = 0; + /** + * @brief returns a stream that reads from the process' stderr + */ + virtual fc::buffered_istream_ptr err_stream() = 0; + + }; + + typedef std::shared_ptr iprocess_ptr; + + +} // namespace fc diff --git a/include/fc/interprocess/process.hpp b/include/fc/interprocess/process.hpp new file mode 100644 index 0000000..54813b8 --- /dev/null +++ b/include/fc/interprocess/process.hpp @@ -0,0 +1,36 @@ +#pragma once +#include + +namespace fc { + + fc::path find_executable_in_path( const fc::string name ); + + /** + * @brief start and manage an local process + * @note this class implements reference semantics. + */ + class process : public iprocess + { + public: + process(); + ~process(); + + virtual iprocess& exec( const fc::path& exe, + vector args, + const fc::path& work_dir = fc::path(), + exec_opts opts = open_all ); + + virtual int result(); + virtual void kill(); + virtual fc::buffered_ostream_ptr in_stream(); + virtual fc::buffered_istream_ptr out_stream(); + virtual fc::buffered_istream_ptr err_stream(); + + class impl; + private: + std::unique_ptr my; + }; + + typedef std::shared_ptr process_ptr; + +} // namespace fc diff --git a/include/fc/invokeable.hpp b/include/fc/invokeable.hpp deleted file mode 100644 index ee7d9e4..0000000 --- a/include/fc/invokeable.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _FC_INVOKEABLE_HPP_ -#define _FC_INVOKEABLE_HPP_ - -namespace fc { - - class invokeable { - public: - virtual ~invokeable(){}; - - virtual void invoke( const promise::ptr& prom, const string& name, size_t num_params, reflect::cref* params ); - - void invoke( const std::string& name ) { invoke( promise::ptr(), name, 0, 0 ); } - }; - -} - -#endif // _FC_INVOKEABLE_HPP_ diff --git a/include/fc/io/base16.hpp b/include/fc/io/base16.hpp new file mode 100644 index 0000000..f3ca29e --- /dev/null +++ b/include/fc/io/base16.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include + +namespace fc { + uint8_t from_hex( char c ); + fc::string to_hex( const char* d, uint32_t s ); + + /** + * @return the number of bytes decoded + */ + size_t from_hex( const fc::string& hex_str, char* out_data, size_t out_data_len ); +} diff --git a/include/fc/io/base58.hpp b/include/fc/io/base58.hpp new file mode 100644 index 0000000..71beb15 --- /dev/null +++ b/include/fc/io/base58.hpp @@ -0,0 +1,8 @@ +#pragma once +#include + +namespace fc { + fc::string to_base58( const char* d, size_t s ); + fc::vector from_base58( const fc::string& base58_str ); + size_t from_base58( const fc::string& base58_str, char* out_data, size_t out_data_len ); +} diff --git a/include/fc/base64.hpp b/include/fc/io/base64.hpp similarity index 100% rename from include/fc/base64.hpp rename to include/fc/io/base64.hpp diff --git a/include/fc/io/buffered_iostream.hpp b/include/fc/io/buffered_iostream.hpp new file mode 100644 index 0000000..5ebb566 --- /dev/null +++ b/include/fc/io/buffered_iostream.hpp @@ -0,0 +1,71 @@ +#pragma once +#include + +namespace fc +{ + namespace detail + { + class buffered_istream_impl; + class buffered_ostream_impl; + } + + /** + * @brief Reads data from an unbuffered stream + * and enables peek functionality. + */ + class buffered_istream : public virtual istream + { + public: + buffered_istream( istream_ptr is ); + buffered_istream( buffered_istream&& o ); + + buffered_istream& operator=( buffered_istream&& i ); + + virtual ~buffered_istream(); + + /** read at least 1 byte or throw, if no data is available + * this method should block cooperatively until data is + * available or fc::eof_exception is thrown. + * + * @pre len > 0 + * @pre buf != nullptr + * @throws fc::eof if at least 1 byte cannot be read + **/ + virtual std::size_t readsome( char* buf, std::size_t len ); + + /** + * This method may block until at least 1 character is + * available. + */ + char peek()const; + + private: + std::unique_ptr my; + }; + typedef std::shared_ptr buffered_istream_ptr; + + + /** + * + */ + class buffered_ostream : public virtual ostream + { + public: + buffered_ostream( ostream_ptr o, size_t bufsize = 4096 ); + buffered_ostream( buffered_ostream&& m ); + ~buffered_ostream(); + + buffered_ostream& operator=( buffered_ostream&& m ); + /** + * This method will return immediately unless the buffer + * is full, in which case it will flush which may block. + */ + virtual size_t writesome( const char* buf, size_t len ); + + virtual void close(); + virtual void flush(); + private: + std::unique_ptr my; + }; + typedef std::shared_ptr buffered_ostream_ptr; +} diff --git a/include/fc/io/datastream.hpp b/include/fc/io/datastream.hpp new file mode 100644 index 0000000..5e54998 --- /dev/null +++ b/include/fc/io/datastream.hpp @@ -0,0 +1,182 @@ +#pragma once +#include +#include +#include + +namespace fc { + +namespace detail +{ + NO_RETURN void throw_datastream_range_error( const char* file, size_t len, size_t over ); +} + +/** + * The purpose of this datastream is to provide a fast, effecient, means + * of calculating the amount of data "about to be written" and then + * writing it. This means having two modes of operation, "test run" where + * you call the entire pack sequence calculating the size, and then + * actually packing it after doing a single allocation. + */ +template +class datastream { + public: + datastream( T start, size_t s ) + :_start(start),_pos(start),_end(start+s){}; + + + inline void skip( size_t s ){ _pos += s; } + inline bool read( char* d, size_t s ) { + if( size_t(_end - _pos) >= (size_t)s ) { + memcpy( d, _pos, s ); + _pos += s; + return true; + } + detail::throw_datastream_range_error( "read", _end-_start, int64_t(-((_end-_pos) - 1))); + } + + inline bool write( const char* d, size_t s ) { + if( _end - _pos >= (int32_t)s ) { + memcpy( _pos, d, s ); + _pos += s; + return true; + } + detail::throw_datastream_range_error( "write", _end-_start, int64_t(-((_end-_pos) - 1))); + } + + inline bool put(char c) { + if( _pos < _end ) { + *_pos = c; + ++_pos; + return true; + } + detail::throw_datastream_range_error( "put", _end-_start, int64_t(-((_end-_pos) - 1))); + } + + inline bool get( unsigned char& c ) { return get( *(char*)&c ); } + inline bool get( char& c ) + { + if( _pos < _end ) { + c = *_pos; + ++_pos; + return true; + } + detail::throw_datastream_range_error( "get", _end-_start, int64_t(-((_end-_pos) - 1))); + } + + T pos()const { return _pos; } + inline bool valid()const { return _pos <= _end && _pos >= _start; } + inline bool seekp(size_t p) { _pos = _start + p; return _pos <= _end; } + inline size_t tellp()const { return _pos - _start; } + inline size_t remaining()const { return _end - _pos; } + private: + T _start; + T _pos; + T _end; +}; + +template<> +class datastream { + public: + datastream( size_t init_size = 0):_size(init_size){}; + inline bool skip( size_t s ) { _size += s; return true; } + inline bool write( const char* ,size_t s ) { _size += s; return true; } + inline bool put(char ) { ++_size; return true; } + inline bool valid()const { return true; } + inline bool seekp(size_t p) { _size = p; return true; } + inline size_t tellp()const { return _size; } + inline size_t remaining()const { return 0; } + private: + size_t _size; +}; + +template +inline datastream& operator<<(datastream& ds, const int32_t& d) { + ds.write( (const char*)&d, sizeof(d) ); + return ds; +} +template +inline datastream& operator>>(datastream& ds, int32_t& d) { + ds.read((char*)&d, sizeof(d) ); + return ds; +} +template +inline datastream& operator<<(datastream& ds, const uint32_t& d) { + ds.write( (const char*)&d, sizeof(d) ); + return ds; +} + +template +inline datastream& operator>>(datastream& ds, uint32_t& d) { + ds.read((char*)&d, sizeof(d) ); + return ds; +} +template +inline datastream& operator<<(datastream& ds, const int64_t& d) { + ds.write( (const char*)&d, sizeof(d) ); + return ds; +} + +template +inline datastream& operator>>(datastream& ds, int64_t& d) { + ds.read((char*)&d, sizeof(d) ); + return ds; +} +template +inline datastream& operator<<(datastream& ds, const uint64_t& d) { + ds.write( (const char*)&d, sizeof(d) ); + return ds; +} + +template +inline datastream& operator>>(datastream& ds, uint64_t& d) { + ds.read((char*)&d, sizeof(d) ); + return ds; +} +template +inline datastream& operator<<(datastream& ds, const int16_t& d) { + ds.write( (const char*)&d, sizeof(d) ); + return ds; +} + +template +inline datastream& operator>>(datastream& ds, int16_t& d) { + ds.read((char*)&d, sizeof(d) ); + return ds; +} +template +inline datastream& operator<<(datastream& ds, const uint16_t& d) { + ds.write( (const char*)&d, sizeof(d) ); + return ds; +} + +template +inline datastream& operator>>(datastream& ds, uint16_t& d) { + ds.read((char*)&d, sizeof(d) ); + return ds; +} +template +inline datastream& operator<<(datastream& ds, const int8_t& d) { + ds.write( (const char*)&d, sizeof(d) ); + return ds; +} + +template +inline datastream& operator>>(datastream& ds, int8_t& d) { + ds.read((char*)&d, sizeof(d) ); + return ds; +} +template +inline datastream& operator<<(datastream& ds, const uint8_t& d) { + ds.write( (const char*)&d, sizeof(d) ); + return ds; +} + +template +inline datastream& operator>>(datastream& ds, uint8_t& d) { + ds.read((char*)&d, sizeof(d) ); + return ds; +} + + +} // namespace fc + diff --git a/include/fc/datastream.hpp b/include/fc/io/datastream_back.hpp similarity index 53% rename from include/fc/datastream.hpp rename to include/fc/io/datastream_back.hpp index d4f965c..8c4e092 100644 --- a/include/fc/datastream.hpp +++ b/include/fc/io/datastream_back.hpp @@ -1,6 +1,5 @@ #pragma once #include -#include #include #include @@ -14,96 +13,78 @@ namespace fc { * actually packing it after doing a single allocation. */ template -struct datastream { +class datastream { + public: datastream( T start, size_t s ) - :m_start(start),m_pos(start),m_end(start+s){}; + :_start(start),_pos(start),_end(start+s){}; - inline void skip( size_t s ){ m_pos += s; } + inline void skip( size_t s ){ _pos += s; } inline bool read( char* d, size_t s ) { - if( size_t(m_end - m_pos) >= (size_t)s ) { - memcpy( d, m_pos, s ); - m_pos += s; + if( size_t(_end - _pos) >= (size_t)s ) { + memcpy( d, _pos, s ); + _pos += s; return true; } - FC_THROW_REPORT( "Attempt to read ${bytes_past} bytes beyond end of buffer with size ${buffer_size} ", - fc::value("bytes_past",int64_t(-((m_end-m_pos) - s))) - ("buffer_size", int64_t(m_end-m_start)) ); + detail::throw_datastream_range_error( _end-start, int64_t(-((_end-_pos) - 1))) return false; } inline bool write( const char* d, size_t s ) { - if( m_end - m_pos >= (int32_t)s ) { - memcpy( m_pos, d, s ); - m_pos += s; + if( _end - _pos >= (int32_t)s ) { + memcpy( _pos, d, s ); + _pos += s; return true; } - FC_THROW_REPORT( "Attempt to write ${bytes_past} bytes beyond end of buffer with size ${buffer_size} ", - fc::value("bytes_past",int64_t(-((m_end-m_pos) - s))) - ("buffer_size", int64_t(m_end-m_start)) ); + detail::throw_datastream_range_error( _end-start, int64_t(-((_end-_pos) - 1))) return false; } inline bool put(char c) { - if( m_pos < m_end ) { - *m_pos = c; - ++m_pos; + if( _pos < _end ) { + *_pos = c; + ++_pos; return true; } - FC_THROW_REPORT( "Attempt to write ${bytes_past} bytes beyond end of buffer with size ${buffer_size} ", - fc::value("bytes_past",int64_t(-((m_end-m_pos) - 1))) - ("buffer_size", int64_t(m_end-m_start)) ); + detail::throw_datastream_range_error( _end-start, int64_t(-((_end-_pos) - 1))) } inline bool get( unsigned char& c ) { return get( *(char*)&c ); } inline bool get( char& c ) { - if( m_pos < m_end ) { - c = *m_pos; - ++m_pos; + if( _pos < _end ) { + c = *_pos; + ++_pos; return true; } - FC_THROW_REPORT( "Attempt to read ${bytes_past} bytes beyond end of buffer of size ${buffer_size} ", - fc::value("bytes_past",int64_t(-((m_end-m_pos) - 1))) - ("buffer_size", int64_t(m_end-m_start)) ); + detail::throw_datastream_range_error( _end-start, int64_t(-((_end-_pos) - 1))) } - T pos()const { return m_pos; } - inline bool valid()const { return m_pos <= m_end && m_pos >= m_start; } - inline bool seekp(size_t p) { m_pos = m_start + p; return m_pos <= m_end; } - inline size_t tellp()const { return m_pos - m_start; } - inline size_t remaining()const { return m_end - m_pos; } + T pos()const { return _pos; } + inline bool valid()const { return _pos <= _end && _pos >= _start; } + inline bool seekp(size_t p) { _pos = _start + p; return _pos <= _end; } + inline size_t tellp()const { return _pos - _start; } + inline size_t remaining()const { return _end - _pos; } private: - T m_start; - T m_pos; - T m_end; + T _start; + T _pos; + T _end; }; template<> -struct datastream { - datastream( size_t init_size = 0):m_size(init_size){}; - inline bool skip( size_t s ) { m_size += s; return true; } - inline bool write( const char* d,size_t s ) { m_size += s; return true; } - inline bool put(char c) { ++m_size; return true; } - inline bool valid()const { return true; } - inline bool seekp(size_t p) { m_size = p; return true; } - inline size_t tellp()const { return m_size; } - inline size_t remaining()const { return 0; } -private: - size_t m_size; +class datastream { + public: + datastream( size_t init_size = 0):_size(init_size){}; + inline bool skip( size_t s ) { _size += s; return true; } + inline bool write( const char* d,size_t s ) { _size += s; return true; } + inline bool put(char c) { ++_size; return true; } + inline bool valid()const { return true; } + inline bool seekp(size_t p) { _size = p; return true; } + inline size_t tellp()const { return _size; } + inline size_t remaining()const { return 0; } + private: + size_t _size; }; -/* -template -inline datastream& operator<<(datastream& ds, const size_t& d) { - ds.write( (const char*)&d, sizeof(d) ); - return *this; -} -template -inline datastream& operator>>(datastream& ds, size_t& d) { - ds.read((char*)&d, sizeof(d) ); - return *this; -} -*/ template inline datastream& operator<<(datastream& ds, const int32_t& d) { ds.write( (const char*)&d, sizeof(d) ); diff --git a/include/fc/fstream.hpp b/include/fc/io/fstream.hpp similarity index 92% rename from include/fc/fstream.hpp rename to include/fc/io/fstream.hpp index fd31862..fe05a9a 100644 --- a/include/fc/fstream.hpp +++ b/include/fc/io/fstream.hpp @@ -1,7 +1,7 @@ #pragma once #include #include -#include +#include namespace fc { class path; @@ -13,7 +13,7 @@ namespace fc { ~ofstream(); void open( const fc::path& file, int m = binary ); - ofstream& write( const char* buf, size_t len ); + size_t writesome( const char* buf, size_t len ); void put( char c ); void close(); void flush(); diff --git a/include/fc/io/iobuffer.hpp b/include/fc/io/iobuffer.hpp new file mode 100644 index 0000000..02f919b --- /dev/null +++ b/include/fc/io/iobuffer.hpp @@ -0,0 +1,81 @@ +#pragma once +#include +#include + +namespace fc +{ + /** + * Records the size, but discards the data. + */ + class size_stream : public virtual fc::ostream + { + public: + size_stream( size_t s = 0):_size(s){} + + size_t size()const { return _size; } + size_t seek( size_t pos ) { return _size = pos; } + + virtual size_t writesome( const char* /*ignored buf*/, size_t len ) + { + _size += len; + return len; + } + + virtual void close(){} + virtual void flush(){} + + private: + size_t _size; + }; + + + class iobuffer : public virtual fc::iostream + { + public: + iobuffer( size_t s ) + :_data(s){} + + size_t size()const { return _data.size(); } + size_t pos()const { return _pos; } + size_t seek( size_t pos ) + { + return _pos = std::min(_data.size(),pos); + } + + virtual size_t readsome( char* buf, size_t len ) + { + auto avail = std::min( _data.size()-_pos, len ); + if( avail == 0 ) throw fc::eof_exception(); + memcpy( buf, _data.data()+_pos, avail ); + _pos += avail; + return avail; + } + /** + * This method may block until at least 1 character is + * available. + */ + char peek()const + { + if( _pos == _data.size() ) throw fc::eof_exception(); + return _data[_pos]; + } + + virtual size_t writesome( const char* buf, size_t len ) + { + auto avail = std::max( _data.size(), _pos + len ); + _data.resize(avail); + memcpy( _data.data()+_pos, buf, len ); + _pos += avail; + return avail; + } + char* data() { return _data.data(); } + + virtual void close(){} + virtual void flush(){} + + private: + std::vector _data; + size_t _pos; + }; + +} diff --git a/include/fc/io/iostream.hpp b/include/fc/io/iostream.hpp new file mode 100644 index 0000000..27945ee --- /dev/null +++ b/include/fc/io/iostream.hpp @@ -0,0 +1,98 @@ +#pragma once +#include +#include +#include + +namespace fc { + + /** + * Provides a fc::thread friendly cooperatively multi-tasked stream that + * will block 'cooperatively' instead of hard blocking. + */ + class istream + { + public: + virtual ~istream(){}; + + /** read at least 1 byte or throw, if no data is available + * this method should block cooperatively until data is + * available or fc::eof is thrown. + * + * @throws fc::eof if at least 1 byte cannot be read + **/ + virtual size_t readsome( char* buf, size_t len ) = 0; + + /** read len bytes or throw, this method is implemented + * in terms of readsome. + * + * @throws fc::eof_exception if len bytes cannot be read + **/ + istream& read( char* buf, size_t len ); + char get(); + }; + typedef std::shared_ptr istream_ptr; + + /** + * Provides a fc::thread friendly cooperatively multi-tasked stream that + * will block 'cooperatively' instead of hard blocking. + */ + class ostream + { + public: + virtual ~ostream(){}; + virtual size_t writesome( const char* buf, size_t len ) = 0; + virtual void close() = 0; + virtual void flush() = 0; + + void put( char c ) { write(&c,1); } + + /** implemented in terms of writesome, guarantees len bytes are sent + * but not flushed. + **/ + ostream& write( const char* buf, size_t len ); + }; + + typedef std::shared_ptr ostream_ptr; + + class iostream : public virtual ostream, public virtual istream {}; + + fc::istream& getline( fc::istream&, fc::string&, char delim = '\n' ); + + template + ostream& operator<<( ostream& o, char (&array)[N] ) + { + return o.write( array, N ); + } + + ostream& operator<<( ostream& o, char ); + ostream& operator<<( ostream& o, const char* v ); + ostream& operator<<( ostream& o, const std::string& v ); + ostream& operator<<( ostream& o, const fc::string& v ); + ostream& operator<<( ostream& o, const double& v ); + ostream& operator<<( ostream& o, const float& v ); + ostream& operator<<( ostream& o, const int64_t& v ); + ostream& operator<<( ostream& o, const uint64_t& v ); + ostream& operator<<( ostream& o, const int32_t& v ); + ostream& operator<<( ostream& o, const uint32_t& v ); + ostream& operator<<( ostream& o, const int16_t& v ); + ostream& operator<<( ostream& o, const uint16_t& v ); + ostream& operator<<( ostream& o, const int8_t& v ); + ostream& operator<<( ostream& o, const uint8_t& v ); +#ifndef _MSC_VER + ostream& operator<<( ostream& o, const size_t& v ); +#endif + + istream& operator>>( istream& o, std::string& v ); + istream& operator>>( istream& o, fc::string& v ); + istream& operator>>( istream& o, char& v ); + istream& operator>>( istream& o, double& v ); + istream& operator>>( istream& o, float& v ); + istream& operator>>( istream& o, int64_t& v ); + istream& operator>>( istream& o, uint64_t& v ); + istream& operator>>( istream& o, int32_t& v ); + istream& operator>>( istream& o, uint32_t& v ); + istream& operator>>( istream& o, int16_t& v ); + istream& operator>>( istream& o, uint16_t& v ); + istream& operator>>( istream& o, int8_t& v ); + istream& operator>>( istream& o, uint8_t& v ); +} diff --git a/include/fc/io/json.hpp b/include/fc/io/json.hpp new file mode 100644 index 0000000..4950a87 --- /dev/null +++ b/include/fc/io/json.hpp @@ -0,0 +1,56 @@ +#pragma once +#include + +namespace fc +{ + class path; + class ostream; + class buffered_istream; + + /** + * Provides interface for json serialization. + * + * json strings are always UTF8 + */ + class json + { + public: + static ostream& to_stream( ostream& out, const fc::string& ); + static ostream& to_stream( ostream& out, const variant& v ); + static ostream& to_stream( ostream& out, const variants& v ); + static ostream& to_stream( ostream& out, const variant_object& v ); + + static variant from_stream( buffered_istream& in ); + + static variant from_string( const string& utf8_str ); + static string to_string( const variant& v ); + static string to_pretty_string( const variant& v ); + static void save_to_file( const variant& v, const string& fi, bool pretty = true ); + static variant from_file( const fc::path& p ); + + template + static T from_file( const fc::path& p ) + { + return json::from_file(p).as(); + } + + template + static string to_string( const T& v ) + { + return to_string( variant(v) ); + } + + template + static string to_pretty_string( const T& v ) + { + return to_pretty_string( variant(v) ); + } + + template + static void save_to_file( const T& v, const string& p, bool pretty = true ) + { + save_to_file( variant(v), p, pretty ); + } + }; + +} // fc diff --git a/include/fc/raw.hpp b/include/fc/io/raw.hpp similarity index 62% rename from include/fc/raw.hpp rename to include/fc/io/raw.hpp index 0733408..52321bc 100644 --- a/include/fc/raw.hpp +++ b/include/fc/io/raw.hpp @@ -1,52 +1,55 @@ #pragma once -#include -#include -#include +#include +#include +#include #include #include #include #include +#include +#include +#include +#include +#include +#include namespace fc { - class value; namespace raw { + template + inline void pack( Stream& s, const variant_object& v ); + template + inline void unpack( Stream& s, variant_object& v ); - template - void unpack( Stream& s, fc::optional& v ); - template - void pack( Stream& s, const fc::optional& v ); + template + inline void pack( Stream& s, const variant& v ); + template + inline void unpack( Stream& s, variant& v ); template - void unpack( Stream& s, fc::value& ); - template - void pack( Stream& s, const fc::value& ); + inline void pack( Stream& s, const fc::time_point& tp ) + { + uint64_t usec = tp.time_since_epoch().count(); + s.write( (const char*)&usec, sizeof(usec) ); + } template - void unpack( Stream& s, fc::string& ); - - template - void pack( Stream& s, const fc::string& ); - - template - inline void pack( Stream& s, const T& v ); - - template - inline void unpack( Stream& s, T& v ); - - template - inline void pack( Stream& s, const fc::vector& v ); - template - inline void unpack( Stream& s, fc::vector& v ); - + inline void unpack( Stream& s, fc::time_point& tp ) + { + uint64_t usec; + s.read( (char*)&usec, sizeof(usec) ); + tp = fc::time_point() + fc::microseconds(usec); + } template inline void pack( Stream& s, const fc::array& v) { s.write((const char*)&v.data[0],N*sizeof(T)); } + template inline void unpack( Stream& s, fc::array& v) { s.read((char*)&v.data[0],N*sizeof(T)); } + template inline void pack( Stream& s, const signed_int& v ) { uint32_t val = (v.value<<1) ^ (v.value>>31); do { @@ -239,12 +242,152 @@ namespace fc { fc::raw::detail::if_reflected< typename fc::reflector::is_defined >::unpack(s,v); } + template + class variant_packer : public variant::visitor + { + public: + variant_packer( Stream& _s ):s(_s){} + virtual void handle()const { } + virtual void handle( const int64_t& v )const + { + fc::raw::pack( s, v ); + } + virtual void handle( const uint64_t& v )const + { + fc::raw::pack( s, v ); + } + virtual void handle( const double& v )const + { + fc::raw::pack( s, v ); + } + virtual void handle( const bool& v )const + { + fc::raw::pack( s, v ); + } + virtual void handle( const string& v )const + { + fc::raw::pack( s, v ); + } + virtual void handle( const variant_object& v)const + { + fc::raw::pack( s, v ); + } + virtual void handle( const variants& v)const + { + fc::raw::pack( s, v ); + } + + Stream& s; + + }; + + + template + inline void pack( Stream& s, const variant& v ) + { + pack( s, uint8_t(v.get_type()) ); + v.visit( variant_packer(s) ); + } + template + inline void unpack( Stream& s, variant& v ) + { + uint8_t t; + unpack( s, t ); + switch( t ) + { + case variant::null_type: + return; + case variant::int64_type: + { + int64_t val; + raw::unpack(s,val); + v = val; + return; + } + case variant::uint64_type: + { + uint64_t val; + raw::unpack(s,val); + v = val; + return; + } + case variant::double_type: + { + double val; + raw::unpack(s,val); + v = val; + return; + } + case variant::bool_type: + { + bool val; + raw::unpack(s,val); + v = val; + return; + } + case variant::string_type: + { + fc::string val; + raw::unpack(s,val); + v = fc::move(val); + return; + } + case variant::array_type: + { + variants val; + raw::unpack(s,val); + v = fc::move(val); + return; + } + case variant::object_type: + { + variant_object val; + raw::unpack(s,val); + v = fc::move(val); + return; + } + default: + FC_THROW_EXCEPTION( parse_error_exception, "Unknown Variant Type ${t}", ("t", t) ); + } + } + + template + inline void pack( Stream& s, const variant_object& v ) + { + unsigned_int vs = v.size(); + pack( s, vs ); + for( auto itr = v.begin(); itr != v.end(); ++itr ) + { + pack( s, itr->key() ); + pack( s, itr->value() ); + } + wlog( "------------ done pack -------------" ); + } + template + inline void unpack( Stream& s, variant_object& v ) + { + unsigned_int vs; + unpack( s, vs ); + + mutable_variant_object mvo; + mvo.reserve(vs.value); + for( auto i = 0; i < vs.value; ++i ) + { + fc::string key; + fc::variant value; + fc::raw::unpack(s,key); + fc::raw::unpack(s,value); + mvo.set( fc::move(key), fc::move(value) ); + } + v = fc::move(mvo); + } template inline fc::vector pack( const T& v ) { datastream ps; raw::pack(ps,v ); fc::vector vec(ps.tellp()); + if( vec.size() ) { datastream ds( vec.data(), size_t(vec.size()) ); raw::pack(ds,v); @@ -275,6 +418,12 @@ namespace fc { raw::unpack(ds,v); return v; } + template + inline void unpack( const char* d, uint32_t s, T& v ) { + datastream ds( d, s ); + raw::unpack(ds,v); + return v; + } } } // namespace fc::raw diff --git a/include/fc/io/raw_fwd.hpp b/include/fc/io/raw_fwd.hpp new file mode 100644 index 0000000..24e1c1a --- /dev/null +++ b/include/fc/io/raw_fwd.hpp @@ -0,0 +1,38 @@ +#pragma once +#include +#include + +namespace fc { namespace raw { + template void unpack( Stream& s, fc::optional& v ); + template void pack( Stream& s, const fc::optional& v ); + + template void unpack( Stream& s, fc::string& ); + template void pack( Stream& s, const fc::string& ); + + template inline void pack( Stream& s, const T& v ); + template inline void unpack( Stream& s, T& v ); + + template inline void pack( Stream& s, const fc::vector& v ); + template inline void unpack( Stream& s, fc::vector& v ); + + template inline void pack( Stream& s, const signed_int& v ); + template inline void unpack( Stream& s, signed_int& vi ); + + template inline void pack( Stream& s, const unsigned_int& v ); + template inline void unpack( Stream& s, unsigned_int& vi ); + + template inline void pack( Stream& s, const char* v ); + template inline void pack( Stream& s, const fc::vector& value ); + template inline void unpack( Stream& s, fc::vector& value ); + + template inline void pack( Stream& s, const fc::array& v); + template inline void unpack( Stream& s, fc::array& v); + + template inline void pack( Stream& s, const bool& v ); + template inline void unpack( Stream& s, bool& v ); + + template inline fc::vector pack( const T& v ); + template inline T unpack( const fc::vector& s ); + template inline T unpack( const char* d, uint32_t s ); + template inline void unpack( const char* d, uint32_t s, T& v ); +} } diff --git a/include/fc/io/raw_unpack_file.hpp b/include/fc/io/raw_unpack_file.hpp new file mode 100644 index 0000000..580a64c --- /dev/null +++ b/include/fc/io/raw_unpack_file.hpp @@ -0,0 +1,24 @@ +#pragma once +#include +#include +#include +#include + +namespace fc +{ + namespace raw + { + template + void unpack_file( const fc::path& filename, T& obj ) + { + try { + fc::file_mapping fmap( filename.generic_string().c_str(), fc::read_only); + fc::mapped_region mapr( fmap, fc::read_only, 0, fc::file_size(filename) ); + auto cs = (const char*)mapr.get_address(); + + fc::datastream ds( cs, mapr.get_size() ); + fc::raw::unpack(ds,obj); + } FC_RETHROW_EXCEPTIONS( info, "unpacking file ${file}", ("file",filename) ); + } + } +} diff --git a/include/fc/io/sstream.hpp b/include/fc/io/sstream.hpp new file mode 100644 index 0000000..0aacb7a --- /dev/null +++ b/include/fc/io/sstream.hpp @@ -0,0 +1,31 @@ +#pragma once +#include +#include + +namespace fc { + + class stringstream : virtual public iostream { + public: + stringstream(); + stringstream( fc::string& s); + stringstream( const fc::string& s); + ~stringstream(); + + fc::string str(); + void str(const fc::string& s); + + void clear(); + + virtual bool eof()const; + virtual size_t writesome( const char* buf, size_t len ); + virtual size_t readsome( char* buf, size_t len ); + virtual void close(); + virtual void flush(); + char peek(); + + private: + class impl; + fwd my; + }; + +} diff --git a/include/fc/io/stdio.hpp b/include/fc/io/stdio.hpp new file mode 100644 index 0000000..63d6e17 --- /dev/null +++ b/include/fc/io/stdio.hpp @@ -0,0 +1,36 @@ +#pragma once +#include + +namespace fc +{ + + class cout_t : virtual public ostream { + public: + virtual size_t writesome( const char* buf, size_t len ); + virtual void close(); + virtual void flush(); + }; + + class cerr_t : virtual public ostream { + public: + virtual size_t writesome( const char* buf, size_t len ); + virtual void close(); + virtual void flush(); + }; + + class cin_t : virtual public istream { + public: + ~cin_t(); + virtual size_t readsome( char* buf, size_t len ); + virtual istream& read( char* buf, size_t len ); + virtual bool eof()const; + }; + + extern cout_t& cout; + extern cerr_t& cerr; + extern cin_t& cin; + + extern std::shared_ptr cin_ptr; + extern std::shared_ptr cout_ptr; + extern std::shared_ptr cerr_ptr; +} diff --git a/include/fc/varint.hpp b/include/fc/io/varint.hpp similarity index 66% rename from include/fc/varint.hpp rename to include/fc/io/varint.hpp index 2e98be5..9f5cebd 100644 --- a/include/fc/varint.hpp +++ b/include/fc/io/varint.hpp @@ -1,5 +1,4 @@ -#ifndef _FC_VARINT_HPP_ -#define _FC_VARINT_HPP_ +#pragma once #include namespace fc { @@ -24,7 +23,13 @@ struct signed_int { int32_t value; }; +class variant; + +void to_variant( const signed_int& var, variant& vo ); +void from_variant( const variant& var, signed_int& vo ); +void to_variant( const unsigned_int& var, variant& vo ); +void from_variant( const variant& var, unsigned_int& vo ); + } // namespace fc -#endif diff --git a/include/fc/iostream.hpp b/include/fc/iostream.hpp deleted file mode 100644 index 4f04fce..0000000 --- a/include/fc/iostream.hpp +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once -#include -#include -#include - -namespace fc { - - class istream { - public: - virtual ~istream(){}; - - virtual size_t readsome( char* buf, size_t len ) = 0; - virtual istream& read( char* buf, size_t len ) = 0; - - virtual bool eof()const = 0; - }; - - class ostream { - public: - virtual ~ostream(){}; - - virtual ostream& write( const char* buf, size_t len ) = 0; - virtual void close(){} - virtual void flush(){} - }; - - class iostream : public virtual ostream, public virtual istream {}; - - - struct cout_t : virtual public ostream { - virtual ostream& write( const char* buf, size_t len ); - virtual void close(); - virtual void flush(); - - virtual ostream& write( const fc::string& ); - }; - - struct cerr_t : virtual public ostream { - virtual ostream& write( const char* buf, size_t len ); - virtual void close(); - virtual void flush(); - - virtual ostream& write( const fc::string& ); - }; - - struct cin_t : virtual public istream { - ~cin_t(); - virtual size_t readsome( char* buf, size_t len ); - virtual istream& read( char* buf, size_t len ); - virtual bool eof()const; - }; - fc::istream& getline( fc::istream&, fc::string&, char delim = '\n' ); - - - extern cout_t cout; - extern cerr_t cerr; - extern cin_t cin; - - - template - ostream& operator<<( ostream& o, const T& v ) { - auto str = fc::lexical_cast(v); - o.write( str.c_str(), static_cast(str.size()) ); - return o; - } - ostream& operator<<( ostream& o, const char* v ); - - template - ostream& operator<<( ostream& o, const fc::string& str ) { - o.write( str.c_str(), static_cast(str.size()) ); - return o; - } - template - istream& operator>>( istream& o, T& v ) { - fc::string str; - getline( o, str, ' ' ); - v = fc::lexical_cast(str); - return o; - } -} diff --git a/include/fc/iostream_wrapper.hpp b/include/fc/iostream_wrapper.hpp deleted file mode 100644 index 1798137..0000000 --- a/include/fc/iostream_wrapper.hpp +++ /dev/null @@ -1,118 +0,0 @@ -#pragma once -#include -#include -#include - -namespace fc { - /** - * Used to wrap references to other streams - */ - class ostream_wrapper : public ostream { - public: - template - ostream_wrapper( Stream& s ) - :my( new impl(s) ){} - - virtual ~ostream_wrapper(){}; - - virtual ostream& write( const char* buf, size_t len ) { - my->write(buf,len); - return *this; - } - virtual void close() { - // TODO: move to cpp - my->close(); - } - virtual void flush() { - my->flush(); - } - - protected: - virtual ostream& write( const fc::string& s ) { - return write( s.c_str(), s.size() ); - } - - struct impl_base : public fc::retainable { - virtual ~impl_base(){} - virtual void write( const char* buf, size_t len ) = 0; - virtual void close() = 0; - virtual void flush() = 0; - }; - - template - struct impl : public impl_base { - impl(T& i):st(i){} - - virtual void write( const char* buf, size_t len ) { - st.write(buf,len); - } - virtual void close() { st.close(); } - virtual void flush() { st.flush(); } - T& st; - }; - - fc::shared_ptr my; - }; - /** - * Used to wrap references to other streams - */ - class istream_wrapper : public istream { - public: - template - istream_wrapper( Stream& s ) - :my( new impl(s) ){} - - virtual ~istream_wrapper(){}; - - virtual size_t readsome( char* buf, size_t len ) { - return my->readsome(buf,len); - } - virtual istream& read( char* buf, size_t len ) { - // slog( "%p %lld", my.get(), len ); - my->read(buf,len); - return *this; - } - virtual void close() { } - virtual bool eof()const{ return my->eof(); } - - /* - virtual istream& read( int64_t& ) { return *this; } - virtual istream& read( uint64_t& ) { return *this; } - virtual istream& read( int32_t& ) { return *this; } - virtual istream& read( uint32_t& ) { return *this; } - virtual istream& read( int16_t& ) { return *this; } - virtual istream& read( uint16_t& ) { return *this; } - virtual istream& read( int8_t& ) { return *this; } - virtual istream& read( uint8_t& ) { return *this; } - virtual istream& read( float& ) { return *this; } - virtual istream& read( double& ) { return *this; } - virtual istream& read( bool& ) { return *this; } - virtual istream& read( char& ) { return *this; } - virtual istream& read( fc::string& ) { return *this; } - */ - - protected: - struct impl_base : public fc::retainable { - virtual ~impl_base(){} - virtual void read( char* buf, size_t len )=0; - virtual size_t readsome( char* buf, size_t len )=0; - virtual bool eof()const=0; - }; - - template - struct impl : public impl_base { - impl(T& i):st(i){} - - virtual size_t readsome( char* buf, size_t len ) { return size_t(st.readsome(buf,len)); } - virtual void read( char* buf, size_t len ) { - st.read(buf,len); - } - virtual bool eof()const { return st.eof() || !st.good(); } - T& st; - }; - - fc::shared_ptr my; - }; - -} // namespace fc - diff --git a/include/fc/json.hpp b/include/fc/json.hpp deleted file mode 100644 index ccfc129..0000000 --- a/include/fc/json.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace fc { - class istream; - class ostream; - class path; - - namespace json { - string to_string( const value& o ); - string to_pretty_string( const value& v ); - - - value from_string( const string& s ); - value from_string( const char* s, const char* e ); - value from_string( const fc::vector& v ); - - - string escape_string( const string& ); - string unescape_string( const string& ); - - void write( ostream& out, const value& val ); - - template - void write( ostream& out, const T& val ) { - write( out, value(val) ); - } - - template - string to_string( const T& o ) { - return json::to_string(value(o)); - } - template - string to_pretty_string( const T& o ) { - return json::to_pretty_string(value(o)); - } - - template - T from_string( const string& s ) { - return value_cast( from_string(s) ); - } - - value from_file( const fc::path& s ); - template - T from_file( const fc::path& s ) { - return value_cast( fc::json::from_file(s) ); - } - - } // namespace json -} // fc - diff --git a/include/fc/json_rpc_client.hpp b/include/fc/json_rpc_client.hpp deleted file mode 100644 index 88bc081..0000000 --- a/include/fc/json_rpc_client.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include - - -namespace fc { namespace json { - - namespace detail { - struct rpc_member { - #ifdef BOOST_NO_VARIADIC_TEMPLATES - #define RPC_MEMBER_FUNCTOR(z,n,IS_CONST) \ - template \ - static std::function( BOOST_PP_ENUM_PARAMS(n,A) ) > \ - functor( P, R (C::*mem_func)(BOOST_PP_ENUM_PARAMS(n,A)) IS_CONST, \ - const rpc_connection::ptr& c = rpc_connection::ptr(), const char* name = nullptr ) { \ - return [=](BOOST_PP_ENUM_BINARY_PARAMS(n,A,a))->fc::future{ \ - return c->invoke( name, make_tuple(BOOST_PP_ENUM_PARAMS(n,a)) ); }; \ - } - BOOST_PP_REPEAT( 8, RPC_MEMBER_FUNCTOR, const ) - BOOST_PP_REPEAT( 8, RPC_MEMBER_FUNCTOR, BOOST_PP_EMPTY() ) - #undef RPC_MEMBER_FUNCTOR - - #else - template - static std::function(Args...)> functor( P&& p, R (C::*mem_func)(Args...), - const rpc_connection::ptr& c = rpc_connection::ptr(), const char* name = nullptr ) { - return [=](Args... args)->fc::future{ - return c->invoke( name, make_tuple(args...) ); }; - } - template - static std::function(Args...)> functor( P&& p, R (C::*mem_func)(Args...)const, - const rpc_connection::ptr& c = rpc_connection::ptr(), const char* name = nullptr ) { - return [=](Args... args)->fc::future{ - return c->invoke( name, make_tuple(args...) ); }; - } - #endif - }; - - struct vtable_visitor { - vtable_visitor( rpc_connection::ptr& c ):_con(c){} - - template - void operator()( const char* name, Function& memb, MemberPtr m )const { - memb = rpc_member::functor( nullptr, m, _con, name ); - } - rpc_connection::ptr& _con; - }; - }; - - - template - class rpc_client : public actor { //ptr { - public: - rpc_client(){} - rpc_client( const rpc_connection::ptr& c ){ set_connection(c); } - //rpc_client( const rpc_client& c ):_con(c._con){} - - void set_connection( const rpc_connection::ptr& c ) { - _con = c; - this->_vtable.reset(new fc::detail::vtable() ); - this->_vtable->template visit_other( fc::json::detail::vtable_visitor(_con) ); - } - const rpc_connection::ptr& connection()const { return _con; } - - private: - rpc_connection::ptr _con; - }; - -} } // fc::json diff --git a/include/fc/json_rpc_connection.hpp b/include/fc/json_rpc_connection.hpp deleted file mode 100644 index 7b5a9cb..0000000 --- a/include/fc/json_rpc_connection.hpp +++ /dev/null @@ -1,196 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - -namespace fc { namespace json { - class rpc_connection; - class error_object; - - struct rpc_server_method : public fc::retainable { - typedef fc::shared_ptr ptr; - virtual value call( const value& v ) = 0; - }; - - namespace detail { - struct pending_result : virtual public promise_base { - typedef shared_ptr ptr; - virtual void handle_result( const fc::value& ) = 0; - void handle_error( const fc::string& ); - int64_t id; - pending_result::ptr next; - protected: - ~pending_result(){} - }; - template - struct pending_result_impl : virtual public promise, virtual public pending_result { - virtual void handle_result( const fc::value& s ) { - this->set_value( value_cast(s) ); - } - protected: - ~pending_result_impl(){} - }; - template<> - struct pending_result_impl : virtual public promise, virtual public pending_result { - virtual void handle_result( const fc::value& ) { - set_value(); - } - protected: - ~pending_result_impl(){} - }; - - template - struct named_param { - typedef fc::false_type type; - static T cast( const value& v ) { return fc::value_cast(v); } - - template - static value to_value( X&& x ) { return value(fc::forward(x)); } - }; - - #define FC_JSON_NAMED_PARAMS( T ) \ - namespace fc { namespace json {namespace detail { \ - template<> \ - struct named_param< fc::tuple > { \ - typedef fc::true_type type; \ - static tuple cast( const value& v ) { return make_tuple(fc::value_cast(v)); } \ - template \ - static value to_value( X&& x ) { return value( x.a0 ); }\ - }; \ - } } } - - template - struct rpc_server_method_impl : public rpc_server_method { - rpc_server_method_impl( const std::function& f ):func(f){} - virtual value call( const value& v ) { - return value( fc::call_fused(func, named_param::type>::cast(v) ) ); - } - std::function func; - }; - template - struct rpc_server_method_impl : public rpc_server_method { - rpc_server_method_impl( const std::function& f ):func(f){} - virtual value call( const value& v ) { - fc::call_fused(func, named_param::type>::cast(v) ); - return value(); - } - std::function func; - }; - - template - struct add_method_visitor { - public: - add_method_visitor( const fc::ptr& p, fc::json::rpc_connection& c ):_ptr(p),_con(c){} - - template - void operator()( const char* name, std::function& meth); - template - void operator()( const char* name, std::function& meth); - template - void operator()( const char* name, std::function& meth); - template - void operator()( const char* name, std::function& meth); - - const fc::ptr& _ptr; - fc::json::rpc_connection& _con; - }; - } - - /** - * This is the base JSON RPC connection that handles the protocol - * level issues. It does not implement a transport which should - * be provided separately and use the handle_message and set_send_delegate - * methods to manage the protocol. - */ - class rpc_connection : public fc::retainable { - public: - rpc_connection(); - rpc_connection(const rpc_connection&); - rpc_connection(rpc_connection&&); - ~rpc_connection(); - rpc_connection& operator=(const rpc_connection&); - rpc_connection& operator=(rpc_connection&&); - - typedef fc::shared_ptr ptr; - - void cancel_pending_requests(); - - template - future invoke( const fc::string& method, Args&& a = nullptr ){ - auto r = new detail::pending_result_impl(); - typename promise::ptr rtn( r, true ); - invoke( detail::pending_result::ptr(r), method, - value(detail::named_param::type>::to_value(a)) ); - return rtn; - } - - template - void notice( const fc::string& method, Args&& a = nullptr ){ - send_notice( method, - value(detail::named_param::type>::to_value(a)) ); - } - - template - void add_interface( const fc::ptr& it ) { - it->TEMPLATE visit( detail::add_method_visitor( it, *this ) ); - } - - void add_method( const fc::string& name, const fc::json::rpc_server_method::ptr& func ); - - virtual void close(){}; - - protected: - void handle_message( const value& m ); - virtual void send_notice( const fc::string& m, value&& param ) = 0; - virtual void send_invoke( uint64_t id, const fc::string& m, value&& param ) = 0; - virtual void send_error( uint64_t id, const error_object& e ) = 0; - virtual void send_result( uint64_t id, value&& r ) = 0; - - - private: - void invoke( detail::pending_result::ptr&& p, const fc::string& m, value&& param ); - void add_method( const fc::string& name, rpc_server_method::ptr&& m ); - template - friend struct detail::add_method_visitor; - - class impl; - fc::shared_ptr my; - }; - - namespace detail { - - template - template - void add_method_visitor::operator()( const char* name, - std::function& meth) { - _con.add_method( name, rpc_server_method::ptr( - new rpc_server_method_impl,R(A1) >(meth) ) ); - } - template - template - void add_method_visitor::operator()( const char* name, - std::function& meth) { - _con.add_method( name, rpc_server_method::ptr( - new rpc_server_method_impl,R(A1,A2) >(meth) ) ); - } - template - template - void add_method_visitor::operator()( const char* name, - std::function& meth) { - _con.add_method( name, rpc_server_method::ptr( - new rpc_server_method_impl,R(A1,A2,A3) >(meth) ) ); - } - template - template - void add_method_visitor::operator()( const char* name, - std::function& meth) { - _con.add_method( name, rpc_server_method::ptr( - new rpc_server_method_impl,R() >(meth) ) ); - } - - } // namespace detail - -} } // fc::json - diff --git a/include/fc/json_rpc_error_object.hpp b/include/fc/json_rpc_error_object.hpp deleted file mode 100644 index d898356..0000000 --- a/include/fc/json_rpc_error_object.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include -#include -#include -#include - - -namespace fc { - class value; - - namespace json { - - class error_object { - public: - error_object( const fc::string& msg, const fc::value& v , int64_t c = -32000); - error_object( const fc::string& msg=fc::string(), int64_t c = -32000 ); - error_object( const error_object& e ); - ~error_object(); - - int64_t code; - fc::string message; - fc::optional data; - }; - -} } - -FC_REFLECT( fc::json::error_object, (code)(message)(data) ) diff --git a/include/fc/json_rpc_process_client.hpp b/include/fc/json_rpc_process_client.hpp deleted file mode 100644 index d1022e5..0000000 --- a/include/fc/json_rpc_process_client.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace fc { namespace json { - - template - class rpc_process_client : public ptr { - public: - - fc::future exec( const fc::path& exe, int opt = fc::process::open_all ) { - return exec( exe, fc::path("."), opt ); - } - fc::future exec( const fc::path& exe, const fc::path& wd, - int opt = fc::process::open_all ) { - return exec( exe, fc::vector(), wd, opt ); - } - fc::future exec( const fc::path& exe, fc::vector&& args , - int opt = fc::process::open_all ) { - return exec( exe, fc::move(args), fc::path("."), opt ); - } - fc::future exec( const fc::path& exe, fc::vector&& args, - const fc::path& wd, int opt = fc::process::open_all ) { - auto r = _proc.exec( canonical(exe), fc::move(args), wd, opt ); - _con.reset( new fc::json::rpc_stream_connection( _proc.out_stream(), _proc.in_stream() ) ); - this->_vtable.reset(new fc::detail::vtable() ); - rpc_connection::ptr p(_con); - this->_vtable->template visit_other( fc::json::detail::vtable_visitor(p) ); - return r; - } - - void kill() { _con->close(); _proc.kill(); } - - /** - * @brief returns a stream that reads from the process' stderr - */ - fc::istream& err_stream() { return _proc.err_stream(); } - - template - void on_close( T&& f) { _con->on_close( fc::forward(f) ); } - - const fc::json::rpc_stream_connection::ptr& connection()const { return _con; } - - ~rpc_process_client() { - if(_con) - _con->close(); - } - private: - fc::process _proc; - fc::json::rpc_stream_connection::ptr _con; - }; -} } diff --git a/include/fc/json_rpc_ssh_process_client.hpp b/include/fc/json_rpc_ssh_process_client.hpp deleted file mode 100644 index cadae75..0000000 --- a/include/fc/json_rpc_ssh_process_client.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#include -#include -#include - -namespace fc { namespace json { - - template - class rpc_ssh_process_client : public rpc_client { - public: - rpc_ssh_process_client(){} - bool valid()const { return proc.valid(); } - - rpc_ssh_process_client( const fc::ssh::process& proc ) - :rpc_client(rpc_connection::ptr(new fc::json::rpc_stream_connection( proc.out_stream(), proc.in_stream() ) ) ){} - - rpc_ssh_process_client& operator = ( const fc::ssh::process& proc ) { - this->set_connection( rpc_connection::ptr(new fc::json::rpc_stream_connection( proc.out_stream(), proc.in_stream() ) ) ); - return *this; - } - - /** - * @brief returns a stream that reads from the process' stderr - */ - fc::istream& err_stream() { return proc.err_stream(); } - - fc::ssh::process& get_ssh_process() { return proc; } - private: - fc::ssh::process proc; - fc::json::rpc_stream_connection::ptr _con; - - }; -} } diff --git a/include/fc/json_rpc_stream_connection.hpp b/include/fc/json_rpc_stream_connection.hpp deleted file mode 100644 index acf689b..0000000 --- a/include/fc/json_rpc_stream_connection.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include - -namespace fc { - class istream; - class ostream; - - namespace json { - class rpc_stream_connection : public rpc_connection { - public: - typedef fc::shared_ptr ptr; - rpc_stream_connection( fc::istream&, fc::ostream& ); - rpc_stream_connection(const rpc_stream_connection& ); - rpc_stream_connection(); - - // the life of the streams must exceed the life of all copies - // of this rpc_stream_connection - void open( fc::istream&, fc::ostream& ); - - // cancels all pending requests, closes the ostream - // results on_close() being called if the stream is not already closed. - virtual void close(); - - /** - * When the connection is closed, call the given method - */ - void on_close( const std::function& ); - - protected: - ~rpc_stream_connection(); - virtual void send_invoke( uint64_t id, const fc::string& m, value&& param ); - virtual void send_notice( const fc::string& m, value&& param ); - virtual void send_error( uint64_t id, const error_object& eo ); - virtual void send_result( uint64_t id, value&& r ); - - private: - class impl; - fc::shared_ptr my; - }; -} } // fc::json diff --git a/include/fc/json_rpc_tcp_connection.hpp b/include/fc/json_rpc_tcp_connection.hpp deleted file mode 100644 index 7f57256..0000000 --- a/include/fc/json_rpc_tcp_connection.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include - -namespace fc { - class tcp_socket; - namespace ip { class endpoint; } - - namespace json { - class rpc_tcp_connection : public rpc_stream_connection { - public: - typedef fc::shared_ptr ptr; - - rpc_tcp_connection(); - rpc_tcp_connection( const rpc_tcp_connection& c ); - ~rpc_tcp_connection(); - - void connect_to( const fc::ip::endpoint& e ); - void start(); - tcp_socket& get_socket()const; - - virtual void close(); - - private: - class impl; - fc::shared_ptr my; - }; - } // json -} // fc diff --git a/include/fc/json_rpc_tcp_server.hpp b/include/fc/json_rpc_tcp_server.hpp deleted file mode 100644 index 7c334b8..0000000 --- a/include/fc/json_rpc_tcp_server.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#include - -namespace fc { - - namespace json { - class rpc_tcp_server { - private: - template - struct add_method_visitor { - add_method_visitor( fc::ptr& p, rpc_connection& s ):_ptr(p),_rpcc(s) { } - - template - void operator()( const char* name, Functor& fun ) { - _rpcc.add_method( name, fun ); - } - - fc::ptr& _ptr; - rpc_connection& _rpcc; - }; - - public: - rpc_tcp_server(); - ~rpc_tcp_server(); - - template - void add_interface( const fc::ptr& ptr ) { - on_new_connection( [=]( rpc_connection& c ) { - ptr->visit( detail::add_method_visitor( ptr, c ) ); - }); - } - - void on_new_connection( const std::function& c ); - - void listen( uint16_t port ); - - private: - class impl; - impl* my; - }; - } -} diff --git a/include/fc/lexical_cast.hpp b/include/fc/lexical_cast.hpp deleted file mode 100644 index 3c0aa3a..0000000 --- a/include/fc/lexical_cast.hpp +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once -#include - -namespace fc { - - namespace detail { - template - struct lexical_cast { }; - - double to_double( const fc::string& s ); - inline double to_double( double d ) { return d; } - - int64_t to_int64( const fc::string& s ); - inline int64_t to_int64( double d ) { return static_cast(d); } - inline int64_t to_int64( int64_t d ) { return d; } - - uint64_t to_uint64( const fc::string& s ); - inline uint64_t to_uint64( double d ) { return static_cast(d); } - inline uint64_t to_uint64( uint64_t d ) { return d; } - - fc::string to_string( double d ); - fc::string to_string( size_t d ); - fc::string to_string( uint64_t d ); - fc::string to_string( uint32_t d ); - fc::string to_string( uint16_t d ); - fc::string to_string( uint8_t d ); - fc::string to_string( int64_t d ); - fc::string to_string( int32_t d ); - fc::string to_string( int16_t d ); - fc::string to_string( int8_t d ); - fc::string to_string( char d ); - inline fc::string to_string( const char* d ) { return d; } - inline fc::string to_string( fc::string s ) { return s; } - - template - struct lexical_cast { - static double cast( const R& v ) { return to_double( v ); } - }; - - template - struct lexical_cast { - static fc::string cast( const R& v ) { return to_string( v ); } - }; - template - struct lexical_cast { - static std::string cast( const R& v ) { return to_string( v ); } - }; - - template - struct lexical_cast { - static uint64_t cast( const R& v ) { return to_uint64( v ); } - }; - - template - struct lexical_cast { static int64_t cast( const R& v ) { return static_cast(to_int64( v )); } }; - - template - struct lexical_cast { static int32_t cast( const R& v ) { return static_cast(to_int64( v )); } }; - - template - struct lexical_cast { static int16_t cast( const R& v ) { return static_cast(to_int64( v )); } }; - - template - struct lexical_cast { static int8_t cast( const R& v ) { return static_cast(to_int64( v )); } }; - - - template - struct lexical_cast { static uint32_t cast( const R& v ) { return static_cast(to_uint64( v )); } }; - - template - struct lexical_cast { static uint16_t cast( const R& v ) { return static_cast(to_uint64( v )); } }; - - template - struct lexical_cast { static uint8_t cast( const R& v ) { return static_cast(to_uint64( v )); } }; - - template - struct lexical_cast { static bool cast( const R& v ) { return v != 0; } }; - - template<> - struct lexical_cast { static char cast( const fc::string& v ) - { return v[0]; } };// TODO: check string len - - template<> - struct lexical_cast { static bool cast( const fc::string& v ) { return v == "true"; } }; - - template<> - struct lexical_cast { static fc::string cast( const bool& v ) { return v ? "true" : "false";} }; - - template - struct lexical_cast { static float cast( const R& v ) { return static_cast(to_double( v )); } }; - } - - - template - T lexical_cast( const R& v ) { - return detail::lexical_cast::cast(v); - } -} diff --git a/include/fc/log.hpp b/include/fc/log.hpp deleted file mode 100644 index 4ad5dd9..0000000 --- a/include/fc/log.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include - -namespace boost { class mutex; } - -namespace fc { - /** wrapper on printf */ - void log( const char* color, const char* file_name, size_t line_num, const char* method_name, const char* format, ... ); - - /** used to add extra fields to be printed (thread,fiber,time,etc) */ - void add_log_field( void (*f)() ); - void remove_log_field( void (*f)() ); - - boost::mutex& log_mutex(); -} - -#ifndef __func__ -#define __func__ __FUNCTION__ -#endif - -#ifndef WIN32 -#define COLOR_CONSOLE 1 -#endif -#include - -#define dlog(...) do { fc::log( CONSOLE_DEFAULT, __FILE__, __LINE__, __func__, __VA_ARGS__ ); }while(false) -#define slog(...) do { fc::log( CONSOLE_DEFAULT, __FILE__, __LINE__, __func__, __VA_ARGS__ ); }while(false) -#define wlog(...) do { fc::log( CONSOLE_BROWN, __FILE__, __LINE__, __func__, __VA_ARGS__ ); }while(false) -#define elog(...) do { fc::log( CONSOLE_RED, __FILE__, __LINE__, __func__, __VA_ARGS__ ); }while(false) - - diff --git a/include/fc/appender.hpp b/include/fc/log/appender.hpp similarity index 83% rename from include/fc/appender.hpp rename to include/fc/log/appender.hpp index f8fa1d4..093cce8 100644 --- a/include/fc/appender.hpp +++ b/include/fc/log/appender.hpp @@ -4,22 +4,22 @@ namespace fc { class appender; class log_message; - class value; class string; + class variant; class appender_factory : public fc::retainable { public: typedef fc::shared_ptr ptr; virtual ~appender_factory(){}; - virtual fc::shared_ptr create( const value& args ) = 0; + virtual fc::shared_ptr create( const variant& args ) = 0; }; namespace detail { template class appender_factory_impl : public appender_factory { public: - virtual fc::shared_ptr create( const value& args ) { + virtual fc::shared_ptr create( const variant& args ) { return fc::shared_ptr(new T(args)); } }; @@ -34,7 +34,7 @@ namespace fc { return register_appender( type, new detail::appender_factory_impl() ); } - static appender::ptr create( const fc::string& name, const fc::string& type, const value& args ); + static appender::ptr create( const fc::string& name, const fc::string& type, const variant& args ); static appender::ptr get( const fc::string& name ); static bool register_appender( const fc::string& type, const appender_factory::ptr& f ); diff --git a/include/fc/console_appender.hpp b/include/fc/log/console_appender.hpp similarity index 69% rename from include/fc/console_appender.hpp rename to include/fc/log/console_appender.hpp index 371d2b9..9fe9f30 100644 --- a/include/fc/console_appender.hpp +++ b/include/fc/log/console_appender.hpp @@ -1,11 +1,14 @@ #pragma once -#include -#include +#include +#include -namespace fc { - class console_appender : public appender { +namespace fc +{ + class console_appender : public appender + { public: - struct color { + struct color + { enum type { red, green, @@ -17,20 +20,23 @@ namespace fc { console_default, }; }; + struct stream { enum type { std_out, std_error }; }; - struct level_color { - level_color( log_level::type l=log_level::all, + struct level_color + { + level_color( log_level l=log_level::all, color::type c=color::console_default ) :level(l),color(c){} - log_level::type level; + log_level level; console_appender::color::type color; }; - struct config { + struct config + { config() - :format( "${when} ${thread} ${context} ${file}:${line} ${method} ${level}] ${message}" ), + :format( "${timestamp} ${thread_name} ${context} ${file}:${line} ${method} ${level}] ${message}" ), stream(console_appender::stream::std_error),flush(true){} fc::string format; @@ -40,16 +46,17 @@ namespace fc { }; - console_appender( const value& args ); - const char* get_color( log_level::type l )const; + console_appender( const variant& args ); + const char* get_color( log_level l )const; virtual void log( const log_message& m ); + private: config cfg; color::type lc[log_level::off+1]; }; } // namespace fc -#include +#include FC_REFLECT_ENUM( fc::console_appender::stream::type, (std_out)(std_error) ) FC_REFLECT_ENUM( fc::console_appender::color::type, (red)(green)(brown)(blue)(magenta)(cyan)(white)(console_default) ) FC_REFLECT( fc::console_appender::level_color, (level)(color) ) diff --git a/include/fc/file_appender.hpp b/include/fc/log/file_appender.hpp similarity index 81% rename from include/fc/file_appender.hpp rename to include/fc/log/file_appender.hpp index 0ffae0d..8adaf6a 100644 --- a/include/fc/file_appender.hpp +++ b/include/fc/log/file_appender.hpp @@ -1,10 +1,12 @@ #pragma once -#include -#include +#include +#include #include namespace fc { +class varaint; + class file_appender : public appender { public: struct config { @@ -15,7 +17,7 @@ class file_appender : public appender { bool flush; bool truncate; }; - file_appender( const value& args ); + file_appender( const variant& args ); ~file_appender(); virtual void log( const log_message& m ); @@ -25,5 +27,5 @@ class file_appender : public appender { }; } // namespace fc -#include +#include FC_REFLECT( fc::file_appender::config, (format)(filename)(flush)(truncate) ) diff --git a/include/fc/log/log_message.hpp b/include/fc/log/log_message.hpp new file mode 100644 index 0000000..c632cc6 --- /dev/null +++ b/include/fc/log/log_message.hpp @@ -0,0 +1,159 @@ +#pragma once +/** + * @file log_message.hpp + * @brief Defines types and helper macros necessary for generating log messages. + */ +#include +#include +#include +#include + +namespace fc +{ + namespace detail + { + class log_context_impl; + class log_message_impl; + } + + /** + * Named scope for log_level enumeration. + */ + class log_level + { + public: + /** + * @brief Define's the various log levels for reporting. + * + * Each log level includes all higher levels such that + * Debug includes Error, but Error does not include Debug. + */ + enum values + { + all, + debug, + info, + warn, + error, + off + }; + log_level( values v = off ):value(v){} + explicit log_level( int v ):value( static_cast(v)){} + operator int()const { return value; } + values value; + }; + + void to_variant( log_level e, variant& v ); + void from_variant( const variant& e, log_level& ll ); + + /** + * @brief provides information about where and when a log message was generated. + * @ingroup AthenaSerializable + * + * @see FC_LOG_CONTEXT + */ + class log_context + { + public: + log_context(); + log_context( log_level ll, + const char* file, + uint64_t line, + const char* method ); + ~log_context(); + explicit log_context( const variant& v ); + variant to_variant()const; + + string get_file()const; + uint64_t get_line_number()const; + string get_method()const; + string get_thread_name()const; + string get_host_name()const; + time_point get_timestamp()const; + log_level get_log_level()const; + string get_context()const; + + void append_context( const fc::string& c ); + + string to_string()const; + private: + std::shared_ptr my; + }; + + void to_variant( const log_context& l, variant& v ); + void from_variant( const variant& l, log_context& c ); + + /** + * @brief aggregates a message along with the context and associated meta-information. + * @ingroup AthenaSerializable + * + * @note log_message has reference semantics, all copies refer to the same log message + * and the message is read-only after construction. + * + * When converted to JSON, log_message has the following form: + * @code + * { + * "context" : { ... }, + * "format" : "string with ${keys}", + * "data" : { "keys" : "values" } + * } + * @endcode + * + * @see FC_LOG_MESSAGE + */ + class log_message + { + public: + log_message(); + /** + * @param ctx - generally provided using the FC_LOG_CONTEXT(LEVEL) macro + */ + log_message( log_context ctx, const char* format, variant_object args = variant_object() ); + ~log_message(); + + log_message( const variant& v ); + variant to_variant()const; + + string get_message()const; + + log_context get_context()const; + string get_format()const; + variant_object get_data()const; + + private: + std::shared_ptr my; + }; + + void to_variant( const log_message& l, variant& v ); + void from_variant( const variant& l, log_message& c ); + + typedef fc::vector log_messages; + + +} // namespace fc + +#ifndef __func__ +#define __func__ __FUNCTION__ +#endif + +/** + * @def FC_LOG_CONTEXT(LOG_LEVEL) + * @brief Automatically captures the File, Line, and Method names and passes them to + * the constructor of fc::log_context along with LOG_LEVEL + * @param LOG_LEVEL - a valid log_level::Enum name. + */ +#define FC_LOG_CONTEXT(LOG_LEVEL) \ + fc::log_context( fc::log_level::LOG_LEVEL, __FILE__, __LINE__, __func__ ) + +/** + * @def FC_LOG_MESSAGE(LOG_LEVEL,FORMAT,...) + * + * @brief A helper method for generating log messages. + * + * @param LOG_LEVEL a valid log_level::Enum name to be passed to the log_context + * @param FORMAT A const char* string containing zero or more references to keys as "${key}" + * @param ... A set of key/value pairs denoted as ("key",val)("key2",val2)... + */ +#define FC_LOG_MESSAGE( LOG_LEVEL, FORMAT, ... ) \ + fc::log_message( FC_LOG_CONTEXT(LOG_LEVEL), FORMAT, fc::mutable_variant_object()__VA_ARGS__ ) + diff --git a/include/fc/log/logger.hpp b/include/fc/log/logger.hpp new file mode 100644 index 0000000..6ea1d43 --- /dev/null +++ b/include/fc/log/logger.hpp @@ -0,0 +1,137 @@ +#pragma once +#include +#include +#include +#include + +namespace fc +{ + + class appender; + + /** + * + * + @code + void my_class::func() + { + fc_dlog( my_class_logger, "Format four: ${arg} five: ${five}", ("arg",4)("five",5) ); + } + @endcode + */ + class logger + { + public: + static logger get( const fc::string& name = "default"); + + logger(); + logger( const string& name, const logger& parent = nullptr ); + logger( std::nullptr_t ); + logger( const logger& c ); + logger( logger&& c ); + ~logger(); + logger& operator=(const logger&); + logger& operator=(logger&&); + friend bool operator==( const logger&, nullptr_t ); + friend bool operator!=( const logger&, nullptr_t ); + + logger& set_log_level( log_level e ); + log_level get_log_level()const; + logger& set_parent( const logger& l ); + logger get_parent()const; + + void set_name( const fc::string& n ); + const fc::string& name()const; + + void add_appender( const fc::shared_ptr& a ); + + bool is_enabled( log_level e )const; + void log( log_message m ); + + private: + class impl; + fc::shared_ptr my; + }; + +} // namespace fc + + +#define fc_dlog( LOGGER, FORMAT, ... ) \ + do { \ + if( (LOGGER).is_enabled( fc::log_level::debug ) ) { \ + (LOGGER).log( FC_LOG_MESSAGE( debug, FORMAT, __VA_ARGS__ ) ); \ + } \ + } while (0) + +#define fc_ilog( LOGGER, FORMAT, ... ) \ + do { \ + if( (LOGGER).is_enabled( fc::log_level::info ) ) { \ + (LOGGER).log( FC_LOG_MESSAGE( info, FORMAT, __VA_ARGS__ ) ); \ + } \ + } while (0) + +#define fc_wlog( LOGGER, FORMAT, ... ) \ + do { \ + if( (LOGGER).is_enabled( fc::log_level::warn ) ) { \ + (LOGGER).log( FC_LOG_MESSAGE( warn, FORMAT, __VA_ARGS__ ) ); \ + } \ + } while (0) + +#define fc_elog( LOGGER, FORMAT, ... ) \ + do { \ + if( (LOGGER).is_enabled( fc::log_level::error ) ) { \ + (LOGGER).log( FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ ) ); \ + } \ + } while (0) + +#define dlog( FORMAT, ... ) \ + do { \ + if( (fc::logger::get()).is_enabled( fc::log_level::debug ) ) { \ + (fc::logger::get()).log( FC_LOG_MESSAGE( debug, FORMAT, __VA_ARGS__ ) ); \ + } \ + } while (0) + +#define ilog( FORMAT, ... ) \ + do { \ + if( (fc::logger::get()).is_enabled( fc::log_level::info ) ) { \ + (fc::logger::get()).log( FC_LOG_MESSAGE( info, FORMAT, __VA_ARGS__ ) ); \ + } \ + } while (0) + +#define wlog( FORMAT, ... ) \ + do { \ + if( (fc::logger::get()).is_enabled( fc::log_level::warn ) ) { \ + (fc::logger::get()).log( FC_LOG_MESSAGE( warn, FORMAT, __VA_ARGS__ ) ); \ + } \ + } while (0) + +#define elog( FORMAT, ... ) \ + do { \ + if( (fc::logger::get()).is_enabled( fc::log_level::error ) ) { \ + (fc::logger::get()).log( FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ ) ); \ + } \ + } while (0) + +#include +#include +#include +#include +#include +#include + + +#define FC_FORMAT_ARG(r, unused, base) \ + BOOST_PP_STRINGIZE(base) ": ${" BOOST_PP_STRINGIZE( base ) "} " + +#define FC_FORMAT_ARGS(r, unused, base) \ + BOOST_PP_LPAREN() BOOST_PP_STRINGIZE(base),fc::variant(base) BOOST_PP_RPAREN() + +#define FC_FORMAT( SEQ )\ + BOOST_PP_SEQ_FOR_EACH( FC_FORMAT_ARG, v, SEQ ) + +#define FC_FORMAT_ARG_PARAMS( SEQ )\ + BOOST_PP_SEQ_FOR_EACH( FC_FORMAT_ARGS, v, SEQ ) + +#define idump( SEQ ) \ + ilog( FC_FORMAT(SEQ), FC_FORMAT_ARG_PARAMS(SEQ) ) + diff --git a/include/fc/logger_config.hpp b/include/fc/log/logger_config.hpp similarity index 81% rename from include/fc/logger_config.hpp rename to include/fc/log/logger_config.hpp index a089052..c46accc 100644 --- a/include/fc/logger_config.hpp +++ b/include/fc/log/logger_config.hpp @@ -1,15 +1,15 @@ #pragma once -#include +#include namespace fc { class path; struct appender_config { - appender_config(const fc::string& n="",const fc::string& t="", const value& a=value()) - :name(n),type(t),args(a),enabled(true){} - string name; - string type; - value args; - bool enabled; + appender_config(const fc::string& n="",const fc::string& t="", variant a=variant()) + :name(n),type(t),args(fc::move(a)),enabled(true){} + string name; + string type; + variant args; + bool enabled; }; struct logger_config { @@ -17,7 +17,7 @@ namespace fc { string name; ostring parent; /// if not set, then parents level is used. - fc::optional level; + fc::optional level; bool enabled; /// if any appenders are sepecified, then parent's appenders are not set. bool additivity; @@ -37,7 +37,7 @@ namespace fc { bool configure_logging( const logging_config& l ); } -#include +#include FC_REFLECT( fc::appender_config, (name)(type)(args)(enabled) ) FC_REFLECT( fc::logger_config, (name)(parent)(level)(enabled)(additivity)(appenders) ) FC_REFLECT( fc::logging_config, (includes)(appenders)(loggers) ) diff --git a/include/fc/logger.hpp b/include/fc/logger.hpp deleted file mode 100644 index 4b2fafc..0000000 --- a/include/fc/logger.hpp +++ /dev/null @@ -1,144 +0,0 @@ -#pragma once -#include -#include -#include -#include - - -namespace fc { - - struct log_level { - enum type { - all, trace, debug, info, warn, error, fatal, off - }; - }; - - struct log_message { - log_message(log_level::type, const string& file, int line, const string& func, const string& format ); - log_message(); - - otime_point when; - log_level::type level; - ostring context; - ostring thread; - ostring fiber; - ostring host; - string file; - int line; - string method; - string format; - value args; - ovalue meta; - - // key based args - template - log_message& operator()( const string& arg, const T& v ) { - return (*this)(arg,value(v)); - } - - log_message& operator()( const string& arg, value&& v ); - log_message& operator()( const string& arg, const value& v ); - // position based args... - log_message& operator()( value&& v ); - log_message& operator()( const value& v ); - }; - - class appender; - - /** - * - * - @code - void my_class::func() - { - fc_dlog( my_class_logger, "Format four: ${arg} five: ${five}", ("arg",4)("five",5) ); - } - @endcode - */ - class logger { - public: - static logger get( const fc::string& name = "default"); - - logger(); - logger( const string& name, const logger& parent = nullptr ); - logger( std::nullptr_t ); - logger( const logger& c ); - logger( logger&& c ); - ~logger(); - logger& operator=(const logger&); - logger& operator=(logger&&); - friend bool operator==( const logger&, std::nullptr_t ); - friend bool operator!=( const logger&, std::nullptr_t ); - - logger& set_log_level( log_level::type e ); - log_level::type get_log_level()const; - logger& set_parent( const logger& l ); - logger get_parent()const; - - void set_name( const fc::string& n ); - const fc::string& name()const; - - void add_appender( const fc::shared_ptr& a ); - - - bool is_enabled( log_level::type e )const; - void log( log_message m ); - - private: - class impl; - fc::shared_ptr my; - }; - - /** - * This helper class is used to automatically print a log message - * once upon construction, and again upon destruction and is therefore - * helpful in catching scope changes. - struct tracer { - tracer( const logger::ptr& lgr ); - ~tracer(); - - void set_message( log_message&& ms g); - - private: - logger::ptr logger; - log_message msg; - }; - */ - -} // namespace fc - -#include -FC_REFLECT( fc::log_message, (when)(level)(context)(thread)(fiber)(host)(method)(file)(line)(format)(args)(meta) ) -FC_REFLECT_ENUM( fc::log_level::type, (all)(trace)(debug)(info)(warn)(error)(fatal)(off) ) - -#define fc_scope_log( LOGGER, FORMAT, ... ) \ - fc::tracer __tracer; \ - if( (LOGGER).is_enabled( fc::log_level::trace ) ) { \ - __tracer.set_message( fc::log_message( fc::log_level::trace, __FILE__, __LINE__, __func__, FORMAT ) __VA_ARGS__ );\ - } - -#define fc_dlog( LOGGER, FORMAT, ... ) \ - if( (LOGGER).is_enabled( fc::log_level::debug ) ) { \ - (LOGGER).log( fc::log_message( fc::log_level::debug, __FILE__, __LINE__, __func__, FORMAT ) __VA_ARGS__ );\ - } - -#define fc_ilog( LOGGER, FORMAT, ... ) \ - if( (LOGGER).is_enabled( fc::log_level::info ) ) { \ - (LOGGER).log( fc::log_message( fc::log_level::info, __FILE__, __LINE__, __func__, FORMAT ) __VA_ARGS__ );\ - } - -#define fc_wlog( LOGGER, FORMAT, ... ) \ - if( (LOGGER).is_enabled( fc::log_level::warn ) ) { \ - (LOGGER).log( fc::log_message( fc::log_level::warn, __FILE__, __LINE__, __func__, FORMAT ) __VA_ARGS__ );\ - } - -#define fc_elog( LOGGER, FORMAT, ... ) \ - if( (LOGGER).is_enabled( fc::log_level::error ) ) { \ - (LOGGER).log( fc::log_message( fc::log_level::error, __FILE__, __LINE__, __func__, FORMAT ) __VA_ARGS__ );\ - } - -#define fc_flog( LOGGER, FORMAT, ... ) \ - if( (LOGGER).is_enabled( fc::log_level::fatal ) ) { \ - (LOGGER).log( fc::log_message( fc::log_level::fatal, __FILE__, __LINE__, __func__, FORMAT ) __VA_ARGS__ );\ - } - diff --git a/include/fc/make_fused.hpp b/include/fc/make_fused.hpp index cc82ff8..acbf901 100644 --- a/include/fc/make_fused.hpp +++ b/include/fc/make_fused.hpp @@ -4,23 +4,23 @@ namespace fc { template - fc::function > make_fused( const fc::function& f ) { + std::function > make_fused( const std::function& f ) { return [=]( fc::tuple<> ){ return f(); }; } template - fc::function) > make_fused( const fc::function& f ) { + std::function) > make_fused( const std::function& f ) { return [f]( fc::tuple t){ return f(t.a); }; } template - fc::function) > make_fused( const fc::function& f ) { + std::function) > make_fused( const std::function& f ) { return [f]( fc::tuple t){ return f(t.a,t.b); }; } template - fc::function) > make_fused( const fc::function& f ) { + std::function) > make_fused( const std::function& f ) { return [f]( fc::tuple t){ return f(t.a,t.b,t.c); }; } template - fc::function) > make_fused( const fc::function& f ) { + std::function) > make_fused( const std::function& f ) { return [f]( fc::tuple t){ return f(t.a,t.b,t.c,t.d); }; } } diff --git a/include/fc/map.hpp b/include/fc/map.hpp deleted file mode 100644 index 1cdb745..0000000 --- a/include/fc/map.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _FC_MAP_HPP_ -namespace fc { - - namespace detail { - class map_impl { - public: - - - }; - } - template - class map : public map_impl { - - - }; - - -} diff --git a/include/fc/endpoint.hpp b/include/fc/network/endpoint.hpp similarity index 100% rename from include/fc/endpoint.hpp rename to include/fc/network/endpoint.hpp diff --git a/include/fc/network/http/connection.hpp b/include/fc/network/http/connection.hpp new file mode 100644 index 0000000..90d9090 --- /dev/null +++ b/include/fc/network/http/connection.hpp @@ -0,0 +1,76 @@ +#pragma once +#include +#include +#include + +namespace fc { + namespace ip { class endpoint; } + class tcp_socket; + + namespace http { + + struct header + { + header( fc::string k, fc::string v ) + :key(fc::move(k)),val(fc::move(v)){} + header(){} + fc::string key; + fc::string val; + }; + + typedef fc::vector
headers; + + struct reply + { + enum status_code { + OK = 200, + RecordCreated = 201, + NotFound = 404, + Found = 302, + InternalServerError = 500 + }; + reply( status_code c = OK):status(c){} + int status; + fc::vector
headers; + fc::vector body; + }; + + struct request + { + fc::string get_header( const fc::string& key )const; + fc::string method; + fc::string domain; + fc::string path; + fc::vector
headers; + fc::vector body; + }; + + fc::vector
parse_urlencoded_params( const fc::string& f ); + + /** + * Connections have reference semantics, all copies refer to the same + * underlying socket. + */ + class connection + { + public: + connection(); + ~connection(); + // used for clients + void connect_to( const fc::ip::endpoint& ep ); + http::reply request( const fc::string& method, const fc::string& url, const fc::string& body, const headers& = headers()); + + // used for servers + fc::tcp_socket& get_socket()const; + + http::request read_request()const; + + class impl; + private: + std::unique_ptr my; + }; + + typedef std::shared_ptr connection_ptr; + +} } // fc::http + diff --git a/include/fc/http/server.hpp b/include/fc/network/http/server.hpp similarity index 87% rename from include/fc/http/server.hpp rename to include/fc/network/http/server.hpp index e8764f1..711ea50 100644 --- a/include/fc/http/server.hpp +++ b/include/fc/network/http/server.hpp @@ -1,7 +1,8 @@ #pragma once -#include +#include #include #include +#include namespace fc { namespace http { @@ -11,18 +12,18 @@ namespace fc { namespace http { * function for every http request. * */ - class server { + class server + { public: server(); server( uint16_t port ); - server( const server& s ); server( server&& s ); ~server(); - server& operator=(const server& s); server& operator=(server&& s); - class response { + class response + { public: class impl; @@ -53,8 +54,8 @@ namespace fc { namespace http { private: class impl; - fc::shared_ptr my; - + std::unique_ptr my; }; + typedef std::shared_ptr server_ptr; } } diff --git a/include/fc/ip.hpp b/include/fc/network/ip.hpp similarity index 83% rename from include/fc/ip.hpp rename to include/fc/network/ip.hpp index ea64ed1..f21eb27 100644 --- a/include/fc/ip.hpp +++ b/include/fc/network/ip.hpp @@ -46,7 +46,10 @@ namespace fc { address _ip; }; } - class value; - void pack( fc::value& , const fc::ip::endpoint& ); - void unpack( const fc::value& , fc::ip::endpoint& ); + class variant; + void to_variant( const ip::endpoint& var, variant& vo ); + void from_variant( const variant& var, ip::endpoint& vo ); + + void to_variant( const ip::address& var, variant& vo ); + void from_variant( const variant& var, ip::address& vo ); } diff --git a/include/fc/tcp_socket.hpp b/include/fc/network/tcp_socket.hpp similarity index 80% rename from include/fc/tcp_socket.hpp rename to include/fc/network/tcp_socket.hpp index e2eb354..69d4ea4 100644 --- a/include/fc/tcp_socket.hpp +++ b/include/fc/network/tcp_socket.hpp @@ -1,11 +1,12 @@ #pragma once #include #include -#include +#include namespace fc { namespace ip { class endpoint; } - class tcp_socket : public iostream { + class tcp_socket : public virtual iostream + { public: tcp_socket(); ~tcp_socket(); @@ -15,13 +16,12 @@ namespace fc { /// istream interface /// @{ virtual size_t readsome( char* buffer, size_t max ); - virtual istream& read( char* buffer, size_t s ); virtual bool eof()const; /// @} /// ostream interface /// @{ - virtual ostream& write( const char* buffer, size_t len ); + virtual size_t writesome( const char* buffer, size_t len ); virtual void flush(); virtual void close(); /// @} @@ -33,8 +33,11 @@ namespace fc { class impl; fc::fwd my; }; + typedef std::shared_ptr tcp_socket_ptr; - class tcp_server { + + class tcp_server + { public: tcp_server(); ~tcp_server(); diff --git a/include/fc/udp_socket.hpp b/include/fc/network/udp_socket.hpp similarity index 100% rename from include/fc/udp_socket.hpp rename to include/fc/network/udp_socket.hpp diff --git a/include/fc/network/url.hpp b/include/fc/network/url.hpp new file mode 100644 index 0000000..6f8c745 --- /dev/null +++ b/include/fc/network/url.hpp @@ -0,0 +1,106 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace fc { + + typedef fc::optional ostring; + typedef fc::optional opath; + typedef fc::optional ovariant_object; + + namespace detail { class url_impl; } + + class mutable_url; + + /** + * Used to pass an immutable URL and + * query its parts. + */ + class url + { + public: + url(); + explicit url( const string& u ); + url( const url& c ); + url( url&& c ); + url( mutable_url&& c ); + url( const mutable_url& c ); + ~url(); + + url& operator=( const url& c ); + url& operator=( url&& c ); + + url& operator=( const mutable_url& c ); + url& operator=( mutable_url&& c ); + + bool operator==( const url& cmp )const; + + operator string()const; + + //// file, ssh, tcp, http, ssl, etc... + string proto()const; + ostring host()const; + ostring user()const; + ostring pass()const; + opath path()const; + ovariant_object args()const; + fc::optional port()const; + + private: + friend class mutable_url; + std::shared_ptr my; + }; + + void to_variant( const url& u, fc::variant& v ); + void from_variant( const fc::variant& v, url& u ); + + /** + * Used to create / manipulate a URL + */ + class mutable_url + { + public: + mutable_url(); + explicit mutable_url( const string& mutable_url ); + mutable_url( const mutable_url& c ); + mutable_url( const url& c ); + mutable_url( mutable_url&& c ); + ~mutable_url(); + + mutable_url& operator=( const url& c ); + mutable_url& operator=( const mutable_url& c ); + mutable_url& operator=( mutable_url&& c ); + + bool operator==( const mutable_url& cmp )const; + bool operator==( const url& cmp )const; + + operator string()const; + + //// file, ssh, tcp, http, ssl, etc... + string proto()const; + ostring host()const; + ostring user()const; + ostring pass()const; + opath path()const; + ovariant_object args()const; + fc::optional port()const; + + void set_proto( string ); + void set_host( string ); + void set_user( string ); + void set_pass( string ); + void set_path( fc::path p ); + void set_args( variant_object ); + void set_port( uint16_t ); + + private: + friend class url; + std::unique_ptr my; + }; + +} // namespace fc + diff --git a/include/fc/numeric_cast.hpp b/include/fc/numeric_cast.hpp deleted file mode 100644 index 3fdb766..0000000 --- a/include/fc/numeric_cast.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -namespace fc { - template - T numeric_cast( const R& v ) { - // TODO: do something smarter here, check ranges, etc - return static_cast(v); - } -} diff --git a/include/fc/optional.hpp b/include/fc/optional.hpp index e32ff74..48ef53f 100644 --- a/include/fc/optional.hpp +++ b/include/fc/optional.hpp @@ -8,6 +8,12 @@ namespace fc { * Simply including boost::optional adds 35,000 lines to each object file, using * fc::optional adds less than 400. */ + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4521) /* multiple copy ctors */ +#endif + template class optional { public: @@ -20,6 +26,12 @@ namespace fc { _valid = o._valid; } + optional( optional& o ) + :_valid(false) { + if( o._valid ) new (&**this) T( *o ); + _valid = o._valid; + } + optional( optional&& o ) :_valid(false) { if( o._valid ) new (&**this) T( fc::move(*o) ); @@ -39,23 +51,36 @@ namespace fc { new (&**this) T( fc::forward(u) ); _valid = true; } else { - **this = fc::forward(u); + **this = static_cast(fc::forward(u)); } return *this; } optional& operator=( const optional& o ) { - if( _valid && o._valid ) { **this = *o; } - else if( !_valid && o._valid ) { - *this = *o; - } // else !_valid && !o._valid == same! + if (this != &o) { + if( _valid && o._valid ) { + **this = *o; + } else if( !_valid && o._valid ) { + *this = *o; + } else if (_valid) { + (**this).~T(); + _valid = false; + } + } return *this; } + optional& operator=( optional&& o ) { - if( _valid && o._valid ) { **this = fc::move(*o); } - else if( !_valid && o._valid ) { - *this = fc::move(*o); - } + if (this != &o) { + if( _valid && o._valid ) { + **this = fc::move(*o); + } else if ( !_valid && o._valid ) { + *this = fc::move(*o); + } else if (_valid) { + (**this).~T(); + _valid = false; + } + } return *this; } @@ -91,5 +116,9 @@ namespace fc { return !left || *left != u; } +#ifdef _MSC_VER +# pragma warning(pop) +#endif + } // namespace fc diff --git a/include/fc/pke.hpp b/include/fc/pke.hpp deleted file mode 100644 index b0edba9..0000000 --- a/include/fc/pke.hpp +++ /dev/null @@ -1,155 +0,0 @@ -#pragma once -#include -#include -#include - -/** - * Define common crypto methods and data types to abstract underlying implementation. - */ -namespace fc { - - template - struct signature { - char data[KeySize/8]; - template - friend T& operator<<( T& ds, const fc::signature& sig ) - { - ds.write(sig.data, KS/8 ); - return ds; - } - template - friend T& operator>>( T& ds, fc::signature& sig ) - { - ds.read(sig.data, KS/8 ); - return ds; - } - bool operator != ( const signature& s )const { - return memcmp( s.data, data, sizeof(data) ) != 0; - } - bool operator == ( const signature& s )const { - return memcmp( s.data, data, sizeof(data) ) == 0; - } - }; - - bool verify_data( const char* key, uint32_t key_size, uint32_t pe, const sha1& hc, const char* sig ); - bool sign_data( const fc::vector& key, uint32_t key_size, uint32_t pe, const sha1& hc, char* sig ); - bool public_encrypt( const char* key, uint32_t key_size, uint32_t pe, const fc::vector& in, fc::vector& out ); - bool public_decrypt( const char* key, uint32_t key_size, uint32_t pe, const fc::vector& in, fc::vector& out ); - bool private_encrypt( const fc::vector& key, uint32_t key_size, uint32_t pe, const fc::vector& in, fc::vector& out ); - bool private_decrypt( const fc::vector& key, uint32_t key_size, uint32_t pe, const fc::vector& in, fc::vector& out ); - bool generate_keys( char* pubkey, fc::vector& privkey, uint32_t key_size, uint32_t pe ); - - template - struct private_key; - - template - struct public_key { - public_key() { memset( key, 0, sizeof(key) ); } - public_key( const public_key& pk ) { memcpy( key, pk.key, sizeof(key) ); } - - bool verify( const sha1& digest, const signature& sig )const { - return verify_data( key, sizeof(key), PublicExponent, digest, sig.data ); - } - bool encrypt( const fc::vector& in, fc::vector& out )const { - return public_encrypt( key, KeySize, PublicExponent, in, out ); - } - bool decrypt( const fc::vector& in, fc::vector& out )const { - return public_decrypt( key, KeySize, PublicExponent, in, out ); - } - - public_key& operator = ( const public_key& pk ) { - memcpy( key, pk.key, sizeof(key) ); - return *this; - } - bool operator == ( const public_key& pk )const { - return 0 == memcmp( key, pk.key, sizeof(key) ); - } - bool operator != ( const public_key& pk )const { - return 0 != memcmp( key, pk.key, sizeof(key) ); - } - bool operator > ( const public_key& pk )const { - return memcmp( key, pk.key, sizeof(key) ) > 0; - } - bool operator < ( const public_key& pk )const { - return memcmp( key, pk.key, sizeof(key) ) < 0; - } - - template - inline friend T& operator<<( T& ds, const fc::public_key& pk ) { - ds.write(pk.key, KS/8 ); - return ds; - } - template - inline friend T& operator>>( T& ds, fc::public_key& pk ) { - ds.read( pk.key, KS/8 ); - return ds; - } - - private: - template - friend void generate_keys( public_key& pub, private_key& priv ); - - char key[KeySize/8]; - }; - - - template - struct private_key { - bool encrypt( const fc::vector& in, fc::vector& out )const { - return private_encrypt( key, KeySize, PublicExponent, in, out ); - } - bool decrypt( const fc::vector& in, fc::vector& out )const { - return private_decrypt( key, KeySize, PublicExponent, in, out ); - } - bool sign( const sha1& digest, signature& sig )const { - return sign_data( key, KeySize, PublicExponent, digest, sig.data ); - } - - template - friend T& operator<<( T& ds, const fc::private_key& pk ) { - uint16_t s = pk.key.size(); - ds.write( (const char*)&s, sizeof(s) ); - ds.write( pk.key.data(), pk.key.size() ); - return ds; - } - template - friend T& operator>>( T& ds, fc::private_key& pk ) { - uint16_t s; - ds.read((char*)&s,sizeof(s) ); - pk.key.resize(s); - ds.read( pk.key.data(), pk.key.size() ); - return ds; - } - private: - template - friend void generate_keys( public_key& pub, private_key& priv ); - fc::vector key; - }; - - template - void generate_keys( public_key& pub, private_key& priv ) { - generate_keys( pub.key, priv.key, KeySize, PublicExponent ); - } - /* - template - inline std::ostream& operator<< ( std::ostream& os, const signature& s ) { - for( uint32_t i = 0; i < KeySize; ++i ) - os << std::hex << int(s.data[i]) << ' '; - return os; - } - */ - - typedef public_key<> public_key_t; - typedef private_key<> private_key_t; - typedef signature<> signature_t; - - class value; - void pack( fc::value& , const fc::signature_t& ); - void unpack( const fc::value& , fc::signature_t& ); - void pack( fc::value& , const fc::public_key_t& ); - void unpack( const fc::value& , fc::private_key_t& ); - void pack( fc::value& , const fc::private_key_t& ); - void unpack( const fc::value& , fc::public_key_t& ); -} // namespace fc - - diff --git a/include/fc/process.hpp b/include/fc/process.hpp deleted file mode 100644 index 4a596a7..0000000 --- a/include/fc/process.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once -#include -#include -#include - -namespace fc { - class istream; - class ostream; - class path; - template class vector; - - fc::path find_executable_in_path( const fc::string name ); - - /** - * @brief start and manage an external process - * - * @note this class implements reference semantics. - */ - class process { - public: - enum exec_opts { - open_none = 0, - open_stdin = 0x01, - open_stdout = 0x02, - open_stderr = 0x04, - open_all = open_stdin|open_stdout|open_stderr, - }; - - /** - * Return a new process executing the specified exe with the specified args. - */ - fc::future exec( const fc::path& exe, int opt = open_all ); - fc::future exec( const fc::path& exe, const fc::path& wd, int opt = open_all ); - fc::future exec( const fc::path& exe, fc::vector&& args , int opt = open_all ); - fc::future exec( const fc::path& exe, fc::vector&& args, const fc::path& wd, int opt = open_all ); - - /** - * Forcefully kills the process. - */ - void kill(); - - /** - * @brief returns a stream that writes to the process' stdin - */ - fc::ostream& in_stream(); - - /** - * @brief returns a stream that reads from the process' stdout - */ - fc::istream& out_stream(); - /** - * @brief returns a stream that reads from the process' stderr - */ - fc::istream& err_stream(); - - FC_REFERENCE_TYPE(process) - }; - -} // namespace fc diff --git a/include/fc/program_options.hpp b/include/fc/program_options.hpp deleted file mode 100644 index f839d72..0000000 --- a/include/fc/program_options.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef _FC_PROGRAM_OPTIONS_HPP_ -#define _FC_PROGRAM_OPTIONS_HPP_ -#include -#include -#include -#include -#include - -namespace boost { - namespace program_options { - class variables_map; - } -} - -namespace fc { - class ostream; - - namespace program_options { - template - class value { - public: - value( T* v ):_v(v){} - value& default_value( const T& d ) { _default = d; } - - T* get()const { return _v; } - private: - fc::optional _default; - T* _v; - }; - - class options_description { - public: - options_description( const char* c ); - ~options_description(); - - options_description& add_options(); - options_description& operator()( const char* o, const char* desc ); - options_description& operator()( const char* o, const value&, const char* desc ); - options_description& operator()( const char* o, const value&, const char* desc ); - options_description& operator()( const char* o, const value >&, const char* desc ); - - private: - class impl; - fwd my; - - friend class variables_map; - friend fc::ostream& operator<<( fc::ostream& o, const options_description& ); - }; - - class variables_map { - public: - variables_map(); - ~variables_map(); - - void parse_command_line( int argc, char** argv, const options_description& d ); - int count( const char* opt ); - private: - class impl; - fwd my; - }; - - } -} -#endif // _FC_PROGRAM_OPTIONS_HPP_ diff --git a/include/fc/reflect.hpp b/include/fc/reflect/reflect.hpp similarity index 96% rename from include/fc/reflect.hpp rename to include/fc/reflect/reflect.hpp index 44d86c2..57bf64a 100644 --- a/include/fc/reflect.hpp +++ b/include/fc/reflect/reflect.hpp @@ -1,12 +1,10 @@ - +#pragma once /** * @file fc/reflect.hpp * * @brief Defines types and macros used to provide reflection. * */ -#ifndef _FC_REFLECT_HPP_ -#define _FC_REFLECT_HPP_ #include #include @@ -16,8 +14,7 @@ #include #include -#include -#include +#include namespace fc { @@ -41,7 +38,7 @@ struct reflector{ * * @code * struct functor { - * template + * template * void operator()( const char* name )const; * }; * @endcode @@ -90,7 +87,7 @@ void throw_bad_enum_cast( const char* k, const char* e ); #define FC_REFLECT_BASE_MEMBER_COUNT( r, OP, elem ) \ - OP fc::reflector::member_count + OP fc::reflector::total_member_count #define FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \ template\ @@ -207,4 +204,3 @@ template<> struct reflector {\ -#endif diff --git a/include/fc/typename.hpp b/include/fc/reflect/typename.hpp similarity index 100% rename from include/fc/typename.hpp rename to include/fc/reflect/typename.hpp diff --git a/include/fc/reflect/variant.hpp b/include/fc/reflect/variant.hpp new file mode 100644 index 0000000..0c41de1 --- /dev/null +++ b/include/fc/reflect/variant.hpp @@ -0,0 +1,99 @@ +#pragma once +#include +#include + +namespace fc +{ + template + void to_variant( const T& o, variant& v ); + template + void from_variant( const variant& v, T& o ); + + + template + class to_variant_visitor + { + public: + to_variant_visitor( mutable_variant_object& mvo, const T& v ) + :vo(mvo),val(v){} + + template + void operator()( const char* name )const + { + vo(name,(val.*member)); + } + + mutable_variant_object& vo; + const T& val; + }; + + template + class from_variant_visitor + { + public: + from_variant_visitor( const variant_object& _vo, T& v ) + :vo(_vo),val(v){} + + template + void operator()( const char* name )const + { + auto itr = vo.find(name); + if( itr != vo.end() ) + from_variant( itr->value(), val.*member ); + } + + const variant_object& vo; + T& val; + }; + + template + struct if_enum + { + template + static inline void to_variant( const T& v, fc::variant& vo ) + { + mutable_variant_object mvo; + fc::reflector::visit( to_variant_visitor( mvo, v ) ); + vo = fc::move(mvo); + } + template + static inline void from_variant( const fc::variant& v, T& o ) + { + const variant_object& vo = v.get_object(); + fc::reflector::visit( from_variant_visitor( vo, o ) ); + } + }; + + template<> + struct if_enum + { + template + static inline void to_variant( const T& o, fc::variant& v ) + { + v = fc::reflector::to_string(o); + } + template + static inline void from_variant( const fc::variant& v, T& o ) + { + if( v.is_string() ) + o = fc::reflector::from_string( v.get_string().c_str() ); + else + // throw if invalid int, by attempting to convert to string + fc::reflector::to_string( o = static_cast(v.as_int64()) ); + } + }; + + + template + void to_variant( const T& o, variant& v ) + { + if_enum::is_enum>::to_variant( o, v ); + } + + template + void from_variant( const variant& v, T& o ) + { + if_enum::is_enum>::from_variant( v, o ); + } + +} diff --git a/include/fc/rpc/json_connection.hpp b/include/fc/rpc/json_connection.hpp new file mode 100644 index 0000000..e275362 --- /dev/null +++ b/include/fc/rpc/json_connection.hpp @@ -0,0 +1,140 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace fc { namespace rpc { + + namespace detail { class json_connection_impl; } + + /** + * @brief Implements JSON-RPC 2.0 over a set of io streams + * + * Each JSON RPC message is expected to be on its own line, violators + * will be prosecuted to the fullest extent of the law. + */ + class json_connection + { + public: + typedef std::function method; + typedef std::function named_param_method; + + json_connection( fc::buffered_istream_ptr in, fc::buffered_ostream_ptr out ); + ~json_connection(); + + /** + * Starts processing messages from input + */ + future exec(); + + logger get_logger()const; + void set_logger( const logger& l ); + + /** + * @name server interface + * + * Adding methods to the interface allows the remote side + * to call them. + */ + ///@{ + void add_method( const fc::string& name, method ); + void add_method( const fc::string& name, named_param_method ); + void remove_method( const fc::string& name ); + //@} + + /** + * @name client interface + */ + ///@{ + void notice( const fc::string& method ); + void notice( const fc::string& method, const variants& args ); + void notice( const fc::string& method, const variant_object& named_args ); + + /// args will be handled as named params + future async_call( const fc::string& method, + const variant_object& args ); + + future async_call( const fc::string& method, mutable_variant_object args ); + + /// Sending in an array of variants will be handled as positional arguments + future async_call( const fc::string& method, + const variants& args ); + + future async_call( const fc::string& method ); + + future async_call( const fc::string& method, + const variant& a1 ); + + future async_call( const fc::string& method, + const variant& a1, + const variant& a2 ); + + future async_call( const fc::string& method, + const variant& a1, + const variant& a2, + const variant& a3 ); + + template + Result call( const fc::string& method, + const variant& a1, + const variant& a2, + const variant& a3, + microseconds timeout = microseconds::maximum()) + { + return async_call( method, a1, a2, a3 ).wait(timeout).as(); + } + + template + Result call( const fc::string& method, + const variant& a1, + const variant& a2, + microseconds timeout = microseconds::maximum()) + { + return async_call( method, a1, a2 ).wait(timeout).as(); + } + + template + Result call( const fc::string& method, + const variant& a1, + microseconds timeout = microseconds::maximum()) + { + return async_call( method, a1 ).wait(timeout).as(); + } + + template + Result call( const fc::string& method, + variant_object a1, + microseconds timeout = microseconds::maximum()) + { + return async_call( method, fc::move(a1) ).wait(timeout).as(); + } + template + Result call( const fc::string& method, + mutable_variant_object a1, + microseconds timeout = microseconds::maximum()) + { + return async_call( method, variant_object( fc::move(a1) ) ).wait(timeout).as(); + } + + + template + Result call( const fc::string& method, microseconds timeout = microseconds::maximum() ) + { + return async_call( method ).wait(timeout).as(); + } + + /// Sending in a variant_object will be issued as named parameters + variant call( const fc::string& method, const variant_object& named_args ); + ///@} + + private: + std::unique_ptr my; + }; + typedef std::shared_ptr json_connection_ptr; + +}} // fc::rpc + + + diff --git a/include/fc/rpc/variant_connection.hpp b/include/fc/rpc/variant_connection.hpp new file mode 100644 index 0000000..cb6973e --- /dev/null +++ b/include/fc/rpc/variant_connection.hpp @@ -0,0 +1,140 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace fc { namespace rpc { + + namespace detail { class variant_connection_impl; } + + /** + * @brief Implements JSON-RPC 2.0 over a set of io streams + * + * Each JSON RPC message is expected to be on its own line, violators + * will be prosecuted to the fullest extent of the law. + */ + class variant_connection + { + public: + typedef std::function method; + typedef std::function named_param_method; + + variant_connection( fc::variant_stream::ptr in, fc::variant_stream::ptr out ); + ~variant_connection(); + + /** + * Starts processing messages from input + */ + future exec(); + + logger get_logger()const; + void set_logger( const logger& l ); + + /** + * @name server interface + * + * Adding methods to the interface allows the remote side + * to call them. + */ + ///@{ + void add_method( const fc::string& name, method ); + void add_method( const fc::string& name, named_param_method ); + void remove_method( const fc::string& name ); + //@} + + /** + * @name client interface + */ + ///@{ + void notice( const fc::string& method ); + void notice( const fc::string& method, const variants& args ); + void notice( const fc::string& method, const variant_object& named_args ); + + /// args will be handled as named params + future async_call( const fc::string& method, + const variant_object& args ); + + future async_call( const fc::string& method, mutable_variant_object args ); + + /// Sending in an array of variants will be handled as positional arguments + future async_call( const fc::string& method, + const variants& args ); + + future async_call( const fc::string& method ); + + future async_call( const fc::string& method, + const variant& a1 ); + + future async_call( const fc::string& method, + const variant& a1, + const variant& a2 ); + + future async_call( const fc::string& method, + const variant& a1, + const variant& a2, + const variant& a3 ); + + template + Result call( const fc::string& method, + const variant& a1, + const variant& a2, + const variant& a3, + microseconds timeout = microseconds::maximum()) + { + return async_call( method, a1, a2, a3 ).wait(timeout).as(); + } + + template + Result call( const fc::string& method, + const variant& a1, + const variant& a2, + microseconds timeout = microseconds::maximum()) + { + return async_call( method, a1, a2 ).wait(timeout).as(); + } + + template + Result call( const fc::string& method, + const variant& a1, + microseconds timeout = microseconds::maximum()) + { + return async_call( method, a1 ).wait(timeout).as(); + } + + template + Result call( const fc::string& method, + variant_object a1, + microseconds timeout = microseconds::maximum()) + { + return async_call( method, fc::move(a1) ).wait(timeout).as(); + } + template + Result call( const fc::string& method, + mutable_variant_object a1, + microseconds timeout = microseconds::maximum()) + { + return async_call( method, variant_object( fc::move(a1) ) ).wait(timeout).as(); + } + + + template + Result call( const fc::string& method, microseconds timeout = microseconds::maximum() ) + { + return async_call( method ).wait(timeout).as(); + } + + /// Sending in a variant_object will be issued as named parameters + variant call( const fc::string& method, const variant_object& named_args ); + ///@} + + private: + std::unique_ptr my; + }; + typedef std::shared_ptr variant_connection_ptr; + +}} // fc::rpc + + + diff --git a/include/fc/rpc/variant_stream.hpp b/include/fc/rpc/variant_stream.hpp new file mode 100644 index 0000000..585b776 --- /dev/null +++ b/include/fc/rpc/variant_stream.hpp @@ -0,0 +1,36 @@ +#pragma once + +namespace fc +{ + + /** + * Thread-safe, circular buffer for passing variants + * between threads. + */ + class variant_stream + { + public: + variant_stream( size_t s ); + ~variant_stream(); + + /** producer api */ + int64_t free(); // number of spaces available + int64_t claim( int64_t num ); + int64_t publish( int64_t pos ); + int64_t wait_free(); // wait for free space + + // producer/consumer api + variant& get( int64_t pos ); + + /** consumer api */ + int64_t begin(); // returns the first index ready to be read + int64_t end(); // returns the first index that cannot be read + int64_t wait(); // wait for variants to be posted + + private: + std::vector _variants; + uint64_t _read_pos; + uint64_t _write_pos; + }; + +} diff --git a/include/fc/server.hpp b/include/fc/server.hpp deleted file mode 100644 index a2976c1..0000000 --- a/include/fc/server.hpp +++ /dev/null @@ -1,27 +0,0 @@ - - -class istream { - public: - template - istream( T& s ) { - - } - - istream& read( char* buf, uint64_t s ); - int64_t readsome( char* buf, uint64_t s ); - bool eof()const; - - private: - struct vtable { - void* (*read)(void*, char* buf, uint64_t s ); - int64_t (*readsome)(void*, char* buf, uint64_t s ); - bool (*eof)(void* ) - }; - - vtable& _vtable; - void* _stream; -}; - - - - diff --git a/include/fc/sha1.hpp b/include/fc/sha1.hpp deleted file mode 100644 index 60a3449..0000000 --- a/include/fc/sha1.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once -#include -#include -#include - -namespace fc { - class path; - - class sha1 { - public: - sha1(); - explicit sha1( const fc::string& hex_str ); - - fc::string str()const; - - operator fc::string()const; - - char* data()const; - - static sha1 hash( const char* d, uint32_t dlen ); - static sha1 hash( const fc::string& ); - static sha1 hash( const fc::path& ); - - template - static sha1 hash( const T& t ) { sha1::encoder e; e << t; return e.result(); } - - class encoder { - public: - encoder(); - ~encoder(); - - void write( const char* d, uint32_t dlen ); - void put( char c ) { write( &c, 1 ); } - void reset(); - sha1 result(); - - private: - struct impl; - fwd my; - }; - - template - inline friend T& operator<<( T& ds, const sha1& ep ) { - ds.write( ep.data(), sizeof(ep) ); - return ds; - } - - template - inline friend T& operator>>( T& ds, sha1& ep ) { - ds.read( ep.data(), sizeof(ep) ); - return ds; - } - friend sha1 operator << ( const sha1& h1, uint32_t i ); - friend bool operator == ( const sha1& h1, const sha1& h2 ); - friend bool operator != ( const sha1& h1, const sha1& h2 ); - friend sha1 operator ^ ( const sha1& h1, const sha1& h2 ); - friend bool operator >= ( const sha1& h1, const sha1& h2 ); - friend bool operator > ( const sha1& h1, const sha1& h2 ); - friend bool operator < ( const sha1& h1, const sha1& h2 ); - - uint32_t _hash[5]; - }; - - class value; - void pack( fc::value& , const fc::sha1& ); - void unpack( const fc::value& , fc::sha1& ); -} - - diff --git a/include/fc/sha256.hpp b/include/fc/sha256.hpp deleted file mode 100644 index 1b04db5..0000000 --- a/include/fc/sha256.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once -#include -#include -#include - -namespace fc { - class path; - - class sha256 { - public: - sha256(); - explicit sha256( const fc::string& hex_str ); - - fc::string str()const; - - operator fc::string()const; - - char* data()const; - - static sha256 hash( const char* d, uint32_t dlen ); - static sha256 hash( const fc::string& ); - static sha256 hash( const fc::path& ); - - template - static sha256 hash( const T& t ) { sha256::encoder e; e << t; return e.result(); } - - class encoder { - public: - encoder(); - ~encoder(); - - void write( const char* d, uint32_t dlen ); - void put( char c ) { write( &c, 1 ); } - void reset(); - sha256 result(); - - private: - struct impl; - fwd my; - }; - - template - inline friend T& operator<<( T& ds, const sha256& ep ) { - ds.write( ep.data(), sizeof(ep) ); - return ds; - } - - template - inline friend T& operator>>( T& ds, sha256& ep ) { - ds.read( ep.data(), sizeof(ep) ); - return ds; - } - friend sha256 operator << ( const sha256& h1, uint32_t i ); - friend bool operator == ( const sha256& h1, const sha256& h2 ); - friend bool operator != ( const sha256& h1, const sha256& h2 ); - friend sha256 operator ^ ( const sha256& h1, const sha256& h2 ); - friend bool operator >= ( const sha256& h1, const sha256& h2 ); - friend bool operator > ( const sha256& h1, const sha256& h2 ); - friend bool operator < ( const sha256& h1, const sha256& h2 ); - - uint64_t _hash[4]; - }; - - class value; - void pack( fc::value& , const fc::sha256& ); - void unpack( const fc::value& , fc::sha256& ); -} - - diff --git a/include/fc/shared_impl.cpp b/include/fc/shared_impl.cpp deleted file mode 100644 index 6781f17..0000000 --- a/include/fc/shared_impl.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once -#include - -namespace fc { -template -typename shared_impl::impl& shared_impl::operator* ()const { return *_impl; } - -template -typename shared_impl::impl* shared_impl::operator-> ()const { return _impl.get(); } - -template -template -shared_impl::shared_impl( U&& u ):_impl(fc::forward(u)){} - -template -shared_impl::shared_impl( const shared_impl& u ):_impl(u._impl){} -//template -//shared_impl::shared_impl( shared_impl& u ):_impl(u._impl){} - -template -shared_impl::shared_impl( shared_impl&& u ):_impl(fc::move(u._impl)){} - -template -shared_impl& shared_impl::operator=( shared_impl&& u ) { - fc_swap(_impl,u._impl); - return *this; -} -template -shared_impl& shared_impl::operator=( const shared_impl& u ) { - _impl = u._impl; - return *this; -} - -template -bool shared_impl::operator !()const { return !_impl; } - -template -shared_impl::~shared_impl(){} - -} - -#define FC_REFERENCE_TYPE_IMPL( TYPE ) \ -template \ -TYPE::TYPE( A1&& a1 ) \ -:my( new typename fc::shared_impl::impl( fc::forward(a1) ) ){}\ -template \ -TYPE::TYPE( A1&& a1, A2&& a2 ) \ -:my( new typename fc::shared_impl::impl( fc::forward(a1), fc::forward(a2) ) ){}\ -template \ -TYPE::TYPE( A1&& a1, A2&& a2, A3&& a3 ) \ -:my( new fc::shared_impl::impl( fc::forward(a1), fc::forward(a2), fc::forward(a3) ) ){}\ -TYPE::TYPE( shared_impl::impl* m ) \ -:my(m){}\ -TYPE::TYPE( TYPE* c )\ -:my(fc::move(c->my)){ delete c; }\ -TYPE::TYPE( TYPE&& c )\ -:my(fc::move(c.my)){}\ -TYPE::TYPE( const TYPE& c )\ -:my(c.my){}\ -TYPE::TYPE() \ -:my( new fc::shared_impl::impl( ) ){}\ -TYPE::~TYPE(){}\ -bool TYPE::operator !()const { return !my; }\ -TYPE& TYPE::operator = ( const TYPE& c ) {\ - my = c.my;\ - return *this;\ -}\ -TYPE& TYPE::operator = ( TYPE&& c ) {\ - fc_swap( my._impl, c.my._impl );\ - return *this;\ -}\ -TYPE& TYPE::operator = ( TYPE* c ) {\ - fc_swap( my._impl, c->my._impl );\ - delete c;\ - return *this;\ -} \ -bool operator==( const TYPE& a, const TYPE& b ) {\ - return a.my._impl.get() == b.my._impl.get(); \ -} \ -bool operator!=( const TYPE& a, const TYPE& b ) {\ - return a.my._impl.get() != b.my._impl.get(); \ -} - - diff --git a/include/fc/shared_impl.hpp b/include/fc/shared_impl.hpp deleted file mode 100644 index 6b43ace..0000000 --- a/include/fc/shared_impl.hpp +++ /dev/null @@ -1,163 +0,0 @@ -#pragma once -#include - -namespace fc { - /** - * @class shared_impl - * @brief used to create types with reference semantics - * - * A type with reference semantics is effectively a shared pointer except that - * it is used like a Java or C# type using '.' notation instead of -> notation. - * - * It is ideal for use with classes that almost always get managed by a shared - * pointer (sockets and long-lived resources). These types are rarely, if ever - * copied by value and often by-value copy or 'deep-copy' has no real meaning. - * - * An additional feature of shared_impl is that your classes implementation - * should be private and defined entirely in your source file. There should be - * no member variables defined in your types header. - * - * To make this design pattern work requires a lot of 'boiler-plate' code for - * handling assignments, moves, copies, etc that cannot be provided via tradtional - * means such as templates or base classes. - * - * To create a new type with reference semantics you place FC_REFERENCE_TYPE(type) - * inside the private section of 'type'. Then in your source file you will - * need to define your 'private' data. - * - * @code - * #include - * - * FC_START_SHARED_IMPL( your_namespace::your_type ) - * impl( int x, int y ); // custom constructor - * - * ... - * int member_variable; - * your private member variables / methods go here. - * ... - * FC_END_SHARED_IMPL - * #include - * @endcode - * - * - * Lastly, you will need to provide the implementation your class below. This - * implementation will need to provide the matching implementations for the - * methods declared by FC_REFERENCE_TYPE(type) in your header. To do this - * use the FC_REFERENCE_TYPE_IMPL(type) - * - * @code - * namespace your_namespace { - * FC_REFERENCE_TYPE(your_type) - * ... your methods here... - * } - * @endcode - * - * Within the body of your methods you can access your private data and members - * via using 'my->member_variable' - * - * If you want to define custom constructors for your reference type, you will - * need to implement them inside the FC_START_SHARED_IMPL block using the pattern: - * - * @code - * FC_START_SHARED_IMPL( your_namespace::your_type ) - * impl( int x, int y ){} // custom constructor - * FC_END_SHARED_IMPL - * @code - * - * A limited number (3) of arguments are supported for custom constructors. - * - * Once you have defined your reference type you can use it like so: - * - * @code - * your_type val = nullptr; // create a null type - * your_type val2 = new your_type(...); // construct a new instance, unnecessary temporary heap alloc - * your_type val3(...); // constructs a new instance, more effecient - * - * val2.your_method(); - * val2 = nullptr; // reset val2 to a null object - * - * val2 = val3; // val2 and val3 now reference the same data - * if( !!val2 ){} // val2 is not null - * else{} // val2 is null - * @endcode - * - * As you can see, when creating types with this method your code will - * look and act like a Java or C# garbage collected type. - * - * Often times your private methods will need to call your public methods, to achieve - * this you can use the following techinque: - * - * @code - * FC_START_SHARED_IMPL( your_namespace::your_type ) - * void private_method( int x, int y ){ - * auto s = self(); - * s.public_method(); - * } - * FC_END_SHARED_IMPL - * @code - * - * For performance reasons, it is best to only call 'self()' once and save the - * result to avoid unnecessary copies of shared pointers which require atomic - * operations. - * - */ - template - struct shared_impl { - class impl; - impl& operator* ()const; - impl* operator-> ()const; - - bool operator !()const; - - template - explicit shared_impl( U&& u ); - - shared_impl( const shared_impl& u ); - // shared_impl( shared_impl& u ); - shared_impl( shared_impl&& u ); - shared_impl& operator=( shared_impl&& u ); - shared_impl& operator=( const shared_impl& u ); - - ~shared_impl(); - - fc::shared_ptr::impl> _impl; - }; - -} - -#define FC_REFERENCE_TYPE( TYPE ) \ - public:\ - TYPE(); \ - TYPE( std::nullptr_t ); \ - TYPE( TYPE* ); \ - TYPE( TYPE&& ); \ - TYPE( const TYPE& ); \ - template \ - TYPE( A1&& ); \ - template \ - TYPE( A1&&, A2&& ); \ - template \ - TYPE( A1&&, A2&&, A3&& ); \ - ~TYPE(); \ - bool operator !()const; \ - friend bool operator==( const TYPE& a, const TYPE& b ); \ - friend bool operator!=( const TYPE& a, const TYPE& b ); \ - TYPE& operator = ( const TYPE& ); \ - TYPE& operator = ( TYPE&& );\ - TYPE& operator = ( TYPE* );\ - TYPE& operator = ( std::nullptr_t );\ - private: \ - friend class shared_impl::impl; \ - TYPE( shared_impl::impl* m ); \ - shared_impl my; - -#define FC_START_SHARED_IMPL( SCOPED_TYPE ) \ -namespace fc { \ -template<> \ -class fc::shared_impl::impl : public fc::retainable { \ - public:\ - SCOPED_TYPE self() { return SCOPED_TYPE(this); } \ - - -#define FC_END_SHARED_IMPL }; } - diff --git a/include/fc/shared_ptr.hpp b/include/fc/shared_ptr.hpp index e7f0ab8..60a2cd3 100644 --- a/include/fc/shared_ptr.hpp +++ b/include/fc/shared_ptr.hpp @@ -1,6 +1,5 @@ #pragma once #include -#include namespace fc { diff --git a/include/fc/signal.hpp b/include/fc/signal.hpp index b2ed9ee..9e9b5a8 100644 --- a/include/fc/signal.hpp +++ b/include/fc/signal.hpp @@ -1,7 +1,10 @@ #pragma once #include #include - +#include +#ifdef emit +#undef emit +#endif namespace fc { @@ -41,6 +44,18 @@ namespace fc { (*_handlers[i])( fc::forward(arg), fc::forward(arg2) ); } } + template + void emit( Arg&& arg, Arg2&& arg2, Arg3&& arg3 ) { + for( size_t i = 0; i < _handlers.size(); ++i ) { + (*_handlers[i])( fc::forward(arg), fc::forward(arg2), fc::forward(arg3) ); + } + } + template + void operator()( Arg&& arg, Arg2&& arg2, Arg3&& arg3 ) { + for( size_t i = 0; i < _handlers.size(); ++i ) { + (*_handlers[i])( fc::forward(arg), fc::forward(arg2), fc::forward(arg3) ); + } + } #else template void emit( Args&&... args ) { @@ -66,6 +81,18 @@ namespace fc { ++itr; } } + signal() + { + _handlers.reserve(4); + } + ~signal() + { + for( auto itr = _handlers.begin(); itr != _handlers.end(); ++itr ) + { + delete *itr; + } + _handlers.clear(); + } private: fc::vector< std::function* > _handlers; diff --git a/include/fc/signals.hpp b/include/fc/signals.hpp index 97e3518..53a7692 100644 --- a/include/fc/signals.hpp +++ b/include/fc/signals.hpp @@ -1,8 +1,7 @@ #include -#include -#include +#include +#include -#include namespace fc { #if !defined(BOOST_NO_TEMPLATE_ALIASES) @@ -12,13 +11,13 @@ namespace fc { #endif template - inline T wait( boost::signal& sig, const microseconds& timeout_us=microseconds::max() ) { + inline T wait( boost::signal& sig, const microseconds& timeout_us=microseconds::maximum() ) { typename promise::ptr p(new promise()); boost::signals::scoped_connection c = sig.connect( [=]( T t ) { p->set_value(t); } ); return p->wait( timeout_us ); } - inline void wait( boost::signal& sig, const microseconds& timeout_us=microseconds::max() ) { + inline void wait( boost::signal& sig, const microseconds& timeout_us=microseconds::maximum() ) { promise::ptr p(new promise()); boost::signals::scoped_connection c = sig.connect( [=]() { p->set_value(); } ); p->wait( timeout_us ); diff --git a/include/fc/ssh/client.hpp b/include/fc/ssh/client.hpp index b88451d..eb24a8e 100644 --- a/include/fc/ssh/client.hpp +++ b/include/fc/ssh/client.hpp @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include @@ -59,7 +59,8 @@ namespace fc { * via client::create(); * */ - class client { + class client + { public: enum trace_level { TRACE_NONE = 0, @@ -88,14 +89,26 @@ namespace fc { void set_logger( const logger& lgr ); const logger& get_logger()const; + /** + * Connect, with no password specified. Authentication will try public key, + * (via agent or explicitly-set key), empty password, then keyboard-interactive + */ void connect( const fc::string& user, const fc::string& host, uint16_t port = 22); /** - * Connect via password or keyboard-interactive + * Connect, specifying a password to be used for password authentication */ void connect( const fc::string& user, const fc::string& pass, const fc::string& host, uint16_t port = 22); /** + * @note THIS METHOD IS DEPRECATED and should be replace with: + * + * ssh::client_ptr sshc = std::make_shared(); + * sshc->connect( ... ) + * ssh::process_ptr proc = std::make_shared( sshc ); + * proc->exec( ... ) + * + * * @brief execute command on remote machine * @param pty_type - whether or not to request a PTY when executing this process, this is necessary * for interactive (non-buffered) IO with the remote process, if left empty no pty will be @@ -104,8 +117,8 @@ namespace fc { * @note Processes launched in this manner will fully buffer stdin and stdout regardless of whether * the process calls flush(). If you need unbuffered (streaming, realtime) access to standard * out then you must launch the process via a shell. - */ ssh::process exec( const fc::string& cmd, const fc::string& pty_type = "" ); + */ /** @@ -115,7 +128,7 @@ namespace fc { * transfer, the callback should return true. To cancel the callback should return false. */ void scp_send( const fc::path& local_path, const fc::path& remote_path, - std::function progress = [](size_t,size_t){return true;} ); + std::function progress = [](uint64_t,uint64_t){return true;} ); /** * @brief recursively sends the contents of local_dir to the remote_path @@ -126,13 +139,22 @@ namespace fc { * Progress will be reported as total bytes transferred for all files. */ void scp_send_dir( const fc::path& local_dir, const fc::path& remote_path, - std::function progress = [](size_t,size_t){return true;} ); + std::function progress = [](uint64_t,uint64_t){return true;} ); /** * @pre remote_path is not a directory * @post remote file is removed from the remote filesystem */ void rm( const fc::path& remote_path ); + + /** + * @pre remote_path is a directory + * @post remote directory is removed from the remote filesystem + */ + void rmdir( const fc::path& remote_path ); + + void rmdir_recursive( const fc::path& remote_path ); + file_attrib stat( const fc::path& remote_path ); /** @@ -149,6 +171,13 @@ namespace fc { */ void create_directories( const fc::path& remote_dir, int mode = owner_read|owner_write|owner_exec ); + /** + * Sets whether the remote system is believed to be a Windows box (by default, it's + * assumed to be running UNIX. This alters how command-line arguments are quoted + * and possibly how filenames are altered when copying files + */ + void set_remote_system_is_windows(bool is_windows = true); + void close(); client(); @@ -157,7 +186,8 @@ namespace fc { private: friend class process; friend class detail::process_impl; - fc::shared_ptr my; + std::unique_ptr my; }; + typedef std::shared_ptr client_ptr; } } // namespace fc::ssh diff --git a/include/fc/ssh/process.hpp b/include/fc/ssh/process.hpp index 8d4c4b8..3f26ead 100644 --- a/include/fc/ssh/process.hpp +++ b/include/fc/ssh/process.hpp @@ -1,13 +1,8 @@ #pragma once -#include -#include +#include -namespace fc { - - class istream; - class ostream; - - namespace ssh { +namespace fc { namespace ssh +{ class client; @@ -21,39 +16,43 @@ namespace fc { * * Process can only be created by mace::ssh::client. */ - class process { //: public fc::retainable { + class process : public iprocess + { public: - //typedef fc::shared_ptr ptr; - - process( const process& p ); - process( process&& p ); - process(); - ~process(); - - bool valid()const; + virtual iprocess& exec( const fc::path& exe, vector args, + const fc::path& work_dir = fc::path(), exec_opts opts = open_all ); /** * Blocks until the result code of the process has been returned. */ - int result(); + virtual int result(); + + /** - * @brief returns a stream that writes to the procss' stdin + * Not supported. libssh2 does not support sending signals to remote processes. + * closing in_stream() is the best you can do */ - fc::ostream& in_stream()const; + virtual void kill(); + + + /** + * @brief returns a stream that writes to the process' stdin + */ + virtual fc::buffered_ostream_ptr in_stream(); + /** * @brief returns a stream that reads from the process' stdout */ - fc::istream& out_stream()const; + virtual fc::buffered_istream_ptr out_stream(); /** * @brief returns a stream that reads from the process' stderr */ - fc::istream& err_stream()const; + virtual fc::buffered_istream_ptr err_stream(); - process& operator=( const process& p ); + process( fc::ssh::client_ptr c ); + ~process(); private: - friend class client; - process( client& c, const fc::string& cmd, const fc::string& pty_type = fc::string() ); - - fc::shared_ptr my; + std::unique_ptr my; }; + } } // fc::ssh diff --git a/include/fc/sstream.hpp b/include/fc/sstream.hpp deleted file mode 100644 index 79baac3..0000000 --- a/include/fc/sstream.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once -#include -#include - -namespace fc { - - class stringstream : virtual public iostream { - public: - stringstream(); - stringstream( fc::string& s); - stringstream( const fc::string& s); - ~stringstream(); - - fc::string str(); - - virtual bool eof()const; - virtual ostream& write( const char* buf, size_t len ); - virtual size_t readsome( char* buf, size_t len ); - virtual istream& read( char* buf, size_t len ); - virtual void close(); - virtual void flush(); - - protected: - virtual istream& read( int64_t& ); - virtual istream& read( uint64_t& ); - virtual istream& read( int32_t& ); - virtual istream& read( uint32_t& ); - virtual istream& read( int16_t& ); - virtual istream& read( uint16_t& ); - virtual istream& read( int8_t& ); - virtual istream& read( uint8_t& ); - virtual istream& read( float& ); - virtual istream& read( double& ); - virtual istream& read( bool& ); - virtual istream& read( char& ); - virtual istream& read( fc::string& ); - - virtual ostream& write( const fc::string& ); - - private: - class impl; - fwd my; - }; - -} diff --git a/include/fc/stream.hpp b/include/fc/stream.hpp deleted file mode 100644 index f5f97fc..0000000 --- a/include/fc/stream.hpp +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once -#include -#include - -namespace fc { - class string; - - class istream { - public: - virtual ~istream(){}; - - virtual size_t readsome( char* buf, size_t len ) = 0; - - template - friend istream& operator>>( istream& i, T& v ){ return i.read(v); } - - virtual bool eof()const = 0; - - protected: - virtual istream& read( int64_t& ) = 0; - virtual istream& read( uint64_t& ) = 0; - virtual istream& read( int32_t& ) = 0; - virtual istream& read( uint32_t& ) = 0; - virtual istream& read( int16_t& ) = 0; - virtual istream& read( uint16_t& ) = 0; - virtual istream& read( int8_t& ) = 0; - virtual istream& read( uint8_t& ) = 0; - virtual istream& read( float& ) = 0; - virtual istream& read( double& ) = 0; - virtual istream& read( bool& ) = 0; - virtual istream& read( char& ) = 0; - virtual istream& read( fc::string& ) = 0; - }; - - class ostream { - public: - virtual ~ostream(){}; - - virtual size_t write( const char* buf, size_t len ) = 0; - virtual void close() = 0; - virtual void flush() = 0; - - template - friend ostream& operator<<( ostream& o, const T& v ){ return o.write(fc::lexical_cast(v)); } - - protected: - virtual ostream& write( const fc::string& ) = 0; - }; - class iostream : public virtual ostream, public virtual istream {}; - - bool getline( fc::istream&, fc::string&, char delim = '\n' ); - - struct cout_t : virtual public ostream { - virtual size_t write( const char* buf, size_t len ); - virtual void close(); - virtual void flush(); - - virtual ostream& write( const fc::string& ); - }; - - struct cerr_t : virtual public ostream { - virtual size_t write( const char* buf, size_t len ); - virtual void close(); - virtual void flush(); - - virtual ostream& write( const fc::string& ); - }; - - struct cin_t : virtual public istream { - virtual size_t readsome( char* buf, size_t len ); - virtual bool eof()const; - - virtual istream& read( int64_t& ); - virtual istream& read( uint64_t& ); - virtual istream& read( int32_t& ); - virtual istream& read( uint32_t& ); - virtual istream& read( int16_t& ); - virtual istream& read( uint16_t& ); - virtual istream& read( int8_t& ); - virtual istream& read( uint8_t& ); - virtual istream& read( float& ); - virtual istream& read( double& ); - virtual istream& read( bool& ); - virtual istream& read( char& ); - virtual istream& read( fc::string& ); - }; - - - extern cout_t cout; - extern cerr_t cerr; - extern cin_t cin; -} - diff --git a/include/fc/string.hpp b/include/fc/string.hpp index 50215b0..c3798e5 100644 --- a/include/fc/string.hpp +++ b/include/fc/string.hpp @@ -22,10 +22,8 @@ namespace std { typedef basic_string, allocator > string; } -#include namespace fc { - // typedef std::string string; /** * @brief wrapper on std::string * @@ -44,7 +42,8 @@ namespace fc { public: typedef char* iterator; typedef const char* const_iterator; - static const size_t npos = -1; + enum { npos = size_t(-1) }; + // static const size_t npos;// = -1; string(); string( const std::string& s ); @@ -74,14 +73,21 @@ namespace fc { void reserve( size_t ); size_t size()const; size_t find( char c, size_t pos = 0 )const; + size_t find(const fc::string& str, size_t pos = 0) const; + size_t find(const char* s, size_t pos = 0) const; size_t rfind( char c, size_t pos = npos )const; size_t rfind( const char* c, size_t pos = npos )const; size_t rfind( const fc::string& c, size_t pos = npos )const; + size_t find_first_of (const fc::string& str, size_t pos = 0) const; + size_t find_first_of (const char* s, size_t pos = 0) const; + string& replace(size_t pos, size_t len, const fc::string& str); + string& replace(size_t pos, size_t len, const char* s); void resize( size_t s ); void clear(); const char* c_str()const; + char* data(); bool operator == ( const char* s )const; bool operator == ( const string& s )const; @@ -101,7 +107,16 @@ namespace fc { fc::fwd my; }; + int64_t to_int64( const fc::string& ); + uint64_t to_uint64( const fc::string& ); + double to_double( const fc::string& ); + fc::string to_string( double ); + fc::string to_string( uint64_t ); + fc::string to_string( int64_t ); + typedef fc::optional ostring; + class variant_object; + fc::string format_string( const fc::string&, const variant_object& ); } // namespace fc diff --git a/include/fc/future.hpp b/include/fc/thread/future.hpp similarity index 86% rename from include/fc/future.hpp rename to include/fc/thread/future.hpp index 438c5b2..06c4793 100644 --- a/include/fc/future.hpp +++ b/include/fc/thread/future.hpp @@ -1,17 +1,15 @@ -#ifndef _FC_FUTURE_HPP_ -#define _FC_FUTURE_HPP_ +#pragma once #include #include #include -#include -#include +#include +#include #include namespace fc { class abstract_thread; - struct void_t; + struct void_t{}; class priority; - class exception_ptr; class thread; namespace detail { @@ -46,9 +44,9 @@ namespace fc { }; } - class promise_base : virtual public retainable { + class promise_base : public virtual retainable{ public: - typedef shared_ptr ptr; + typedef fc::shared_ptr ptr; promise_base(const char* desc="?"); const char* get_desc()const; @@ -63,6 +61,7 @@ namespace fc { void _wait( const microseconds& timeout_us ); void _wait_until( const time_point& timeout_us ); void _enqueue_thread(); + void _dequeue_thread(); void _notify(); void _set_timeout(); void _set_value(const void* v); @@ -78,6 +77,9 @@ namespace fc { bool _ready; mutable spin_yield_lock _spin_yield; thread* _blocked_thread; +#ifndef NDEBUG + unsigned _blocked_fiber_count; +#endif time_point _timeout; fc::exception_ptr _exceptp; bool _canceled; @@ -88,12 +90,12 @@ namespace fc { template class promise : virtual public promise_base { public: - typedef shared_ptr< promise > ptr; + typedef fc::shared_ptr< promise > ptr; promise( const char* desc = "?" ):promise_base(desc){} promise( const T& val ){ set_value(val); } promise( T&& val ){ set_value(fc::move(val) ); } - const T& wait(const microseconds& timeout = microseconds::max() ){ + const T& wait(const microseconds& timeout = microseconds::maximum() ){ this->_wait( timeout ); return *result; } @@ -124,11 +126,11 @@ namespace fc { template<> class promise : virtual public promise_base { public: - typedef shared_ptr< promise > ptr; + typedef fc::shared_ptr< promise > ptr; promise( const char* desc = "?" ):promise_base(desc){} - promise( const void_t& v ){ set_value(); } + promise( const void_t& ){ set_value(); } - void wait(const microseconds& timeout = microseconds::max() ){ + void wait(const microseconds& timeout = microseconds::maximum() ){ this->_wait( timeout ); } void wait_until(const time_point& tp ) { @@ -136,7 +138,7 @@ namespace fc { } void set_value(){ this->_set_value(nullptr); } - void set_value( const void_t& v ) { this->_set_value(nullptr); } + void set_value( const void_t& ) { this->_set_value(nullptr); } template void on_complete( CompletionHandler&& c ) { @@ -164,8 +166,8 @@ namespace fc { template class future { public: - future( const shared_ptr>& p ):m_prom(p){} - future( shared_ptr>&& p ):m_prom(fc::move(p)){} + future( const fc::shared_ptr>& p ):m_prom(p){} + future( fc::shared_ptr>&& p ):m_prom(fc::move(p)){} future(){} operator const T&()const { return wait(); } @@ -173,7 +175,7 @@ namespace fc { /// @pre valid() /// @post ready() /// @throws timeout - const T& wait( const microseconds& timeout = microseconds::max() )const { + const T& wait( const microseconds& timeout = microseconds::maximum() )const { return m_prom->wait(timeout); } @@ -207,20 +209,20 @@ namespace fc { } private: friend class thread; - shared_ptr> m_prom; + fc::shared_ptr> m_prom; }; template<> class future { public: - future( const shared_ptr>& p ):m_prom(p){} - future( shared_ptr>&& p ):m_prom(fc::move(p)){} + future( const fc::shared_ptr>& p ):m_prom(p){} + future( fc::shared_ptr>&& p ):m_prom(fc::move(p)){} future(){} /// @pre valid() /// @post ready() /// @throws timeout - void wait( const microseconds& timeout = microseconds::max() ){ + void wait( const microseconds& timeout = microseconds::maximum() ){ m_prom->wait(timeout); } @@ -248,8 +250,7 @@ namespace fc { private: friend class thread; - shared_ptr> m_prom; + fc::shared_ptr> m_prom; }; } -#endif // _FC_FUTURE_HPP_ diff --git a/include/fc/mutex.hpp b/include/fc/thread/mutex.hpp similarity index 98% rename from include/fc/mutex.hpp rename to include/fc/thread/mutex.hpp index c8a1a79..f94b577 100644 --- a/include/fc/mutex.hpp +++ b/include/fc/thread/mutex.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include namespace fc { class microseconds; diff --git a/include/fc/priority.hpp b/include/fc/thread/priority.hpp similarity index 100% rename from include/fc/priority.hpp rename to include/fc/thread/priority.hpp diff --git a/include/fc/scoped_lock.hpp b/include/fc/thread/scoped_lock.hpp similarity index 100% rename from include/fc/scoped_lock.hpp rename to include/fc/thread/scoped_lock.hpp diff --git a/include/fc/spin_lock.hpp b/include/fc/thread/spin_lock.hpp similarity index 98% rename from include/fc/spin_lock.hpp rename to include/fc/thread/spin_lock.hpp index 6dfbd1a..c69bbc6 100644 --- a/include/fc/spin_lock.hpp +++ b/include/fc/thread/spin_lock.hpp @@ -1,3 +1,4 @@ +#pragma once namespace boost { template class atomic; } diff --git a/include/fc/spin_yield_lock.hpp b/include/fc/thread/spin_yield_lock.hpp similarity index 100% rename from include/fc/spin_yield_lock.hpp rename to include/fc/thread/spin_yield_lock.hpp diff --git a/include/fc/task.hpp b/include/fc/thread/task.hpp similarity index 95% rename from include/fc/task.hpp rename to include/fc/thread/task.hpp index 9c36e6d..f86ce37 100644 --- a/include/fc/task.hpp +++ b/include/fc/thread/task.hpp @@ -1,7 +1,6 @@ -#ifndef _FC_TASK_HPP_ -#define _FC_TASK_HPP_ -#include -#include +#pragma once +#include +#include #include #include @@ -93,4 +92,3 @@ namespace fc { } -#endif // _FC_TASK_HPP_ diff --git a/include/fc/thread.hpp b/include/fc/thread/thread.hpp similarity index 91% rename from include/fc/thread.hpp rename to include/fc/thread/thread.hpp index 3fb1634..ee60c70 100644 --- a/include/fc/thread.hpp +++ b/include/fc/thread/thread.hpp @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include @@ -15,6 +15,9 @@ namespace fc { /** * Returns the current thread. + Note: Creates fc::thread object (but not a boost thread) if no current thread assigned yet + (this can happend if current() is called from the main thread of application or from + an existing "unknown" boost thread). In such cases, thread_d doesn't have access boost::thread object. */ static thread& current(); @@ -105,7 +108,7 @@ namespace fc { ~thread(); template - int wait_any( const fc::future& f1, const fc::future& f2, const microseconds& timeout_us = microseconds::max()) { + int wait_any( const fc::future& f1, const fc::future& f2, const microseconds& timeout_us = microseconds::maximum()) { fc::vector proms(2); proms[0] = fc::static_pointer_cast(f1.m_prom); proms[1] = fc::static_pointer_cast(f2.m_prom); @@ -162,10 +165,10 @@ namespace fc { * @return 0 if f1 is ready, 1 if f2 is ready or throw on error. */ template - int wait_any( const fc::future& f1, const fc::future& f2, const microseconds timeout_us = microseconds::max()) { + int wait_any( const fc::future& f1, const fc::future& f2, const microseconds timeout_us = microseconds::maximum()) { return fc::thread::current().wait_any(f1,f2,timeout_us); } - int wait_any( fc::vector&& v, const microseconds& timeout_us = microseconds::max() ); + int wait_any( fc::vector&& v, const microseconds& timeout_us = microseconds::maximum() ); int wait_any_until( fc::vector&& v, const time_point& tp ); template diff --git a/include/fc/unique_lock.hpp b/include/fc/thread/unique_lock.hpp similarity index 63% rename from include/fc/unique_lock.hpp rename to include/fc/thread/unique_lock.hpp index c1531fe..0facf4d 100644 --- a/include/fc/unique_lock.hpp +++ b/include/fc/thread/unique_lock.hpp @@ -1,5 +1,5 @@ -#ifndef _FC_UNIQUE_LOCK_HPP_ -#define _FC_UNIQUE_LOCK_HPP_ +#pragma once +#include namespace fc { struct try_to_lock_t{}; @@ -14,9 +14,11 @@ namespace fc { public: unique_lock( T& l, const fc::time_point& abs ):_lock(l) { _locked = _lock.try_lock_until(abs); } unique_lock( T& l, try_to_lock_t ):_lock(l) { _locked = _lock.try_lock(); } - unique_lock( T& l ):_lock(l) { _lock.lock(); _locked = true; } - ~unique_lock() { _lock.unlock(); _locked = false; } - operator bool()const { return _locked; } + unique_lock( T& l ): _locked(false), _lock(l) { lock(); } + ~unique_lock() { if (_locked) unlock(); } + operator bool() const { return _locked; } + void unlock() { assert(_locked); if (_locked) { _lock.unlock(); _locked = false;} } + void lock() { assert(!_locked); if (!_locked) { _lock.lock(); _locked = true; } } private: unique_lock( const unique_lock& ); unique_lock& operator=( const unique_lock& ); @@ -38,4 +40,3 @@ namespace fc { */ #define synchronized(X) fc::unique_lock __lock(((X))); -#endif diff --git a/include/fc/thread/wait_condition.hpp b/include/fc/thread/wait_condition.hpp new file mode 100644 index 0000000..75670d2 --- /dev/null +++ b/include/fc/thread/wait_condition.hpp @@ -0,0 +1,68 @@ +#pragma once +#include +#include +#include +#include + +namespace fc +{ + /** + * A thread-safe, fiber-aware condition variable that + * can be used to signal/wait on a certain condition between + * threads. + */ + template + class wait_condition + { + public: + void wait( const microseconds& timeout = microseconds::maximum() ) + { + typename fc::promise::ptr p = new fc::promise(); + { synchronized( _prom_lock ) + _promises.push_back( p ); + } + p->wait(timeout); + } + + template + T wait( LockType& l, const microseconds& timeout = microseconds::maximum() ) + { + typename fc::promise::ptr p( new fc::promise()); + { synchronized( _prom_lock ) + _promises.push_back( p ); + } + l.unlock(); + return p->wait(timeout); + } + + void notify_one( const T& t=T()) + { + typename fc::promise::ptr prom; + { synchronized( _prom_lock ) + if( _promises.size() ) + { + prom = _promises.front(); + _promises.pop_front(); + } + } + + if( prom && prom->retain_count() > 1 ) + prom->set_value(t); + } + void notify_all(const T& t=T()) + { + std::deque::ptr> all; + { synchronized( _prom_lock ) + all = fc::move(_promises); + } + for( auto itr = all.begin(); itr != all.end(); ++itr ) + { + if( (*itr)->retain_count() > 1 ) + (*itr)->set_value(t); + } + } + private: + fc::spin_yield_lock _prom_lock; + std::deque::ptr> _promises; + }; +} diff --git a/include/fc/thread_d.hpp b/include/fc/thread_d.hpp deleted file mode 100644 index 8a0c245..0000000 --- a/include/fc/thread_d.hpp +++ /dev/null @@ -1,393 +0,0 @@ -#include -#include - -#include -#include "context.hpp" -#include -#include -#include -#include - -namespace fc { - class thread_d { - public: - thread_d(fc::thread& s) - :self(s), boost_thread(0), - task_in_queue(0), - done(false), - current(0), - pt_head(0), - ready_head(0), - ready_tail(0), - blocked(0) - { - static char cnt = 0; - name = fc::string("th_") + char('a'+cnt); - cnt++; - } - fc::thread& self; - boost::thread* boost_thread; - bc::stack_allocator stack_alloc; - boost::mutex task_ready_mutex; - boost::condition_variable task_ready; - - boost::atomic task_in_queue; - std::vector task_pqueue; - std::vector task_sch_queue; - std::vector sleep_pqueue; - std::vector free_list; - - bool done; - std::string name; - cmt::context* current; - - cmt::context* pt_head; - - cmt::context* ready_head; - cmt::context* ready_tail; - - cmt::context* blocked; - - time_point check_for_timeouts(); - - - void debug( const std::string& s ) { - boost::unique_lock lock(detail::log_mutex()); - - std::cerr<<"--------------------- "<cur_task ) std::cerr<<'('<cur_task->get_desc()<<')'; - std::cerr<<" ---------------------------\n"; - std::cerr<<" Ready\n"; - cmt::context* c = ready_head; - while( c ) { - std::cerr<<" "<cur_task ) std::cerr<<'('<cur_task->get_desc()<<')'; - cmt::context* p = c->caller_context; - while( p ) { - std::cerr<<" -> "<caller_context; - } - std::cerr<<"\n"; - c = c->next; - } - std::cerr<<" Blocked\n"; - c = blocked; - while( c ) { - std::cerr<<" ctx: "<< c; - if( c->cur_task ) std::cerr<<'('<cur_task->get_desc()<<')'; - std::cerr << " blocked on prom: "; - for( uint32_t i = 0; i < c->blocking_prom.size(); ++i ) { - std::cerr<blocking_prom[i].prom<<'('<blocking_prom[i].prom->get_desc()<<')'; - if( i + 1 < c->blocking_prom.size() ) { - std::cerr<<","; - } - } - - cmt::context* p = c->caller_context; - while( p ) { - std::cerr<<" -> "<caller_context; - } - std::cerr<<"\n"; - c = c->next_blocked; - } - std::cerr<<"-------------------------------------------------\n"; - } - - // insert at from of blocked linked list - inline void add_to_blocked( cmt::context* c ) { - c->next_blocked = blocked; - blocked = c; - } - - void pt_push_back(cmt::context* c) { - c->next = pt_head; - pt_head = c; - /* - cmt::context* n = pt_head; - int i = 0; - while( n ) { - ++i; - n = n->next; - } - wlog( "idle context...%2% %1%", c, i ); - */ - } - cmt::context::ptr ready_pop_front() { - cmt::context::ptr tmp = 0; - if( ready_head ) { - tmp = ready_head; - ready_head = tmp->next; - if( !ready_head ) - ready_tail = 0; - tmp->next = 0; - } - return tmp; - } - void ready_push_front( const cmt::context::ptr& c ) { - c->next = ready_head; - ready_head = c; - if( !ready_tail ) - ready_tail = c; - } - void ready_push_back( const cmt::context::ptr& c ) { - c->next = 0; - if( ready_tail ) { - ready_tail->next = c; - } else { - ready_head = c; - } - ready_tail = c; - } - struct task_priority_less { - bool operator()( const task::ptr& a, const task::ptr& b ) { - return a->prio.value < b->prio.value ? true : (a->prio.value > b->prio.value ? false : a->posted_num > b->posted_num ); - } - }; - struct task_when_less { - bool operator()( const task::ptr& a, const task::ptr& b ) { - return a->when < b->when; - } - }; - - void enqueue( const task::ptr& t ) { - time_point now = system_clock::now(); - task::ptr cur = t; - while( cur ) { - if( cur->when > now ) { - task_sch_queue.push_back(cur); - std::push_heap( task_sch_queue.begin(), - task_sch_queue.end(), task_when_less() ); - } else { - task_pqueue.push_back(cur); - BOOST_ASSERT( this == thread::current().my ); - std::push_heap( task_pqueue.begin(), - task_pqueue.end(), task_priority_less() ); - } - cur = cur->next; - } - } - task* dequeue() { - // get a new task - BOOST_ASSERT( this == thread::current().my ); - - task* pending = 0; - - pending = task_in_queue.exchange(0,boost::memory_order_consume); - if( pending ) { enqueue( pending ); } - - task::ptr p(0); - if( task_sch_queue.size() ) { - if( task_sch_queue.front()->when <= system_clock::now() ) { - p = task_sch_queue.front(); - std::pop_heap(task_sch_queue.begin(), task_sch_queue.end(), task_when_less() ); - task_sch_queue.pop_back(); - return p; - } - } - if( task_pqueue.size() ) { - p = task_pqueue.front(); - std::pop_heap(task_pqueue.begin(), task_pqueue.end(), task_priority_less() ); - task_pqueue.pop_back(); - } - return p; - } - - /** - * This should be before or after a context switch to - * detect quit/cancel operations and throw an exception. - */ - void check_fiber_exceptions() { - if( current && current->canceled ) { - BOOST_THROW_EXCEPTION( error::task_canceled() ); - } else if( done ) { - BOOST_THROW_EXCEPTION( error::thread_quit() ); - } - } - - /** - * Find the next available context and switch to it. - * If none are available then create a new context and - * have it wait for something to do. - */ - bool start_next_fiber( bool reschedule = false ) { - check_for_timeouts(); - if( !current ) current = new cmt::context( &fc::thread::current() ); - - // check to see if any other contexts are ready - if( ready_head ) { - cmt::context* next = ready_pop_front(); - // jump to next context, saving current context - cmt::context* prev = current; - current = next; - if( reschedule ) ready_push_back(current); - - slog( "jump from %p to %p", prev, next ); - bc::jump_fcontext( &prev->my_context, &next->my_context, 0 ); - current = prev; - BOOST_ASSERT( current ); - } else { // all contexts are blocked, create a new context - // that will process posted tasks... - if( reschedule ) ready_push_back(current); - - cmt::context* next; - if( pt_head ) { - next = pt_head; - pt_head = pt_head->next; - next->next = 0; - } else { - next = new cmt::context( &thread_d::start_process_tasks, stack_alloc, - &fc::thread::current() ); - } - cmt::context* prev = current; - current = next; - slog( "jump from %p to %p", prev, next ); - bc::jump_fcontext( &prev->my_context, &next->my_context, (intptr_t)this ); - current = prev; - BOOST_ASSERT( current ); - } - - if( current->canceled ) - BOOST_THROW_EXCEPTION( cmt::error::task_canceled() ); - - return true; - } - - static void start_process_tasks( intptr_t my ) { - thread_d* self = (thread_d*)my; - try { - self->process_tasks(); - } catch ( ... ) { - std::cerr<<"fiber exited with uncaught exception:\n "<< - boost::current_exception_diagnostic_information() <free_list.push_back(self->current); - self->start_next_fiber( false ); - } - - bool run_next_task() { - time_point timeout_time = check_for_timeouts(); - task* next = dequeue(); - if( next ) { - next->set_active_context( current ); - current->cur_task = next; - next->run(); - current->cur_task = 0; - next->set_active_context(0); - next->release(); - //delete next; - return true; - } - return false; - } - bool has_next_task() { - if( task_pqueue.size() || - (task_sch_queue.size() && task_sch_queue.front()->when <= system_clock::now()) || - task_in_queue.load( boost::memory_order_relaxed ) ) - return true; - return false; - } - void clear_free_list() { - for( uint32_t i = 0; i < free_list.size(); ++i ) { - delete free_list[i]; - } - free_list.clear(); - } - void process_tasks() { - while( !done || blocked ) { - if( run_next_task() ) continue; - - // if I have something else to do other than - // process tasks... do it. - if( ready_head ) { - pt_push_back( current ); - start_next_fiber(false); - continue; - } - - clear_free_list(); - - { // lock scope - boost::unique_lock lock(task_ready_mutex); - if( has_next_task() ) continue; - time_point timeout_time = check_for_timeouts(); - - if( timeout_time == time_point::max() ) { - task_ready.wait( lock ); - } else if( timeout_time != time_point::min() ) { - task_ready.wait_until( lock, timeout_time ); - } - } - } - } - - void yield_until( const time_point& tp, bool reschedule ) { - check_fiber_exceptions(); - - if( tp <= system_clock::now() ) - return; - - if( !current ) { - current = new cmt::context(&cmt::thread::current()); - } - - current->resume_time = tp; - current->clear_blocking_promises(); - - sleep_pqueue.push_back(current); - std::push_heap( sleep_pqueue.begin(), - sleep_pqueue.end(), sleep_priority_less() ); - - start_next_fiber(reschedule); - - // clear current context from sleep queue... - for( uint32_t i = 0; i < sleep_pqueue.size(); ++i ) { - if( sleep_pqueue[i] == current ) { - sleep_pqueue[i] = sleep_pqueue.back(); - sleep_pqueue.pop_back(); - std::make_heap( sleep_pqueue.begin(), - sleep_pqueue.end(), sleep_priority_less() ); - break; - } - } - - current->resume_time = time_point::max(); - check_fiber_exceptions(); - } - - void wait( const promise_base::ptr& p, const time_point& timeout ) { - if( p->ready() ) return; - if( timeout < system_clock::now() ) - BOOST_THROW_EXCEPTION( cmt::error::future_wait_timeout() ); - - if( !current ) { - current = new cmt::context(&cmt::thread::current()); - } - - //slog( " %1% blocking on %2%", current, p.get() ); - current->add_blocking_promise(p.get(),true); - - // if not max timeout, added to sleep pqueue - if( timeout != time_point::max() ) { - current->resume_time = timeout; - sleep_pqueue.push_back(current); - std::push_heap( sleep_pqueue.begin(), - sleep_pqueue.end(), - sleep_priority_less() ); - } - - // elog( "blocking %1%", current ); - add_to_blocked( current ); - // debug("swtiching fibers..." ); - - - start_next_fiber(); - // slog( "resuming %1%", current ); - - //slog( " %1% unblocking blocking on %2%", current, p.get() ); - current->remove_blocking_promise(p.get()); - - check_fiber_exceptions(); - } - }; -} // namespace fc diff --git a/include/fc/time.hpp b/include/fc/time.hpp index d2bda19..aec234e 100644 --- a/include/fc/time.hpp +++ b/include/fc/time.hpp @@ -1,20 +1,20 @@ #pragma once #include #include -#include #include namespace fc { class microseconds { public: explicit microseconds( int64_t c = 0) :_count(c){} - static microseconds max() { return microseconds(0x7fffffffffffffffll); } + static microseconds maximum() { return microseconds(0x7fffffffffffffffll); } friend microseconds operator + (const microseconds& l, const microseconds& r ) { return microseconds(l._count+r._count); } - friend microseconds operator - (const microseconds& l, const microseconds& r ) { return microseconds(l._count-r._count); } bool operator==(const microseconds& c)const { return _count == c._count; } friend bool operator>(const microseconds& a, const microseconds& b){ return a._count > b._count; } + friend bool operator>=(const microseconds& a, const microseconds& b){ return a._count >= b._count; } friend bool operator<(const microseconds& a, const microseconds& b){ return a._count < b._count; } + friend bool operator<=(const microseconds& a, const microseconds& b){ return a._count <= b._count; } microseconds& operator+=(const microseconds& c) { _count += c._count; return *this; } int64_t count()const { return _count; } private: @@ -28,37 +28,25 @@ namespace fc { public: explicit time_point( microseconds e = microseconds() ) :elapsed(e){} static time_point now(); - static time_point max() { return time_point( microseconds::max() ); } - static time_point min() { return time_point(); } + static time_point maximum() { return time_point( microseconds::maximum() ); } + static time_point (min)() { return time_point(); } operator fc::string()const; static time_point from_iso_string( const fc::string& s ); const microseconds& time_since_epoch()const { return elapsed; } bool operator > ( const time_point& t )const { return elapsed._count > t.elapsed._count; } + bool operator >=( const time_point& t )const { return elapsed._count >=t.elapsed._count; } bool operator < ( const time_point& t )const { return elapsed._count < t.elapsed._count; } bool operator <=( const time_point& t )const { return elapsed._count <=t.elapsed._count; } bool operator ==( const time_point& t )const { return elapsed._count ==t.elapsed._count; } bool operator !=( const time_point& t )const { return elapsed._count !=t.elapsed._count; } time_point& operator += ( const microseconds& m ) { elapsed+=m; return *this; } friend time_point operator + ( const time_point& t, const microseconds& m ) { return time_point(t.elapsed+m); } - friend time_point operator - ( const time_point& t, const microseconds& m ) { return time_point(t.elapsed-m); } friend microseconds operator - ( const time_point& t, const time_point& m ) { return microseconds(t.elapsed.count() - m.elapsed.count()); } private: microseconds elapsed; }; - // forward declare io - class value; - void pack( fc::value& , const fc::time_point& ); - void unpack( const fc::value& , fc::time_point& ); - - namespace raw { - template - void unpack( Stream& s, fc::time_point& v ); - template - void pack( Stream& s, const fc::time_point& v ); - } - typedef fc::optional otime_point; } diff --git a/include/fc/time_io.hpp b/include/fc/time_io.hpp deleted file mode 100644 index 4fb284b..0000000 --- a/include/fc/time_io.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include -#include - -namespace fc { - namespace raw { - template - void unpack( Stream& s, fc::time_point& v ) { - int64_t micro; - fc::raw::unpack(s, micro ); - v = fc::time_point( fc::microseconds(micro); - } - template - void pack( Stream& s, const fc::time_point& v ) { - fc::raw::pack( s, v.time_since_epoch().count() ); - } - } -} diff --git a/include/fc/unique_ptr.hpp b/include/fc/unique_ptr.hpp new file mode 100644 index 0000000..609eff8 --- /dev/null +++ b/include/fc/unique_ptr.hpp @@ -0,0 +1,60 @@ +#pragma once +#include +#include + +namespace fc +{ + template + class unique_ptr + { + public: + typedef T* pointer; + + explicit unique_ptr( pointer t = nullptr ):_p(t){} + + unique_ptr( unique_ptr&& m ) + :_p(m._p){ m._p = nullptr; } + + ~unique_ptr() { delete _p; } + + operator bool()const { return _p != nullptr; } + friend bool operator==(const unique_ptr& p, nullptr_t) + { + return p._p == nullptr; + } + + friend bool operator!=(const unique_ptr& p, nullptr_t) + { + return p._p != nullptr; + } + + unique_ptr& operator=( nullptr_t ) + { + delete _p; _p = nullptr; + } + + unique_ptr& operator=( unique_ptr&& o ) + { + fc_swap( _p, o._p ); + return *this; + } + + pointer operator->()const { return _p; } + T& operator*()const { return *_p; } + + void reset( pointer v ) + { + delete _p; _p = v; + } + pointer release() + { + auto tmp = _p; + _p = nullptr; + return tmp; + } + + private: + pointer _p; + }; + +} diff --git a/include/fc/url.hpp b/include/fc/url.hpp deleted file mode 100644 index a1bfc91..0000000 --- a/include/fc/url.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include -#include -#include - -namespace fc { - - typedef fc::optional ostring; - - struct url { - url(){} - url( const string& url ); - /* - url( const url& u ); - - url( url&& u ); - url& operator=(url&& c); - url& operator=(const url& c); - */ - - operator string()const { return to_string(); } - string to_string()const; - url& from_string( const string& s ); - - bool operator==( const url& cmp )const; - - string proto; // file, ssh, tcp, http, ssl, etc... - ostring host; - ostring user; - ostring pass; - ostring path; - ostring args; - fc::optional port; - }; - -} // namespace fc - -#include -FC_REFLECT( fc::url, (proto)(host)(user)(pass)(path)(args)(port) ) - diff --git a/include/fc/utility.hpp b/include/fc/utility.hpp index 96742ae..0c6c77e 100644 --- a/include/fc/utility.hpp +++ b/include/fc/utility.hpp @@ -2,14 +2,23 @@ #include #include -//#define nullptr 0 +#ifdef _MSC_VER +#pragma warning(disable: 4482) // nonstandard extension used enum Name::Val, standard in C++11 +#define NO_RETURN __declspec(noreturn) +#else +#define NO_RETURN __attribute__((noreturn)) +#endif + -typedef decltype(sizeof(int)) size_t; namespace std { typedef decltype(sizeof(int)) size_t; + typedef decltype(nullptr) nullptr_t; } namespace fc { + using std::size_t; + typedef decltype(nullptr) nullptr_t; + template struct remove_reference { typedef T type; }; template struct remove_reference { typedef T type; }; template struct remove_reference { typedef T type; }; @@ -36,14 +45,16 @@ namespace fc { template struct is_class { typedef decltype(detail::is_class_helper(0)) type; enum value_enum { value = type::value }; }; - +#ifdef min +#undef min +#endif template const T& min( const T& a, const T& b ) { return a < b ? a: b; } } // outside of namespace fc becuase of VC++ conflict with std::swap template - void fc_swap( T& a, T& b ) { + void fc_swap( T& a, T& b ) { T tmp = fc::move(a); a = fc::move(b); b = fc::move(tmp); diff --git a/include/fc/value.hpp b/include/fc/value.hpp deleted file mode 100644 index 0f095e8..0000000 --- a/include/fc/value.hpp +++ /dev/null @@ -1,240 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#ifdef _MSC_VER - // Disable warning C4482: nonstandard extention used: enum 'enum_type::enum_value' used in qualified name - #pragma warning( disable: 4482 ) -#endif - -namespace fc { - template struct tuple; - - /** - * @brief a dynamic container that can hold - * integers, reals, strings, booleans, arrays, and - * or null. - * - * This type serves as an intermediate representation between - * C++ type and serialized type (JSON,XML,etc). - * - * As much as possible value attempts to preserve 'type' information, but - * type information is not always provided equally by all serialization formats. - * - * value is move aware, so move it when you can to avoid expensive copies - */ - class value { - public: - enum value_type { - null_type, string_type, bool_type, - int8_type, int16_type, int32_type, int64_type, - uint8_type, uint16_type, uint32_type, uint64_type, - double_type, float_type, - array_type, object_type - }; - - class key_val; - class object { - public: - typedef fc::vector::const_iterator const_iterator; - fc::vector fields; - }; - typedef fc::vector array; - - struct const_visitor { - virtual ~const_visitor(){} - virtual void operator()(const int8_t& v )=0; - virtual void operator()(const int16_t& v )=0; - virtual void operator()(const int32_t& v )=0; - virtual void operator()(const int64_t& v )=0; - virtual void operator()(const uint8_t& v )=0; - virtual void operator()(const uint16_t& v )=0; - virtual void operator()(const uint32_t& v )=0; - virtual void operator()(const uint64_t& v )=0; - virtual void operator()(const float& v )=0; - virtual void operator()(const double& v )=0; - virtual void operator()(const bool& v )=0; - virtual void operator()(const fc::string& v )=0; - virtual void operator()(const object& )=0; - virtual void operator()(const fc::vector& )=0; - virtual void operator()()=0; - }; - - value(); - value(value&& m ); - value(const value& m ); - - value(const char* c ); - value(char* c ); - value(int8_t ); - value(int16_t ); - value(int32_t ); - value(int64_t ); - value(uint8_t ); - value(uint16_t ); - value(uint32_t ); - value(uint64_t ); - value(double ); - value(float ); - value(bool ); - value(fc::string&& ); - value(fc::string& ); - value(const fc::string& ); - - value(object&& o ); - value(const object& o ); - value(object& o ); - - /// initialize an object with a single key/value pair - value(const fc::string&, const value& v ); - template - value(const fc::string& s, const T& v ) { - set( s, v ); - } - - value(fc::vector&& a ); - value(fc::vector& a ); - value(const fc::vector& a ); - - ~value(); - - value& operator=(value&& v ); - value& operator=(const value& v ); - - - /** - * Include fc/value_cast.hpp for implementation - */ - template - explicit value(const T& v ); - - template - value& operator=( const T& v ); - - template - T cast()const; - - /** used to iterate over object fields, use array index + size to iterate over array */ - object::const_iterator find(const char* key )const; - object::const_iterator begin()const; - object::const_iterator end()const; - - /** avoid creating temporary string just for comparisons! **/ - value& operator[](const char* key ); - const value& operator[](const char* key )const; - value& operator[](const fc::string& key ); - const value& operator[](const fc::string& key )const; - - /** array & object interface **/ - void clear(); - size_t size()const; - - /** array interface **/ - void resize(size_t s ); - void reserve(size_t s ); - value& push_back(value&& v ); - value& push_back(const value& v ); - const fc::vector& as_array()const; - fc::vector& as_array(); - const fc::string& as_string()const; - fc::string& as_string(); - const value::object& as_object()const; - value::object& as_object(); - - /** same as push_back(), used for short-hand construction of value()(1)(2)(3)(4) */ - value& operator()(fc::value v ); - value& operator[](int32_t idx ); - const value& operator[](int32_t idx )const; - - /** gets the stored type **/ - value_type type()const; - bool is_null()const; - bool is_string()const; - bool is_object()const; - bool is_array()const; - - void visit(const_visitor&& v )const; - - /** same as set(key, v ), used for short-hand construction of value()("key",1)("key2",2) */ - value& operator()(const char* key, fc::value v ); - value& set(const char* key, fc::value v ); - value& set(const fc::string& key, fc::value v ); - value& clear(const fc::string& key ); - - template - value& set(S&& key, T&& v ) { return set(fc::forward(key), fc::value(fc::forward(v) ) ); } - - private: - /** throws exceptions on errors - * - * Defined in fc/value_cast.hpp because it depends upon - * reflection - */ - template - friend T value_cast(const value& v ); - - aligned<40> holder; - }; - typedef fc::optional ovalue; - bool operator == (const value& v, std::nullptr_t ); - bool operator != (const value& v, std::nullptr_t ); - - class value::key_val { - public: - key_val(){}; - - key_val(fc::string k ) - :key(fc::move(k)){} - - key_val(const fc::string& k, const value& v ) - :key(k),val(v){} - - key_val(key_val&& m ) - :key(fc::move(m.key)),val(fc::move(m.val)){ } - - key_val(const key_val& m ) - :key(m.key),val(m.val){} - - ~key_val(){ } - - key_val& operator=(key_val&& k ) { - fc_swap(key, k.key ); - fc_swap(val, k.val ); - return *this; - } - - key_val& operator=(const key_val& k ) { - key = k.key; - val = k.val; - return *this; - } - - fc::string key; - value val; - }; - -} // namespace fc - -#include -FC_REFLECT_ENUM(fc::value::value_type, - (null_type) - (string_type) - (bool_type) - (int8_type) - (int16_type) - (int32_type) - (int64_type) - (uint8_type) - (uint16_type) - (uint32_type) - (uint64_type) - (double_type) - (float_type) - (array_type) - (object_type) -) diff --git a/include/fc/value_cast.hpp b/include/fc/value_cast.hpp deleted file mode 100644 index d29ca2c..0000000 --- a/include/fc/value_cast.hpp +++ /dev/null @@ -1,180 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//#include - -namespace fc { - - namespace detail { - - void cast_value( const value& v, int8_t& ); - void cast_value( const value& v, int16_t& ); - void cast_value( const value& v, int32_t& ); - void cast_value( const value& v, int64_t& ); - void cast_value( const value& v, uint8_t& ); - void cast_value( const value& v, uint16_t& ); - void cast_value( const value& v, uint32_t& ); - void cast_value( const value& v, uint64_t& ); - void cast_value( const value& v, double& ); - void cast_value( const value& v, float& ); - void cast_value( const value& v, bool& ); - void cast_value( const value& v, fc::string& ); - void cast_value( const value& v, value& ); - - template - void cast_value( const value& v, T& t) { - unpack(v,t); - } - template - void cast_value( const value& v, std::vector& out ) { - if( v.type() != value::array_type ) { - FC_THROW_REPORT( "Error casting ${type} to array", fc::value("type", fc::reflector::to_string(v.type()) ) ); - } - out.resize(v.size()); - slog( "out .size %d", out.size() ); - const fc::vector& val = v.as_array(); - auto oitr = out.begin(); - int idx = 0; - for( auto itr = val.begin(); itr != val.end(); ++itr, ++oitr, ++idx ) { - try { - *oitr = itr->cast(); //value_cast(*itr); - // value_cast( *itr, *oitr ); - } catch ( fc::error_report& er ) { - throw FC_REPORT_PUSH( er, "Error casting value[${index}] to ${type}", - fc::value("index",idx) - ("type", fc::get_typename::name()) - ); - } - } - } - - template - void cast_value( const value& v, fc::vector& out ) { - if( v.type() != value::array_type ) { - FC_THROW_REPORT( "Error casting ${type} to array", fc::value("type", fc::reflector::to_string(v.type()) ) ); - } - out.resize(v.size()); - slog( "out .size %d", out.size() ); - const fc::vector& val = v.as_array(); - auto oitr = out.begin(); - int idx = 0; - for( auto itr = val.begin(); itr != val.end(); ++itr, ++oitr, ++idx ) { - try { - *oitr = itr->cast(); //value_cast(*itr); - // value_cast( *itr, *oitr ); - } catch ( fc::error_report& er ) { - throw FC_REPORT_PUSH( er, "Error casting value[${index}] to ${type}", - fc::value("index",idx) - ("type", fc::get_typename::name()) - ); - } - } - } - - template - struct cast_if_tuple { - template - static T cast( const value& v ) { - typename fc::deduce::type out; - cast_value(v,out); - // v.visit(cast_visitor(out)); - return out; - } - }; - template<> - struct cast_if_tuple { - struct member_visitor { - member_visitor( const value& v ) - :_val(v),idx(0){} - template - void operator()( Member& m ) { - try { - m = value_cast(_val[idx]); - } catch ( fc::error_report& er ) { - throw FC_REPORT_PUSH( er, "Error parsing tuple element ${index}", fc::value().set("index",idx) ); - } - ++idx; - } - const value& _val; - int idx; - }; - - template - static Tuple cast( const value& v ) { - typename fc::deduce::type out; - out.visit( member_visitor(v) ); - return out; - } - }; - - template - struct cast_if_reflected { - template - static T cast( const value& v ) { - return cast_if_tuple::type>::template cast(v); - } - }; - - template<> - struct cast_if_reflected { - template - static T cast( const value& v ) { - T tmp; - unpack(v,tmp); - return tmp; - } - }; - - void new_value_holder_void( value* v ); - } // namespace detail - - - /** - * Convert from value v to T - * - * Performs the following conversions - * true -> 1.0, 1, "true" - * - * Not all casts are 'clean', the following conversions - * could cause errors: - * - * signed int -> unsigned - * large int -> smaller int - * real -> int - * non-numeric string -> number - * object -> string or number - * array -> string or number - * number,string,array -> object - */ - template - T value_cast( const value& v ) { - return detail::cast_if_reflected::type>::is_defined>::template cast< typename fc::deduce::type >(v); - } - - template - value::value( const T& v ) { - detail::new_value_holder_void(this); - fc::pack( *this, v); - } - template - value& value::operator=( const T& v ) { - this->~value(); - value tmp(v); - *this = fc::move(tmp); - return *this; - } - template - T value::cast()const { - return value_cast(*this); - } -} diff --git a/include/fc/value_io.hpp b/include/fc/value_io.hpp deleted file mode 100644 index e69f002..0000000 --- a/include/fc/value_io.hpp +++ /dev/null @@ -1,332 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace fc { - template - T value_cast( const value& v ); - - struct void_t{}; - - template - void pack(fc::value& jsv, const T& v ); - - template - void unpack( const fc::value& jsv, T& v ); - - template - void pack( fc::value& v, const tuple& t ); - template - void unpack( const fc::value& val, tuple& t ); - - template - void pack( fc::value& jsv, const fc::optional& v ); - - template - void unpack( const fc::value& jsv, fc::optional& v ); - - inline void pack( fc::value& jsv, const char& v ) { jsv = fc::string(&v,1); } - inline void pack( fc::value& jsv, const fc::value& v ) { jsv = v; } - inline void pack( fc::value& jsv, fc::value& v ) { jsv = v; } - inline void pack( fc::value& jsv, fc::value&& v ) { jsv = fc::move(v); } - inline void pack( fc::value& jsv, const void_t& v ) { jsv = fc::value(); } - inline void pack( fc::value& jsv, const bool& v ) { jsv = v; } - inline void pack( fc::value& jsv, const float& v ) { jsv = v; } - inline void pack( fc::value& jsv, const double& v ) { jsv = v; } - inline void pack( fc::value& jsv, const uint8_t& v ) { jsv = v; } - inline void pack( fc::value& jsv, const uint16_t& v ) { jsv = v; } - inline void pack( fc::value& jsv, const uint32_t& v ) { jsv = v; } - inline void pack( fc::value& jsv, const uint64_t& v ) { jsv = v; } - inline void pack( fc::value& jsv, const int8_t& v ) { jsv = v; } - inline void pack( fc::value& jsv, const int16_t& v ) { jsv = v; } - inline void pack( fc::value& jsv, const int32_t& v ) { jsv = v; } - inline void pack( fc::value& jsv, const int64_t& v ) { jsv = v; } - inline void pack( fc::value& jsv, const fc::string& v ) { jsv = value(v); } - inline void pack( fc::value& jsv, fc::string& v ) { jsv = v; } - inline void pack( fc::value& jsv, fc::string&& v ) { jsv = fc::move(v); } - inline void pack( fc::value& jsv, const char* v ) { jsv = fc::string(v); } - - void pack( fc::value& jsv, const fc::vector& value ); - template - void pack( fc::value& jsv, const fc::vector& value ); - template - void pack( fc::value& jsv, const std::vector& value ); - - - inline void unpack( const fc::value& jsv, fc::value& v ) { v = jsv; } - template - void unpack( const fc::value& jsv, const T& v ); - template - void unpack( const fc::value& jsv, T& v ); - void unpack( const fc::value& jsv, bool& v ); - - inline void unpack( const fc::value& jsv, void_t& v ){ }; - - void unpack( const fc::value& jsv, float& v ); - void unpack( const fc::value& jsv, double& v ); - void unpack( const fc::value& jsv, uint8_t& v ); - void unpack( const fc::value& jsv, uint16_t& v ); - void unpack( const fc::value& jsv, uint32_t& v ); - void unpack( const fc::value& jsv, uint64_t& v ); - void unpack( const fc::value& jsv, int8_t& v ); - void unpack( const fc::value& jsv, int16_t& v ); - void unpack( const fc::value& jsv, int32_t& v ); - void unpack( const fc::value& jsv, int64_t& v ); - void unpack( const fc::value& jsv, fc::string& v ); - - void unpack( const fc::value& jsv, fc::vector& value ); - - void unpack( const fc::value& jsv, fc::vector& value ); - template - void unpack( const fc::value& jsv, fc::vector& value ); - template - void unpack( const fc::value& jsv, std::vector& value ); - - namespace detail { - template - struct pack_object_visitor { - pack_object_visitor(const Class& _c, fc::value& _val) - :c(_c),obj(_val){} - - /** - VC++ does not understand the difference of return types, so an extra layer is needed. - */ - template - inline void pack_helper( const T& v, const char* name )const { - value* o = &obj[name]; - fc::pack( *o, v ); - } - template - inline void pack_helper( const fc::optional& v, const char* name )const { - if( !!v ) { - fc::pack( obj[name], *v ); - } - } - template - inline void operator()( const char* name )const { - pack_helper( c.*p, name ); - } - - private: - const Class& c; - fc::value& obj; - }; - - template - struct is_optional { - typedef fc::false_type type; - }; - template - struct is_optional > { - typedef fc::true_type type; - }; - - template - struct unpack_object_visitor { - unpack_object_visitor(Class& _c, const fc::value& _val) - :c(_c),obj(_val){} - - template - void operator()( const char* name )const { - if( obj.find(name) != obj.end()) { - try { - fc::unpack( obj[name], c.*p ); - } catch ( fc::error_report& er ) { - throw FC_REPORT_PUSH( er, "Error parsing field '${field_name}'", fc::value("field_name",name) ); - } - } - else { - if( !is_optional< typename fc::remove_reference::type >::type::value ) { - wlog( "unable to find name: '%s'",name); - } - } - } - Class& c; - const fc::value& obj; - }; - - template - struct if_enum { - template - static inline void pack( fc::value& jsv, const T& v ) { - jsv = fc::value::object(); - detail::pack_object_visitor pov(v,jsv); - fc::reflector::visit(pov); - } - template - static inline void unpack( const fc::value& jsv, T& v ) { - detail::unpack_object_visitor pov(v,jsv ); - fc::reflector::visit(pov); - } - }; - - template<> struct if_enum { - template - static inline void pack( fc::value& jsv, const T& v ) { - fc::pack( jsv, fc::reflector::to_string(v) ); - } - template - static inline void unpack( const fc::value& jsv, T& v ) { - if( jsv.is_string() ) { - v = fc::reflector::from_string( fc::value_cast(jsv).c_str() ); - } else { - // throw if invalid int, by attempting to convert to string - fc::reflector::to_string( v = static_cast(value_cast(jsv)) ); - } - } - }; - - - template - struct if_reflected { - template - static inline void pack(fc::value& s, const T& v ) { - v.did_not_implement_reflect_macro(); - } - template - static inline void unpack( const fc::value& s, T& v ) { - v.did_not_implement_reflect_macro(); - } - }; - - template<> - struct if_reflected { - template - static inline void pack( fc::value& jsv, const T& v ) { - if_enum::is_enum>::pack( jsv,v ); - } - template - static inline void unpack( const fc::value& jsv, T& v ) { - if_enum::is_enum>::unpack( jsv,v ); - } - }; - - } // namesapce detail - - inline void unpack( const fc::value& jsv, char& v ) { - auto s = value_cast(jsv); - if( s.size() ) v = s[0]; - } - inline void unpack( const fc::value& jsv, bool& v ) { v = value_cast(jsv); } - inline void unpack( const fc::value& jsv, float& v ) { v = value_cast(jsv); } - inline void unpack( const fc::value& jsv, double& v ) { v = value_cast(jsv); } - inline void unpack( const fc::value& jsv, uint8_t& v ) { v = value_cast(jsv); } - inline void unpack( const fc::value& jsv, uint16_t& v ) { v = value_cast(jsv); } - inline void unpack( const fc::value& jsv, uint32_t& v ) { v = value_cast(jsv); } - inline void unpack( const fc::value& jsv, uint64_t& v ) { v = value_cast(jsv); } - inline void unpack( const fc::value& jsv, int8_t& v ) { v = value_cast(jsv); } - inline void unpack( const fc::value& jsv, int16_t& v ) { v = value_cast(jsv); } - inline void unpack( const fc::value& jsv, int32_t& v ) { v = value_cast(jsv); } - inline void unpack( const fc::value& jsv, int64_t& v ) { v = value_cast(jsv); } - inline void unpack( const fc::value& jsv, fc::string& v ) { v = value_cast(jsv); } - - template - void pack( fc::value& jsv, const fc::optional& v ) { - if( v ) pack( jsv, *v ); - else jsv = fc::value(); - } - template - void unpack( const fc::value& jsv, fc::optional& v ) { - if( !jsv.is_null() ) { - T tmp; - unpack( jsv, tmp ); - v = fc::move(tmp); - } - } - - - template - inline void pack( fc::value& jsv, const fc::vector& value ) { - jsv = fc::value::array(); - jsv.resize(value.size()); - typename fc::vector::const_iterator itr = value.begin(); - typename fc::vector::const_iterator end = value.end(); - uint32_t i = 0; - while( itr != end ) { - fc::pack( jsv[i], *itr ); - ++itr; - ++i; - } - } - template - inline void pack( fc::value& jsv, const std::vector& value ) { - jsv = fc::value::array(); - jsv.resize(value.size()); - auto itr = value.begin(); - auto end = value.end(); - uint32_t i = 0; - while( itr != end ) { - fc::pack( jsv[i], *itr ); - ++itr; - ++i; - } - } - struct tuple_to_value_visitor { - tuple_to_value_visitor( value& v ):_val(v),_count(0) { } - template - void operator()( T&& t ) { - _val[_count] = value(fc::forward(t) ); - ++_count; - } - value& _val; - int _count; - }; - struct tuple_from_value_visitor { - tuple_from_value_visitor( const value& v ):_val(v),_count(0) { } - template - void operator()( T&& t ) { - if( _count < _val.size() ) unpack( _val[_count], t ); - ++_count; - } - const value& _val; - int _count; - }; - - template - inline void pack( fc::value& val, const tuple& t ) { - val = fc::value::array( tuple::size ); - t.visit( tuple_to_value_visitor(val) ); - } - template - inline void unpack( const fc::value& val, tuple& t ) { - if( val.size() < tuple::size ) - FC_THROW_REPORT( "Attempt to unpack tuple of size ${size} from array of size ${array_size}", - fc::value( "size", tuple::size)("array_size",val.size() ) ); - t.visit( tuple_from_value_visitor(val) ); - } - - template - inline void unpack( const fc::value& jsv, fc::vector& val ) { - val.resize( jsv.size() ); - uint32_t s = jsv.size(); - for( uint32_t i = 0; i < s; ++i ) { - unpack( jsv[i], val[i] ); - } - } - template - inline void unpack( const fc::value& jsv, std::vector& val ) { - val.resize( jsv.size() ); - uint32_t s = jsv.size(); - for( uint32_t i = 0; i < s; ++i ) { - unpack( jsv[i], val[i] ); - } - } - - // default case - template - inline void pack( fc::value& jsv, const T& v ) { - detail::if_reflected< typename fc::reflector::is_defined >::pack(jsv,v); - } - - template - inline void unpack( const fc::value& jsv, T& v ) { - detail::if_reflected< typename fc::reflector::is_defined >::unpack(jsv,v); - } - -} // namespace fc - diff --git a/include/fc/variant.hpp b/include/fc/variant.hpp new file mode 100644 index 0000000..896a79d --- /dev/null +++ b/include/fc/variant.hpp @@ -0,0 +1,296 @@ +#pragma once +#include +#include +#include +#include + +namespace fc +{ + /** + * @defgroup serializable Serializable _types + * @brief Clas_ses that may be converted to/from an variant + * + * To make a class 'serializable' the following methods must be available + * for your Serializable_type + * + * @code + * void to_variant( const Serializable_type& e, variant& v ); + * void from_variant( const variant& e, Serializable_type& ll ); + * @endcode + */ + + class variant; + class variant_object; + class mutable_variant_object; + class time_point; + + void to_variant( const uint16_t& var, variant& vo ); + void from_variant( const variant& var, uint16_t& vo ); + void to_variant( const uint32_t& var, variant& vo ); + void from_variant( const variant& var, uint32_t& vo ); + void to_variant( const uint8_t& var, variant& vo ); + void from_variant( const variant& var, uint8_t& vo ); + + void to_variant( const variant_object& var, variant& vo ); + void from_variant( const variant& var, variant_object& vo ); + void to_variant( const mutable_variant_object& var, variant& vo ); + void from_variant( const variant& var, mutable_variant_object& vo ); + void to_variant( const vector& var, variant& vo ); + void from_variant( const variant& var, vector& vo ); + void to_variant( const time_point& var, variant& vo ); + void from_variant( const variant& var, time_point& vo ); + #ifdef __APPLE__ + void to_variant( size_t s, variant& v ); + #endif + void to_variant( const std::string& s, variant& v ); + + template + void to_variant( const std::shared_ptr& var, variant& vo ); + + template + void from_variant( const variant& var, std::shared_ptr& vo ); + + typedef vector variants; + + /** + * @brief stores null, int64, uint64, double, bool, string, vector, + * and variant_object's. + * + * variant's allocate everything but strings, arrays, and objects on the + * stack and are 'move aware' for values allcoated on the heap. + * + * Memory usage on 64 bit systems is 16 bytes and 12 bytes on 32 bit systems. + */ + class variant + { + public: + enum type_id + { + null_type = 0, + int64_type = 1, + uint64_type = 2, + double_type = 3, + bool_type = 4, + string_type = 5, + array_type = 6, + object_type = 7 + }; + + /// Constructs a null_type variant + variant(); + /// Constructs a null_type variant + variant( nullptr_t ); + + /// @param str - UTF8 string + variant( const char* str ); + variant( char* str ); + variant( wchar_t* str ); + variant( const wchar_t* str ); + variant( int val ); + variant( float val ); + variant( int64_t val ); + variant( uint64_t val ); + variant( double val ); + variant( bool val ); + variant( fc::string val ); + variant( variant_object ); + variant( mutable_variant_object ); + variant( variants ); + variant( const variant& ); + variant( variant&& ); + ~variant(); + + /** + * Read-only access to the content of the variant. + */ + class visitor + { + public: + virtual ~visitor(){} + /// handles null_type variants + virtual void handle()const = 0; + virtual void handle( const int64_t& v )const = 0; + virtual void handle( const uint64_t& v )const = 0; + virtual void handle( const double& v )const = 0; + virtual void handle( const bool& v )const = 0; + virtual void handle( const string& v )const = 0; + virtual void handle( const variant_object& v)const = 0; + virtual void handle( const variants& v)const = 0; + }; + + void visit( const visitor& v )const; + + type_id get_type()const; + + bool is_null()const; + bool is_string()const; + bool is_bool()const; + bool is_int64()const; + bool is_uint64()const; + bool is_double()const; + bool is_object()const; + bool is_array()const; + /** + * int64, uint64, double,bool + */ + bool is_numeric()const; + + int64_t as_int64()const; + uint64_t as_uint64()const; + bool as_bool()const; + double as_double()const; + + /** Convert's double, ints, bools, etc to a string + * @throw if get_type() == array_type | get_type() == object_type + */ + string as_string()const; + + /// @pre get_type() == string_type + const string& get_string()const; + + /// @throw if get_type() != array_type | null_type + variants& get_array(); + + /// @throw if get_type() != array_type + const variants& get_array()const; + + /// @throw if get_type() != object_type | null_type + variant_object& get_object(); + + /// @throw if get_type() != object_type + const variant_object& get_object()const; + + /// @pre is_object() + const variant& operator[]( const char* )const; + /// @pre is_array() + const variant& operator[]( size_t pos )const; + /// @pre is_array() + size_t size()const; + + /** + * _types that use non-intrusive variant conversion can implement the + * following method to implement conversion from variant to T. + * + * + * void from_variant( const Variant& var, T& val ) + * + * + * The above form is not always convienant, so the this templated + * method is used to enable conversion from Variants to other + * types. + */ + template + T as()const + { + T tmp; + from_variant( *this, tmp ); + return tmp; + } + + variant& operator=( variant&& v ); + variant& operator=( const variant& v ); + + template + variant& operator=( T&& v ) + { + *this = variant( fc::forward(v) ); + return *this; + } + + template + variant( const optional& v ) + { + if( v ) *this = variant(*v); + } + + template + explicit variant( const T& val ); + + + private: + double _data; ///< Alligned according to double requirements + char _type[sizeof(void*)]; ///< pad to void* size + }; + typedef optional ovariant; + + /** @ingroup Serializable */ + void from_variant( const variant& var, string& vo ); + /** @ingroup Serializable */ + void from_variant( const variant& var, variants& vo ); + void from_variant( const variant& var, variant& vo ); + /** @ingroup Serializable */ + void from_variant( const variant& var, int64_t& vo ); + /** @ingroup Serializable */ + void from_variant( const variant& var, uint64_t& vo ); + /** @ingroup Serializable */ + void from_variant( const variant& var, bool& vo ); + /** @ingroup Serializable */ + void from_variant( const variant& var, double& vo ); + /** @ingroup Serializable */ + void from_variant( const variant& var, float& vo ); + /** @ingroup Serializable */ + void from_variant( const variant& var, int32_t& vo ); + /** @ingroup Serializable */ + void from_variant( const variant& var, uint32_t& vo ); + /** @ingroup Serializable */ + template + void from_variant( const variant& var, optional& vo ) + { + if( var.is_null() ) vo = optional(); + else + { + vo = T(); + from_variant( var, *vo ); + } + } + + /** @ingroup Serializable */ + template + void from_variant( const variant& var, vector& tmp ) + { + const variants& vars = var.get_array(); + tmp.clear(); + tmp.reserve( vars.size() ); + for( auto itr = vars.begin(); itr != vars.end(); ++itr ) + tmp.push_back( itr->as() ); + } + + /** @ingroup Serializable */ + template + void to_variant( const vector& t, variant& v ) + { + vector vars(t.size()); + for( size_t i = 0; i < t.size(); ++i ) + vars[i] = variant(t[i]); + v = vars; + } + + + template + variant::variant( const T& val ) + { + memset( this, 0, sizeof(*this) ); + to_variant( val, *this ); + } + #ifdef __APPLE__ + inline void to_variant( size_t s, variant& v ) { v = variant(uint64_t(s)); } + #endif + template + void to_variant( const std::shared_ptr& var, variant& vo ) + { + if( var ) to_variant( *var, vo ); + else vo = nullptr; + } + + template + void from_variant( const variant& var, std::shared_ptr& vo ) + { + if( var.is_null() ) vo = nullptr; + else if( vo ) from_variant( var, *vo ); + else { + vo = std::make_shared(); + from_variant( var, *vo ); + } + } + +} // namespace fc diff --git a/include/fc/variant_object.hpp b/include/fc/variant_object.hpp new file mode 100644 index 0000000..a5942ce --- /dev/null +++ b/include/fc/variant_object.hpp @@ -0,0 +1,216 @@ +#pragma once +#include +#include +#include + +namespace fc +{ + class mutable_variant_object; + + /** + * @ingroup Serializable + * + * @brief An order-perserving dictionary of variant's. + * + * Keys are kept in the order they are inserted. + * This dictionary implements copy-on-write + * + * @note This class is not optimized for random-access on large + * sets of key-value pairs. + */ + class variant_object + { + public: + /** @brief a key/value pair */ + class entry + { + public: + entry(); + entry( string k, variant v ); + entry( entry&& e ); + entry( const entry& e); + entry& operator=(const entry&); + entry& operator=(entry&&); + + const string& key()const; + const variant& value()const; + void set( variant v ); + + variant& value(); + + private: + string _key; + variant _value; + }; + + typedef vector< entry >::const_iterator iterator; + + /** + * @name Immutable Interface + * + * Calling these methods will not result in copies of the + * underlying type. + */ + ///@{ + iterator begin()const; + iterator end()const; + iterator find( const string& key )const; + iterator find( const char* key )const; + const variant& operator[]( const string& key )const; + const variant& operator[]( const char* key )const; + size_t size()const; + bool contains( const char* key ) { return find(key) != end(); } + ///@} + + variant_object(); + + /** initializes the first key/value pair in the object */ + variant_object( string key, variant val ); + + template + variant_object( string key, T&& val ) + :_key_value( std::make_shared >() ) + { + *this = variant_object( move(key), variant(forward(val)) ); + } + variant_object( const variant_object& ); + variant_object( variant_object&& ); + + variant_object( const mutable_variant_object& ); + variant_object( mutable_variant_object&& ); + + variant_object& operator=( variant_object&& ); + variant_object& operator=( const variant_object& ); + + variant_object& operator=( mutable_variant_object&& ); + variant_object& operator=( const mutable_variant_object& ); + + private: + std::shared_ptr< vector< entry > > _key_value; + friend class mutable_variant_object; + }; + /** @ingroup Serializable */ + void to_variant( const variant_object& var, variant& vo ); + /** @ingroup Serializable */ + void from_variant( const variant& var, variant_object& vo ); + + + /** + * @ingroup Serializable + * + * @brief An order-perserving dictionary of variant's. + * + * Keys are kept in the order they are inserted. + * This dictionary implements copy-on-write + * + * @note This class is not optimized for random-access on large + * sets of key-value pairs. + */ + class mutable_variant_object + { + public: + /** @brief a key/value pair */ + typedef variant_object::entry entry; + + typedef vector< entry >::iterator iterator; + typedef vector< entry >::const_iterator const_iterator; + + /** + * @name Immutable Interface + * + * Calling these methods will not result in copies of the + * underlying type. + */ + ///@{ + iterator begin()const; + iterator end()const; + iterator find( const string& key )const; + iterator find( const char* key )const; + const variant& operator[]( const string& key )const; + const variant& operator[]( const char* key )const; + size_t size()const; + ///@} + variant& operator[]( const string& key ); + variant& operator[]( const char* key ); + + /** + * @name mutable Interface + * + * Calling these methods will result in a copy of the underlying type + * being created if there is more than one reference to this object. + */ + ///@{ + void reserve( size_t s); + iterator begin(); + iterator end(); + void erase( const string& key ); + /** + * + * @return end() if key is not found + */ + iterator find( const string& key ); + iterator find( const char* key ); + + + /** replaces the value at \a key with \a var or insert's \a key if not found */ + mutable_variant_object& set( string key, variant var ); + /** Appends \a key and \a var without checking for duplicates, designed to + * simplify construction of dictionaries using (key,val)(key2,val2) syntax + */ + /** + * Convenience method to simplify the manual construction of + * variant_object's + * + * Instead of: + * mutable_variant_object("c",c).set("a",a).set("b",b); + * + * You can use: + * mutable_variant_object( "c", c )( "b", b)( "c",c ) + * + * @return *this; + */ + mutable_variant_object& operator()( string key, variant var ); + template + mutable_variant_object& operator()( string key, T&& var ) + { + set(move(key), variant( forward(var) ) ); + return *this; + } + ///@} + + + template + explicit mutable_variant_object( T&& v ) + :_key_value( new vector() ) + { + *this = variant(fc::forward(v)).get_object(); + } + + mutable_variant_object(); + + /** initializes the first key/value pair in the object */ + mutable_variant_object( string key, variant val ); + template + mutable_variant_object( string key, T&& val ) + :_key_value( new vector() ) + { + set( move(key), variant(forward(val)) ); + } + + mutable_variant_object( mutable_variant_object&& ); + mutable_variant_object( const mutable_variant_object& ); + mutable_variant_object( const variant_object& ); + + mutable_variant_object& operator=( mutable_variant_object&& ); + mutable_variant_object& operator=( const mutable_variant_object& ); + mutable_variant_object& operator=( const variant_object& ); + private: + std::unique_ptr< vector< entry > > _key_value; + friend class variant_object; + }; + /** @ingroup Serializable */ + void to_variant( const mutable_variant_object& var, variant& vo ); + /** @ingroup Serializable */ + void from_variant( const variant& var, mutable_variant_object& vo ); + +} // namespace fc diff --git a/include/fc/vector.hpp b/include/fc/vector.hpp index 4396c4e..9220777 100644 --- a/include/fc/vector.hpp +++ b/include/fc/vector.hpp @@ -3,8 +3,6 @@ #include #include #include -#include -#include namespace fc { @@ -51,13 +49,11 @@ namespace fc { vector_impl():_data(nullptr){} vector_impl( vector_impl&& c):_data(c._data){c._data =nullptr; } vector_impl( const vector_impl& c):_data(nullptr) { - //slog( "copy: c.size %d", c.size() ); if( c.size() ) { _data = detail::data::allocate( c.size() ); _data->size = c.size(); memcpy(begin(),c.begin(), static_cast(c.size()) ); } - //slog( "copy: this.size %d", size() ); } vector_impl(const_iterator b, const_iterator e ):_data(nullptr) { resize(e-b); @@ -102,7 +98,16 @@ namespace fc { } void reserve( size_t i ) { - _data = detail::data::reallocate( _data, i ); + if( nullptr == _data ) + { + _data = detail::data::allocate( i ); + _data->size = 0; + _data->capacity = i; + } + else + { + _data = detail::data::reallocate( _data, i ); + } } void resize( size_t i ) { @@ -120,6 +125,11 @@ namespace fc { resize( size()+1 ); back() = fc::forward(v); } + template + void emplace_back( U&& v ) { + resize( size()+1 ); + back() = fc::forward(v); + } template iterator insert( const_iterator loc, U&& t ) { @@ -223,6 +233,7 @@ namespace fc { iterator begin() { return _data ? &front() : 0;} const_iterator begin()const { return _data ? &front() : 0;} const_iterator end()const { return _data ? (&back())+1: 0;} + iterator end(){ return _data ? (&back())+1: 0;} T& operator[]( size_t i ) { return (&_data->first)[i]; } const T& operator[]( size_t i )const { return (&_data->first)[i]; } @@ -283,6 +294,14 @@ namespace fc { new (&back()+1) T(fc::forward(v)); ++this->_data->size; } + template + void emplace_back( U&& v ) { + this->reserve( this->size()+1 ); + new (&back()+1) T(fc::forward(v)); + ++this->_data->size; + } + + template iterator insert( const_iterator loc, U&& t ) { diff --git a/include/fc/vector_g.hpp b/include/fc/vector_g.hpp deleted file mode 100644 index 0876022..0000000 --- a/include/fc/vector_g.hpp +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef _FC_VECTOR_HPP_ -#define _FC_VECTOR_HPP_ -#include - -namespace fc { - class vector_impl { - public: - size_t size()const; - size_t capacity()const; - void pop_back(); - void clear(); - void resize( size_t ); - void reserve( size_t ); - - protected: - vector_impl( abstract_value_type& v, size_t size ); - vector_impl( const vector_impl& ); - vector_impl( vector_impl&& ); - ~vector_impl(); - - vector_impl& operator=( const vector_impl& v ); - vector_impl& operator=( vector_impl&& v ); - - void _push_back( const void* v ); - void _push_back_m( void* v ); - - void* _back(); - const void* _back()const; - - void* _at(size_t); - const void* _at(size_t)const; - - void* _insert( void* pos, const void* t ); - void* _insert( void* pos, void* t ); - void* _erase( void* pos ); - void* _erase( void* first, void* last ); - - struct vector_impl_d* my; - }; - - class vector_pod_impl { - public: - size_t size()const; - size_t capacity()const; - void pop_back(); - void clear(); - void resize( size_t ); - void reserve( size_t ); - - protected: - vector_pod_impl( unsigned int size_of, size_t size ); - vector_pod_impl( const vector_pod_impl& ); - vector_pod_impl( vector_pod_impl&& ); - ~vector_pod_impl(); - - vector_pod_impl& operator=( const vector_pod_impl& v ); - vector_pod_impl& operator=( vector_pod_impl&& v ); - - void _push_back( const void* v ); - void _push_back_m( void* v ); - - void* _back(); - const void* _back()const; - - void* _at(size_t); - const void* _at(size_t)const; - - void* _insert( void* pos, const void* t ); - void* _erase( void* pos ); - void* _erase( void* first, void* last ); - - struct vector_pod_impl_d* my; - }; - - template - class vector_base : public vector_impl { - public: - vector_base( size_t s ):vector_impl( value_type::instance(), s ){}; - vector_base( const vector_base& c ):vector_impl( c ){}; - vector_base( vector_base&& c ):vector_impl( fc::move(c) ){}; - - vector_base& operator=( const vector_base& v ){ vector_impl::operator=(v); return *this; } - vector_base& operator=( vector_base&& v ) { vector_impl::operator=(fc::move(v)); return *this; } - }; - - template - class vector_base : public vector_pod_impl { - public: - vector_base( size_t s ):vector_pod_impl( sizeof(T), s ){}; - vector_base( const vector_base& c ):vector_pod_impl( c ){}; - vector_base( vector_base&& c ):vector_pod_impl( fc::move(c) ){}; - - vector_base& operator=( const vector_base& v ){ vector_pod_impl::operator=(v); return *this; } - vector_base& operator=( vector_base&& v ) { vector_pod_impl::operator=(fc::move(v)); return *this; } - }; - - template - class vector : public vector_base::value > { - public: - vector( size_t size = 0 ):vector_base::value>( size ){} - vector( const vector& v ):vector_base::value>(v){} - vector( vector&& v ):vector_base::value>(fc::move(v)){} - - vector& operator=( const vector& v ){ vector_base::value>::operator=(v); return *this; } - vector& operator=( vector&& v ) { vector_base::value>::operator=(fc::move(v)); return *this; } - - typedef T* iterator; - typedef const T* const_iterator; - - T* begin() { return &front(); } - const T* begin()const { return &front(); } - const T* end()const { return &back() + 1; } - - void push_back( const T& t ) { _push_back(&t); } - void push_back( T&& t ) { _push_back_m(&t); } - - T& back() { return *((T*)this->_back()); } - const T& back()const { return *((const T*)this->_back()); } - - T& front() { return *((T*)this->_at(0)); } - const T& front()const { return *((const T*)this->_at(0)); } - - T& operator[]( size_t p ) { return *((T*)this->_at(p)); } - const T& operator[]( size_t p )const { return *((const T*)this->_at(p)); } - - T& at( size_t p ) { return *((T*)this->_at(p)); } - const T& at( size_t p )const { return *((const T*)this->_at(p)); } - - iterator insert( iterator pos, const T& t ) { return (iterator*)this->_insert( pos, &t ); } - iterator insert( iterator pos, T&& t ) { return (iterator*)this->_insert_m(pos, &t); } - iterator erase( iterator pos ) { return (iterator*)this->_erase(pos); } - iterator erase( iterator first, iterator last ) { return (iterator*)this->_erase(first,last); } - }; - namespace reflect { - template class reflector; - template class reflector>; - } -} // namespace fc - -#endif // _FC_VECTOR_HPP_ diff --git a/include/fc/wait_any.hpp b/include/fc/wait_any.hpp index f31428b..c3d6207 100644 --- a/include/fc/wait_any.hpp +++ b/include/fc/wait_any.hpp @@ -1,7 +1,6 @@ -#ifndef _FC_WAIT_ANY_HPP_ -#define _FC_WAIT_ANY_HPP_ +#pragma once #include -#include +#include namespace fc { template @@ -12,4 +11,3 @@ namespace fc { return wait( fc::move(p), timeout_us ); } } -#endif // _FC_WAIT_ANY_HPP_ diff --git a/src/asio.cpp b/src/asio.cpp index 90cbc14..3e4dbdb 100644 --- a/src/asio.cpp +++ b/src/asio.cpp @@ -1,14 +1,28 @@ #include -#include -#include +#include #include +#include namespace fc { namespace asio { namespace detail { void read_write_handler( const promise::ptr& p, const boost::system::error_code& ec, size_t bytes_transferred ) { if( !ec ) p->set_value(bytes_transferred); - else p->set_exception( fc::copy_exception( boost::system::system_error(ec) ) ); + else { + // elog( "%s", boost::system::system_error(ec).what() ); + // p->set_exception( fc::copy_exception( boost::system::system_error(ec) ) ); + if( ec == boost::asio::error::eof ) + { + p->set_exception( fc::exception_ptr( new fc::eof_exception( + FC_LOG_MESSAGE( error, "${message} ", ("message", boost::system::system_error(ec).what())) ) ) ); + } + else + { + // elog( "${message} ", ("message", boost::system::system_error(ec).what())); + p->set_exception( fc::exception_ptr( new fc::exception( + FC_LOG_MESSAGE( error, "${message} ", ("message", boost::system::system_error(ec).what())) ) ) ); + } + } } void read_write_handler_ec( promise* p, boost::system::error_code* oec, const boost::system::error_code& ec, size_t bytes_transferred ) { p->set_value(bytes_transferred); @@ -37,17 +51,41 @@ namespace fc { } p->set_value( eps ); } else { - p->set_exception( fc::copy_exception( boost::system::system_error(ec) ) ); + //elog( "%s", boost::system::system_error(ec).what() ); + //p->set_exception( fc::copy_exception( boost::system::system_error(ec) ) ); + p->set_exception( + fc::exception_ptr( new fc::exception( + FC_LOG_MESSAGE( error, "process exited with: ${message} ", + ("message", boost::system::system_error(ec).what())) ) ) ); } } } - boost::asio::io_service& default_io_service() { - static boost::asio::io_service* io = new boost::asio::io_service(); - static boost::asio::io_service::work the_work(*io); - static boost::thread io_t([=] { fc::thread::current().set_name("asio1"); io->run(); }); - static boost::thread io_t2([=]{ fc::thread::current().set_name("asio2"); io->run(); }); - static boost::thread io_t3([=]{ fc::thread::current().set_name("asio3"); io->run(); }); - return *io; + boost::asio::io_service& default_io_service(bool cleanup) { + static boost::asio::io_service io; + static boost::asio::io_service::work the_work(io); + static fc::thread fc1("asio1"); + static fc::thread fc2("asio2"); + static fc::thread fc3("asio3"); + static fc::future future1( fc1.async([=]() { io.run(); }) ); + static fc::future future2( fc2.async([=]() { io.run(); }) ); + static fc::future future3( fc3.async([=]() { io.run(); }) ); + /* + static boost::thread io_t([=] { fc1 = &fc::thread::current(); fc1->set_name("asio1"); io.run(); }); + static boost::thread io_t2([=]{ fc2 = &fc::thread::current(); fc2->set_name("asio2"); io.run(); }); + static boost::thread io_t3([=]{ fc3 = &fc::thread::current(); fc3->set_name("asio3"); io.run(); }); + */ + if (cleanup) + { + io.stop(); + fc1.quit(); + fc2.quit(); + fc3.quit(); + future1.wait(); + future2.wait(); + future3.wait(); + } + + return io; } namespace tcp { diff --git a/src/bigint.cpp b/src/bigint.cpp deleted file mode 100644 index ad8d5ce..0000000 --- a/src/bigint.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include -#include - -namespace fc { - bigint::bigint( const char* bige, uint32_t l ) { - n = BN_bin2bn( (const unsigned char*)bige, l, NULL ); - } - - bigint::bigint( unsigned long i ) - :n(BN_new()) { - BN_set_word( n, i ); - } - - bigint::bigint( const bigint& c ) { - n = BN_dup( c.n ); - } - - bigint::bigint( bigint&& b ) { - n = b.n; - b.n = 0; - } - - bigint::~bigint() { - if(n!=0) BN_free(n); - } - - bool bigint::is_negative()const { return BN_is_negative(n); } - int64_t bigint::to_int64()const { return BN_get_word(n); } - - int64_t bigint::log2()const { return BN_num_bits(n); } - bool bigint::operator < ( const bigint& c )const { - return BN_cmp( n, c.n ) < 0; - } - bool bigint::operator > ( const bigint& c )const { - return BN_cmp( n, c.n ) > 0; - } - bool bigint::operator >= ( const bigint& c )const { - return BN_cmp( n, c.n ) >= 0; - } - bool bigint::operator == ( const bigint& c )const { - return BN_cmp( n, c.n ) == 0; - } - - bigint bigint::operator + ( const bigint& a )const { - bigint tmp(*this); - BN_add( tmp.n, n, a.n ); - return tmp; - } - bigint bigint::operator * ( const bigint& a )const { - BN_CTX* ctx = BN_CTX_new(); - bigint tmp(*this); - BN_mul( tmp.n, n, a.n, ctx ); - BN_CTX_free(ctx); - return tmp; - } - bigint bigint::operator / ( const bigint& a ) const { - BN_CTX* ctx = BN_CTX_new(); - bigint tmp(*this); - BN_div( tmp.n, NULL, n, a.n, ctx ); - BN_CTX_free(ctx); - return tmp; - } - bigint bigint::operator - ( const bigint& a )const { - bigint tmp(*this); - BN_sub( tmp.n, n, a.n ); - return tmp; - } - - - bigint& bigint::operator = ( bigint&& a ) { - fc_swap( a.n, n ); - return *this; - } - bigint& bigint::operator = ( const bigint& a ) { - if( &a == this ) - return *this; - BN_copy( n, a.n ); - return *this; - } - bigint::operator fc::string()const { - return BN_bn2dec(n); - } -} // namespace fc diff --git a/src/console_appender.cpp b/src/console_appender.cpp deleted file mode 100644 index 84f5f1a..0000000 --- a/src/console_appender.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include -#include -#include -#ifndef WIN32 -#include -#endif - -namespace fc { - console_appender::console_appender( const value& args ) { - cfg = fc::value_cast(args); - for( int i = 0; i < log_level::off+1; ++i ) - lc[i] = color::console_default; - for( auto itr = cfg.level_colors.begin(); itr != cfg.level_colors.end(); ++itr ) - lc[itr->level] = itr->color; - } - const char* get_console_color(console_appender::color::type t ) { - switch( t ) { - case console_appender::color::red: return CONSOLE_RED; - case console_appender::color::green: return CONSOLE_GREEN; - case console_appender::color::brown: return CONSOLE_BROWN; - case console_appender::color::blue: return CONSOLE_BLUE; - case console_appender::color::magenta: return CONSOLE_MAGENTA; - case console_appender::color::cyan: return CONSOLE_CYAN; - case console_appender::color::white: return CONSOLE_WHITE; - case console_appender::color::console_default: - default: - return CONSOLE_DEFAULT; - } - } - const char* console_appender::get_color( log_level::type l )const { - return get_console_color( lc[l] ); - } - void console_appender::log( const log_message& m ) { - fc::string message = fc::substitute( m.format, m.args ); - fc::value lmsg(m); - - FILE* out = stream::std_error ? stderr : stdout; - fc::string fmt_str = fc::substitute( cfg.format, value(m).set( "message", message) ); - - fc::unique_lock lock(log_mutex()); - #ifndef WIN32 - if(isatty(fileno(out))) fprintf( out, "\r%s", get_color( m.level ) ); - #endif - - fprintf( out, "%s", fmt_str.c_str() ); - - #ifndef WIN32 - if(isatty(fileno(out))) fprintf( out, "\r%s", CONSOLE_DEFAULT ); - #endif - fprintf( out, "\n" ); - if( cfg.flush ) fflush( out ); - } - -} diff --git a/src/crypto/base32.cpp b/src/crypto/base32.cpp new file mode 100644 index 0000000..a41e300 --- /dev/null +++ b/src/crypto/base32.cpp @@ -0,0 +1,28 @@ +#include +#include +#include +namespace fc +{ + fc::vector from_base32( const fc::string& b32 ) + { + auto len = cyoBase32DecodeGetLength( b32.size() ); + fc::vector v(len); + cyoBase32Decode( v.data(), b32.c_str(), b32.size() ); + return v; + } + + fc::string to_base32( const char* data, size_t len ) + { + auto s = cyoBase16EncodeGetLength(len); + fc::string b32; + b32.resize(s); + cyoBase16Encode( b32.data(), data, len ); + b32.resize( b32.size()-1); // strip the nullterm + return b32; + } + + fc::string to_base32( const fc::vector& vec ) + { + return to_base32( vec.data(), vec.size() ); + } +} diff --git a/src/crypto/base36.cpp b/src/crypto/base36.cpp new file mode 100644 index 0000000..cbd1cc1 --- /dev/null +++ b/src/crypto/base36.cpp @@ -0,0 +1,50 @@ +#include +#include +#include + +namespace fc +{ + fc::string to_base36( const char* data, size_t len ) + { + if( len == 0 ) return fc::string(); + fc::bigint value( data, len ); + auto base36 = "0123456789abcdefghijklmnopqrstuvwxyz"; + fc::vector out( static_cast(len * 1.6) + 1 ); + int pos = out.size() - 1; + out[pos] = '\0'; + fc::bigint _36(36); + do { + if( value ) { + --pos; + out[pos] = base36[(value % _36).to_int64()]; + } + } while (value /= _36); + + return &out[pos]; //fc::string( &out[pos], out.size() - pos); + } + + fc::string to_base36( const fc::vector& vec ) + { + return to_base36( (const char*)vec.data(), vec.size() ); + } + + fc::vector from_base36( const fc::string& b36 ) + { + fc::bigint value; + + fc::bigint pos = 0; + fc::bigint _36(36); + for( auto itr = b36.begin(); itr != b36.end(); ++itr ) + { + if( *itr - '0' < 10 ) value = value + _36.exp(pos) * fc::bigint(*itr - '0'); + else if( *itr - 'a' < 26 ) value = value + (_36.exp(pos) * fc::bigint(10+*itr - 'a')); + else if( *itr - 'A' < 26 ) value = value + (_36.exp(pos) * fc::bigint(10+*itr - 'A')); + else + { + wlog("unknown '${char}'", ("char",fc::string(&*itr,1)) ); + } + ++pos; + } + return value; + } +} diff --git a/src/base58.cpp b/src/crypto/base58.cpp similarity index 98% rename from src/base58.cpp rename to src/crypto/base58.cpp index 2b1905f..aeffe3f 100644 --- a/src/base58.cpp +++ b/src/crypto/base58.cpp @@ -21,10 +21,9 @@ #include #include -#include +#include #include -#include -#include +#include #include #include @@ -567,7 +566,7 @@ inline bool DecodeBase58(const char* psz, std::vector& vchRet) while (isspace(*p)) p++; if (*p != '\0') { - slog( "%s '%c'", pszBase58,*p ); + //slog( "%s '%c'", pszBase58,*p ); return false; } break; @@ -613,7 +612,7 @@ fc::string to_base58( const char* d, size_t s ) { fc::vector from_base58( const fc::string& base58_str ) { std::vector out; if( !DecodeBase58( base58_str.c_str(), out ) ) { - FC_THROW_REPORT( "Unable to decode base58 string ${base58_str}", fc::value().set("base58_str",base58_str) ); + FC_THROW_EXCEPTION( exception, "Unable to decode base58 string ${base58_str}", ("base58_str",base58_str) ); } return fc::vector((const char*)out.data(), ((const char*)out.data())+out.size() ); } @@ -624,7 +623,7 @@ size_t from_base58( const fc::string& base58_str, char* out_data, size_t out_dat //slog( "%s", base58_str.c_str() ); std::vector out; if( !DecodeBase58( base58_str.c_str(), out ) ) { - FC_THROW_REPORT( "Unable to decode base58 string ${base58_str}", fc::value().set("base58_str",base58_str) ); + FC_THROW_EXCEPTION( exception, "Unable to decode base58 string ${base58_str}", ("base58_str",base58_str) ); } memcpy( out_data, out.data(), out.size() ); diff --git a/src/base64.cpp b/src/crypto/base64.cpp similarity index 99% rename from src/base64.cpp rename to src/crypto/base64.cpp index 05e25e1..2752c57 100644 --- a/src/base64.cpp +++ b/src/crypto/base64.cpp @@ -1,4 +1,4 @@ -#include +#include #include /* base64.cpp and base64.h diff --git a/src/crypto/bigint.cpp b/src/crypto/bigint.cpp new file mode 100644 index 0000000..431b36c --- /dev/null +++ b/src/crypto/bigint.cpp @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#include + +namespace fc { + bigint::bigint( const char* bige, uint32_t l ) { + n = BN_bin2bn( (const unsigned char*)bige, l, NULL ); + } + bigint::bigint( const fc::vector& bige ) { + n = BN_bin2bn( (const unsigned char*)bige.data(), bige.size(), NULL ); + } + bigint::bigint( BIGNUM* in ) + { + n = BN_dup(in); + } + + BIGNUM* bigint::dup()const + { + return BN_dup( n ); + } + + bigint::bigint( unsigned long i ) + :n(BN_new()) { + BN_set_word( n, i ); + } + + bigint::bigint( const bigint& c ) { + n = BN_dup( c.n ); + } + + bigint::bigint( bigint&& b ) { + n = b.n; + b.n = 0; + } + + bigint::~bigint() { + if(n!=0) BN_free(n); + } + + bool bigint::is_negative()const { return BN_is_negative(n); } + int64_t bigint::to_int64()const { return BN_get_word(n); } + + int64_t bigint::log2()const { return BN_num_bits(n); } + bool bigint::operator < ( const bigint& c )const { + return BN_cmp( n, c.n ) < 0; + } + bool bigint::operator > ( const bigint& c )const { + return BN_cmp( n, c.n ) > 0; + } + bool bigint::operator >= ( const bigint& c )const { + return BN_cmp( n, c.n ) >= 0; + } + bool bigint::operator == ( const bigint& c )const { + return BN_cmp( n, c.n ) == 0; + } + bool bigint::operator != ( const bigint& c )const { + return BN_cmp( n, c.n ) == 0; + } + bigint::operator bool()const + { + return !BN_is_zero( n ); + } + bigint bigint::operator++(int) + { + bigint tmp = *this; + *this = *this + bigint(1); + return tmp; + } + bigint& bigint::operator++() + { + return *this = *this + bigint(1); + } + bigint bigint::operator--(int) + { + bigint tmp = *this; + *this = *this - bigint(1); + return tmp; + } + bigint& bigint::operator--() + { + return *this = *this - bigint(1); + } + + bigint bigint::operator + ( const bigint& a )const { + bigint tmp(*this); + BN_add( tmp.n, n, a.n ); + return tmp; + } + bigint bigint::operator * ( const bigint& a )const { + BN_CTX* ctx = BN_CTX_new(); + bigint tmp(*this); + BN_mul( tmp.n, n, a.n, ctx ); + BN_CTX_free(ctx); + return tmp; + } + bigint bigint::operator / ( const bigint& a ) const { + BN_CTX* ctx = BN_CTX_new(); + bigint tmp;//(*this); + BN_div( tmp.n, NULL, n, a.n, ctx ); + BN_CTX_free(ctx); + return tmp; + } + bigint bigint::operator % ( const bigint& a ) const { + BN_CTX* ctx = BN_CTX_new(); + bigint tmp;//(*this); + BN_mod( tmp.n, n, a.n, ctx ); + BN_CTX_free(ctx); + return tmp; + } + + bigint bigint::operator /= ( const bigint& a ) { + BN_CTX* ctx = BN_CTX_new(); + bigint tmp;//*this); + BN_div( tmp.n, NULL, n, a.n, ctx ); + fc_swap( tmp.n, n ); + BN_CTX_free(ctx); + return tmp; + } + + + bigint bigint::operator - ( const bigint& a )const { + bigint tmp; + BN_sub( tmp.n, n, a.n ); + return tmp; + } + bigint bigint::exp( const bigint& a )const + { + BN_CTX* ctx = BN_CTX_new(); + bigint tmp; + BN_exp( tmp.n, n, a.n, ctx ); + BN_CTX_free(ctx); + return tmp; + } + + + bigint& bigint::operator = ( bigint&& a ) { + fc_swap( a.n, n ); + return *this; + } + bigint& bigint::operator = ( const bigint& a ) { + if( &a == this ) + return *this; + BN_copy( n, a.n ); + return *this; + } + bigint::operator fc::string()const { + return BN_bn2dec(n); + } + + bigint::operator fc::vector()const { + fc::vector to(BN_num_bytes(n)); + BN_bn2bin(n,(unsigned char*)to.data()); + return to; + } + + /** encodes the big int as base64 string, or a number */ + void to_variant( const bigint& bi, variant& v ) + { + fc::vector ve = bi; + v = fc::variant(base64_encode((unsigned char*)ve.data(),ve.size())); + } + + /** decodes the big int as base64 string, or a number */ + void from_variant( const variant& v, bigint& bi ) + { + if( v.is_numeric() ) bi = bigint( static_cast(v.as_uint64()) ); + else + { + std::string b64 = v.as_string(); + std::string bin = base64_decode(b64); + bi = bigint(bin.c_str(), bin.size() ); + } + } + +} // namespace fc diff --git a/src/blowfish.cpp b/src/crypto/blowfish.cpp similarity index 94% rename from src/blowfish.cpp rename to src/crypto/blowfish.cpp index 74f58dc..5d3cbb4 100644 --- a/src/blowfish.cpp +++ b/src/crypto/blowfish.cpp @@ -6,9 +6,8 @@ // Cryptography", Second Edition. #include -#include -#include -#include +#include +#include namespace fc { //Extract low order byte @@ -310,13 +309,13 @@ void blowfish::start(unsigned char* ucKey, uint64_t keysize, const sblock& roCha m_oChain = roChain; if(keysize<1) - FC_THROW(invalid_key_length()); + FC_THROW_EXCEPTION( exception, "invalid key length" ); //Check the Key - the key length should be between 1 and 56 bytes if(keysize>56) keysize = 56; unsigned char aucLocalKey[56]; unsigned int i, j; - memcpy(aucLocalKey, ucKey, keysize); + memcpy(aucLocalKey, ucKey, static_cast(keysize)); //Reflexive Initialization of the Blowfish. //Generating the Subkeys from the Key flood P and S boxes with PI memcpy(m_auiP, scm_auiInitP, sizeof m_auiP); @@ -452,7 +451,7 @@ void blowfish::encrypt(unsigned char* buf, uint64_t n, int iMode) { //Check the buffer's length - should be > 0 and multiple of 8 if((n==0)||(n%8!=0)) - FC_THROW(invalid_buffer_length()); + FC_THROW_EXCEPTION( exception, "invalid buffer length ${n}, not multiple of 8", ("n", n) ); sblock work; if(iMode == CBC) //CBC mode, using the Chain { @@ -495,7 +494,7 @@ void blowfish::decrypt(unsigned char* buf, uint64_t n, int iMode) { //Check the buffer's length - should be > 0 and multiple of 8 if((n==0)||(n%8!=0)) - FC_THROW(invalid_buffer_length()); + FC_THROW_EXCEPTION( exception, "invalid buffer length ${n}, not multiple of 8", ("n", n) ); sblock work; if(iMode == CBC) //CBC mode, using the Chain { @@ -540,7 +539,7 @@ void blowfish::encrypt(const unsigned char* in, unsigned char* out, uint64_t n, { //Check the buffer's length - should be > 0 and multiple of 8 if((n==0)||(n%8!=0)) - FC_THROW(invalid_buffer_length()); + FC_THROW_EXCEPTION( exception, "invalid buffer length ${n}, not multiple of 8", ("n", n) ); sblock work; if(iMode == CBC) //CBC mode, using the Chain { @@ -583,7 +582,7 @@ void blowfish::decrypt(const unsigned char* in, unsigned char* out, uint64_t n, { //Check the buffer's length - should be > 0 and multiple of 8 if((n==0)||(n%8!=0)) - FC_THROW(invalid_buffer_length()); + FC_THROW_EXCEPTION( exception, "invalid buffer length ${n}, not multiple of 8", ("n", n) ); sblock work; if(iMode == CBC) //CBC mode, using the Chain { diff --git a/src/dh.cpp b/src/crypto/dh.cpp similarity index 96% rename from src/dh.cpp rename to src/crypto/dh.cpp index 642deb2..492cbcd 100644 --- a/src/dh.cpp +++ b/src/crypto/dh.cpp @@ -1,4 +1,4 @@ -#include +#include #include namespace fc { @@ -84,7 +84,7 @@ namespace fc { DH_free(dh); return valid = true; } - bool diffie_hellman::compute_shared_key( const std::vector& pubk ) { + bool diffie_hellman::compute_shared_key( const vector& pubk ) { return compute_shared_key( &pubk.front(), pubk.size() ); } diff --git a/src/crypto/elliptic.cpp b/src/crypto/elliptic.cpp new file mode 100644 index 0000000..2c15abb --- /dev/null +++ b/src/crypto/elliptic.cpp @@ -0,0 +1,429 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fc { namespace ecc { + namespace detail + { + class public_key_impl + { + public: + public_key_impl() + :_key(nullptr) + { + } + ~public_key_impl() + { + if( _key != nullptr ) + { + EC_KEY_free(_key); + } + } + public_key_impl( const public_key_impl& cpy ) + { + _key = cpy._key ? EC_KEY_dup( cpy._key ) : nullptr; + } + EC_KEY* _key; + }; + class private_key_impl + { + public: + private_key_impl() + :_key(nullptr) + { + } + ~private_key_impl() + { + if( _key != nullptr ) + { + EC_KEY_free(_key); + } + } + private_key_impl( const private_key_impl& cpy ) + { + _key = cpy._key ? EC_KEY_dup( cpy._key ) : nullptr; + } + EC_KEY* _key; + }; + } + void * ecies_key_derivation(const void *input, size_t ilen, void *output, size_t *olen) + { + if (*olen < SHA512_DIGEST_LENGTH) { + return NULL; + } + *olen = SHA512_DIGEST_LENGTH; + return (void*)SHA512((const unsigned char*)input, ilen, (unsigned char*)output); + } + + // Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields + // recid selects which key is recovered + // if check is non-zero, additional checks are performed + int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check) + { + if (!eckey) FC_THROW_EXCEPTION( exception, "null key" ); + + int ret = 0; + BN_CTX *ctx = NULL; + + BIGNUM *x = NULL; + BIGNUM *e = NULL; + BIGNUM *order = NULL; + BIGNUM *sor = NULL; + BIGNUM *eor = NULL; + BIGNUM *field = NULL; + EC_POINT *R = NULL; + EC_POINT *O = NULL; + EC_POINT *Q = NULL; + BIGNUM *rr = NULL; + BIGNUM *zero = NULL; + int n = 0; + int i = recid / 2; + + const EC_GROUP *group = EC_KEY_get0_group(eckey); + if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; } + BN_CTX_start(ctx); + order = BN_CTX_get(ctx); + if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; } + x = BN_CTX_get(ctx); + if (!BN_copy(x, order)) { ret=-1; goto err; } + if (!BN_mul_word(x, i)) { ret=-1; goto err; } + if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; } + field = BN_CTX_get(ctx); + if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; } + if (BN_cmp(x, field) >= 0) { ret=0; goto err; } + if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } + if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; } + if (check) + { + if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } + if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; } + if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; } + } + if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } + n = EC_GROUP_get_degree(group); + e = BN_CTX_get(ctx); + if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; } + if (8*msglen > n) BN_rshift(e, e, 8-(n & 7)); + zero = BN_CTX_get(ctx); + if (!BN_zero(zero)) { ret=-1; goto err; } + if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; } + rr = BN_CTX_get(ctx); + if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; } + sor = BN_CTX_get(ctx); + if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; } + eor = BN_CTX_get(ctx); + if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; } + if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; } + if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; } + + ret = 1; + + err: + if (ctx) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + if (R != NULL) EC_POINT_free(R); + if (O != NULL) EC_POINT_free(O); + if (Q != NULL) EC_POINT_free(Q); + return ret; + } + + + int static inline EC_KEY_regenerate_key(EC_KEY *eckey, const BIGNUM *priv_key) + { + int ok = 0; + BN_CTX *ctx = NULL; + EC_POINT *pub_key = NULL; + + if (!eckey) return 0; + + const EC_GROUP *group = EC_KEY_get0_group(eckey); + + if ((ctx = BN_CTX_new()) == NULL) + goto err; + + pub_key = EC_POINT_new(group); + + if (pub_key == NULL) + goto err; + + if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx)) + goto err; + + EC_KEY_set_private_key(eckey,priv_key); + EC_KEY_set_public_key(eckey,pub_key); + + ok = 1; + + err: + + if (pub_key) EC_POINT_free(pub_key); + if (ctx != NULL) BN_CTX_free(ctx); + + return(ok); + } + +/* + public_key::public_key() + :my( new detail::public_key_impl() ) + { + } + + public_key::public_key( fc::bigint pub_x, fc::bigint pub_y ) + :my( new detail::public_key_impl() ) + { + } + + public_key::~public_key() + { + } + */ + + private_key::private_key() + {} + + private_key private_key::regenerate( const fc::sha256& secret ) + { + private_key self; + self.my->_key = EC_KEY_new_by_curve_name( NID_secp256k1 ); + if( !self.my->_key ) FC_THROW_EXCEPTION( exception, "Unable to generate EC key" ); + + BIGNUM* bn = BN_bin2bn( (const unsigned char*)&secret, 32, BN_new() ); + if( bn == NULL ) + { + FC_THROW_EXCEPTION( exception, "unable to create bignum from secret" ); + } + + if( !EC_KEY_regenerate_key(self.my->_key,bn) ) + { + BN_clear_free(bn); + FC_THROW_EXCEPTION( exception, "unable to regenerate key" ); + } + + BN_clear_free(bn); + return self; + } + + fc::sha256 private_key::get_secret()const + { + fc::sha256 sec; + const BIGNUM* bn = EC_KEY_get0_private_key(my->_key); + if( bn == NULL ) + { + FC_THROW_EXCEPTION( exception, "get private key failed" ); + } + int nbytes = BN_num_bytes(bn); + BN_bn2bin(bn, &((unsigned char*)&sec)[32-nbytes] ); + return sec; + } + + private_key private_key::generate() + { + private_key self; + EC_KEY* k = EC_KEY_new_by_curve_name( NID_secp256k1 ); + if( !k ) FC_THROW_EXCEPTION( exception, "Unable to generate EC key" ); + self.my->_key = k; + if( !EC_KEY_generate_key( self.my->_key ) ) + { + elog( "key generation error" ); + } + +#if 0 + = bigint( EC_KEY_get0_private_key( k ); + EC_POINT* pub = EC_KEY_get0_public_key( k ); + EC_GROUP* group = EC_KEY_get0_group( k ); + + EC_POINT_get_affine_coordinates_GFp( group, pub, self.my->_pub_x.get(), self.my->_pub_y.get(), nullptr/*ctx*/ ); + + EC_KEY_free(k); +#endif + + return self; + } + + signature private_key::sign( const fc::sha256& digest ) + { + unsigned int buf_len = ECDSA_size(my->_key); +// fprintf( stderr, "%d %d\n", buf_len, sizeof(sha256) ); + signature sig; + assert( buf_len == sizeof(sig) ); + + if( !ECDSA_sign( 0, + (const unsigned char*)&digest, sizeof(digest), + (unsigned char*)&sig, &buf_len, my->_key ) ) + { + fprintf( stderr, "sign error\n"); + } + + + return sig; + } + bool public_key::verify( const fc::sha256& digest, const fc::ecc::signature& sig ) + { + return 1 == ECDSA_verify( 0, (unsigned char*)&digest, sizeof(digest), (unsigned char*)&sig, sizeof(sig), my->_key ); + } + + std::vector public_key::serialize() + { + EC_KEY_set_conv_form( my->_key, POINT_CONVERSION_COMPRESSED ); + size_t nbytes = i2o_ECPublicKey( my->_key, nullptr ); + std::vector dat(nbytes); + char* front = &dat[0]; + i2o_ECPublicKey( my->_key, (unsigned char**)&front ); + fprintf( stderr, "public key size: %lu\n", nbytes ); + return dat; + /* + EC_POINT* pub = EC_KEY_get0_public_key( my->_key ); + EC_GROUP* group = EC_KEY_get0_group( my->_key ); + EC_POINT_get_affine_coordinates_GFp( group, pub, self.my->_pub_x.get(), self.my->_pub_y.get(), nullptr ); + */ + } + public_key::public_key() + { + } + public_key::~public_key() + { + } + public_key::public_key( const std::vector& v ) + { + const char* front = &v[0]; + my->_key = EC_KEY_new_by_curve_name( NID_secp256k1 ); + my->_key = o2i_ECPublicKey( &my->_key, (const unsigned char**)&front, v.size() ); + if( !my->_key ) + { + fprintf( stderr, "decode error occurred??" ); + } + } + + bool private_key::verify( const fc::sha256& digest, const fc::ecc::signature& sig ) + { + return 1 == ECDSA_verify( 0, (unsigned char*)&digest, sizeof(digest), (unsigned char*)&sig, sizeof(sig), my->_key ); + } + + public_key private_key::get_public_key()const + { + + public_key pub; + pub.my->_key = EC_KEY_new_by_curve_name( NID_secp256k1 ); + EC_KEY_set_public_key( pub.my->_key, EC_KEY_get0_public_key( my->_key ) ); + return pub; + } + + private_key::private_key( std::vector k ) + { +#if 0 + fc::bigint priv(k); + my->_key = EC_KEY_new_by_curve_name( NID_sect283r1 ); + auto k = my->_key; + + if( !k ) FC_THROW_EXCEPTION( exception, "Unable to generate EC key" ); + + EC_KEY_set_private_key( my->_key, priv.get() ); + + EC_GROUP* group = EC_KEY_get0_group( k ); + EC_POINT* pub = EC_POINT_new(group); + + fc::bigint x, y; + EC_POINT_set_affine_coordinates_GFp( group, pub, x.get(), y.get(), nullptr/*ctx*/ ); + + bool fail = false; + fail = EC_KEY_set_private_key( k, pub ) == 0; + fail = fail | EC_KEY_check_key( k ) == 0; + + EC_POINT_free( pub ); + + if( fail ) FC_THROW_EXCEPTION( exception, "Unable to load private key" ); +#endif + } + + fc::sha512 private_key::get_shared_secret( const public_key& other ) + { + fc::sha512 buf; + ECDH_compute_key( (unsigned char*)&buf, sizeof(buf), EC_KEY_get0_public_key(other.my->_key), my->_key, ecies_key_derivation ); + return buf; + } + + private_key::~private_key() + { + } + + public_key::public_key( const compact_signature& c, const fc::sha256& digest ) + { + int nV = c.data[0]; + if (nV<27 || nV>=35) + FC_THROW_EXCEPTION( exception, "unable to reconstruct public key from signature" ); + + ECDSA_SIG *sig = ECDSA_SIG_new(); + BN_bin2bn(&c.data[1],32,sig->r); + BN_bin2bn(&c.data[33],32,sig->s); + + my->_key = EC_KEY_new_by_curve_name(NID_secp256k1); + + if (nV >= 31) + { + EC_KEY_set_conv_form( my->_key, POINT_CONVERSION_COMPRESSED ); + nV -= 4; + fprintf( stderr, "compressed\n" ); + } + + if (ECDSA_SIG_recover_key_GFp(my->_key, sig, (unsigned char*)&digest, sizeof(digest), nV - 27, 0) == 1) + { + ECDSA_SIG_free(sig); + return; + } + ECDSA_SIG_free(sig); + FC_THROW_EXCEPTION( exception, "unable to reconstruct public key from signature" ); + } + + compact_signature private_key::sign_compact( const fc::sha256& digest ) + { + ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&digest, sizeof(digest), my->_key); + + if (sig==NULL) + FC_THROW_EXCEPTION( exception, "Unable to sign" ); + + compact_signature csig; + + int nBitsR = BN_num_bits(sig->r); + int nBitsS = BN_num_bits(sig->s); + if (nBitsR <= 256 && nBitsS <= 256) + { + int nRecId = -1; + auto my_pub_key = get_public_key().serialize(); + for (int i=0; i<4; i++) + { + public_key keyRec; + keyRec.my->_key = EC_KEY_new_by_curve_name( NID_secp256k1 ); + // keyRec.fSet = true; + // if (fCompressedPubKey) keyRec.SetCompressedPubKey(); + if (ECDSA_SIG_recover_key_GFp(keyRec.my->_key, sig, (unsigned char*)&digest, sizeof(digest), i, 1) == 1) + { + if (keyRec.serialize() == my_pub_key ) + { + nRecId = i; + break; + } + } + } + + if (nRecId == -1) + FC_THROW_EXCEPTION( exception, "unable to construct recoverable key"); + + csig.data[0] = nRecId+27+4;//(fCompressedPubKey ? 4 : 0); + BN_bn2bin(sig->r,&csig.data[33-(nBitsR+7)/8]); + BN_bn2bin(sig->s,&csig.data[65-(nBitsS+7)/8]); + } + ECDSA_SIG_free(sig); + return csig; + } + +} } diff --git a/src/hex.cpp b/src/crypto/hex.cpp similarity index 87% rename from src/hex.cpp rename to src/crypto/hex.cpp index ac51309..375726a 100644 --- a/src/hex.cpp +++ b/src/crypto/hex.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include namespace fc { @@ -10,7 +10,7 @@ namespace fc { return c - 'a' + 10; if( c >= 'A' && c <= 'F' ) return c - 'A' + 10; - FC_THROW_MSG( "Invalid hex character '%s'", c ); + FC_THROW_EXCEPTION( exception, "Invalid hex character '${c}'", ("c", fc::string(&c,1) ) ); return 0; } diff --git a/src/crypto/pke.cpp b/src/crypto/pke.cpp new file mode 100644 index 0000000..a425621 --- /dev/null +++ b/src/crypto/pke.cpp @@ -0,0 +1,365 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fc { + + namespace detail { + class pke_impl + { + public: + pke_impl():rsa(nullptr){} + ~pke_impl() + { + if( rsa != nullptr ) + RSA_free(rsa); + } + RSA* rsa; + }; + } // detail + + public_key::operator bool()const { return !!my; } + private_key::operator bool()const { return !!my; } + + public_key::public_key() + {} + + public_key::public_key( const bytes& d ) + :my( std::make_shared() ) + { + string pem = "-----BEGIN RSA PUBLIC KEY-----\n"; + auto b64 = fc::base64_encode( (const unsigned char*)d.data(), d.size() ); + for( size_t i = 0; i < b64.size(); i += 64 ) + pem += b64.substr( i, 64 ) + "\n"; + pem += "-----END RSA PUBLIC KEY-----\n"; + // fc::cerr<rsa = PEM_read_bio_RSAPublicKey(mem, NULL, NULL, NULL ); + BIO_free(mem); + } + public_key::public_key( const public_key& k ) + :my(k.my) + { + } + + public_key::public_key( public_key&& k ) + :my(std::move(k.my)) + { + } + + public_key::~public_key() { } + + public_key& public_key::operator=(const public_key& p ) + { + my = p.my; return *this; + } + public_key& public_key::operator=( public_key&& p ) + { + my = std::move(p.my); return *this; + } + bool public_key::verify( const sha1& digest, const array& sig )const + { + return 0 != RSA_verify( NID_sha1, (const uint8_t*)&digest, 20, + (uint8_t*)&sig, 2048/8, my->rsa ); + } + + bool public_key::verify( const sha1& digest, const signature& sig )const + { + assert( sig.size() == 2048/8 ); + return 0 != RSA_verify( NID_sha1, (const uint8_t*)&digest, 20, + (uint8_t*)sig.data(), 2048/8, my->rsa ); + } + bool public_key::verify( const sha256& digest, const signature& sig )const + { + assert( sig.size() == 2048/8 ); + return 0 != RSA_verify( NID_sha256, (const uint8_t*)&digest, 32, + (uint8_t*)sig.data(), 2048/8, my->rsa ); + } + bytes public_key::encrypt( const char* b, size_t l )const + { + FC_ASSERT( my && my->rsa ); + bytes out( RSA_size(my->rsa) ); //, char(0) ); + int rtn = RSA_public_encrypt( l, + (unsigned char*)b, + (unsigned char*)out.data(), + my->rsa, RSA_PKCS1_OAEP_PADDING ); + if( rtn >= 0 ) { + out.resize(rtn); + return out; + } + FC_THROW_EXCEPTION( exception, "openssl: ${message}", ("message",fc::string(ERR_error_string( ERR_get_error(),NULL))) ); + } + + bytes public_key::encrypt( const bytes& in )const + { + FC_ASSERT( my && my->rsa ); + bytes out( RSA_size(my->rsa) ); //, char(0) ); + int rtn = RSA_public_encrypt( in.size(), + (unsigned char*)in.data(), + (unsigned char*)out.data(), + my->rsa, RSA_PKCS1_OAEP_PADDING ); + fc::cerr<<"rtn: "<= 0 ) { + out.resize(rtn); + return out; + } + FC_THROW_EXCEPTION( exception, "openssl: ${message}", ("message",fc::string(ERR_error_string( ERR_get_error(),NULL))) ); + } + bytes public_key::decrypt( const bytes& in )const + { + FC_ASSERT( my && my->rsa ); + bytes out( RSA_size(my->rsa) );//, char(0) ); + int rtn = RSA_public_decrypt( in.size(), + (unsigned char*)in.data(), + (unsigned char*)out.data(), + my->rsa, RSA_PKCS1_OAEP_PADDING ); + if( rtn >= 0 ) { + out.resize(rtn); + return out; + } + FC_THROW_EXCEPTION( exception, "openssl: ${message}", ("message",fc::string(ERR_error_string( ERR_get_error(),NULL))) ); + } + + bytes public_key::serialize()const + { + bytes ba; + if( !my ) { return ba; } + + BIO *mem = BIO_new(BIO_s_mem()); + int e = PEM_write_bio_RSAPublicKey( mem, my->rsa ); + if( e != 1 ) + { + BIO_free(mem); + FC_THROW_EXCEPTION( exception, "openssl: ${message}", ("message",fc::string(ERR_error_string( ERR_get_error(),NULL))) ); + } + char* dat; + uint32_t l = BIO_get_mem_data( mem, &dat ); + + fc::stringstream ss( string( dat, l ) ); + fc::stringstream key; + fc::string tmp; + fc::getline( ss, tmp ); + fc::getline( ss, tmp ); + while( tmp.size() && tmp[0] != '-' ) + { + key << tmp; + fc::getline( ss, tmp ); + } + auto str = key.str(); + str = fc::base64_decode( str ); + ba = bytes( str.begin(), str.end() ); + + BIO_free(mem); + return ba; + } + + private_key::private_key() + { + } + private_key::private_key( const bytes& d ) + :my( std::make_shared() ) + { + + string pem = "-----BEGIN RSA PRIVATE KEY-----\n"; + auto b64 = fc::base64_encode( (const unsigned char*)d.data(), d.size() ); + for( size_t i = 0; i < b64.size(); i += 64 ) + pem += b64.substr( i, 64 ) + "\n"; + pem += "-----END RSA PRIVATE KEY-----\n"; + // fc::cerr<rsa = PEM_read_bio_RSAPrivateKey(mem, NULL, NULL, NULL ); + BIO_free(mem); + + FC_ASSERT( my->rsa, "read private key" ); + } + + private_key::private_key( const private_key& k ) + :my(k.my) + { + } + private_key::private_key( private_key&& k ) + :my(std::move(k.my) ) + { + } + private_key::~private_key() { } + + private_key& private_key::operator=(const private_key& p ) + { + my = p.my; return *this; + } + private_key& private_key::operator=(private_key&& p ) + { + my = std::move(p.my); return *this; + } + + void private_key::sign( const sha1& digest, array& sig )const + { + FC_ASSERT( (size_t(RSA_size(my->rsa)) <= sizeof(sig)), "Invalid RSA size" ); + uint32_t slen = 0; + if( 1 != RSA_sign( NID_sha1, (uint8_t*)&digest, + 20, (unsigned char*)&sig, &slen, my->rsa ) ) + { + FC_THROW_EXCEPTION( exception, "rsa sign failed with ${message}", ("message",fc::string(ERR_error_string( ERR_get_error(),NULL))) ); + } + } + + signature private_key::sign( const sha1& digest )const + { + if( !my ) FC_THROW_EXCEPTION( assert_exception, "!null" ); + signature sig; + sig.resize( RSA_size(my->rsa) ); + + uint32_t slen = 0; + if( 1 != RSA_sign( NID_sha1, (uint8_t*)digest.data(), + 20, (unsigned char*)sig.data(), &slen, my->rsa ) ) + { + FC_THROW_EXCEPTION( exception, "rsa sign failed with ${message}", ("message",fc::string(ERR_error_string( ERR_get_error(),NULL))) ); + } + return sig; + } + signature private_key::sign( const sha256& digest )const + { + if( !my ) FC_THROW_EXCEPTION( assert_exception, "!null" ); + signature sig; + sig.resize( RSA_size(my->rsa) ); + + uint32_t slen = 0; + if( 1 != RSA_sign( NID_sha256, (uint8_t*)digest.data(), + 32, (unsigned char*)sig.data(), &slen, my->rsa ) ) + { + FC_THROW_EXCEPTION( exception, "rsa sign failed with ${message}", ("message",fc::string(ERR_error_string( ERR_get_error(),NULL))) ); + } + return sig; + } + + + bytes private_key::encrypt( const bytes& in )const + { + if( !my ) FC_THROW_EXCEPTION( assert_exception, "!null" ); + bytes out; + out.resize( RSA_size(my->rsa) ); + int rtn = RSA_private_encrypt( in.size(), + (unsigned char*)in.data(), + (unsigned char*)out.data(), + my->rsa, RSA_PKCS1_OAEP_PADDING ); + if( rtn >= 0 ) { + out.resize(rtn); + return out; + } + + FC_THROW_EXCEPTION( exception, "encrypt failed" ); + } + + bytes private_key::decrypt( const char* in, size_t l )const + { + if( !my ) FC_THROW_EXCEPTION( assert_exception, "!null" ); + bytes out; + out.resize( RSA_size(my->rsa) ); + int rtn = RSA_private_decrypt( l, + (unsigned char*)in, + (unsigned char*)out.data(), + my->rsa, RSA_PKCS1_OAEP_PADDING ); + if( rtn >= 0 ) { + out.resize(rtn); + return out; + } + FC_THROW_EXCEPTION( exception, "decrypt failed" ); + } + bytes private_key::decrypt( const bytes& in )const + { + if( !my ) FC_THROW_EXCEPTION( assert_exception, "!null" ); + bytes out; + out.resize( RSA_size(my->rsa) ); + int rtn = RSA_private_decrypt( in.size(), + (unsigned char*)in.data(), + (unsigned char*)out.data(), + my->rsa, RSA_PKCS1_OAEP_PADDING ); + if( rtn >= 0 ) { + out.resize(rtn); + return out; + } + FC_THROW_EXCEPTION( exception, "decrypt failed" ); + } + + bytes private_key::serialize()const + { + bytes ba; + if( !my ) { return ba; } + + BIO *mem = BIO_new(BIO_s_mem()); + int e = PEM_write_bio_RSAPrivateKey( mem, my->rsa, NULL, NULL, 0, NULL, NULL ); + if( e != 1 ) + { + BIO_free(mem); + FC_THROW_EXCEPTION( exception, "Error writing private key, ${message}", ("message",fc::string(ERR_error_string( ERR_get_error(),NULL))) ); + } + char* dat; + uint32_t l = BIO_get_mem_data( mem, &dat ); + // return bytes( dat, dat + l ); + + stringstream ss( string( dat, l ) ); + stringstream key; + string tmp; + fc::getline( ss, tmp ); + fc::getline( ss, tmp ); + + while( tmp.size() && tmp[0] != '-' ) + { + key << tmp; + fc::getline( ss, tmp ); + } + auto str = key.str(); + str = fc::base64_decode( str ); + ba = bytes( str.begin(), str.end() ); + // ba = bytes( dat, dat + l ); + BIO_free(mem); + return ba; + } + + void generate_key_pair( public_key& pub, private_key& priv ) + { + static bool init = true; + if( init ) { ERR_load_crypto_strings(); init = false; } + + pub.my = std::make_shared(); + priv.my = pub.my; + pub.my->rsa = RSA_generate_key( 2048, 65537, NULL, NULL ); + } + + /** encodes the big int as base64 string, or a number */ + void to_variant( const public_key& bi, variant& v ) + { + v = bi.serialize(); + } + + /** decodes the big int as base64 string, or a number */ + void from_variant( const variant& v, public_key& bi ) + { + bi = public_key( v.as >() ); + } + + + /** encodes the big int as base64 string, or a number */ + void to_variant( const private_key& bi, variant& v ) + { + v = bi.serialize(); + } + + /** decodes the big int as base64 string, or a number */ + void from_variant( const variant& v, private_key& bi ) + { + bi = private_key( v.as >() ); + } + +} // fc diff --git a/src/crypto/sha1.cpp b/src/crypto/sha1.cpp new file mode 100644 index 0000000..2617d97 --- /dev/null +++ b/src/crypto/sha1.cpp @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include + +namespace fc +{ + +sha1::sha1() { memset( _hash, 0, sizeof(_hash) ); } +sha1::sha1( const string& hex_str ) { + fc::from_hex( hex_str, (char*)_hash, sizeof(_hash) ); +} + +string sha1::str()const { + return fc::to_hex( (char*)_hash, sizeof(_hash) ); +} +sha1::operator string()const { return str(); } + +char* sha1::data()const { return (char*)&_hash[0]; } + + +struct sha1::encoder::impl { + SHA_CTX ctx; +}; + +sha1::encoder::~encoder() {} +sha1::encoder::encoder() { + reset(); +} + +sha1 sha1::hash( const char* d, uint32_t dlen ) { + encoder e; + e.write(d,dlen); + return e.result(); +} +sha1 sha1::hash( const string& s ) { + return hash( s.c_str(), s.size() ); +} + +void sha1::encoder::write( const char* d, uint32_t dlen ) { + SHA1_Update( &my->ctx, d, dlen); +} +sha1 sha1::encoder::result() { + sha1 h; + SHA1_Final((uint8_t*)h.data(), &my->ctx ); + return h; +} +void sha1::encoder::reset() { + SHA1_Init( &my->ctx); +} + +sha1 operator << ( const sha1& h1, uint32_t i ) { + sha1 result; + uint8_t* r = (uint8_t*)result._hash; + uint8_t* s = (uint8_t*)h1._hash; + for( uint32_t p = 0; p < sizeof(h1._hash)-1; ++p ) + r[p] = s[p] << i | (s[p+1]>>(8-i)); + r[19] = s[19] << i; + return result; +} +sha1 operator ^ ( const sha1& h1, const sha1& h2 ) { + sha1 result; + result._hash[0] = h1._hash[0] ^ h2._hash[0]; + result._hash[1] = h1._hash[1] ^ h2._hash[1]; + result._hash[2] = h1._hash[2] ^ h2._hash[2]; + result._hash[3] = h1._hash[3] ^ h2._hash[3]; + result._hash[4] = h1._hash[4] ^ h2._hash[4]; + return result; +} +bool operator >= ( const sha1& h1, const sha1& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) >= 0; +} +bool operator > ( const sha1& h1, const sha1& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) > 0; +} +bool operator < ( const sha1& h1, const sha1& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) < 0; +} +bool operator != ( const sha1& h1, const sha1& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) != 0; +} +bool operator == ( const sha1& h1, const sha1& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0; +} + +} // fc diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp new file mode 100644 index 0000000..0e4526e --- /dev/null +++ b/src/crypto/sha256.cpp @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include + +namespace fc { + + sha256::sha256() { memset( _hash, 0, sizeof(_hash) ); } + sha256::sha256( const string& hex_str ) { + fc::from_hex( hex_str, (char*)_hash, sizeof(_hash) ); + } + + string sha256::str()const { + return fc::to_hex( (char*)_hash, sizeof(_hash) ); + } + sha256::operator string()const { return str(); } + + char* sha256::data()const { return (char*)&_hash[0]; } + + + struct sha256::encoder::impl { + SHA256_CTX ctx; + }; + + sha256::encoder::~encoder() {} + sha256::encoder::encoder() { + reset(); + } + + sha256 sha256::hash( const char* d, uint32_t dlen ) { + encoder e; + e.write(d,dlen); + return e.result(); + } + sha256 sha256::hash( const string& s ) { + return hash( s.c_str(), s.size() ); + } + + void sha256::encoder::write( const char* d, uint32_t dlen ) { + SHA256_Update( &my->ctx, d, dlen); + } + sha256 sha256::encoder::result() { + sha256 h; + SHA256_Final((uint8_t*)h.data(), &my->ctx ); + return h; + } + void sha256::encoder::reset() { + SHA256_Init( &my->ctx); + } + + sha256 operator << ( const sha256& h1, uint32_t i ) { + sha256 result; + uint8_t* r = (uint8_t*)result._hash; + uint8_t* s = (uint8_t*)h1._hash; + for( uint32_t p = 0; p < sizeof(h1._hash)-1; ++p ) + r[p] = s[p] << i | (s[p+1]>>(8-i)); + r[31] = s[31] << i; + return result; + } + sha256 operator ^ ( const sha256& h1, const sha256& h2 ) { + sha256 result; + result._hash[0] = h1._hash[0] ^ h2._hash[0]; + result._hash[1] = h1._hash[1] ^ h2._hash[1]; + result._hash[2] = h1._hash[2] ^ h2._hash[2]; + result._hash[3] = h1._hash[3] ^ h2._hash[3]; + return result; + } + bool operator >= ( const sha256& h1, const sha256& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) >= 0; + } + bool operator > ( const sha256& h1, const sha256& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) > 0; + } + bool operator < ( const sha256& h1, const sha256& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) < 0; + } + bool operator != ( const sha256& h1, const sha256& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) != 0; + } + bool operator == ( const sha256& h1, const sha256& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0; + } + + void to_variant( const sha256& bi, variant& v ) + { + v = fc::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ); + } + void from_variant( const variant& v, sha256& bi ) + { + fc::vector ve = v.as< vector >(); + if( ve.size() ) + { + memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); + } + else + memset( &bi, char(0), sizeof(bi) ); + } +} diff --git a/src/crypto/sha512.cpp b/src/crypto/sha512.cpp new file mode 100644 index 0000000..0c598c5 --- /dev/null +++ b/src/crypto/sha512.cpp @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include +#include + +namespace fc { + + sha512::sha512() { memset( _hash, 0, sizeof(_hash) ); } + sha512::sha512( const string& hex_str ) { + fc::from_hex( hex_str, (char*)_hash, sizeof(_hash) ); + } + + string sha512::str()const { + return fc::to_hex( (char*)_hash, sizeof(_hash) ); + } + sha512::operator string()const { return str(); } + + char* sha512::data()const { return (char*)&_hash[0]; } + + + struct sha512::encoder::impl { + SHA512_CTX ctx; + }; + + sha512::encoder::~encoder() {} + sha512::encoder::encoder() { + reset(); + } + + sha512 sha512::hash( const char* d, uint32_t dlen ) { + encoder e; + e.write(d,dlen); + return e.result(); + } + sha512 sha512::hash( const string& s ) { + return hash( s.c_str(), s.size() ); + } + + void sha512::encoder::write( const char* d, uint32_t dlen ) { + SHA512_Update( &my->ctx, d, dlen); + } + sha512 sha512::encoder::result() { + sha512 h; + SHA512_Final((uint8_t*)h.data(), &my->ctx ); + return h; + } + void sha512::encoder::reset() { + SHA512_Init( &my->ctx); + } + + sha512 operator << ( const sha512& h1, uint32_t i ) { + sha512 result; + uint8_t* r = (uint8_t*)result._hash; + uint8_t* s = (uint8_t*)h1._hash; + for( uint32_t p = 0; p < sizeof(h1._hash)-1; ++p ) + r[p] = s[p] << i | (s[p+1]>>(8-i)); + r[63] = s[63] << i; + return result; + } + sha512 operator ^ ( const sha512& h1, const sha512& h2 ) { + sha512 result; + result._hash[0] = h1._hash[0] ^ h2._hash[0]; + result._hash[1] = h1._hash[1] ^ h2._hash[1]; + result._hash[2] = h1._hash[2] ^ h2._hash[2]; + result._hash[3] = h1._hash[3] ^ h2._hash[3]; + result._hash[4] = h1._hash[4] ^ h2._hash[4]; + result._hash[5] = h1._hash[5] ^ h2._hash[5]; + result._hash[6] = h1._hash[6] ^ h2._hash[6]; + result._hash[7] = h1._hash[7] ^ h2._hash[7]; + return result; + } + bool operator >= ( const sha512& h1, const sha512& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) >= 0; + } + bool operator > ( const sha512& h1, const sha512& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) > 0; + } + bool operator < ( const sha512& h1, const sha512& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) < 0; + } + bool operator != ( const sha512& h1, const sha512& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) != 0; + } + bool operator == ( const sha512& h1, const sha512& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0; + } + + void to_variant( const sha512& bi, variant& v ) + { + v = fc::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ); + } + void from_variant( const variant& v, sha512& bi ) + { + fc::vector ve = v.as< vector >(); + if( ve.size() ) + { + memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); + } + else + memset( &bi, char(0), sizeof(bi) ); + } +} diff --git a/src/error_report.cpp b/src/error_report.cpp deleted file mode 100644 index a6ac843..0000000 --- a/src/error_report.cpp +++ /dev/null @@ -1,189 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -namespace fc { - -error_frame::error_frame( const fc::string& f, uint64_t l, const fc::string& m, const fc::string& d, fc::value met ) -:desc(d),file(fc::path(f).filename().generic_string()),line(l),method(m),meta(fc::move(met)),time(fc::time_point::now()),detail(false){} - -error_frame::error_frame( bool is_detail, const fc::string& f, uint64_t l, const fc::string& m, const fc::string& d, fc::value met ) -:desc(d),file(fc::path(f).filename().generic_string()),line(l),method(m),meta(fc::move(met)),time(fc::time_point::now()),detail(is_detail){} -error_report::error_report() -{ -} -error_frame::error_frame(const fc::error_frame& e) -:desc(e.desc),file(e.file),line(e.line),method(e.method),meta(e.meta),time(e.time),detail(e.detail){} - -error_frame::error_frame(fc::error_frame&& e) -:desc(fc::move(e.desc)), - file(fc::move(e.file)), - line(e.line), - method(fc::move(e.method)), - meta(fc::move(e.meta)), - time(e.time), - detail(e.detail) - {} - -fc::error_frame& fc::error_frame::operator=(const fc::error_frame& f ) { - auto tmp = f; - fc_swap( tmp, *this ); - return *this; -} -fc::error_frame& fc::error_frame::operator=(fc::error_frame&& e ) -{ - desc=fc::move(e.desc); - file=fc::move(e.file); - line=fc::move(e.line); - method=fc::move(e.method); - time=e.time; - meta=fc::move(e.meta); - detail = e.detail; - return *this; -} - -error_report::error_report( const fc::string& file, uint64_t line, const fc::string& method, const fc::string& desc, fc::value meta ) -{ - push_frame( file, line, method, desc, meta ); -} - - -fc::error_frame& error_report::current() -{ - if( !stack.size() ) stack.resize(1); - return stack.back(); -} - -fc::error_report& error_report::pop_frame() -{ - stack.pop_back(); - return *this; -} - -fc::error_report& error_report::push_frame( const fc::string& file, uint64_t line, const fc::string& method, const fc::string& desc, fc::value meta ) -{ - stack.push_back( fc::error_frame( file, line, method, desc, meta ) ); - return *this; -} -fc::error_report& error_report::push_frame( bool detail, const fc::string& file, uint64_t line, const fc::string& method, const fc::string& desc, fc::value meta ) -{ - stack.push_back( fc::error_frame( detail, file, line, method, desc, meta ) ); - return *this; -} - -fc::error_report& error_report::append( const error_report& e ) -{ - // TODO: what to do about the 'failure...?' - stack.reserve( stack.size()+e.stack.size()); - for( uint32_t i = 0; i < e.stack.size(); ++i ) { - stack.push_back( e.stack[i] ); - } - return *this; -} - -fc::string error_frame::to_detail_string()const { - fc::stringstream ss; - ss << to_string() << "\n\t"; - ss << file << ":" << line << "\t"<val.is_string() ) { - ss<val.cast(); - } else { - ss << fc::json::to_string( itr->val ); - } - } else { - ss << "${"<(), keys ); - } - else if( in.is_object() ) { - for( auto itr = in.begin(); itr != in.end(); ++itr ) { - out[fc::substitute(itr->key, keys)] = recursive_substitute( itr->val, keys ); - } - return out; - } - else if( in.is_array() ) { - for( size_t i = 0; i < in.size(); ++i ) { - out.push_back( recursive_substitute( in[i], keys ) ); - } - } - return in; -} - -fc::string error_report::to_string()const { - fc::stringstream ss; - for( uint32_t i = 0; i < stack.size(); ++i ) { - ss << stack[i].to_string() << "\n"; - } - return ss.str(); -} -fc::string error_report::to_detail_string()const { - fc::stringstream ss; - for( uint32_t i = 0; i < stack.size(); ++i ) { - ss << stack[i].to_detail_string() << "\n"; - } - return ss.str(); -} -fc::exception_ptr error_report::copy_exception() { - return boost::copy_exception(*this); -} - -} // namespace fc diff --git a/src/exception.cpp b/src/exception.cpp index 9b1f64d..b0bcde7 100644 --- a/src/exception.cpp +++ b/src/exception.cpp @@ -1,109 +1,344 @@ -#include -#include +#include #include -#include -#include +#include +#include +#include -namespace fc { - #define bexcept void* e = &my[0]; (*((boost::exception_ptr*)e)) - #define cbexcept const void* e = &my[0]; (*((const boost::exception_ptr*)e)) +namespace fc +{ + namespace detail + { + enum exception_code + { + unspecified_exception_code = 0, ///< for exceptions we threw that don't have an assigned code + unhandled_exception_code = 1, ///< for unhandled 3rd party exceptions + timeout_exception_code = 2, ///< timeout exceptions + file_not_found_exception_code = 3, + parse_error_exception_code = 4, + invalid_arg_exception_code = 5, + key_not_found_exception_code = 6, + bad_cast_exception_code = 7, + out_of_range_exception_code = 8, + canceled_exception_code = 9, + assert_exception_code = 10, + eof_exception_code = 11, + std_exception_code = 12, + }; - exception_ptr::exception_ptr() { - new (&my[0]) boost::exception_ptr(); - } - exception_ptr::exception_ptr( const boost::exception_ptr& c ){ - static_assert( sizeof(my) >= sizeof(c), "boost::exception_ptr is larger than space reserved for it" ); - new (&my[0]) boost::exception_ptr(c); - } - exception_ptr::exception_ptr( boost::exception_ptr&& c ){ - new (&my[0]) boost::exception_ptr(fc::move(c)); - } - exception_ptr::exception_ptr( const exception_ptr& c ){ - new (&my[0]) boost::exception_ptr(c); - } - exception_ptr::exception_ptr( exception_ptr&& c ){ - new (&my[0]) boost::exception_ptr(fc::move(c)); - } - exception_ptr::~exception_ptr(){ - bexcept.~exception_ptr(); - } - exception_ptr& exception_ptr::operator=(const boost::exception_ptr& c){ - bexcept = c; - return *this; - } - exception_ptr& exception_ptr::operator=(boost::exception_ptr&& c){ - bexcept = fc::move(c); - return *this; - } + void to_variant( detail::exception_code e, variant& v ) + { + switch( e ) + { + case unhandled_exception_code: + v = "unhandled"; + break; + case timeout_exception_code: + v = "timeout"; + break; + case key_not_found_exception_code: + v = "invalid_key"; + break; + case bad_cast_exception_code: + v = "bad_cast"; + break; + case file_not_found_exception_code: + v = "file_not_found"; + break; + case parse_error_exception_code: + v = "parse_error"; + break; + case invalid_arg_exception_code: + v = "invalid_arg"; + break; + case out_of_range_exception_code: + v = "out_of_range"; + break; + case canceled_exception_code: + v = "canceled"; + break; + case assert_exception_code: + v = "assert"; + break; + case std_exception_code: + v = "std"; + break; + case eof_exception_code: + v = "eof"; + break; + case unspecified_exception_code: + default: + v = "unspecified"; + break; + + } + } + void from_variant( const variant& e, detail::exception_code& ll ) + { + string v = e.as_string(); + if( v == "unspecified" ) ll = unspecified_exception_code; + else if( v == "unhandled" ) ll = unhandled_exception_code; + else if( v == "timeout" ) ll = timeout_exception_code; + else if( v == "key_not_found" ) ll = key_not_found_exception_code; + else if( v == "bad_cast" ) ll = bad_cast_exception_code; + else if( v == "file_not_found" ) ll = file_not_found_exception_code; + else if( v == "parse_error" ) ll = parse_error_exception_code; + else if( v == "invalid_arg" ) ll = invalid_arg_exception_code; + else if( v == "out_of_range" ) ll = out_of_range_exception_code; + else if( v == "canceled" ) ll = canceled_exception_code; + else if( v == "assert" ) ll = assert_exception_code; + else if( v == "std" ) ll = std_exception_code; + else if( v == "eof" ) ll = eof_exception_code; + else FC_THROW_EXCEPTION( bad_cast_exception, + "Invalid Error Report _code '${code}'", + ("code", v) ); + } - exception_ptr& exception_ptr::operator=(const exception_ptr& c){ - bexcept = c; - return *this; - } - exception_ptr& exception_ptr::operator=(exception_ptr&& c){ - bexcept = fc::move(c); - return *this; - } + class exception_impl + { + public: + exception_code _ecode; + log_messages _elog; + variant _props; + }; + } - fc::string exception_ptr::diagnostic_information()const{ - const void* e = &my[0]; - return boost::diagnostic_information( *((const boost::exception_ptr*)e) ).c_str(); - } + std_exception::std_exception( log_message&& m, std::exception_ptr e, const char* w ) + :unhandled_exception( fc::move(m), e ) + { + my->_ecode = detail::std_exception_code; + _what = w; + } + std_exception::std_exception( const exception& e ) + :unhandled_exception(e) + { + from_variant( my->_props ); + } - exception_ptr::operator const boost::exception_ptr& ()const{ - const void* e = &my[0]; - return (*((const boost::exception_ptr*)e)); - } - exception_ptr::operator boost::exception_ptr& (){ - void* e = &my[0]; - return (*((boost::exception_ptr*)e)); - } + std_exception::std_exception( log_messages m ) + :unhandled_exception(fc::move(m) ) + { + my->_ecode = detail::std_exception_code; + } - exception_ptr current_exception() { - return boost::current_exception(); - } - void rethrow_exception( const exception_ptr& e ) { - boost::rethrow_exception( static_cast(e) ); - } - exception_ptr::operator bool()const { - const void* e = &my[0]; - return (*((boost::exception_ptr*)e)); - } + void std_exception::from_variant( const variant& v ) + { + _what = v.get_object()["what"].as_string(); + } + void std_exception::to_variant( variant& v ) + { + v = variant_object( "what", _what ); + } - fc::string to_string( char v ) { return fc::string(&v,1); } - fc::string to_string( uint64_t v ) { return fc::lexical_cast(v).c_str(); } - fc::string to_string( int64_t v ){ return fc::lexical_cast(v).c_str(); } - fc::string to_string( double v ){ return fc::lexical_cast(v).c_str(); } - fc::string to_string( float v ){ return fc::lexical_cast(v).c_str(); } - fc::string to_string( int32_t v ){ return fc::lexical_cast(v).c_str(); } - fc::string to_string( uint32_t v ){ return fc::lexical_cast(v).c_str(); } - fc::string to_string( int16_t v ){ return fc::lexical_cast(v).c_str(); } - fc::string to_string( uint16_t v ){ return fc::lexical_cast(v).c_str(); } -// fc::string to_string( size_t v ){ return fc::lexical_cast(v).c_str(); } - //fc::string to_string( long int v ){ return fc::lexical_cast(v).c_str(); } + unhandled_exception::unhandled_exception( log_message&& m, std::exception_ptr e ) + :exception( fc::move(m) ) + { + my->_ecode = detail::unhandled_exception_code; + _inner = e; + } + unhandled_exception::unhandled_exception( const exception& r ) + :exception(r) + { + } + unhandled_exception::unhandled_exception( log_messages m ) + :exception() + { my->_elog = fc::move(m); + my->_ecode = detail::unhandled_exception_code; + } + std::exception_ptr unhandled_exception::get_inner_exception()const { return _inner; } + NO_RETURN void unhandled_exception::dynamic_rethrow_exception()const + { + if( !(_inner == std::exception_ptr()) ) std::rethrow_exception( _inner ); + else { fc::exception::dynamic_rethrow_exception(); } + } + std::shared_ptr unhandled_exception::dynamic_copy_exception()const + { + auto e = std::make_shared( *this ); + e->_inner = _inner; + return e; + } - void throw_exception( const char* func, const char* file, int line, const char* msg ) { - ::boost::exception_detail::throw_exception_(fc::generic_exception(msg),func, file, line ); - } - void throw_exception_( const char* func, const char* file, int line, const char* msg, - const fc::string& a1 ) { - ::boost::exception_detail::throw_exception_(fc::generic_exception( (boost::format(msg) % a1.c_str() ).str().c_str()) ,func, file, line ); - } - void throw_exception_( const char* func, const char* file, int line, const char* msg, - const fc::string& a1, const fc::string& a2 ) { - ::boost::exception_detail::throw_exception_(fc::generic_exception( (boost::format(msg) % a1.c_str() %a2.c_str()).str().c_str()),func, file, line ); - } - void throw_exception_( const char* func, const char* file, int line, const char* msg, - const fc::string& a1, const fc::string& a2, const fc::string& a3 ) { - ::boost::exception_detail::throw_exception_(fc::generic_exception(msg),func, file, line ); - } - void throw_exception_( const char* func, const char* file, int line, const char* msg, - const fc::string& a1, const fc::string& a2, const fc::string& a3, const fc::string& a4 ) { - ::boost::exception_detail::throw_exception_(fc::generic_exception(msg),func, file, line ); - } - fc::string except_str() { return boost::current_exception_diagnostic_information(); }//boost::current_exception_diagonstic_information(); } - //fc::current_exception().diagnostic_information(); } +#define FC_EXCEPTION_IMPL( TYPE ) \ + TYPE::TYPE( log_message&& m ) \ + :exception( fc::move(m) ) { my->_ecode = detail::TYPE ##_code; } \ + TYPE::TYPE(){ my->_ecode = detail::TYPE ##_code; } \ + TYPE::TYPE(const TYPE& t):exception(t){} \ + TYPE::TYPE( log_messages m ) \ + :exception() { my->_elog = fc::move(m); my->_ecode = detail::TYPE ##_code; } -} + FC_EXCEPTION_IMPL(timeout_exception) + FC_EXCEPTION_IMPL(file_not_found_exception) + FC_EXCEPTION_IMPL(parse_error_exception) + FC_EXCEPTION_IMPL(invalid_arg_exception) + FC_EXCEPTION_IMPL(key_not_found_exception) + FC_EXCEPTION_IMPL(bad_cast_exception) + FC_EXCEPTION_IMPL(out_of_range_exception) + FC_EXCEPTION_IMPL(canceled_exception) + FC_EXCEPTION_IMPL(assert_exception) + FC_EXCEPTION_IMPL(eof_exception) + + + + exception::exception() + :my( new detail::exception_impl() ) + { + my->_ecode = detail::unspecified_exception_code; + } + + exception::exception( log_message&& msg) + :my( new detail::exception_impl() ) + { + my->_ecode = detail::unspecified_exception_code; + my->_elog.push_back( fc::move( msg ) ); + } + exception::exception( const exception& c ) + :my( new detail::exception_impl(*c.my) ) + { + } + exception::exception( exception&& c ) + :my( fc::move(c.my) ){} + + exception::~exception(){} + + + void to_variant( const exception& e, variant& v ) + { + v = mutable_variant_object( "stack", e.my->_elog ) + ( "type", e.my->_ecode) + ( "props", e.my->_props ); + } + void from_variant( const variant& v, exception& ll ) + { + auto obj = v.get_object(); + ll.my->_elog = obj["stack"].as(); + ll.my->_ecode = obj["type"].as(); + ll.my->_props = obj["props"]; + } + + const log_messages& exception::get_log()const { return my->_elog; } + void exception::append_log( log_message m ) + { + my->_elog.push_back( fc::move(m) ); + } + + /** + * Generates a detailed string including file, line, method, + * and other information that is generally only useful for + * developers. + */ + string exception::to_detail_string( log_level ll )const + { + fc::stringstream ss; + ss << variant(my->_ecode).as_string() <<"\n"; + for( auto itr = my->_elog.begin(); itr != my->_elog.end(); ) + { + ss << itr->get_message() <<"\n"; //fc::format_string( itr->get_format(), itr->get_data() ) <<"\n"; + ss << " " << json::to_string( itr->get_data() )<<"\n"; + ss << " " << itr->get_context().to_string(); + ++itr; + if( itr != my->_elog.end() ) ss<<"\n"; + } + return ss.str(); + } + + /** + * Generates a user-friendly error report. + */ + string exception::to_string( log_level ll )const + { + fc::stringstream ss; + ss << what() << "(" << variant(my->_ecode).as_string() <<")\n"; + for( auto itr = my->_elog.begin(); itr != my->_elog.end(); ++itr ) + { + ss << fc::format_string( itr->get_format(), itr->get_data() ) <<"\n"; + // ss << " " << itr->get_context().to_string() <<"\n"; + } + return ss.str(); + } + + /** + * Rethrows the exception restoring the proper type based upon + * the error code. This is used to propagate exception types + * across conversions to/from JSON + */ + NO_RETURN void exception::dynamic_rethrow_exception()const + { + switch( my->_ecode ) + { + case detail::unhandled_exception_code: + throw unhandled_exception( my->_elog ); + case detail::timeout_exception_code: + throw timeout_exception( my->_elog ); + case detail::key_not_found_exception_code: + throw key_not_found_exception( my->_elog ); + case detail::bad_cast_exception_code: + throw bad_cast_exception( my->_elog ); + case detail::parse_error_exception_code: + throw parse_error_exception( my->_elog ); + case detail::canceled_exception_code: + throw canceled_exception( my->_elog); + case detail::assert_exception_code: + throw assert_exception( my->_elog ); + case detail::file_not_found_exception_code: + throw file_not_found_exception( my->_elog ); + case detail::invalid_arg_exception_code: + throw invalid_arg_exception( my->_elog ); + case detail::out_of_range_exception_code: + throw out_of_range_exception( my->_elog ); + case detail::eof_exception_code: + throw eof_exception( my->_elog ); + case detail::std_exception_code: + throw std_exception( *this ); + case detail::unspecified_exception_code: + default: + throw fc::exception(*this); + } + } + exception_ptr exception::dynamic_copy_exception()const + { + switch( my->_ecode ) + { + case detail::unhandled_exception_code: + return std::make_shared( my->_elog ); + case detail::timeout_exception_code: + return std::make_shared( my->_elog ); + case detail::key_not_found_exception_code: + return std::make_shared( my->_elog ); + case detail::bad_cast_exception_code: + return std::make_shared( my->_elog ); + case detail::parse_error_exception_code: + return std::make_shared( my->_elog ); + case detail::canceled_exception_code: + return std::make_shared( my->_elog); + case detail::assert_exception_code: + return std::make_shared( my->_elog ); + case detail::file_not_found_exception_code: + return std::make_shared( my->_elog ); + case detail::invalid_arg_exception_code: + return std::make_shared( my->_elog ); + case detail::out_of_range_exception_code: + return std::make_shared( my->_elog ); + case detail::eof_exception_code: + return std::make_shared( my->_elog ); + case detail::std_exception_code: + return std::make_shared( *this ); + case detail::unspecified_exception_code: + default: + return std::make_shared(*this); + } + } + fc::string except_str() + { + return boost::current_exception_diagnostic_information(); + } + void throw_bad_enum_cast( int64_t i, const char* e ) + { + FC_THROW_EXCEPTION( bad_cast_exception, "invalid index '${key}' in enum '${enum}'", ("key",i)("enum",e) ); + } + void throw_bad_enum_cast( const char* k, const char* e ) + { + FC_THROW_EXCEPTION( bad_cast_exception, "invalid name '${key}' in enum '${enum}'", ("key",k)("enum",e) ); + } + +} // fc diff --git a/src/filesystem.cpp b/src/filesystem.cpp index 6980572..972b66a 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -1,20 +1,24 @@ //#define BOOST_NO_SCOPED_ENUMS #include +#include #include #include +#include #include #include -#include -#include +#include namespace fc { - void pack( fc::value& v, const fc::path& s ) { - v = s.generic_string(); + void to_variant( const fc::path& t, variant& v ) { + v = t.generic_string(); } - void unpack( const fc::value& v, fc::path& s ) { - s = path(fc::value_cast(v)); + void from_variant( const fc::variant& v, fc::path& t ) { + t = fc::path(v.as_string()); } + // Note: we can do this cast because the separator should be an ASCII character + char path::separator_char = static_cast(boost::filesystem::path("/").make_preferred().native()[0]); + path::path(){} path::~path(){}; path::path( const boost::filesystem::path& p ) @@ -69,7 +73,7 @@ namespace fc { */ fc::string path::windows_string()const { auto gs = _p->generic_string(); - for( int i =0 ; i < gs.size(); ++i ) { + for( size_t i =0 ; i < gs.size(); ++i ) { if( gs[i] == '/' ) gs[i] = '\\'; } return gs; @@ -140,59 +144,161 @@ namespace fc { try { boost::filesystem::create_directories(p); } catch ( ... ) { - FC_THROW_REPORT( "Unable to create directories ${path}", fc::value().set("path", p ).set("inner", fc::except_str() ) ); + FC_THROW( "Unable to create directories ${path}", ("path", p )("inner", fc::except_str() ) ); } } bool is_directory( const path& p ) { return boost::filesystem::is_directory(p); } bool is_regular_file( const path& p ) { return boost::filesystem::is_regular_file(p); } uint64_t file_size( const path& p ) { return boost::filesystem::file_size(p); } void remove_all( const path& p ) { boost::filesystem::remove_all(p); } - void rename( const path& f, const path& t ) { - try { - boost::filesystem::rename( boost::filesystem::path(f), boost::filesystem::path(t) ); - } catch ( boost::system::system_error& e ) { - FC_THROW_REPORT( "Rename from ${srcfile} to ${dstfile} failed because ${reason}", - fc::value().set("srcfile",f).set("dstfile",t).set("reason",e.what() ) ); - } catch ( ... ) { - FC_THROW_REPORT( "Rename from ${srcfile} to ${dstfile} failed", - fc::value().set("srcfile",f).set("dstfile",t).set("inner", fc::except_str() ) ); - } - } void copy( const path& f, const path& t ) { try { boost::filesystem::copy( boost::filesystem::path(f), boost::filesystem::path(t) ); } catch ( boost::system::system_error& e ) { - FC_THROW_REPORT( "Copy from ${srcfile} to ${dstfile} failed because ${reason}", - fc::value().set("srcfile",f).set("dstfile",t).set("reason",e.what() ) ); + FC_THROW( "Copy from ${srcfile} to ${dstfile} failed because ${reason}", + ("srcfile",f)("dstfile",t)("reason",e.what() ) ); } catch ( ... ) { - FC_THROW_REPORT( "Copy from ${srcfile} to ${dstfile} failed", - fc::value().set("srcfile",f).set("dstfile",t).set("inner", fc::except_str() ) ); + FC_THROW( "Copy from ${srcfile} to ${dstfile} failed", + ("srcfile",f)("dstfile",t)("inner", fc::except_str() ) ); + } + } + void rename( const path& f, const path& t ) { + try { + boost::filesystem::rename( boost::filesystem::path(f), boost::filesystem::path(t) ); + } catch ( boost::system::system_error& e ) { + FC_THROW( "Rename from ${srcfile} to ${dstfile} failed because ${reason}", + ("srcfile",f)("dstfile",t)("reason",e.what() ) ); + } catch ( ... ) { + FC_THROW( "Rename from ${srcfile} to ${dstfile} failed", + ("srcfile",f)("dstfile",t)("inner", fc::except_str() ) ); } } void create_hard_link( const path& f, const path& t ) { try { boost::filesystem::create_hard_link( f, t ); } catch ( ... ) { - FC_THROW_REPORT( "Unable to create hard link from '${from}' to '${to}'", - fc::value().set( "from", f ) - .set("to",t).set("exception", fc::except_str() ) ); + FC_THROW( "Unable to create hard link from '${from}' to '${to}'", + ( "from", f )("to",t)("exception", fc::except_str() ) ); } } bool remove( const path& f ) { try { return boost::filesystem::remove( f ); } catch ( ... ) { - FC_THROW_REPORT( "Unable to remove '${path}'", fc::value().set( "path", f ).set("exception", fc::except_str() ) ); + FC_THROW( "Unable to remove '${path}'", ( "path", f )("exception", fc::except_str() ) ); } } fc::path canonical( const fc::path& p ) { try { return boost::filesystem::canonical(p); } catch ( ... ) { - FC_THROW_REPORT( "Unable to resolve path '${path}'", fc::value().set( "path", p ).set("exception", fc::except_str() ) ); + FC_THROW( "Unable to resolve path '${path}'", ( "path", p )("exception", fc::except_str() ) ); } } fc::path absolute( const fc::path& p ) { return boost::filesystem::absolute(p); } path unique_path() { return boost::filesystem::unique_path(); } path temp_directory_path() { return boost::filesystem::temp_directory_path(); } + + // Return path when appended to a_From will resolve to same as a_To + fc::path make_relative(const fc::path& from, const fc::path& to) { + boost::filesystem::path a_From = boost::filesystem::absolute(from); + boost::filesystem::path a_To = boost::filesystem::absolute(to); + boost::filesystem::path ret; + boost::filesystem::path::const_iterator itrFrom(a_From.begin()), itrTo(a_To.begin()); + // Find common base + for( boost::filesystem::path::const_iterator toEnd( a_To.end() ), fromEnd( a_From.end() ) ; itrFrom != fromEnd && itrTo != toEnd && *itrFrom == *itrTo; ++itrFrom, ++itrTo ); + // Navigate backwards in directory to reach previously found base + for( boost::filesystem::path::const_iterator fromEnd( a_From.end() ); itrFrom != fromEnd; ++itrFrom ) { + if( (*itrFrom) != "." ) + ret /= ".."; + } + // Now navigate down the directory branch + for (; itrTo != a_To.end(); ++itrTo) + ret /= *itrTo; + return ret; + } + + temp_file::temp_file(const fc::path& p, bool create) + : temp_file_base(p / fc::unique_path()) + { + if (fc::exists(*_path)) + { + FC_THROW( "Name collision: ${path}", ("path", _path->string()) ); + } + if (create) + { + fc::ofstream ofs(*_path, fc::ofstream::out | fc::ofstream::binary); + ofs.close(); + } + } + + temp_file::temp_file(temp_file&& other) + : temp_file_base(std::move(other._path)) + { + } + + temp_file& temp_file::operator=(temp_file&& other) + { + if (this != &other) + { + remove(); + _path = std::move(other._path); + } + return *this; + } + + temp_directory::temp_directory(const fc::path& p) + : temp_file_base(p / fc::unique_path()) + { + if (fc::exists(*_path)) + { + FC_THROW( "Name collision: ${path}", ("path", _path->string()) ); + } + fc::create_directories(*_path); + } + + temp_directory::temp_directory(temp_directory&& other) + : temp_file_base(std::move(other._path)) + { + } + + temp_directory& temp_directory::operator=(temp_directory&& other) + { + if (this != &other) + { + remove(); + _path = std::move(other._path); + } + return *this; + } + + const fc::path& temp_file_base::path() const + { + if (!_path) + { + FC_THROW( "Temporary directory has been released." ); + } + return *_path; + } + + void temp_file_base::remove() + { + if (_path) + { + try + { + fc::remove_all(*_path); + } + catch (...) + { + // eat errors on cleanup + } + release(); + } + } + + void temp_file_base::release() + { + _path = fc::optional(); + } } diff --git a/src/file_mapping.cpp b/src/interprocess/file_mapping.cpp similarity index 96% rename from src/file_mapping.cpp rename to src/interprocess/file_mapping.cpp index 0d68fb8..7ff557a 100644 --- a/src/file_mapping.cpp +++ b/src/interprocess/file_mapping.cpp @@ -10,7 +10,7 @@ namespace fc { - mapped_region::mapped_region( const file_mapping& fm, mode_t m, size_t start, size_t size ) + mapped_region::mapped_region( const file_mapping& fm, mode_t m, uint64_t start, size_t size ) :my( *fm.my, m == read_only ? boost::interprocess::read_only : boost::interprocess::read_write ,start, size) { } mapped_region::mapped_region( const file_mapping& fm, mode_t m ) :my( *fm.my, m == read_only ? boost::interprocess::read_only : boost::interprocess::read_write) { } diff --git a/src/interprocess/process.cpp b/src/interprocess/process.cpp new file mode 100644 index 0000000..55a5e6c --- /dev/null +++ b/src/interprocess/process.cpp @@ -0,0 +1,185 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fc { + namespace bp = boost::process; + namespace io = boost::iostreams; + +fc::path find_executable_in_path( const fc::string name ) { + try { + return fc::string(bp::find_executable_in_path( std::string(name), "" )); + } catch (...) { + const char* p = std::getenv("PATH"); + FC_THROW( "Unable to find executable ${exe} in path.", + ("exe", name) + ("inner", fc::except_str() ) + ("PATH", fc::string(p!=nullptr?p:"") ) ); + } + return fc::path(); +} + + +class process::impl +{ + public: + impl() + :stat( fc::asio::default_io_service() ){} + + ~impl() + { + try + { + if( _in ) + { + _in->close(); + } + if( _exited.valid() && !_exited.ready()) + { + //child->terminate(); + _exited.wait(); + } + } + catch(...) + { + wlog( "caught exception cleaning up process: ${except_str}", ("except_str",fc::except_str()) ); + } + } + + std::shared_ptr child; + + std::shared_ptr _inp; + std::shared_ptr _outp; + std::shared_ptr _errp; + + buffered_istream_ptr _out; + buffered_istream_ptr _err; + buffered_ostream_ptr _in; + + bp::status stat; + bp::context pctx; + + fc::future _exited; +}; + +process::process() +:my( new process::impl() ){} +process::~process(){} + +iprocess& process::exec( const fc::path& exe, + fc::vector args, + const fc::path& work_dir, exec_opts opt ) +{ + + my->pctx.work_dir = work_dir.string(); + + if( opt&open_stdout) + my->pctx.streams[boost::process::stdout_id] = bp::behavior::async_pipe(); + else + my->pctx.streams[boost::process::stdout_id] = bp::behavior::null(); + + + if( opt& open_stderr ) + my->pctx.streams[boost::process::stderr_id] = bp::behavior::async_pipe(); + else + my->pctx.streams[boost::process::stderr_id] = bp::behavior::null(); + + if( opt& open_stdin ) + my->pctx.streams[boost::process::stdin_id] = bp::behavior::async_pipe(); + else + my->pctx.streams[boost::process::stdin_id] = bp::behavior::close(); + + std::vector a; + a.reserve(size_t(args.size())); + for( uint32_t i = 0; i < args.size(); ++i ) { + a.push_back( fc::move(args[i]) ); + } + my->child.reset( new bp::child( bp::create_child( exe.string(), fc::move(a), my->pctx ) ) ); + + if( opt & open_stdout ) { + bp::handle outh = my->child->get_handle( bp::stdout_id ); + my->_outp.reset( new bp::pipe( fc::asio::default_io_service(), outh.release() ) ); + } + if( opt & open_stderr ) { + bp::handle errh = my->child->get_handle( bp::stderr_id ); + my->_errp.reset( new bp::pipe( fc::asio::default_io_service(), errh.release() ) ); + } + if( opt & open_stdin ) { + bp::handle inh = my->child->get_handle( bp::stdin_id ); + my->_inp.reset( new bp::pipe( fc::asio::default_io_service(), inh.release() ) ); + } + + + promise::ptr p(new promise("process")); + my->stat.async_wait( my->child->get_id(), [=]( const boost::system::error_code& ec, int exit_code ) + { + //slog( "process::result %d", exit_code ); + if( !ec ) { + #ifdef BOOST_POSIX_API + if( WIFEXITED(exit_code) ) p->set_value( WEXITSTATUS(exit_code) ); + else + { + p->set_exception( + fc::exception_ptr( new fc::exception( + FC_LOG_MESSAGE( error, "process exited with: ${message} ", + ("message", strsignal(WTERMSIG(exit_code))) ) ) ) ); + } + #else + p->set_value(exit_code); + #endif + } + else + { + p->set_exception( + fc::exception_ptr( new fc::exception( + FC_LOG_MESSAGE( error, "process exited with: ${message} ", + ("message", boost::system::system_error(ec).what())) ) ) ); + } + }); + my->_in = std::make_shared(std::make_shared>(my->_inp)); + my->_out = std::make_shared(std::make_shared>(my->_outp)); + my->_err = std::make_shared(std::make_shared>(my->_errp)); + my->_exited = p; + return *this; +} + +/** + * Forcefully kills the process. + */ +void process::kill() { + my->child->terminate(); +} + +/** + * @brief returns a stream that writes to the process' stdin + */ +fc::buffered_ostream_ptr process::in_stream() { + return my->_in; +} + +/** + * @brief returns a stream that reads from the process' stdout + */ +fc::buffered_istream_ptr process::out_stream() { + return my->_out; +} +/** + * @brief returns a stream that reads from the process' stderr + */ +fc::buffered_istream_ptr process::err_stream() { + return my->_err; +} + +int process::result() +{ + return my->_exited.wait(); +} + +} diff --git a/src/io/buffered_iostream.cpp b/src/io/buffered_iostream.cpp new file mode 100644 index 0000000..d6cf1f9 --- /dev/null +++ b/src/io/buffered_iostream.cpp @@ -0,0 +1,138 @@ +#include +#include +#include +#include + +#include + +namespace fc +{ + namespace detail + { + class buffered_istream_impl + { + public: + buffered_istream_impl( istream_ptr is ) + :_istr(fc::move(is)){} + + istream_ptr _istr; + boost::asio::streambuf _rdbuf; + }; + static const size_t minimum_read_size = 1024; + } + + buffered_istream::buffered_istream( istream_ptr is ) + :my( new detail::buffered_istream_impl( fc::move(is) ) ) + { + FC_ASSERT( my->_istr != nullptr, " this shouldn't be null" ); + } + + buffered_istream::buffered_istream( buffered_istream&& o ) + :my( fc::move(o.my) ){} + + buffered_istream& buffered_istream::operator=( buffered_istream&& i ) + { + my = fc::move(i.my); + return *this; + } + + buffered_istream::~buffered_istream(){} + + size_t buffered_istream::readsome( char* buf, size_t len ) + { + size_t bytes_from_rdbuf = static_cast(my->_rdbuf.sgetn(buf, len)); + if (bytes_from_rdbuf) + return bytes_from_rdbuf; + + + if( len > detail::minimum_read_size ) + return my->_istr->readsome(buf,len); + + char tmp[detail::minimum_read_size]; + size_t bytes_read = my->_istr->readsome( tmp, detail::minimum_read_size ); + + size_t bytes_to_deliver_immediately = std::min(bytes_read,len); + + memcpy( buf, tmp, bytes_to_deliver_immediately ); + + + if( bytes_read > len ) + { + my->_rdbuf.sputn( tmp + len, bytes_read - len ); + } + + return bytes_to_deliver_immediately; + } + + char buffered_istream::peek()const + { + if( my->_rdbuf.size() ) + { + return my->_rdbuf.sgetc(); + } + + char tmp[detail::minimum_read_size]; + size_t bytes_read = my->_istr->readsome( tmp, detail::minimum_read_size ); + my->_rdbuf.sputn( tmp, bytes_read ); + + if( my->_rdbuf.size() ) + { + return my->_rdbuf.sgetc(); + } + FC_THROW_EXCEPTION( assert_exception, + "at least one byte should be available, or eof should have been thrown" ); + } + + + namespace detail + { + class buffered_ostream_impl + { + public: + buffered_ostream_impl( ostream_ptr os ) + :_ostr(fc::move(os)){} + + ostream_ptr _ostr; + boost::asio::streambuf _rdbuf; + }; + } + + buffered_ostream::buffered_ostream( ostream_ptr os, size_t bufsize ) + :my( new detail::buffered_ostream_impl( fc::move(os) ) ) + { + } + + buffered_ostream::buffered_ostream( buffered_ostream&& o ) + :my( fc::move(o.my) ){} + + buffered_ostream& buffered_ostream::operator=( buffered_ostream&& i ) + { + my = fc::move(i.my); + return *this; + } + + buffered_ostream::~buffered_ostream(){} + + size_t buffered_ostream::writesome( const char* buf, size_t len ) + { + size_t written = static_cast(my->_rdbuf.sputn( buf, len )); + if( written < len ) { flush(); } + return written + static_cast(my->_rdbuf.sputn( buf+written, len-written )); + } + + void buffered_ostream::flush() + { + char buffer[2048]; + while( size_t bytes_from_rdbuf = static_cast(my->_rdbuf.sgetn(buffer,sizeof(buffer))) ) + my->_ostr->write( buffer, bytes_from_rdbuf ); + my->_ostr->flush(); + } + + void buffered_ostream::close() + { + flush(); + my->_ostr->close(); + } + + +} diff --git a/src/io/datastream.cpp b/src/io/datastream.cpp new file mode 100644 index 0000000..da38e14 --- /dev/null +++ b/src/io/datastream.cpp @@ -0,0 +1,7 @@ +#include +#include + +NO_RETURN void fc::detail::throw_datastream_range_error(char const* method, size_t len, size_t over) +{ + FC_THROW_EXCEPTION( out_of_range_exception, "${method} datastream of length ${len} over by ${over}", ("method",fc::string(method))("len",len)("over",over) ); +} diff --git a/src/fstream.cpp b/src/io/fstream.cpp similarity index 73% rename from src/fstream.cpp rename to src/io/fstream.cpp index e927eed..0619fab 100644 --- a/src/fstream.cpp +++ b/src/io/fstream.cpp @@ -1,6 +1,9 @@ -#include +#include #include #include +#include +#include + namespace fc { class ofstream::impl : public fc::retainable { @@ -22,9 +25,9 @@ namespace fc { void ofstream::open( const fc::path& file, int m ) { my->ofs.open( file.string().c_str(), std::ios::binary ); } - ofstream& ofstream::write( const char* buf, size_t len ) { + size_t ofstream::writesome( const char* buf, size_t len ) { my->ofs.write(buf,len); - return *this; + return len; } void ofstream::put( char c ) { my->ofs.put(c); @@ -49,11 +52,19 @@ namespace fc { my->ifs.open( file.string().c_str(), std::ios::binary ); } size_t ifstream::readsome( char* buf, size_t len ) { - return size_t(my->ifs.readsome( buf, len )); + auto s = size_t(my->ifs.readsome( buf, len )); + if( s <= 0 ) { + read( buf, 1 ); + s = 1; + } + return s; } ifstream& ifstream::read( char* buf, size_t len ) { - my->ifs.read(buf,len); - return *this; + if( eof() ) FC_THROW_EXCEPTION( eof_exception , ""); + my->ifs.read(buf,len); + if (my->ifs.gcount() < int64_t(len)) + FC_THROW_EXCEPTION( eof_exception , ""); + return *this; } ifstream& ifstream::seekg( size_t p, seekdir d ) { switch( d ) { @@ -65,7 +76,7 @@ namespace fc { } void ifstream::close() { return my->ifs.close(); } - bool ifstream::eof()const { return my->ifs.eof(); } + bool ifstream::eof()const { return !my->ifs.good(); } } // namespace fc diff --git a/src/io/iostream.cpp b/src/io/iostream.cpp new file mode 100644 index 0000000..a0936d0 --- /dev/null +++ b/src/io/iostream.cpp @@ -0,0 +1,354 @@ +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include + +namespace fc { + + struct cin_buffer { + cin_buffer():eof(false),write_pos(0),read_pos(0),cinthread("cin"){ + + cinthread.async( [=](){read();} ); + } + + void read() { + char c; + std::cin.read(&c,1); + while( !std::cin.eof() ) { + while( write_pos - read_pos > 0xfffff ) { + fc::promise::ptr wr( new fc::promise() ); + write_ready = wr; + if( write_pos - read_pos <= 0xfffff ) { + wr->wait(); + } + write_ready.reset(); + } + buf[write_pos&0xfffff] = c; + ++write_pos; + + fc::promise::ptr tmp; + { // copy read_ready because it is accessed from multiple threads + fc::scoped_lock lock( read_ready_mutex ); + tmp = read_ready; + } + + if( tmp && !tmp->ready() ) { + tmp->set_value(); + } + std::cin.read(&c,1); + } + eof = true; + fc::promise::ptr tmp; + { // copy read_ready because it is accessed from multiple threads + fc::scoped_lock lock( read_ready_mutex ); + tmp = read_ready; + } + if( tmp && !tmp->ready() ) { + tmp->set_exception( exception_ptr( new eof_exception() )); + } + } + boost::mutex read_ready_mutex; + fc::promise::ptr read_ready; + fc::promise::ptr write_ready; + + volatile bool eof; + + volatile uint64_t write_pos; + char buf[0xfffff+1]; // 1 mb buffer + volatile uint64_t read_pos; + fc::thread cinthread; + }; + + cin_buffer& get_cin_buffer() { + static cin_buffer* b = new cin_buffer(); + return *b; + } + + + fc::thread& cin_thread() { static fc::thread i("cin"); return i; } + + fc::istream& getline( fc::istream& i, fc::string& s, char delim ) { + fc::stringstream ss; + try + { + char c; + i.read( &c, 1 ); + while( true ) { + if( c == delim ) { s = ss.str(); return i; } + if( c != '\r' ) ss.write(&c,1); + i.read( &c, 1 ); + } + } catch ( fc::eof_exception& ) + { + } + s = ss.str(); + return i; + } + + + size_t cout_t::writesome( const char* buf, size_t len ) { std::cout.write(buf,len); return len; } + void cout_t::close() {} + void cout_t::flush() { std::cout.flush(); } + + size_t cerr_t::writesome( const char* buf, size_t len ) { std::cerr.write(buf,len); return len; } + void cerr_t::close() {}; + void cerr_t::flush() { std::cerr.flush(); } + + + size_t cin_t::readsome( char* buf, size_t len ) { + cin_buffer& b = get_cin_buffer(); + int64_t avail = b.write_pos - b.read_pos; + avail = (fc::min)(int64_t(len),avail); + int64_t u = 0; + + if( !((avail>0) && (len>0)) ) { + read( buf, 1 ); + ++buf; + ++u; + --len; + } + + while( (avail>0) && (len>0) ) { + *buf = b.buf[b.read_pos&0xfffff]; + ++b.read_pos; + ++buf; + --avail; + --len; + ++u; + } + return size_t(u); + } + + cin_t::~cin_t() { + /* + cin_buffer& b = get_cin_buffer(); + if( b.read_ready ) { + b.read_ready->wait(); + } + */ + } + istream& cin_t::read( char* buf, size_t len ) { + cin_buffer& b = get_cin_buffer(); + do { + while( !b.eof && (b.write_pos - b.read_pos)==0 ){ + // wait for more... + fc::promise::ptr rr( new fc::promise() ); + { // copy read_ready because it is accessed from multiple threads + fc::scoped_lock lock( b.read_ready_mutex ); + b.read_ready = rr; + } + if( b.write_pos - b.read_pos == 0 ) { + rr->wait(); + } + // b.read_ready.reset(); + { // copy read_ready because it is accessed from multiple threads + fc::scoped_lock lock( b.read_ready_mutex ); + b.read_ready.reset(); + } + } + if( b.eof ) FC_THROW_EXCEPTION( eof_exception, "cin" ); + size_t r = readsome( buf, len ); + buf += r; + len -= r; + + auto tmp = b.write_ready; // copy write_writey because it is accessed from multiple thwrites + if( tmp && !tmp->ready() ) { + tmp->set_value(); + } + } while( len > 0 && !b.eof ); + if( b.eof ) FC_THROW_EXCEPTION( eof_exception, "cin" ); + return *this; + } + + bool cin_t::eof()const { return get_cin_buffer().eof; } + + + std::shared_ptr cin_ptr = std::make_shared(); + std::shared_ptr cout_ptr = std::make_shared(); + std::shared_ptr cerr_ptr = std::make_shared(); + cout_t& cout = *cout_ptr; + cerr_t& cerr = *cerr_ptr; + cin_t& cin = *cin_ptr; + + + ostream& operator<<( ostream& o, const char v ) + { + o.write( &v, 1 ); + return o; + } + ostream& operator<<( ostream& o, const char* v ) + { + o.write( v, strlen(v) ); + return o; + } + + ostream& operator<<( ostream& o, const std::string& v ) + { + o.write( v.c_str(), v.size() ); + return o; + } + + ostream& operator<<( ostream& o, const fc::string& v ) + { + o.write( v.c_str(), v.size() ); + return o; + } + + ostream& operator<<( ostream& o, const double& v ) + { + return o << boost::lexical_cast(v).c_str(); + } + + ostream& operator<<( ostream& o, const float& v ) + { + return o << boost::lexical_cast(v).c_str(); + } + + ostream& operator<<( ostream& o, const int64_t& v ) + { + return o << boost::lexical_cast(v).c_str(); + } + + ostream& operator<<( ostream& o, const uint64_t& v ) + { + return o << boost::lexical_cast(v).c_str(); + } + + ostream& operator<<( ostream& o, const int32_t& v ) + { + return o << boost::lexical_cast(v).c_str(); + } + + ostream& operator<<( ostream& o, const uint32_t& v ) + { + return o << boost::lexical_cast(v).c_str(); + } + + ostream& operator<<( ostream& o, const int16_t& v ) + { + return o << boost::lexical_cast(v).c_str(); + } + + ostream& operator<<( ostream& o, const uint16_t& v ) + { + return o << boost::lexical_cast(v).c_str(); + } + + ostream& operator<<( ostream& o, const int8_t& v ) + { + return o << boost::lexical_cast(v).c_str(); + } + + ostream& operator<<( ostream& o, const uint8_t& v ) + { + return o << boost::lexical_cast(v).c_str(); + } + +#ifdef __APPLE__ + ostream& operator<<( ostream& o, const size_t& v ) + { + return o << boost::lexical_cast(v).c_str(); + } + +#endif + + istream& operator>>( istream& o, std::string& v ) + { + return o; + } + + istream& operator>>( istream& o, fc::string& v ) + { + return o; + } + + istream& operator>>( istream& o, char& v ) + { + o.read(&v,1); + return o; + } + + istream& operator>>( istream& o, double& v ) + { + return o; + } + + istream& operator>>( istream& o, float& v ) + { + return o; + } + + istream& operator>>( istream& o, int64_t& v ) + { + return o; + } + + istream& operator>>( istream& o, uint64_t& v ) + { + return o; + } + + istream& operator>>( istream& o, int32_t& v ) + { + return o; + } + + istream& operator>>( istream& o, uint32_t& v ) + { + return o; + } + + istream& operator>>( istream& o, int16_t& v ) + { + return o; + } + + istream& operator>>( istream& o, uint16_t& v ) + { + return o; + } + + istream& operator>>( istream& o, int8_t& v ) + { + return o; + } + + istream& operator>>( istream& o, uint8_t& v ) + { + return o; + } + + + char istream::get() + { + char tmp; + read(&tmp,1); + return tmp; + } + + istream& istream::read( char* buf, size_t len ) + { + auto pos = buf; + while( size_t(pos-buf) < len ) + pos += readsome( pos, len - (pos - buf) ); + return *this; + } + + ostream& ostream::write( const char* buf, size_t len ) + { + auto pos = buf; + while( size_t(pos-buf) < len ) + pos += writesome( pos, len - (pos - buf) ); + return *this; + } + +} diff --git a/src/io/json.cpp b/src/io/json.cpp new file mode 100644 index 0000000..c2fa1a8 --- /dev/null +++ b/src/io/json.cpp @@ -0,0 +1,483 @@ +#include +#include +#include +#include +#include +#include +#include +//#include + +namespace fc +{ + template + variant variant_from_stream( T& in ); + template + char parseEscape( T& in ) + { + if( in.peek() == '\\' ) + { + try { + in.get(); + switch( in.peek() ) + { + case 't': + in.get(); + return '\t'; + case 'n': + in.get(); + return '\n'; + case 'r': + in.get(); + return '\r'; + case '\\': + in.get(); + return '\\'; + default: + return in.get(); + } + } FC_RETHROW_EXCEPTIONS( info, "Stream ended with '\\'" ); + } + FC_THROW_EXCEPTION( parse_error_exception, "Expected '\\'" ); + } + + + template + void skip_white_space( T& in ) + { + while( true ) + { + switch( in.peek() ) + { + case ' ': + case '\t': + case '\n': + case '\r': + in.get(); + break; + default: + return; + } + } + } + + template + fc::string stringFromStream( T& in ) + { + fc::stringstream token; + try + { + char c = in.peek(); + + if( c != '"' ) + FC_THROW_EXCEPTION( parse_error_exception, + "Expected '\"' but read '${char}'", + ("char", string(&c, (&c) + 1) ) ); + in.get(); + while( true ) + { + + switch( c = in.peek() ) + { + case '\\': + token << parseEscape( in ); + break; + case '"': + in.get(); + return token.str(); + default: + token << c; + in.get(); + } + } + FC_THROW_EXCEPTION( parse_error_exception, "EOF before closing '\"' in string '${token}'", + ("token", token.str() ) ); + } FC_RETHROW_EXCEPTIONS( warn, "while parsing token '${token}'", + ("token", token.str() ) ); + } + + template + variant_object objectFromStream( T& in ) + { + mutable_variant_object obj; + try + { + char c = in.peek(); + if( c != '{' ) + FC_THROW_EXCEPTION( parse_error_exception, + "Expected '{', but read '${char}'", + ("char",string(&c, &c + 1)) ); + in.get(); + skip_white_space(in); + while( in.peek() != '}' ) + { + if( in.peek() == ',' ) + { + in.get(); + } + skip_white_space(in); + string key = stringFromStream( in ); + skip_white_space(in); + if( in.peek() != ':' ) + { + FC_THROW_EXCEPTION( parse_error_exception, "Expected ':' after key \"${key}\"", + ("key", key) ); + } + in.get(); + auto val = variant_from_stream( in ); + + obj(std::move(key),std::move(val)); + skip_white_space(in); + } + if( in.peek() == '}' ) + { + in.get(); + return obj; + } + FC_THROW_EXCEPTION( parse_error_exception, "Expected '}' after ${variant}", ("variant", obj ) ); + + + } FC_RETHROW_EXCEPTIONS( warn, "Error parsing object" ); + } + + template + variants arrayFromStream( T& in ) + { + variants ar; + try + { + if( in.peek() != '[' ) + FC_THROW_EXCEPTION( parse_error_exception, "Expected '['" ); + in.get(); + skip_white_space(in); + + while( in.peek() != ']' ) + { + while( in.peek() == ',' ) + in.get(); + ar.push_back( variant_from_stream(in) ); + skip_white_space(in); + } + if( in.peek() != ']' ) + FC_THROW_EXCEPTION( parse_error_exception, "Expected ']' after parsing ${variant}", + ("variant", ar) ); + + in.get(); + } FC_RETHROW_EXCEPTIONS( warn, "Attempting to parse array ${array}", + ("array", ar ) ); + return ar; + } + + template + variant number_from_stream( T& in ) + { + char buf[30]; + memset( buf, 0, sizeof(buf) ); + char* pos = buf; + bool dot = false; + bool neg = false; + if( in.peek() == '-') + { + neg = true; + *pos = in.get(); + ++pos; + } + bool done = false; + while( !done) + { + char c = in.peek(); + switch( c ) + { + case '.': + { + if( dot ) + { + done = true; + break; + } + dot = true; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + *pos = c; + ++pos; + in.get(); + break; + default: + done = true; + break; + } + } + if( dot ) return to_double(buf); + if( neg ) return to_int64(buf); + return to_uint64(buf); + } + template + variant token_from_stream( T& in ) + { + fc::stringstream ss; + while( char c = in.peek() ) + { + switch( c ) + { + case 'n': + case 'u': + case 'l': + case 't': + case 'r': + case 'e': + case 'f': + case 'a': + case 's': + ss.put( in.get() ); + break; + default: + { + fc::string str = ss.str(); + if( str == "null" ) return variant(); + if( str == "true" ) return true; + if( str == "false" ) return false; + else + { + FC_THROW_EXCEPTION( parse_error_exception, "Invalid token '${token}'", + ("token",str) ); + } + } + } + } + FC_THROW_EXCEPTION( parse_error_exception, "Unexpected EOF" ); + } + + + template + variant variant_from_stream( T& in ) + { + skip_white_space(in); + variant var; + while( char c = in.peek() ) + { + switch( c ) + { + case ' ': + case '\t': + case '\n': + case '\r': + in.get(); + continue; + case '"': + return stringFromStream( in ); + case '{': + return objectFromStream( in ); + case '[': + return arrayFromStream( in ); + case '-': + case '.': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return number_from_stream( in ); + // null, true, false, or 'warning' / string + case 'n': + case 't': + case 'f': + return token_from_stream( in ); + case 0x04: // ^D end of transmission + FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); + default: + ilog( "unhandled char '${c}' int ${int}", ("c", fc::string( &c, 1 ) )("int", int(c)) ); + } + } + return variant(); + } + variant json::from_string( const fc::string& utf8_str ) + { + fc::stringstream in( utf8_str ); + return variant_from_stream( in ); + } + + /* + void toUTF8( const char str, ostream& os ) + { + // validate str == valid utf8 + utf8::replace_invalid( &str, &str + 1, ostream_iterator(os) ); + } + + void toUTF8( const wchar_t c, ostream& os ) + { + utf8::utf16to8( &c, (&c)+1, ostream_iterator(os) ); + } + */ + + /** + * Convert '\t', '\a', '\n', '\\' and '"' to "\t\a\n\\\"" + * + * All other characters are printed as UTF8. + */ + void escape_string( const string& str, ostream& os ) + { + os << '"'; + for( auto itr = str.begin(); itr != str.end(); ++itr ) + { + switch( *itr ) + { + case '\t': + os << "\\t"; + break; + case '\n': + os << "\\n"; + break; + case '\\': + os << "\\\\"; + break; + case '\r': + os << "\\r"; + break; + case '\a': + os << "\\a"; + break; + case '\"': + os << "\\\""; + break; + default: + os << *itr; + //toUTF8( *itr, os ); + } + } + os << '"'; + } + ostream& json::to_stream( ostream& out, const fc::string& str ) + { + escape_string( str, out ); + return out; + } + + template + void to_stream( T& os, const variants& a ) + { + os << '['; + auto itr = a.begin(); + + while( itr != a.end() ) + { + to_stream( os, *itr ); + ++itr; + if( itr != a.end() ) + os << ','; + } + os << ']'; + } + template + void to_stream( T& os, const variant_object& o ) + { + os << '{'; + auto itr = o.begin(); + + while( itr != o.end() ) + { + escape_string( itr->key(), os ); + os << ':'; + to_stream( os, itr->value() ); + ++itr; + if( itr != o.end() ) + os << ','; + } + os << '}'; + } + + template + void to_stream( T& os, const variant& v ) + { + switch( v.get_type() ) + { + case variant::null_type: + os << "null"; + return; + case variant::int64_type: + os << v.as_int64(); + return; + case variant::uint64_type: + os << v.as_uint64(); + return; + case variant::double_type: + os << v.as_double(); + return; + case variant::bool_type: + os << v.as_string(); + return; + case variant::string_type: + escape_string( v.get_string(), os ); + return; + case variant::array_type: + { + const variants& a = v.get_array(); + to_stream( os, a ); + return; + } + case variant::object_type: + { + const variant_object& o = v.get_object(); + to_stream(os, o ); + return; + } + } + } + + fc::string json::to_string( const variant& v ) + { + fc::stringstream ss; + fc::to_stream( ss, v ); + return ss.str(); + } + + fc::string json::to_pretty_string( const variant& v ) + { + return to_string(v); + } + + void json::save_to_file( const variant& v, const string& fi, bool pretty ) + { + fc::ofstream o( fi.c_str() ); + fc::to_stream( o, v ); + } + variant json::from_file( const fc::path& p ) + { + auto tmp = std::make_shared( p, ifstream::binary ); + buffered_istream bi( tmp ); + return variant_from_stream( bi ); + } + variant json::from_stream( buffered_istream& in ) + { + return variant_from_stream( in ); + } + + ostream& json::to_stream( ostream& out, const variant& v ) + { + fc::to_stream( out, v ); + return out; + } + ostream& json::to_stream( ostream& out, const variants& v ) + { + fc::to_stream( out, v ); + return out; + } + ostream& json::to_stream( ostream& out, const variant_object& v ) + { + fc::to_stream( out, v ); + return out; + } + +} // fc diff --git a/src/sstream.cpp b/src/io/sstream.cpp similarity index 73% rename from src/sstream.cpp rename to src/io/sstream.cpp index 7767479..1534f08 100644 --- a/src/sstream.cpp +++ b/src/io/sstream.cpp @@ -1,6 +1,7 @@ -#include +#include #include -#include +#include +#include #include namespace fc { @@ -31,23 +32,42 @@ namespace fc { return my->ss.str();//.c_str();//*reinterpret_cast(&st); } + void stringstream::str(const fc::string& s) { + my->ss.str(s); + } + + void stringstream::clear() { + my->ss.clear(); + } + + bool stringstream::eof()const { return my->ss.eof(); } - ostream& stringstream::write( const char* buf, size_t len ) { + size_t stringstream::writesome( const char* buf, size_t len ) { my->ss.write(buf,len); - return *this; + if( my->ss.eof() ) + { + FC_THROW_EXCEPTION( eof_exception, "stringstream" ); + } + return len; } size_t stringstream::readsome( char* buf, size_t len ) { - return static_cast(my->ss.readsome(buf,len)); - } - istream& stringstream::read( char* buf, size_t len ) { - my->ss.read(buf,len); - return *this; + size_t r = static_cast(my->ss.readsome(buf,len)); + if( my->ss.eof() || r == 0 ) + { + FC_THROW_EXCEPTION( eof_exception, "stringstream" ); + } + return r; } void stringstream::close(){ my->ss.flush(); }; void stringstream::flush(){ my->ss.flush(); }; + /* + istream& stringstream::read( char* buf, size_t len ) { + my->ss.read(buf,len); + return *this; + } istream& stringstream::read( int64_t& v ) { my->ss >> v; return *this; } istream& stringstream::read( uint64_t& v ) { my->ss >> v; return *this; } istream& stringstream::read( int32_t& v ) { my->ss >> v; return *this; } @@ -66,7 +86,17 @@ namespace fc { my->ss.write( s.c_str(), s.size() ); return *this; } + */ + char stringstream::peek() + { + char c = my->ss.peek(); + if( my->ss.eof() ) + { + FC_THROW_EXCEPTION( eof_exception, "stringstream" ); + } + return c; + } } diff --git a/src/io/varint.cpp b/src/io/varint.cpp new file mode 100644 index 0000000..a3eaac2 --- /dev/null +++ b/src/io/varint.cpp @@ -0,0 +1,10 @@ +#include +#include + +namespace fc +{ +void to_variant( const signed_int& var, variant& vo ) { vo = var.value; } +void from_variant( const variant& var, signed_int& vo ) { vo.value = static_cast(var.as_int64()); } +void to_variant( const unsigned_int& var, variant& vo ) { vo = var.value; } +void from_variant( const variant& var, unsigned_int& vo ) { vo.value = static_cast(var.as_uint64()); } +} diff --git a/src/iostream.cpp b/src/iostream.cpp deleted file mode 100644 index c53e050..0000000 --- a/src/iostream.cpp +++ /dev/null @@ -1,168 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace fc { - ostream& operator<<( ostream& o, const char* v ) { - o.write( v, strlen(v) ); - return o; - } - - struct cin_buffer { - cin_buffer():eof(false),write_pos(0),read_pos(0),cinthread("cin"){ - - cinthread.async( [=](){read();} ); - } - - void read() { - char c; - std::cin.read(&c,1); - while( !std::cin.eof() ) { - while( write_pos - read_pos > 0xfffff ) { - fc::promise::ptr wr( new fc::promise() ); - write_ready = wr; - if( write_pos - read_pos <= 0xfffff ) { - wr->wait(); - } - write_ready.reset(); - } - buf[write_pos&0xfffff] = c; - ++write_pos; - - fc::promise::ptr tmp; - { // copy read_ready because it is accessed from multiple threads - fc::scoped_lock lock( read_ready_mutex ); - tmp = read_ready; - } - if( tmp && !tmp->ready() ) { - tmp->set_value(); - } - std::cin.read(&c,1); - } - eof = true; - fc::promise::ptr tmp; - { // copy read_ready because it is accessed from multiple threads - fc::scoped_lock lock( read_ready_mutex ); - tmp = read_ready; - } - if( tmp && !tmp->ready() ) { - tmp->set_value(); - } - } - boost::mutex read_ready_mutex; - fc::promise::ptr read_ready; - fc::promise::ptr write_ready; - - volatile bool eof; - - volatile uint64_t write_pos; - char buf[0xfffff+1]; // 1 mb buffer - volatile uint64_t read_pos; - fc::thread cinthread; - }; - - cin_buffer& get_cin_buffer() { - static cin_buffer* b = new cin_buffer(); - return *b; - } - - - fc::thread& cin_thread() { static fc::thread i("cin"); return i; } - - fc::istream& getline( fc::istream& i, fc::string& s, char delim ) { - fc::stringstream ss; - char c; - i.read( &c, 1 ); - while( !i.eof() ) { - if( c == delim ) { s = ss.str(); return i; } - if( c != '\r' ) ss.write(&c,1); - i.read( &c, 1 ); - } - s = ss.str(); - return i; - } - - - ostream& cout_t::write( const char* buf, size_t len ) { std::cout.write(buf,len); return *this; } - void cout_t::close() {} - void cout_t::flush() { std::cout.flush(); } - - ostream& cout_t::write( const fc::string& s ) { std::cout.write(s.c_str(),s.size()); return *this; } - - ostream& cerr_t::write( const char* buf, size_t len ) { std::cerr.write(buf,len); return *this; } - void cerr_t::close() {}; - void cerr_t::flush() { std::cerr.flush(); } - - ostream& cerr_t::write( const fc::string& s ) { std::cerr<< static_cast(s); return *this; } - - size_t cin_t::readsome( char* buf, size_t len ) { - cin_buffer& b = get_cin_buffer(); - int64_t avail = b.write_pos - b.read_pos; - avail = (fc::min)(int64_t(len),avail); - int64_t u = 0; - while( (avail>0) && (len>0) ) { - *buf = b.buf[b.read_pos&0xfffff]; - ++b.read_pos; - ++buf; - --avail; - --len; - ++u; - } - return size_t(u); - } - - cin_t::~cin_t() { - /* - cin_buffer& b = get_cin_buffer(); - if( b.read_ready ) { - b.read_ready->wait(); - } - */ - } - istream& cin_t::read( char* buf, size_t len ) { - cin_buffer& b = get_cin_buffer(); - do { - while( !b.eof && (b.write_pos - b.read_pos)==0 ){ - // wait for more... - fc::promise::ptr rr( new fc::promise() ); - { // copy read_ready because it is accessed from multiple threads - fc::scoped_lock lock( b.read_ready_mutex ); - b.read_ready = rr; - } - if( b.write_pos - b.read_pos == 0 ) { - rr->wait(); - } - // b.read_ready.reset(); - { // copy read_ready because it is accessed from multiple threads - fc::scoped_lock lock( b.read_ready_mutex ); - b.read_ready.reset(); - } - } - if( b.eof ) return *this; - size_t r = readsome( buf, len ); - buf += r; - len -= r; - - auto tmp = b.write_ready; // copy write_writey because it is accessed from multiple thwrites - if( tmp && !tmp->ready() ) { - tmp->set_value(); - } - - - } while( len > 0 && !b.eof ); - return *this; - } - - bool cin_t::eof()const { return get_cin_buffer().eof; } - - cout_t cout; - cerr_t cerr; - cin_t cin; -} diff --git a/src/json.cpp b/src/json.cpp deleted file mode 100644 index c187bb9..0000000 --- a/src/json.cpp +++ /dev/null @@ -1,1055 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace fc { namespace json { - /** - * Placeholder for unparsed json data. - */ - class string { - public: - template - string( T&& v ):json_data( fc::forward(v) ){} - string( const string& s ):json_data(s.json_data){} - string( string&& s ):json_data(fc::move(s.json_data)){} - string(){} - - string& operator=( const fc::string& s ) { - json_data = std::vector(s.begin(),s.end()); - return *this; - } - template - string& operator=( T&& t ) { - json_data = fc::forward(t); - return *this; - } - string& operator=( string&& s ) { - json_data = fc::move(s.json_data); - return *this; - } - string& operator=( const string& s ) - { - json_data = s.json_data; - return *this; - } - std::vector json_data; - }; - -} } - -typedef std::map jmap; - - - namespace errors { - enum error_type { - unknown_error = 0x0001, // Other errors not specified below - warning = 0x0002, // Other warnigns not specified below - sytnax_error = 0x0004, // fatal syntax errors unclosed brace - sytnax_warning = 0x0008, // recoverable syntax error (missing, missing ':', unquoted string) - missing_comma = 0x0010, // if the error was related to json syntax and not semantic - string_to_int = 0x0020, // any time lexical cast from string to int is required - double_to_int = 0x0040, // any time a double is received for an int - int_overflow = 0x0080, // any time int value is greater than underlying type - signed_to_unsigned = 0x0100, // any time a negative value is read for an unsigned field - int_to_bool = 0x0200, // any time an int is read for a bool - string_to_bool = 0x0400, // any time a string is read for a bool - bad_array_index = 0x0800, // atempt to read a vector field beyond end of sequence - unexpected_key = 0x1000, // fields in object - missing_key = 0x2000, // check required fields - type_mismatch = 0x4000, // expected a fundamental, got object, expected object, got array, etc. - type_conversion = 0x8000, // also set any time a conversion occurs - all = 0xffff, - none = 0x0000 - }; - } // namespace errors - - /** - * Stores information about errors that occurred durring the parse. - * - * By default extra fields are 'ignored' as warning - * Loss of presision errors are warning. - * String to Int conversion warnings - * Double to Int - * Int to bool - * - */ - struct parse_error { - parse_error( int32_t ec, fc::string msg, char* s = 0, char* e = 0 ) - :message(fc::move(msg)),type(ec),start(s),end(e){} - - parse_error( parse_error&& m ) - :message(fc::move(m.message)),type(m.type),start(m.start),end(m.end){} - - fc::string message; - int32_t type; - char* start; - char* end; - }; - - /** - * Collects errors and manages how they are responded to. - */ - class error_collector { - public: - error_collector( error_collector&& e ) - :m_errors(fc::move(e.m_errors)){ - memcpy((char*)m_eclass,(char*)e.m_eclass, sizeof(m_eclass) ); - } - /* - error_collector( const error_collector&& e ) - :m_errors(e.m_errors){ - memcpy((char*)m_eclass,(char*)e.m_eclass, sizeof(m_eclass) ); - } - */ - ~error_collector() throw() { - try { - m_errors.clear(); - }catch(...){} - } - - enum error_defaults { - default_report = errors::all, - default_recover = errors::all, - default_throw = errors::none, - default_ignore = ~(default_report|default_recover|default_throw) - }; - - error_collector(){ - m_eclass[report_error_t] = default_report; - m_eclass[recover_error_t] = default_recover; - m_eclass[throw_error_t] = default_throw; - m_eclass[ignore_error_t] = default_ignore; - } - - inline bool report( int32_t e )const { - return 0 != (m_eclass[report_error_t] & e); - } - inline bool recover( int32_t e )const { - return 0 != (m_eclass[recover_error_t] & e); - } - inline bool ignore( int32_t e )const { - return 0 != (m_eclass[ignore_error_t] & e); - } - - void report_error( int32_t e ) { - m_eclass[report_error_t] |= e; - m_eclass[ignore_error_t] &= ~e; - } - void recover_error( int32_t e ) { - m_eclass[recover_error_t] |= e; - m_eclass[ignore_error_t] &= ~e; - } - void throw_error( int32_t e ) { - m_eclass[throw_error_t] |= e; - m_eclass[ignore_error_t] &= ~e; - } - void ignore_error( int32_t e ) { - m_eclass[ignore_error_t] |= e; - m_eclass[report_error_t] &= ~m_eclass[ignore_error_t]; - m_eclass[recover_error_t] &= ~m_eclass[ignore_error_t]; - m_eclass[throw_error_t] &= ~m_eclass[ignore_error_t]; - } - - void post_error( int32_t ec, fc::string msg, char* s = 0, char* e = 0 ) { - m_errors.push_back( parse_error( ec, fc::move(msg), s, e ) ); - if( ec & m_eclass[throw_error_t] ) { - throw fc::move(*this); - } - } - const fc::vector& get_errors()const { - return m_errors; - } - - private: - enum error_class { - ignore_error_t, - report_error_t, - recover_error_t, - throw_error_t, - num_error_classes - }; - uint32_t m_eclass[num_error_classes]; - fc::vector m_errors; - }; - fc::value to_value( char* start, char* end, error_collector& ec ); - - - - - - - - - - -namespace fc { namespace json { - fc::string escape_string( const fc::string& s ) { - // calculate escape string size. - uint32_t ecount = 0; - for( auto i = s.begin(); i != s.end(); ++i ) { - if( ' '<= *i && *i <= '~' && *i !='\\' && *i != '"' ) { - ecount+=1; - } else { - switch( *i ) { - case '\t' : - case '\n' : - case '\r' : - case '\\' : - case '"' : - ecount += 2; break; - default: - ecount += 4; - } - } - } - // unless the size changed, just return it. - if( ecount == s.size() ) { return s; } - - // reserve the bytes - fc::string out; out.reserve(ecount); - // print it out. - for( auto i = s.begin(); i != s.end(); ++i ) { - if( ' '<= *i && *i <= '~' && *i !='\\' && *i != '"' ) { - out += *i; - } else { - out += '\\'; - switch( *i ) { - case '\t' : out += 't'; break; - case '\n' : out += 'n'; break; - case '\r' : out += 'r'; break; - case '\\' : out += '\\'; break; - case '"' : out += '"'; break; - default: - out += "x"; - const char* const hexdig = "0123456789abcdef"; - out += hexdig[*i >> 4]; - out += hexdig[*i & 0xF]; - } - } - } - return out; - } - - fc::string unescape_string( const fc::string& s ) { - fc::string out; out.reserve(s.size()); - for( auto i = s.begin(); i != s.end(); ++i ) { - if( *i != '\\' ) { - if( *i != '"' ) out += *i; - } - else { - ++i; - if( i == out.end() ) return out; - switch( *i ) { - case 't' : out += '\t'; break; - case 'n' : out += '\n'; break; - case 'r' : out += '\r'; break; - case '\\' : out += '\\'; break; - case '"' : out += '"'; break; - case 'x' : { - ++i; if( i == out.end() ) return out; - char c = fc::from_hex(*i); - ++i; if( i == out.end() ) { out += c; return out; } - c = c<<4 | fc::from_hex(*i); - out += c; - break; - } - default: - out += '\\'; - out += *i; - } - } - } - return out; - } - - /** - * Any unescaped quotes are dropped. - * Because unescaped strings are always shorter, we can simply reuse - * the memory of s. - * - * @param s a null terminated string that contains one or more escape chars - */ - char* inplace_unescape_string( char* s ) { - while( *s == '"' ) ++s; - char* out = s; - - for( auto i = s; *i != '\0'; ++i ) { - if( *i != '\\' ) { - if( *i != '"' ) { - *out = *i; - ++out; - } - } - else { - ++i; - if( *i == '\0' ) { *out = '\0'; return s; } - switch( *i ) { - case 't' : *out = '\t'; ++out; break; - case 'n' : *out = '\n'; ++out; break; - case 'r' : *out = '\r'; ++out; break; - case '\\': *out = '\\'; ++out; break; - case '"' : *out = '"'; ++out; break; - case 'x' : { - ++i; if( *i == '\0' ){ *out = '\0'; return s; } - char c = fc::from_hex(*i); - ++i; if( *i == '\0' ){ *out = c; ++out; *out = '\0'; return s; } - c = c<<4 | fc::from_hex(*i); - *out = c; - ++out; - break; - } - default: - *out = '\\'; - ++out; - *out = *i; - ++out; - } - } - } - *out = '\0'; - return s; - } - } }// fc::json - -/** - * Ignores leading white space. - * If it starts with [,", or { reads until matching ],", or } - * If it starts with something else it reads until [{",}]: or whitespace only - * allowing a starting - or a single . - * - * @note internal json syntax errors are not caught, only bracket errors - * are caught by this method. This makes it easy for error recovery - * when values are read recursivley. - * - * @param in start of input - * @param end end of input - * @param oend output parameter to the end of the value - * - * @return a pointer to the start of the value - */ -char* read_value( char* in, char* end, char*& oend ) { - char* start = in; - char* oin = in; - // ignore leading whitespace - while( (in < end) && ((*in == ' ') || (*in == '\t') || (*in == '\n') || (*in == '\r')) ) { - ++in; - } - start = in; - if( start == end ) { - oend = end; - return start; - } - - bool found_dot = false; - // check for literal vs object, array or string - switch( *in ) { - case ':': - case ',': - case '=': - oend = in+1; - return start; - case '[': - case '{': - case '"': - break; - default: { // literal - // read until non-literal character - // allow it to start with - - // allow only one '.' - while( in != end ) { - switch( *in ) { - case '[': case ']': - case '{': case '}': - case ':': case '=': - case ',': case '"': - case ' ': case '\t': case '\n': case '\r': { - oend = in; - return start; - } - case '.': - if( found_dot ) { - oend = in; - return start; - } - found_dot = true; - break; - case '-': - if( in-start ){ oend = in; return start; } - } - ++in; - } - oend = in; - return start; - } - } // end literal check - - int depth = 0; - bool in_quote = false; - bool in_escape = false; - // read until closing ]} or " ignoring escaped " - while( in != end ) { - if( !in_quote ) { - switch( *in ) { - case '[': - case '{': ++depth; break; - case ']': - case '}': --depth; break; - case '"': - ++depth; - in_quote = true; - break; - default: // do nothing; - break; - } - } else { // in quote - switch( *in ) { - case '"': if( !in_escape ) { - --depth; - in_quote = false; - break; - } - case '\\': - in_escape = !in_escape; - break; - default: - in_escape = false; - } - } - ++in; - if( !depth ) { oend = in; return start; } - } - if( depth != 0 ) { - // TODO: Throw Parse Error! - elog("Parse Error!! '%s' size: %d", fc::string( oin, end ).c_str(), (oin-start)); - } - oend = in; return start; -} - -struct temp_set { - temp_set( char* v, char t ) - :old(*v),val(v) { *val = t; } - ~temp_set() { *val = old; } - char old; - char* val; -}; - -/** - * A,B,C - * Warn on extra ',' or missing ',' - */ -void read_values( fc::value::array& a, char* in, char* end, error_collector& ec ) { - if( in >= end ) return; - char* ve = 0; - char* v = read_value( in, end, ve ); - while( *v == ',' ) { - wlog( "unexpected ','"); - v = read_value( ve, end, ve ); - } - if( v == ve ) return; // no values - - { temp_set temp(ve,'\0'); a.push_back( to_value( v, ve, ec ) ); } - - char* c; - char* ce = 0; - do { // expect comma + value | '' - - // expect comma or '' - c = read_value( ve, end, ce ); - - // '' means we are done, no errors - if( c == ce ) return; - - if( *c != ',' ) // we got a value when expecting ',' - { - wlog( "missing ," ); - temp_set temp(ce,'\0'); a.push_back( to_value(c, ce, ec) ); - ve = ce; - continue; // start back at start - } - - // expect value - v = read_value( ce, end, ve ); - while ( *v == ',' ) { // but got comma - // expect value - wlog( "extra comma at c->ce" ); - c = v; ce = ve; - v = read_value( ve, end, ve ); - } - if( v == ve ) { - wlog( "trailing comma at c->ce" ); - } else { // got value - temp_set temp(ve,'\0'); - a.push_back( to_value( v, ve, ec) ); - } - } while( ve < end );// expect comma + value | '' -} - - -/** - * Reads one level deep, does not recruse into sub objects. - */ -char* read_key_val( std::map& obj, bool sc, char* in, char* end, error_collector& ec ) { - char* name_end = 0; - char* name = in; - do { - // read first char - name = read_value( name, end, name_end ); - if( sc ) { // if we expect a , - if( *name != ',' ) { // but didn't get one - wlog( "expected ',' but got %1%", name ); // warn and accept name - } else { // we got the exepcted , read the expected name - name = read_value( name_end, end, name_end ); - } - } else { // don't start with ',' - while( *name == ',' ) { // while we don't have a name, keep looking - wlog( "unexpected ',' " ); - name = read_value( name_end, end, name_end ); - } - } - } while( *name == ',' ); - - - // now we should have a name. - if( name_end >= end -1 ) { - temp_set ntemp(name_end,'\0'); - elog( "early end after reading name %1%", name ); - return name_end; - } - if( *name != '"' ) { - temp_set ntemp(name_end,'\0'); - wlog( "unquoted name '%1%'", name ); - } else { - temp_set ntemp(name_end,'\0'); - name = fc::json::inplace_unescape_string(name); - } - - char* col_end = 0; - char* col = read_value( name_end, end, col_end ); - - char* val_end = 0; - char* val = 0; - - bool sep_error = false; - if( col_end-col == 1 ) { - switch( *col ) { - case ':': break; - case ';': - case '=': - wlog( "found %1% instead of ':'", *col ); - break; - default: - sep_error = true; - } - } else { - sep_error = true; - } - - if( sep_error ) { - temp_set ntemp(name_end,'\0'); - temp_set vtemp(col_end,'\0'); - wlog( "expected ':' but got %1%", col ); - wlog( "assuming this is the value... " ); - val = col; - val_end = col_end; - } else { - if( name_end >= end -1 ) { - temp_set ntemp(name_end,'\0'); - temp_set vtemp(col_end,'\0'); - elog( "early end after reading name '%1%' and col '%2%'", name, col ); - return name_end; - } - val = read_value( col_end, end, val_end ); - if( val == end ) { - wlog( "no value specified" ); - } - } - temp_set ntemp(name_end,'\0'); - temp_set vtemp(val_end,'\0'); - //slog( "name: '%1%'", fc::string(name,name_end) ); - obj[name] = std::vector(val,val_end); -// obj.fields.push_back( key_val( name, to_value( val, val_end, ec ) ) ); - return val_end; -} - - - - - -/** - * Reads an optional ',' followed by key : value, returning the next input position - * @param sc - start with ',' - */ -char* read_key_val( fc::value::object& obj, bool sc, char* in, char* end, error_collector& ec ) { - char* name_end = 0; - char* name = in; - do { - // read first char - name = read_value( name, end, name_end ); - if( name == name_end ) - return name; - if( sc ) { // if we expect a , - if( *name != ',' ) { // but didn't get one - if( *name != '}' ) - wlog( "expected ',' or '}' but got '%s'", name ); // warn and accept name - } else { // we got the exepcted , read the expected name - name = read_value( name_end, end, name_end ); - } - } else { // don't start with ',' - while( *name == ',' ) { // while we don't have a name, keep looking - wlog( "unexpected ',' " ); - name = read_value( name_end, end, name_end ); - } - } - } while( *name == ',' ); - - - // now we should have a name. - if( name_end >= end -1 ) { - temp_set ntemp(name_end,'\0'); - elog( "early end after reading name '%s'", name ); - return name_end; - } - if( *name != '"' ) { - temp_set ntemp(name_end,'\0'); - wlog( "unquoted name '%1%'", name ); - } else { - temp_set ntemp(name_end,'\0'); - name = fc::json::inplace_unescape_string(name); - } - - char* col_end = 0; - char* col = read_value( name_end, end, col_end ); - - char* val_end = 0; - char* val = 0; - - bool sep_error = false; - if( col_end-col == 1 ) { - switch( *col ) { - case ':': break; - case ';': - case '=': - wlog( "found %1% instead of ':'", *col ); - break; - default: - sep_error = true; - } - } else { - sep_error = true; - } - - if( sep_error ) { - temp_set ntemp(name_end,'\0'); - temp_set vtemp(col_end,'\0'); - wlog( "expected ':' but got %1%", col ); - wlog( "assuming this is the value... " ); - val = col; - val_end = col_end; - } else { - if( name_end >= end -1 ) { - temp_set ntemp(name_end,'\0'); - temp_set vtemp(col_end,'\0'); - elog( "early end after reading name '%1%' and col '%2%'", name, col ); - return name_end; - } - val = read_value( col_end, end, val_end ); - if( val == end ) { - wlog( "no value specified" ); - } - } - temp_set ntemp(name_end,'\0'); - temp_set vtemp(val_end,'\0'); - obj.fields.push_back( fc::value::key_val( name, to_value( val, val_end, ec ) ) ); - return val_end; -} - -// first_key =:: '' | "name" : VALUE *list_key -// list_key '' | ',' "name" : VALUE -void read_key_vals( fc::value::object& obj, char* in, char* end, error_collector& ec ) { - bool ex_c = false; - char* kv_end = in; - do { - //slog( "%1% bytes to read", (end-kv_end) ); - kv_end = read_key_val( obj, ex_c, kv_end, end, ec ); - ex_c = true; - } while( kv_end < end ); -} -// first_key =:: '' | "name" : VALUE *list_key -// list_key '' | ',' "name" : VALUE -std::map read_key_vals( char* in, char* end, error_collector& ec ) { - std::map m; - bool ex_c = false; - char* kv_end = in; - do { - //slog( "%1% bytes to read", (end-kv_end) ); - kv_end = read_key_val( m, ex_c, kv_end, end, ec ); - ex_c = true; - } while( kv_end < end ); - return m; -} - - - -/** - * @brief adaptor for to_value( char*, char*, error_collector& ) - */ -fc::value to_value( fc::vector&& v, error_collector& ec ) { - if( v.size() == 0 ) return fc::value(); - return to_value( v.data(), v.data() + v.size(), ec ); -} - -/** - * Returns a fc::value containing from the json string. - * - * @param ec - determines how to respond to parse errors and logs - * any errors that occur while parsing the string. - */ -fc::value to_value( char* start, char* end, error_collector& ec ) { - if( start == end ) return fc::value(); - - char* ve = 0; - char* s = read_value( start, end, ve ); - //slog( "'%1%'", fc::string(start,ve) ); - switch( s[0] ) { - case '[': { - fc::value::array a; - read_values( a, s+1, ve -1, ec ); - return a; - } - case '{': { - fc::value::object o; - read_key_vals( o, s+1, ve -1, ec ); - fc::value v = fc::move(o); - return v; - } - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': { - temp_set move_end(ve,'\0'); - for( char* n = s+1; n != ve; ++n ) { - if( *n == '.' ) { - return fc::lexical_cast(s); - } - } - return fc::lexical_cast(s); - } - case '-': { - temp_set move_end(ve,'\0'); - for( char* n = s+1; n != ve; ++n ) { - if( *n == '.' ) { - return fc::lexical_cast(s); - } - } - return fc::lexical_cast(s); - } - case '.': { - temp_set move_end(ve,'\0'); - return fc::lexical_cast(s); - } - case '\"': { - temp_set move_end(ve,'\0'); - return fc::json::inplace_unescape_string( s ); - } - case 'n': { - temp_set move_end(ve,'\0'); - if( strcmp(s,"null" ) == 0) return fc::value(); - } - case 't': { - temp_set move_end(ve,'\0'); - if( strcmp(s,"true" ) == 0) return true; - } - case 'f': { - temp_set move_end(ve,'\0'); - if( strcmp(s,"false" ) == 0) return false; - } - - default: - wlog( "return unable to parse... return as string '%s'", fc::string(s,ve).c_str() ); - return fc::value( fc::string( s, ve) ); - } -} -namespace fc { namespace json { - -fc::string pretty_print( const fc::string& v, uint8_t indent ) { - int level = 0; - fc::stringstream ss; - bool first = false; - bool quote = false; - bool escape = false; - for( uint32_t i = 0; i < v.size(); ++i ) { - switch( v[i] ) { - case '\\': - if( !escape ) { - if( quote ) - escape = true; - } else { escape = false; } - ss<&& v, uint8_t indent ) { - int level = 0; - fc::stringstream ss; - bool first = false; - bool quote = false; - bool escape = false; - for( uint32_t i = 0; i < v.size(); ++i ) { - switch( v[i] ) { - case '\\': - if( !escape ) { - if( quote ) - escape = true; - } else { escape = false; } - ss< - struct value_visitor : value::const_visitor { - value_visitor( Stream& s ):os(s){} - Stream& os; - virtual void operator()( const int8_t& v ){ os << v; } - virtual void operator()( const int16_t& v ){ os << v; } - virtual void operator()( const int32_t& v ){ os << v; } - virtual void operator()( const int64_t& v ){ os << v; } - virtual void operator()( const uint8_t& v ){ os << v; } - virtual void operator()( const uint16_t& v ){ os << v; } - virtual void operator()( const uint32_t& v ){ os << v; } - virtual void operator()( const uint64_t& v ){ os << v; } - virtual void operator()( const float& v ){ os << v; } - virtual void operator()( const double& v ){ os << v; } - virtual void operator()( const bool& v ){ os << (v ? "true" : "false"); } - virtual void operator()( const fc::string& v ){ os << '"' << fc::json::escape_string(v) <<'"'; } - virtual void operator()( const fc::value::object& o ){ - os << '{'; - for( uint32_t i = 0; i < o.fields.size(); ++i ) { - if( i ) os <<','; - (*this)( o.fields[i].key ); - os<<':'; - o.fields[i].val.visit( value_visitor(*this) ); - } - os << '}'; - } - virtual void operator()( const value::array& o ){ - os << '['; - for( auto i = o.begin(); i != o.end(); ++i ) { - if( i != o.begin() ) os <<','; - i->visit( value_visitor(*this) ); - } - os << ']'; - } - virtual void operator()( ){ os << "null"; } - }; - - template - void to_json( const fc::value& v, Stream& os ) { - v.visit( value_visitor(os) ); - } - - void write( ostream& out, const value& val ) { - to_json( val, out ); - } - - fc::string to_string( const fc::value& v ) { - fc::stringstream ss; - to_json( v, ss ); - return ss.str(); - } - - fc::string to_pretty_string( const fc::value& v ) { - return pretty_print( to_string(v), 4 ); - } - - value from_file( const fc::path& local_path ) { - if( !exists(local_path) ) { - FC_THROW_REPORT( "Source file ${filename} does not exist", value().set("filename",local_path.string()) ); - } - if( is_directory( local_path ) ) { - FC_THROW_REPORT( "Source path ${path} is a directory; a file was expected", - value().set("path",local_path.string()) ); - } - try { - // memory map the file - size_t fsize = static_cast(file_size(local_path)); - if( fsize == 0 ) { return value(); } - file_mapping fmap( local_path.string().c_str(), read_only ); - - - mapped_region mr( fmap, fc::read_only, 0, fsize ); - - const char* pos = reinterpret_cast(mr.get_address()); - const char* end = pos + fsize; - - // TODO: implement a const version of to_value - fc::vector tmp(pos,end); - - error_collector ec; - return to_value(tmp.data(), tmp.data()+fsize,ec); - } catch ( ... ) { - FC_THROW_REPORT( "Error loading JSON object from file '${path}'", - fc::value().set( "file", local_path ) - .set( "exception", fc::except_str() ) - ); - } - } - - value from_string( const fc::string& s ) { - std::vector v(s.begin(),s.end()); - //slog( "from_string( '%s' )", s.c_str() ); - return from_string( v.data(), v.data()+v.size() ); - } - value from_string( fc::vector&& v ) { - error_collector ec; - return to_value( v.data(), v.data() + v.size(), ec ); - } - - value from_string( const char* s, const char* e ) { - return from_string( fc::vector(s,e) ); - } - -} } diff --git a/src/json_rpc_connection.cpp b/src/json_rpc_connection.cpp deleted file mode 100644 index 4f96cba..0000000 --- a/src/json_rpc_connection.cpp +++ /dev/null @@ -1,167 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -namespace fc { namespace json { - - namespace detail { - - void pending_result::handle_error( const fc::string& e ) { - try { - FC_THROW_MSG( "%s", e ); - } catch ( ... ) { - set_exception( fc::current_exception() ); - } - } - - } - - class rpc_connection::impl : public fc::retainable { - public: - impl():_next_req_id(0){ } - ~impl(){ cancel_pending_requests(); } - int64_t _next_req_id; - std::unordered_map _methods; - - detail::pending_result::ptr _pr_head; - detail::pending_result::ptr _pr_tail; - - void cancel_pending_requests() { - auto cur = _pr_head; - while( cur ) { - cur->set_exception( fc::copy_exception( fc::generic_exception("canceled") ) ); - cur = cur->next; - } - _pr_head.reset(); - _pr_tail.reset(); - } - }; - - - void rpc_connection::add_method( const fc::string& name, fc::shared_ptr&& p ) { - my->_methods[name] = fc::move(p); - } - void rpc_connection::handle_message( const value& v ) { - auto id_itr = v.find( "id" ); - auto m_itr = v.find( "method" ); - auto end = v.end(); - - if( m_itr != end ) { - fc::string mname = value_cast(m_itr->val); - - auto smeth = my->_methods.find( mname ); - if( smeth == my->_methods.end() ) { - if( id_itr != end ) { - // TODO: send invalid method reply - auto id = value_cast(id_itr->val); - send_error( id, fc::json::error_object( "Unknown method '"+mname+"'" )); - } - // nothing to do, unknown method - } else { // known method, attempt to call it and send reply; - auto p_itr = v.find( "params" ); - - value nul; - const value& params = (p_itr != end) ? p_itr->val : nul; - // slog( "params '%s'", to_string( params ).c_str() ); - - if( id_itr != end ) { // capture reply - auto id = value_cast(id_itr->val); - try { - send_result( id, smeth->second->call(params) ); - } catch ( fc::error_report& eo ) { - if( eo.stack.size() ) { - send_error( id, error_object( eo.current().desc, fc::value(eo) ) ); - } else { - send_error( id, error_object( "error report", fc::value(eo) ) ); - } - } catch ( const fc::json::error_object& eo ) { - wlog( "%s", eo.message.c_str() ); - send_error( id, eo ); - } catch ( ... ) { - wlog( "%s", fc::except_str().c_str() ); - send_error( id, error_object( fc::except_str(), fc::value() ) ); - } - } else { // ignore exception + result - try { smeth->second->call( params ); }catch(...){} - } - } - return; - } else if( id_itr != end ) { // we id but no method, therefore potential reply - int id = value_cast(id_itr->val); - auto cur = my->_pr_head; - decltype(cur) prev; - while( cur ) { - if( cur->id == id ) { - if( prev ) prev->next = cur->next; - else my->_pr_head = cur->next; - if( !cur->next ) my->_pr_tail = cur->next; - - try { - auto r_itr = v.find( "result" ); - if( r_itr != end ) { - cur->handle_result( r_itr->val ); - } else { - auto e_itr = v.find( "error" ); - if( e_itr != end ) { - cur->set_exception( fc::value_cast(e_itr->val["data"]).copy_exception() ); - } else { - elog( "no result nor error field" ); - } - } - } catch( ... ) { - cur->set_exception( fc::current_exception() ); - } - return; - } - cur = cur->next; - } - FC_THROW_REPORT( "Unexpected reply with id ${id}", id_itr->val ); - } - FC_THROW_REPORT( "Method with no 'id' or 'method' field" ); - } - - - rpc_connection::rpc_connection() - :my( new impl() ){ } - - rpc_connection::rpc_connection( const rpc_connection& c ) - :my(c.my){ } - rpc_connection::rpc_connection( rpc_connection&& c ) { - fc_swap(my,c.my); - } - rpc_connection::~rpc_connection() { - } - - rpc_connection& rpc_connection::operator=(const rpc_connection& m) { - my= m.my; - return *this; - } - rpc_connection& rpc_connection::operator=(rpc_connection&& m) { - fc_swap(m.my,my); - return *this; - } - - void rpc_connection::cancel_pending_requests() { - my->cancel_pending_requests(); - } - - void rpc_connection::invoke( detail::pending_result::ptr&& p, - const fc::string& m, value&& param ) { - p->id = my->_next_req_id; - if( my->_pr_tail ) { - my->_pr_tail->next = p; - my->_pr_tail = my->_pr_tail->next; - } else { - my->_pr_tail = p; - my->_pr_head = my->_pr_tail; - } - send_invoke( my->_next_req_id++, m, fc::move(param) ); - } - - -} } // fc::json diff --git a/src/json_rpc_error_object.cpp b/src/json_rpc_error_object.cpp deleted file mode 100644 index 0c6a189..0000000 --- a/src/json_rpc_error_object.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include - - -namespace fc { namespace json { - error_object::error_object( const fc::string& m, const fc::value& v, int64_t c ) - :code(c),message(m),data(v){ } - error_object::error_object(const fc::string& m, int64_t c) - :code(c),message(m){ } - error_object::error_object(const error_object& e) - :code(e.code),message(e.message),data(e.data){} - error_object::~error_object(){} -}} diff --git a/src/json_rpc_stream_connection.cpp b/src/json_rpc_stream_connection.cpp deleted file mode 100644 index e00d11a..0000000 --- a/src/json_rpc_stream_connection.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -namespace fc { namespace json { - - class rpc_stream_connection::impl : public fc::retainable { - public: - fc::istream& in; - fc::ostream& out; - rpc_stream_connection& self; - std::function on_close; - - fc::logger log; - - impl( fc::istream& i, fc::ostream& o, rpc_stream_connection& s ) - :in(i),out(o),self(s){ - _read_loop_complete = fc::async( [=](){ read_loop(); } ); - log = logger::get( "fc::json::rpc_stream_connection" ); - } - - ~impl() { - try { - self.cancel_pending_requests(); - _read_loop_complete.cancel(); - _read_loop_complete.wait(); - } catch ( ... ) {} - } - - fc::future _read_loop_complete; - void read_loop() { - try { - fc::string line; - fc::getline( in, line ); - while( !in.eof() ) { - fc::async( [=]() { - try { - fc_dlog( log, "Received: '${line}'", ("line",line) ); - fc::value v= fc::json::from_string( line ); - self.handle_message(v); - } catch ( fc::error_report& er ) { - fc_wlog( log, "Error handling request '${line}'\n ${report}", ("line",line)("report",er.to_detail_string() ) ); - } catch (...) { - fc_wlog( log, "Error handling request '${exception}'",("exception",fc::except_str()) ); - return; - } - }); - fc::getline( in, line ); - } - } catch ( ... ) { - wlog( "%s", fc::except_str().c_str() ); - } - // slog( "cancel..."); - self.cancel_pending_requests(); - // slog( "close!" ); - if( !!on_close ) on_close(); - } - }; - - rpc_stream_connection::rpc_stream_connection( fc::istream& i, fc::ostream& o ) - :my( new impl(i,o,*this) ){ - } - rpc_stream_connection::rpc_stream_connection(){ } - rpc_stream_connection::rpc_stream_connection(const rpc_stream_connection& c):my(c.my){ } - rpc_stream_connection::~rpc_stream_connection(){ - close(); - } - - // the life of the streams must exceed the life of all copies - // of this rpc_stream_connection - void rpc_stream_connection::open( fc::istream& i, fc::ostream& o) { - my.reset( new impl(i,o,*this) ); - } - - // cancels all pending requests, closes the ostream - // results on_close() being called if the stream is not already closed. - void rpc_stream_connection::close() { - if( my ) my->out.close(); - my.reset(nullptr); - } - - /** - * When the connection is closed, call the given method - */ - void rpc_stream_connection::on_close( const std::function& oc ) { - my->on_close = oc; - } - - void rpc_stream_connection::send_invoke( uint64_t id, const fc::string& m, value&& param ) { - fc::stringstream ss; - ss<<"{\"id\":"<log, "Sent: '${line}'", ("line",o) ); - my->out.write( o.c_str(), o.size() ); - my->out.flush(); - } - void rpc_stream_connection::send_notice( const fc::string& m, value&& param ) { - fc::stringstream ss; - ss<<"{\"method\":\""<log, "Sent: '${line}'", ("line",o) ); - my->out.write( o.c_str(), o.size() ); - my->out.flush(); - } - void rpc_stream_connection::send_error( uint64_t id, const json::error_object& eo ) { - fc::stringstream ss; - ss<<"{\"id\":"<log, "Sent: '${line}'", ("line",o) ); - my->out.write( o.c_str(), o.size() ); - my->out.flush(); - } - void rpc_stream_connection::send_result( uint64_t id, value&& r ) { - fc::stringstream ss; - ss<<"{\"id\":"<log, "Sent: '${line}'", ("line",o) ); - my->out.write( o.c_str(), o.size() ); - my->out.flush(); - } - -} } // fc::json - - - diff --git a/src/json_rpc_tcp_connection.cpp b/src/json_rpc_tcp_connection.cpp deleted file mode 100644 index 52dfee9..0000000 --- a/src/json_rpc_tcp_connection.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include - -namespace fc { - - namespace json { - class rpc_tcp_connection::impl : public fc::retainable { - public: - tcp_socket sock; - ~impl(){ } - }; - - rpc_tcp_connection::rpc_tcp_connection() - :my( new impl() ){ - } - rpc_tcp_connection::rpc_tcp_connection( const rpc_tcp_connection& c ) - :rpc_stream_connection(c),my(c.my){} - - rpc_tcp_connection::~rpc_tcp_connection(){ - close(); - } - - void rpc_tcp_connection::connect_to( const fc::ip::endpoint& ep ) { - my->sock.connect_to(ep); - open( my->sock, my->sock ); - } - void rpc_tcp_connection::start() { - open( my->sock, my->sock ); - } - void rpc_tcp_connection::close() { - rpc_stream_connection::close(); - //my->sock.close(); - } - - tcp_socket& rpc_tcp_connection::get_socket()const { return my->sock; } - - - } - -} diff --git a/src/json_rpc_tcp_server.cpp b/src/json_rpc_tcp_server.cpp deleted file mode 100644 index f5e6d39..0000000 --- a/src/json_rpc_tcp_server.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -#include -#include - -namespace fc { - namespace json { - class rpc_tcp_server::impl { - public: - std::function on_con; - fc::tcp_server tcp_serv; - fc::vector cons; - }; - rpc_tcp_server::rpc_tcp_server() - :my( new impl() ){} - rpc_tcp_server::~rpc_tcp_server() { - delete my; - } - - void rpc_tcp_server::on_new_connection( const std::function& c ) { - my->on_con = c; - } - - void rpc_tcp_server::listen( uint16_t port ) { - - my->tcp_serv.listen(port); - fc::async([this](){ - try { - rpc_tcp_connection::ptr con(new rpc_tcp_connection() ); - while( my->tcp_serv.accept( con->get_socket() ) ) { - slog( "new connection!" ); - my->on_con( *con ); - con->start(); - rpc_tcp_connection* tcpc = con.get(); - my->cons.push_back(con); - con->on_close( [=]() { - for( int i = 0; i < my->cons.size(); ++i ) { - if( my->cons[i].get() == tcpc ) { - fc_swap( my->cons[i], my->cons.back() ); - auto tmp = my->cons.back(); - my->cons.pop_back(); - fc::async([tmp](){slog("free con");}); - // TODO: swap to end, pop back - return; - } - } - }); - con.reset(new rpc_tcp_connection() ); - } - } catch ( ... ) { - wlog( "tcp listen failed..." ); - } - }); - } - - - } -} diff --git a/src/lexical_cast.cpp b/src/lexical_cast.cpp deleted file mode 100644 index 142e200..0000000 --- a/src/lexical_cast.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -namespace fc { - - namespace detail { - double to_double( const fc::string& s ) { - return boost::lexical_cast(s.c_str()); - } - int64_t to_int64( const fc::string& s ) { - return boost::lexical_cast(s.c_str()); - } - uint64_t to_uint64( const fc::string& s ) { - return boost::lexical_cast(s.c_str()); - } - fc::string to_string( double d ){ return boost::lexical_cast(d); } - #ifdef __APPLE__ - fc::string to_string( size_t d ){ return boost::lexical_cast(d); } - #endif - fc::string to_string( uint64_t d ){ return boost::lexical_cast(d); } - fc::string to_string( uint32_t d ){ return boost::lexical_cast(d); } - fc::string to_string( uint16_t d ){ return boost::lexical_cast(d); } - fc::string to_string( uint8_t d ){ return boost::lexical_cast(d); } - fc::string to_string( int64_t d ){ return boost::lexical_cast(d); } - fc::string to_string( int32_t d ){ return boost::lexical_cast(d); } - fc::string to_string( int16_t d ){ return boost::lexical_cast(d); } - fc::string to_string( int8_t d ){ return boost::lexical_cast(d); } - fc::string to_string( char d ){ return boost::lexical_cast(d); } - } -} diff --git a/src/log.cpp b/src/log.cpp deleted file mode 100644 index fa10025..0000000 --- a/src/log.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include -#include -#include -#include -#include -#ifndef WIN32 -#include -#endif - -#include -#include - -namespace fc { - const char* thread_name(); - void* thread_ptr(); - - const char* short_name( const char* file_name ) { - const char* end = file_name + strlen(file_name); - --end; - while( end >= file_name ) { - if( *end == '/' || *end == '\\' ) { - return end + 1; - } - --end; - } - return file_name; - } - boost::mutex& log_mutex() { - static boost::mutex* m = new boost::mutex(); return *m; - } - - #ifdef WIN32 - #define isatty _isatty - #define fileno _fileno - #endif // WIN32 - - void log( const char* color, const char* file_name, size_t line_num, - const char* method_name, const char* format, ... ) { - #ifndef WIN32 - if(isatty(fileno(stderr))) - fprintf( stderr, "\r%s",color); - #endif - fc::unique_lock lock(log_mutex()); - // fc::string sname = fc::path(file_name).filename().generic_string(); - fprintf( stderr, "%-15s %-15s %-5d %-15s ", thread_name(), short_name(file_name), int(line_num), method_name ); - va_list args; - va_start(args,format); - vfprintf( stderr, format, args ); - va_end(args); - #ifndef WIN32 - if (isatty(fileno(stderr))) - fprintf( stderr, "%s", CONSOLE_DEFAULT ); - #endif - fprintf( stderr, "\n" ); - fflush( stderr ); - return; - } - - /** used to add extra fields to be printed (thread,fiber,time,etc) */ - void add_log_field( void (*f)( ) ) { - } - - void remove_log_field( void (*f)( ) ) { - } -} diff --git a/src/appender.cpp b/src/log/appender.cpp similarity index 59% rename from src/appender.cpp rename to src/log/appender.cpp index 6140479..737625c 100644 --- a/src/appender.cpp +++ b/src/log/appender.cpp @@ -1,14 +1,14 @@ -#include -#include -#include -#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include "console_defines.h" namespace fc { @@ -22,6 +22,8 @@ namespace fc { return lm; } appender::ptr appender::get( const fc::string& s ) { + static fc::spin_lock appender_spinlock; + scoped_lock lock(appender_spinlock); return get_appender_map()[s]; } bool appender::register_appender( const fc::string& type, const appender_factory::ptr& f ) @@ -29,11 +31,11 @@ namespace fc { get_appender_factory_map()[type] = f; return true; } - appender::ptr appender::create( const fc::string& name, const fc::string& type, const value& args ) + appender::ptr appender::create( const fc::string& name, const fc::string& type, const variant& args ) { auto fact_itr = get_appender_factory_map().find(type); if( fact_itr == get_appender_factory_map().end() ) { - wlog( "Unknown appender type '%s'", type.c_str() ); + //wlog( "Unknown appender type '%s'", type.c_str() ); return appender::ptr(); } auto ap = fact_itr->second->create( args ); @@ -41,4 +43,6 @@ namespace fc { return ap; } + static bool reg_console_appender = appender::register_appender( "console" ); + static bool reg_file_appender = appender::register_appender( "file" ); } // namespace fc diff --git a/src/log/console_appender.cpp b/src/log/console_appender.cpp new file mode 100644 index 0000000..31341f3 --- /dev/null +++ b/src/log/console_appender.cpp @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#endif +#include +#define COLOR_CONSOLE 1 +#include "console_defines.h" +#include +#include + +namespace fc { + console_appender::console_appender( const variant& args ) + { + try + { + cfg = args.as();//fc::variant_cast(args); + for( int i = 0; i < log_level::off+1; ++i ) + lc[i] = color::console_default; + for( auto itr = cfg.level_colors.begin(); itr != cfg.level_colors.end(); ++itr ) + lc[itr->level] = itr->color; + } + catch ( exception& e ) + { + fc::cerr< lock(log_mutex()); + #ifndef WIN32 + if(isatty(fileno(out))) fprintf( out, "\r%s", get_color( m.get_context().get_log_level() ) ); + #endif + + fprintf( out, "%s", fmt_str.c_str() ); + + #ifndef WIN32 + if(isatty(fileno(out))) fprintf( out, "\r%s", CONSOLE_DEFAULT ); + #endif + fprintf( out, "\n" ); + if( cfg.flush ) fflush( out ); + } + +} diff --git a/include/fc/console_defines.h b/src/log/console_defines.h similarity index 100% rename from include/fc/console_defines.h rename to src/log/console_defines.h diff --git a/src/file_appender.cpp b/src/log/file_appender.cpp similarity index 54% rename from src/file_appender.cpp rename to src/log/file_appender.cpp index 7e9b6ad..b30ec3b 100644 --- a/src/file_appender.cpp +++ b/src/log/file_appender.cpp @@ -1,10 +1,11 @@ -#include +#include #include -#include +#include #include -#include -#include -#include +#include +#include +#include + namespace fc { class file_appender::impl : public fc::retainable { @@ -14,27 +15,27 @@ namespace fc { boost::mutex slock; }; file_appender::config::config( const fc::path& p ) - :format( "${when} ${thread} ${context} ${file}:${line} ${method} ${level}] ${message}" ), + :format( "${timestamp} ${thread_name} ${context} ${file}:${line} ${method} ${level}] ${message}" ), filename(p),flush(true),truncate(true){} - file_appender::file_appender( const value& args ) + file_appender::file_appender( const variant& args ) :my( new impl() ) { try { - my->cfg = fc::value_cast(args); + my->cfg = args.as(); my->out.open( my->cfg.filename.string().c_str() ); } catch ( ... ) { - elog( "%s", fc::except_str().c_str() ); + //elog( "%s", fc::except_str().c_str() ); } } file_appender::~file_appender(){} void file_appender::log( const log_message& m ) { - fc::string message = fc::substitute( m.format, m.args ); - fc::value lmsg(m); + fc::string message = fc::format_string( m.get_format(), m.get_data() ); + fc::variant lmsg(m); - fc::string fmt_str = fc::substitute( my->cfg.format, value(m).set( "message", message) ); + fc::string fmt_str = fc::format_string( my->cfg.format, mutable_variant_object(lmsg.get_object())( "message", message) ); { fc::scoped_lock lock(my->slock); my->out << fmt_str << "\n"; diff --git a/src/log/log_message.cpp b/src/log/log_message.cpp new file mode 100644 index 0000000..42e9491 --- /dev/null +++ b/src/log/log_message.cpp @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fc +{ + namespace detail + { + class log_context_impl + { + public: + log_level level; + string file; + uint64_t line; + string method; + string thread_name; + string hostname; + string context; + time_point timestamp; + }; + + class log_message_impl + { + public: + log_message_impl( log_context&& ctx ) + :context( std::move(ctx) ){} + log_message_impl(){} + + log_context context; + string format; + variant_object args; + }; + } + + + + log_context::log_context() + :my( std::make_shared() ){} + + log_context::log_context( log_level ll, const char* file, uint64_t line, + const char* method ) + :my( std::make_shared() ) + { + my->level = ll; + my->file = fc::path(file).filename().generic_string(); // TODO truncate filename + my->line = line; + my->method = method; + my->timestamp = time_point::now(); + my->thread_name = fc::thread::current().name(); + } + + log_context::log_context( const variant& v ) + :my( std::make_shared() ) + { + auto obj = v.get_object(); + my->level = obj["level"].as(); + my->file = obj["file"].as_string(); + my->line = obj["line"].as_uint64(); + my->method = obj["method"].as_string(); + my->method = obj["hostname"].as_string(); + my->thread_name = obj["thread_name"].as_string(); + my->timestamp = obj["timestamp"].as(); + if( obj.contains( "context" ) ) + my->context = obj["context"].as(); + } + + fc::string log_context::to_string()const + { + return my->thread_name + " " + my->file + ":" + fc::to_string(my->line) + " " + my->method; + + } + + void log_context::append_context( const fc::string& s ) + { + my->context += "->" + s; + } + + log_context::~log_context(){} + + + void to_variant( const log_context& l, variant& v ) + { + v = l.to_variant(); + } + + void from_variant( const variant& l, log_context& c ) + { + c = log_context(l); + } + + void from_variant( const variant& l, log_message& c ) + { + c = log_message(l); + } + void to_variant( const log_message& m, variant& v ) + { + v = m.to_variant(); + } + + void to_variant( log_level e, variant& v ) + { + switch( e ) + { + case log_level::all: + v = "all"; + return; + case log_level::debug: + v = "debug"; + return; + case log_level::info: + v = "info"; + return; + case log_level::warn: + v = "warn"; + return; + case log_level::error: + v = "error"; + return; + case log_level::off: + v = "off"; + return; + } + } + void from_variant( const variant& v, log_level& e ) + { + try + { + if( v.as_string() == "all" ) e = log_level::all; + else if( v.as_string() == "debug" ) e = log_level::debug; + else if( v.as_string() == "info" ) e = log_level::info; + else if( v.as_string() == "warn" ) e = log_level::warn; + else if( v.as_string() == "error" ) e = log_level::error; + else if( v.as_string() == "off" ) e = log_level::off; + else FC_THROW_EXCEPTION( bad_cast_exception, "Failed to cast from Variant to log_level" ); + } FC_RETHROW_EXCEPTIONS( error, + "Expected 'all|debug|info|warn|error|off', but got '${variant}'", + ("variant",v) ); + } + + + + string log_context::get_file()const { return my->file; } + uint64_t log_context::get_line_number()const { return my->line; } + string log_context::get_method()const { return my->method; } + string log_context::get_thread_name()const { return my->thread_name; } + string log_context::get_host_name()const { return my->hostname; } + time_point log_context::get_timestamp()const { return my->timestamp; } + log_level log_context::get_log_level()const{ return my->level; } + + + variant log_context::to_variant()const + { + mutable_variant_object o; + o( "level", variant(my->level) ) + ( "file", my->file ) + ( "line", my->line ) + ( "method", my->method ) + ( "hostname", my->hostname ) + ( "thread_name", my->thread_name ) + ( "timestamp", variant(my->timestamp) ); + + if( my->context.size() ) + o( "context", my->context ); + + return o; + } + + log_message::~log_message(){} + log_message::log_message() + :my( std::make_shared() ){} + + log_message::log_message( log_context ctx, const char* format, variant_object args ) + :my( std::make_shared(std::move(ctx)) ) + { + my->format = format; + my->args = std::move(args); + } + + log_message::log_message( const variant& v ) + :my( std::make_shared( log_context( v.get_object()["context"] ) ) ) + { + my->format = v.get_object()["format"].as_string(); + my->args = v.get_object()["data"].get_object(); + } + + variant log_message::to_variant()const + { + return mutable_variant_object( "context", my->context ) + ( "format", my->format ) + ( "data", my->args ); + } + + log_context log_message::get_context()const { return my->context; } + string log_message::get_format()const { return my->format; } + variant_object log_message::get_data()const { return my->args; } + + string log_message::get_message()const + { + return format_string( my->format, my->args ); + } + + +} // fc + diff --git a/src/logger.cpp b/src/log/logger.cpp similarity index 59% rename from src/logger.cpp rename to src/log/logger.cpp index f1615fd..830a279 100644 --- a/src/logger.cpp +++ b/src/log/logger.cpp @@ -1,36 +1,14 @@ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include -// tmp... -#include - namespace fc { - log_message::log_message(){} - log_message::log_message(log_level::type ll, const string& f, int l, const string& fun, const string& fmt ) - :when( fc::time_point::now() ), level(ll), thread( fc::thread::current().name() ),file(fc::path(f).filename().generic_string()),line(l),method(fun),format(fmt){} - - log_message& log_message::operator()( const fc::string& k, fc::value&& v ) { - args[k] = fc::move(v); - return *this; - } - log_message& log_message::operator()( fc::value&& v ) { - args.push_back( fc::move(v) ); - return *this; - } - log_message& log_message::operator()( const fc::string& k, const fc::value& v ) { - args[k] = v; - return *this; - } - log_message& log_message::operator()( const fc::value& v ) { - args.push_back( v ); - return *this; - } class logger::impl : public fc::retainable { public: @@ -40,7 +18,7 @@ namespace fc { logger _parent; bool _enabled; bool _additivity; - log_level::type _level; + log_level _level; fc::vector _appenders; }; @@ -49,7 +27,15 @@ namespace fc { logger::logger() :my( new impl() ){} - logger::logger(std::nullptr_t){} + logger::logger(nullptr_t){} + + logger::logger( const string& name, const logger& parent ) + :my( new impl() ) + { + my->_name = name; + my->_parent = parent; + } + logger::logger( const logger& l ) :my(l.my){} @@ -70,13 +56,13 @@ namespace fc { bool operator==( const logger& l, std::nullptr_t ) { return !l.my; } bool operator!=( const logger& l, std::nullptr_t ) { return l.my; } - bool logger::is_enabled( log_level::type e )const { + bool logger::is_enabled( log_level e )const { return e >= my->_level; } void logger::log( log_message m ) { - if( !m.context ) m.context = my->_name; - else m.context = *m.context + "->" + my->_name; + m.get_context().append_context( my->_name ); + for( auto itr = my->_appenders.begin(); itr != my->_appenders.end(); ++itr ) (*itr)->log( m ); @@ -87,8 +73,12 @@ namespace fc { void logger::set_name( const fc::string& n ) { my->_name = n; } const fc::string& logger::name()const { return my->_name; } + extern bool do_default_config; + std::unordered_map& get_logger_map() { + static bool force_link_default_config = fc::do_default_config; static std::unordered_map lm; + (void)force_link_default_config; // hide warning; return lm; } @@ -101,8 +91,8 @@ namespace fc { logger logger::get_parent()const { return my->_parent; } logger& logger::set_parent(const logger& p) { my->_parent = p; return *this; } - log_level::type logger::get_log_level()const { return my->_level; } - logger& logger::set_log_level(log_level::type ll) { my->_level = ll; return *this; } + log_level logger::get_log_level()const { return my->_level; } + logger& logger::set_log_level(log_level ll) { my->_level = ll; return *this; } void logger::add_appender( const fc::shared_ptr& a ) { my->_appenders.push_back(a); } diff --git a/src/logger_config.cpp b/src/log/logger_config.cpp similarity index 57% rename from src/logger_config.cpp rename to src/log/logger_config.cpp index 95619ba..5762b8d 100644 --- a/src/logger_config.cpp +++ b/src/log/logger_config.cpp @@ -1,15 +1,18 @@ -#include -#include -#include +#include +#include +#include #include #include #include -#include -#include +#include +#include +#include +#include +#include namespace fc { - std::unordered_map& get_logger_map(); - std::unordered_map& get_appender_map(); + extern std::unordered_map& get_logger_map(); + extern std::unordered_map& get_appender_map(); logger_config& logger_config::add_appender( const string& s ) { appenders.push_back(s); return *this; } void configure_logging( const fc::path& lc ) @@ -18,6 +21,7 @@ namespace fc { } bool configure_logging( const logging_config& cfg ) { + try { static bool reg_console_appender = appender::register_appender( "console" ); static bool reg_file_appender = appender::register_appender( "file" ); get_logger_map().clear(); @@ -43,34 +47,35 @@ namespace fc { auto ap = appender::get( *a ); if( ap ) { lgr.add_appender(ap); } } + return reg_console_appender || reg_file_appender; } - return true; + } catch ( exception& e ) + { + fc::cerr< -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -FC_START_SHARED_IMPL(fc::http::connection) +class fc::http::connection::impl +{ + public: fc::tcp_socket sock; fc::ip::endpoint ep; impl() { @@ -17,7 +20,7 @@ FC_START_SHARED_IMPL(fc::http::connection) int read_until( char* buffer, char* end, char c = '\n' ) { char* p = buffer; // try { - while( p < end && !sock.read(p,1).eof() ) { + while( p < end && 1 == sock.readsome(p,1) ) { if( *p == c ) { *p = '\0'; return (p - buffer)-1; @@ -37,7 +40,7 @@ FC_START_SHARED_IMPL(fc::http::connection) fc::vector line(1024*8); int s = read_until( line.data(), line.data()+line.size(), ' ' ); // HTTP/1.1 s = read_until( line.data(), line.data()+line.size(), ' ' ); // CODE - rep.status = fc::lexical_cast(fc::string(line.data())); + rep.status = static_cast(to_int64(fc::string(line.data()))); s = read_until( line.data(), line.data()+line.size(), '\n' ); // DESCRIPTION while( (s = read_until( line.data(), line.data()+line.size(), '\n' )) > 1 ) { @@ -52,31 +55,29 @@ FC_START_SHARED_IMPL(fc::http::connection) h.val = fc::string(skey,end); rep.headers.push_back(h); if( h.key == "Content-Length" ) { - rep.body.resize( fc::lexical_cast( fc::string(h.val) ) ); + rep.body.resize( static_cast(to_uint64( fc::string(h.val) ) )); } } if( rep.body.size() ) { - //slog( "Reading body size %d", rep.body.size() ); sock.read( rep.body.data(), rep.body.size() ); } return rep; - } catch ( ... ) { - elog( "%s", fc::except_str().c_str() ); + } catch ( fc::exception& e ) { + elog( "${exception}", ("exception",e.to_detail_string() ) ); sock.close(); - FC_THROW_REPORT( "Error parsing reply" ); rep.status = http::reply::InternalServerError; return rep; } } - -FC_END_SHARED_IMPL -#include +}; namespace fc { namespace http { -FC_REFERENCE_TYPE_IMPL( connection ) + connection::connection() + :my( new connection::impl() ){} + connection::~connection(){} // used for clients @@ -87,7 +88,7 @@ void connection::connect_to( const fc::ip::endpoint& ep ) { http::reply connection::request( const fc::string& method, const fc::string& url, - const fc::string& body ) { + const fc::string& body, const headers& he ) { if( !my->sock.is_open() ) { wlog( "Re-open socket!" ); @@ -98,6 +99,10 @@ http::reply connection::request( const fc::string& method, req << method <<" "<key <<": " << i->val<<"\r\n"; + } if( body.size() ) req << "Content-Length: "<< body.size() << "\r\n"; req << "\r\n"; fc::string head = req.str(); @@ -114,7 +119,7 @@ http::reply connection::request( const fc::string& method, return my->parse_reply(); } catch ( ... ) { my->sock.close(); - FC_THROW_REPORT( "Error Sending HTTP Request" ); // TODO: provide more info + FC_THROW_EXCEPTION( exception, "Error Sending HTTP Request" ); // TODO: provide more info // return http::reply( http::reply::InternalServerError ); // TODO: replace with connection error } } @@ -145,14 +150,16 @@ http::request connection::read_request()const { h.val = fc::string(skey,end); req.headers.push_back(h); if( h.key == "Content-Length" ) { - req.body.resize( fc::lexical_cast( fc::string(h.val) ) ); + req.body.resize( static_cast(to_uint64( fc::string(h.val) ) )); } if( h.key == "Host" ) { req.domain = h.val; } } + // TODO: some common servers won't give a Content-Length, they'll use + // Transfer-Encoding: chunked. handle that here. + if( req.body.size() ) { - slog( "Reading body size %d", req.body.size() ); my->sock.read( req.body.data(), req.body.size() ); } return req; diff --git a/src/http_server.cpp b/src/network/http/http_server.cpp similarity index 77% rename from src/http_server.cpp rename to src/network/http/http_server.cpp index 6349f06..e658a78 100644 --- a/src/http_server.cpp +++ b/src/network/http/http_server.cpp @@ -1,14 +1,17 @@ -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace fc { namespace http { - class server::response::impl : public fc::retainable { + class server::response::impl : public fc::retainable + { public: - impl( const fc::http::connection& c, const std::function& cont = std::function() ) + impl( const fc::http::connection_ptr& c, const std::function& cont = std::function() ) :body_bytes_sent(0),body_length(0),con(c),handle_next_req(cont) {} @@ -27,18 +30,20 @@ namespace fc { namespace http { } ss << "Content-Length: "<get_socket().write( s.c_str(), s.size() ); } http::reply rep; int64_t body_bytes_sent; uint64_t body_length; - http::connection con; + http::connection_ptr con; std::function handle_next_req; }; - class server::impl : public fc::retainable { + class server::impl + { public: impl(){} impl(uint16_t p ) { @@ -53,28 +58,25 @@ namespace fc { namespace http { }catch(...){} } void accept_loop() { - try { - http::connection con; - while( tcp_serv.accept( con.get_socket() ) ) { - slog( "Accept Connection" ); + http::connection_ptr con = std::make_shared(); + while( tcp_serv.accept( con->get_socket() ) ) { + ilog( "Accept Connection" ); fc::async( [=](){ handle_connection( con, on_req ); } ); - con = http::connection(); + con = std::make_shared(); } - } catch ( ... ) { - wlog( "tcp listen failed...%s", fc::except_str().c_str() ); - } } - void handle_connection( const http::connection& c, + void handle_connection( const http::connection_ptr& c, std::function do_on_req ) { - wlog( "reading request.." ); try { http::server::response rep( fc::shared_ptr( new response::impl(c, [=](){ this->handle_connection(c,do_on_req); } ) ) ); - auto req = c.read_request(); + auto req = c->read_request(); if( do_on_req ) do_on_req( req, rep ); - } catch ( ... ) { - wlog( "unable to read request %s", fc::except_str().c_str()); + c->get_socket().close(); + } catch ( fc::exception& e ) { + wlog( "unable to read request ${1}", ("1", e.to_detail_string() ) );//fc::except_str().c_str()); } + wlog( "done handle connection" ); } std::function on_req; fc::tcp_server tcp_serv; @@ -84,10 +86,8 @@ namespace fc { namespace http { server::server(){} server::server( uint16_t port ) :my( new impl(port) ){} - server::server( const server& s ):my(s.my){} server::server( server&& s ):my(fc::move(s.my)){} - server& server::operator=(const server& s) { my = s.my; return *this; } server& server::operator=(server&& s) { fc_swap(my,s.my); return *this; } server::~server(){} @@ -131,10 +131,10 @@ namespace fc { namespace http { my->send_header(); } my->body_bytes_sent += len; - my->con.get_socket().write( data, len ); + my->con->get_socket().write( data, static_cast(len) ); if( my->body_bytes_sent == int64_t(my->body_length) ) { if( my->handle_next_req ) { - slog( "handle next request..." ); + ilog( "handle next request..." ); //fc::async( std::function(my->handle_next_req) ); fc::async( my->handle_next_req ); } diff --git a/src/ip.cpp b/src/network/ip.cpp similarity index 76% rename from src/ip.cpp rename to src/network/ip.cpp index f7f8840..9a906bd 100644 --- a/src/ip.cpp +++ b/src/network/ip.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include #include #include @@ -54,12 +54,24 @@ namespace fc { namespace ip { return string(_ip) + ':' + fc::string(boost::lexical_cast(_port).c_str()); } -} - void pack( fc::value& v, const fc::ip::endpoint& s ) { - v = fc::string(s); +} // namespace ip + + void to_variant( const ip::endpoint& var, variant& vo ) + { + vo = fc::string(var); } - void unpack( const fc::value& v, fc::ip::endpoint& s ) { - s = fc::ip::endpoint::from_string(fc::value_cast(v)); + void from_variant( const variant& var, ip::endpoint& vo ) + { + vo = ip::endpoint::from_string(var.as_string()); + } + + void to_variant( const ip::address& var, variant& vo ) + { + vo = fc::string(var); + } + void from_variant( const variant& var, ip::address& vo ) + { + vo = ip::address(var.as_string()); } } diff --git a/src/network/resolve.cpp b/src/network/resolve.cpp new file mode 100644 index 0000000..ec6b159 --- /dev/null +++ b/src/network/resolve.cpp @@ -0,0 +1,15 @@ +#include +#include + +namespace fc +{ + fc::vector resolve( const fc::string& host, uint16_t port ) + { + auto ep = fc::asio::tcp::resolve( host, std::to_string(uint64_t(port)) ); + fc::vector eps; + eps.reserve(ep.size()); + for( auto itr = ep.begin(); itr != ep.end(); ++itr ) + eps.push_back( fc::ip::endpoint(itr->address().to_v4().to_ulong(), itr->port()) ); + return eps; + } +} diff --git a/src/network/tcp_socket.cpp b/src/network/tcp_socket.cpp new file mode 100644 index 0000000..daabd2e --- /dev/null +++ b/src/network/tcp_socket.cpp @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include + +namespace fc { + + class tcp_socket::impl { + public: + impl():_sock( fc::asio::default_io_service() ){ } + ~impl(){ + if( _sock.is_open() ) _sock.close(); + } + boost::asio::ip::tcp::socket _sock; + }; + bool tcp_socket::is_open()const { + return my->_sock.is_open(); + } + + tcp_socket::tcp_socket(){}; + + tcp_socket::~tcp_socket(){}; + + void tcp_socket::flush() {} + void tcp_socket::close() { + if( is_open() ) my->_sock.close(); + } + + bool tcp_socket::eof()const { + return !my->_sock.is_open(); + } + + size_t tcp_socket::writesome( const char* buf, size_t len ) { + fc::cerr.write( buf, len ); + return fc::asio::write_some( my->_sock, boost::asio::buffer( buf, len ) ); + } + + + size_t tcp_socket::readsome( char* buf, size_t len ) { + auto r = fc::asio::read_some( my->_sock, boost::asio::buffer( buf, len ) ); + //fc::cerr.write( buf, r ); + return r; + } + + void tcp_socket::connect_to( const fc::ip::endpoint& e ) { + fc::asio::tcp::connect(my->_sock, fc::asio::tcp::endpoint( boost::asio::ip::address_v4(e.get_address()), e.port() ) ); + } + + class tcp_server::impl { + public: + impl(uint16_t port): + _accept( fc::asio::default_io_service(), boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port) ){ + } + ~impl(){ + _accept.close(); + } + + boost::asio::ip::tcp::acceptor _accept; + }; + void tcp_server::close() { + if( my && my->_accept.is_open() ) my->_accept.close(); + delete my; my = nullptr; + } + tcp_server::tcp_server() + :my(nullptr) { + } + tcp_server::~tcp_server() { + delete my; + } + + + bool tcp_server::accept( tcp_socket& s ) { + if( !my ) return false; + fc::promise::ptr p( new promise("tcp::accept") ); + my->_accept.async_accept( s.my->_sock, [=]( const boost::system::error_code& e ) { + p->set_value(e); + } ); + auto ec = p->wait(); + if( ec ) FC_THROW_EXCEPTION( exception, "system error: ${message}", ("message", fc::string(boost::system::system_error(ec).what()) )); + return true; + } + void tcp_server::listen( uint16_t port ) { + if( my ) delete my; + my = new impl(port); + } + + + +} // namespace fc diff --git a/src/udp_socket.cpp b/src/network/udp_socket.cpp similarity index 85% rename from src/udp_socket.cpp rename to src/network/udp_socket.cpp index 334570e..45df767 100644 --- a/src/udp_socket.cpp +++ b/src/network/udp_socket.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include #include @@ -40,7 +40,10 @@ namespace fc { my->_sock.async_send_to( boost::asio::buffer(b,l), to_asio_ep(to), [=]( const boost::system::error_code& ec, size_t bt ) { if( !ec ) p->set_value(bt); - else p->set_exception( fc::copy_exception( boost::system::system_error(ec) ) ); + else + p->set_exception( fc::exception_ptr( new fc::exception( + FC_LOG_MESSAGE( error, "${message} ", + ("message", boost::system::system_error(ec).what())) ) ) ); }); return p->wait(); } @@ -70,7 +73,9 @@ namespace fc { my->_sock.async_receive_from( boost::asio::buffer(b,l), from, [=]( const boost::system::error_code& ec, size_t bt ) { if( !ec ) p->set_value(bt); - else p->set_exception( fc::copy_exception( boost::system::system_error(ec) ) ); + else p->set_exception( fc::exception_ptr( new fc::exception( + FC_LOG_MESSAGE( error, "${message} ", + ("message", boost::system::system_error(ec).what())) ) ) ); }); auto r = p->wait(); _from = to_fc_ep(from); diff --git a/src/network/url.cpp b/src/network/url.cpp new file mode 100644 index 0000000..23a7e79 --- /dev/null +++ b/src/network/url.cpp @@ -0,0 +1,199 @@ +#include +#include +#include +#include +#include + +namespace fc +{ + namespace detail + { + class url_impl + { + public: + void parse( const fc::string& s ) + { + fc::stringstream ss(s); + fc::string skip,_lpath,_largs,luser,lpass; + fc::getline( ss, _proto, ':' ); + fc::getline( ss, skip, '/' ); + fc::getline( ss, skip, '/' ); + + if( s.find('@') != size_t(fc::string::npos) ) { + fc::string user_pass; + fc::getline( ss, user_pass, '@' ); + fc::stringstream upss(user_pass); + if( user_pass.find( ':' ) != size_t(fc::string::npos) ) { + fc::getline( upss, luser, ':' ); + fc::getline( upss, lpass, ':' ); + _user = fc::move(luser); + _pass = fc::move(lpass); + } else { + _user = fc::move(user_pass); + } + } + fc::string host_port; + fc::getline( ss, host_port, '/' ); + auto pos = host_port.find( ':' ); + if( pos != fc::string::npos ) { + try { + _port = static_cast(to_uint64( host_port.substr( pos+1 ) )); + } catch ( ... ) { + FC_THROW_EXCEPTION( parse_error_exception, "Unable to parse port field in url",( "url", s ) ); + } + _host = host_port.substr(0,pos); + } else { + _host = fc::move(host_port); + } + fc::getline( ss, _lpath, '?' ); +#ifdef WIN32 + // On windows, a URL like file:///c:/autoexec.bat would result in _lpath = c:/autoexec.bat + // which is what we really want (it's already an absolute path) + if (!stricmp(_proto.c_str(), "file")) + _path = _lpath; + else + _path = fc::path( "/" ) / _lpath; // let other schemes behave like unix +#else + // On unix, a URL like file:///etc/rc.local would result in _lpath = etc/rc.local + // but we really want to make it the absolute path /etc/rc.local + _path = fc::path( "/" ) / _lpath; +#endif + fc::getline( ss, _largs ); + if( _args && _args->size() ) + { + // TODO: args = fc::move(_args); + } + } + + string _proto; + ostring _host; + ostring _user; + ostring _pass; + opath _path; + ovariant_object _args; + fc::optional _port; + }; + } + + void to_variant( const url& u, fc::variant& v ) + { + v = fc::string(u); + } + void from_variant( const fc::variant& v, url& u ) + { + u = url( v.as_string() ); + } + + url::operator string()const + { + fc::stringstream ss; + ss<_proto<<"://"; + if( my->_user ) { + ss << *my->_user; + if( my->_pass ) { + ss<<":"<<*my->_pass; + } + ss<<"@"; + } + if( my->_host ) ss<<*my->_host; + if( my->_port ) ss<<":"<<*my->_port; + if( my->_path ) ss<_path->generic_string(); + // if( my->_args ) ss<<"?"<<*my->_args; + return ss.str(); + } + + url::url( const fc::string& u ) + :my( std::make_shared() ) + { + my->parse(u); + } + + std::shared_ptr get_null_url() + { + static auto u = std::make_shared(); + return u; + } + + url::url() + :my( get_null_url() ) + { } + + url::url( const url& u ) + :my(u.my){} + + url::url( url&& u ) + :my( fc::move(u.my) ) + { + u.my = get_null_url(); + } + + url::url( const mutable_url& mu ) + :my( std::make_shared(*mu.my) ) + { + + } + url::url( mutable_url&& mu ) + :my( fc::move( mu.my ) ) + { } + + url::~url(){} + + url& url::operator=(const url& u ) + { + my = u.my; + return *this; + } + + url& url::operator=(url&& u ) + { + if( this != &u ) + { + my = fc::move(u.my); + u.my= get_null_url(); + } + return *this; + } + url& url::operator=(const mutable_url& u ) + { + my = std::make_shared(*u.my); + return *this; + } + url& url::operator=(mutable_url&& u ) + { + my = fc::move(u.my); + return *this; + } + + string url::proto()const + { + return my->_proto; + } + ostring url::host()const + { + return my->_host; + } + ostring url::user()const + { + return my->_user; + } + ostring url::pass()const + { + return my->_pass; + } + opath url::path()const + { + return my->_path; + } + ovariant_object url::args()const + { + return my->_args; + } + fc::optional url::port()const + { + return my->_port; + } + + + +} + diff --git a/src/pke.cpp b/src/pke.cpp deleted file mode 100644 index ad0e7d7..0000000 --- a/src/pke.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace fc { - void pack( fc::value& v, const fc::public_key_t& s ) { - fc::vector ve = fc::raw::pack( s ); - v = to_base58( ve.data(), size_t(ve.size()) ); - } - void unpack( const fc::value& v, fc::public_key_t& s ) { - try { - auto ve = from_base58(fc::value_cast(v)); - s = fc::raw::unpack(ve); - } catch ( ... ) { - wlog( "error unpacking signature" ); - } - } - - void pack( fc::value& v, const fc::private_key_t& s ) { - fc::vector ve = fc::raw::pack( s ); - v = to_base58( ve.data(), ve.size() ); - } - void unpack( const fc::value& v, fc::private_key_t& s ) { - try { - auto ve = from_base58(fc::value_cast(v)); - s = fc::raw::unpack(ve); - } catch ( ... ) { - wlog( "error unpacking private_key" ); - } - } - void pack( fc::value& v, const fc::signature_t& s ) { - fc::vector ve = fc::raw::pack( s ); - v = to_base58( ve.data(), ve.size() ); - } - void unpack( const fc::value& v, fc::signature_t& s ) { - try { - auto ve = from_base58(fc::value_cast(v)); - s = fc::raw::unpack(ve); - } catch ( ... ) { - wlog( "error unpacking signature" ); - } - } - - RSA* get_pub( const char* key, uint32_t key_size, uint32_t pe ) - { - RSA* rsa = RSA_new(); - rsa->n = BN_bin2bn( (unsigned char*)key, key_size, NULL ); - rsa->e = BN_new(); - BN_set_word(rsa->e, pe ); - return rsa; - } - RSA* get_priv( const fc::vector& d, uint32_t /*key_size*/, uint32_t /*pe*/ ) - { - BIO* mem = (BIO*)BIO_new_mem_buf( (void*)&d.front(), d.size() ); - RSA* rsa = PEM_read_bio_RSAPrivateKey(mem, NULL, NULL, NULL ); - BIO_free(mem); - return rsa; - } - - bool verify_data( const char* key, uint32_t key_size, uint32_t pe, const sha1& digest, const char* sig ) - { - RSA* pub = get_pub( key,key_size,pe); - auto v = RSA_verify( NID_sha1, (const uint8_t*)digest.data(), 20, (uint8_t*)sig, key_size, pub ); - RSA_free(pub); - return 0 != v; - } - bool sign_data( const fc::vector& key, uint32_t key_size, uint32_t pe, const sha1& digest, char* sig ) - { - RSA* priv = get_priv( key,key_size,pe); - if( !priv ) { - generic_exception g(fc::generic_exception("Error loading private key: " + fc::string(ERR_error_string( ERR_get_error(),NULL))) ); - FC_THROW(g); - } - uint32_t slen = 0; - if( 1 != RSA_sign( NID_sha1, (uint8_t*)digest.data(), sizeof(digest), (unsigned char*)sig, &slen, priv ) ) - { - RSA_free(priv); - generic_exception g(fc::generic_exception("Error signing data: " + fc::string(ERR_error_string( ERR_get_error(),NULL))) ); - FC_THROW(g); - - } - RSA_free(priv); - return true; - } - - bool public_encrypt( const char* key, uint32_t key_size, uint32_t pe, const fc::vector& in, fc::vector& out ) - { - RSA* pub = get_pub( key,key_size/8,pe); - out.resize(RSA_size(pub)); - int rtn = RSA_public_encrypt( in.size(), (unsigned char*)&in.front(), (unsigned char*)&out.front(), pub, RSA_PKCS1_OAEP_PADDING ); - RSA_free(pub); - if( rtn >= 0 ) - { - out.resize(rtn); - return true; - } - out.resize(0); - FC_THROW( fc::generic_exception( ERR_error_string( ERR_get_error(), NULL ) ) ); - return false; - } - bool public_decrypt( const char* key, uint32_t key_size, uint32_t pe, const fc::vector& in, fc::vector& out ) - { - RSA* pub = get_pub( key,key_size/8,pe); - out.resize(RSA_size(pub)); - int rtn = RSA_public_decrypt( RSA_size(pub), (unsigned char*)&in.front(), (unsigned char*)&out.front(), pub, RSA_PKCS1_OAEP_PADDING ); - RSA_free(pub); - if( rtn >= 0 ) - { - out.resize(rtn); - return true; - } - out.resize(0); - FC_THROW( fc::generic_exception( ERR_error_string( ERR_get_error(), NULL ) ) ); - return false;; - } - bool private_encrypt( const fc::vector& key, uint32_t key_size, uint32_t pe, const fc::vector& in, fc::vector& out ) - { - RSA* priv = get_priv( key,key_size/8,pe); - int rtn = RSA_private_encrypt( in.size(), (unsigned char*)&in.front(), (unsigned char*)&out.front(), priv, RSA_PKCS1_OAEP_PADDING ); - RSA_free(priv); - if( rtn >= 0 ) - { - out.resize(rtn); - return true; - } - out.resize(0); - return false;; - } - bool private_decrypt( const fc::vector& key, uint32_t key_size, uint32_t pe, const fc::vector& in, fc::vector& out ) - { - - RSA* priv = get_priv( key,key_size/8,pe); - out.resize(RSA_size(priv)); - int rtn = RSA_private_decrypt( in.size(), (unsigned char*)&in.front(), (unsigned char*)&out.front(), priv, RSA_PKCS1_OAEP_PADDING ); - RSA_free(priv); - if( rtn >= 0 ) - { - out.resize(rtn); - return true; - } - out.resize(0); - FC_THROW( fc::generic_exception( ERR_error_string( ERR_get_error(), NULL ) ) ); - return false; - } - - bool generate_keys( char* pubkey, fc::vector& privkey, uint32_t key_size, uint32_t pe ) - { - static bool init = true; - if( init ) { ERR_load_crypto_strings(); init = false; } - - RSA* rsa = RSA_generate_key( key_size, pe, NULL, NULL ); - BN_bn2bin( rsa->n, (unsigned char*)pubkey ); - - BIO *mem = BIO_new(BIO_s_mem()); - int e = PEM_write_bio_RSAPrivateKey(mem, rsa, NULL, NULL, 0, NULL, NULL ); - if( e != 1 ) - { - BIO_free(mem); - RSA_free(rsa); - FC_THROW(generic_exception("Error writing PrivateKey") ); - } - - char* dat; - uint32_t l = BIO_get_mem_data( mem, &dat ); - privkey.resize(l); - memcpy( &privkey.front(), dat, l ); - - BIO_free(mem); - RSA_free(rsa); - return true; - } -} diff --git a/src/process.cpp b/src/process.cpp deleted file mode 100644 index 4a79311..0000000 --- a/src/process.cpp +++ /dev/null @@ -1,221 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace fc { - namespace bp = boost::process; - namespace io = boost::iostreams; - - fc::path find_executable_in_path( const fc::string name ) { - try { - return fc::string(bp::find_executable_in_path( std::string(name), "" )); - } catch (...) { - const char* p = std::getenv("PATH"); - FC_THROW_REPORT( "Unable to find executable ${exe} in path.", - fc::value().set("exe", name) - .set("inner", fc::except_str() ) - .set("PATH", fc::string(p!=nullptr?p:"") ) ); - } - return fc::path(); - } - - class process_sink : public io::sink { - public: - struct category : io::sink::category, io::flushable_tag {}; - typedef char type; - - process_sink( std::shared_ptr& p ):m_in(p){} - - std::streamsize write( const char* s, std::streamsize n ) { - if( !m_in ) return -1; - return static_cast(fc::asio::write( *m_in, - boost::asio::const_buffers_1( s, static_cast(n) ) )); - } - void close() { if(m_in) m_in->close(); } - bool flush() { return true; } - - private: - std::shared_ptr& m_in; - }; - - class process_source : public io::source { - public: - typedef char type; - - process_source( std::shared_ptr& pi ) - :m_pi(pi){} - - std::streamsize read( char* s, std::streamsize n ) { - if( !m_pi ) return -1; - try { - return static_cast(fc::asio::read_some( *m_pi, boost::asio::buffer( s, static_cast(n) ) )); - } catch ( const boost::system::system_error& e ) { - // wlog( "%s", fc::except_str().c_str() ); - if( e.code() == boost::asio::error::eof ) - return -1; - wlog( "%s", fc::except_str().c_str() ); - throw; - } catch ( ... ) { - //wlog( "%s", fc::except_str().c_str() ); - return -1; - } - } - private: - std::shared_ptr& m_pi; - }; -} // namespace fc - -FC_START_SHARED_IMPL( fc::process ) - public: - impl() - :stat( fc::asio::default_io_service() ), - std_out(process_source(outp)), - std_err(process_source(errp)), - std_in(process_sink(inp)), - _ins(std_in), - _outs(std_out), - _errs(std_err){} - - ~impl() { - try { - if( inp ) { - inp->close(); - } - if( _exited.valid() && !_exited.ready()) { - //child->terminate(); - _exited.wait(); - } - }catch(...) { - wlog( "caught exception cleaning up process: %s", fc::except_str().c_str() ); - } - } - - std::shared_ptr child; - std::shared_ptr outp; - std::shared_ptr errp; - std::shared_ptr inp; - - bp::status stat; - bp::context pctx; - - // provide useful buffering - io::stream std_out; - io::stream std_err; - io::stream std_in; - - fc::future _exited; - - // adapt to ostream and istream interfaces - fc::ostream_wrapper _ins; - fc::istream_wrapper _outs; - fc::istream_wrapper _errs; -FC_END_SHARED_IMPL -#include - -namespace fc { - -FC_REFERENCE_TYPE_IMPL( process ) - - -fc::future process::exec( const fc::path& exe, fc::vector&& args, - const fc::path& work_dir, int opt ) { - - my->pctx.work_dir = work_dir.string(); - - if( opt&open_stdout) - my->pctx.streams[boost::process::stdout_id] = bp::behavior::async_pipe(); - else - my->pctx.streams[boost::process::stdout_id] = bp::behavior::null(); - - - if( opt& open_stderr ) - my->pctx.streams[boost::process::stderr_id] = bp::behavior::async_pipe(); - else - my->pctx.streams[boost::process::stderr_id] = bp::behavior::null(); - - if( opt& open_stdout ) - my->pctx.streams[boost::process::stdin_id] = bp::behavior::async_pipe(); - else - my->pctx.streams[boost::process::stdin_id] = bp::behavior::close(); - - std::vector a; - a.reserve(size_t(args.size())); - for( uint32_t i = 0; i < args.size(); ++i ) { - a.push_back( args[i] ); - } - my->child.reset( new bp::child( bp::create_child( exe.string(), fc::move(a), my->pctx ) ) ); - - if( opt & open_stdout ) { - bp::handle outh = my->child->get_handle( bp::stdout_id ); - my->outp.reset( new bp::pipe( fc::asio::default_io_service(), outh.release() ) ); - } - if( opt & open_stderr ) { - bp::handle errh = my->child->get_handle( bp::stderr_id ); - my->errp.reset( new bp::pipe( fc::asio::default_io_service(), errh.release() ) ); - } - if( opt & open_stdin ) { - bp::handle inh = my->child->get_handle( bp::stdin_id ); - my->inp.reset( new bp::pipe( fc::asio::default_io_service(), inh.release() ) ); - } - - - promise::ptr p(new promise("process")); - my->stat.async_wait( my->child->get_id(), [=]( const boost::system::error_code& ec, int exit_code ) - { - //slog( "process::result %d", exit_code ); - if( !ec ) { - #ifdef BOOST_POSIX_API - try { - if( WIFEXITED(exit_code) ) - p->set_value( WEXITSTATUS(exit_code) ); - else { - FC_THROW_MSG( "process exited with: %s ", strsignal(WTERMSIG(exit_code)) ); - } - } catch ( ... ) { - p->set_exception( fc::current_exception() ); - } - #else - p->set_value(exit_code); - #endif - } - else p->set_exception( fc::copy_exception( boost::system::system_error(ec) ) ); - }); - return my->_exited = p; -} - -/** - * Forcefully kills the process. - */ -void process::kill() { - my->child->terminate(); -} - -/** - * @brief returns a stream that writes to the process' stdin - */ -fc::ostream& process::in_stream() { - return my->_ins; -} - -/** - * @brief returns a stream that reads from the process' stdout - */ -fc::istream& process::out_stream() { - return my->_outs; -} -/** - * @brief returns a stream that reads from the process' stderr - */ -fc::istream& process::err_stream() { - return my->_errs; -} - -} diff --git a/src/program_options.cpp b/src/program_options.cpp deleted file mode 100644 index eebc192..0000000 --- a/src/program_options.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include -#include -#include -#include - -namespace fc { namespace program_options { - - class options_description::impl { - public: - impl( const char* c ) - :opts(c){} - - boost::program_options::options_description opts; - }; - - options_description::options_description( const char* c ) - :my(c) - { } - - options_description::~options_description(){ - - } - - - options_description& options_description::add_options(){ - return *this; - } - - options_description& options_description::operator()( const char* o, const char* desc ){ - my->opts.add_options()( o, desc ); - return *this; - } - - options_description& options_description::operator()( const char* o, const value& v, const char* desc ){ - my->opts.add_options()( o, boost::program_options::value(reinterpret_cast(v.get())), desc ); - return *this; - } - - options_description& options_description::operator()( const char* o, const value& v, const char* desc ){ - my->opts.add_options()( o, boost::program_options::value(v.get()), desc ); - return *this; - } - - options_description& options_description::operator()( const char* o, const value >& v, const char* desc ){ - my->opts.add_options()( o, boost::program_options::value >(v.get()), desc ); - //my->opts.add_options()( o, desc ); - return *this; - } - - class variables_map::impl { - public: - boost::program_options::variables_map vm; - }; - - variables_map::variables_map(){} - variables_map::~variables_map(){} - - void variables_map::parse_command_line( int argc, char** argv, const options_description& d ) { - boost::program_options::store( boost::program_options::parse_command_line( argc, argv, d.my->opts ), my->vm ); - } - int variables_map::count( const char* opt ) { - return my->vm.count(opt); - } - - fc::ostream& operator<<( fc::ostream& o, const options_description& od ) { - std::stringstream ss; ss << od.my->opts; - fc::cout << ss.str().c_str(); - return o; - } - -} } diff --git a/src/reflect.cpp b/src/reflect.cpp deleted file mode 100644 index b5897fe..0000000 --- a/src/reflect.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include - -namespace fc { - void throw_bad_enum_cast( int64_t i, const char* e ) { - FC_THROW_REPORT( "Unknown field ${field} not in enum ${enum}", - fc::value().set("field",i).set("enum",e) ); - } - void throw_bad_enum_cast( const char* k, const char* e ){ - FC_THROW_REPORT( "Field '${field}' not in enum ${enum}", - fc::value().set("field",k).set("enum",e) ); - } -} diff --git a/src/rpc/json_connection.cpp b/src/rpc/json_connection.cpp new file mode 100644 index 0000000..c5f95a4 --- /dev/null +++ b/src/rpc/json_connection.cpp @@ -0,0 +1,464 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fc { namespace rpc { + + namespace detail + { + class json_connection_impl + { + public: + json_connection_impl( fc::buffered_istream_ptr&& in, fc::buffered_ostream_ptr&& out ) + :_in(fc::move(in)),_out(fc::move(out)),_eof(false),_next_id(0),_logger("json_connection"){} + + fc::buffered_istream_ptr _in; + fc::buffered_ostream_ptr _out; + + fc::future _done; + bool _eof; + + uint64_t _next_id; + boost::unordered_map::ptr> _awaiting; + boost::unordered_map _methods; + boost::unordered_map _named_param_methods; + + fc::mutex _write_mutex; + //std::function _on_close; + + logger _logger; + + void send_result( variant id, variant result ) + { + { + fc::scoped_lock lock(_write_mutex); + *_out << "{\"id\":"; + json::to_stream( *_out, id ); + *_out << ",\"result\":"; + json::to_stream( *_out, result); + *_out << "}\n"; + } + _out->flush(); + } + void send_error( variant id, fc::exception& e ) + { + { + fc::scoped_lock lock(_write_mutex); + *_out << "{\"id\":"; + json::to_stream( *_out, id ); + *_out << ",\"error\":{\"message\":"; + json::to_stream( *_out, fc::string(e.what()) ); + *_out <<",\"code\":0,\"data\":"; + json::to_stream( *_out, variant(e)); + *_out << "}}\n"; + } + wlog( "exception: ${except}", ("except", variant(e)) ); + _out->flush(); + } + + void handle_message( const variant_object& obj ) + { + wlog( "recv: ${msg}", ("msg", obj) ); + try + { + auto m = obj.find("method"); + auto i = obj.find("id"); + if( m != obj.end() ) + { + try + { + auto p = obj.find("params"); + variant result; + if( p == obj.end() ) + { + auto pmi = _methods.find(m->value().as_string()); + auto nmi = _named_param_methods.find(m->value().as_string()); + if( pmi != _methods.end() ) + { + result = pmi->second( variants() ); + } + else if( nmi != _named_param_methods.end() ) + { + result = nmi->second( variant_object() ); + } + else // invalid method + { + FC_THROW_EXCEPTION( exception, "Invalid Method '${method}'", ("method",m->value().as_string())); + } + } + else if( p->value().is_array() ) + { + auto pmi = _methods.find(m->value().as_string()); + if( pmi != _methods.end() ) + { + result = pmi->second( p->value().get_array() ); + } + else // invalid method / param combo + { + FC_THROW_EXCEPTION( exception, "Invalid method or params '${method}'", + ("method",m->value().as_string())); + } + + } + else if( p->value().is_object() ) + { + auto nmi = _named_param_methods.find(m->value().as_string()); + if( nmi != _named_param_methods.end() ) + { + result = nmi->second( p->value().get_object() ); + } + else // invalid method / param combo? + { + FC_THROW_EXCEPTION( exception, "Invalid method or params '${method}'", + ("method",m->value().as_string())); + } + } + else // invalid params + { + FC_THROW_EXCEPTION( exception, "Invalid Params for method ${method}", + ("method",m->value().as_string())); + } + if( i != obj.end() ) + { + send_result( i->value(), result ); + } + } + catch ( fc::exception& e ) + { + if( i != obj.end() ) + { + send_error( i->value(), e ); + } + else + { + fc_wlog( _logger, "json rpc exception: ${exception}", ("exception",e) ); + } + } + } + else if( i != obj.end() ) + { + uint64_t id = i->value().as_int64(); + auto await = _awaiting.find(id); + if( await != _awaiting.end() ) + { + auto r = obj.find("result"); + auto e = obj.find("error"); + if( r != obj.end() ) + { + await->second->set_value( r->value() ); + } + else if( e != obj.end() ) + { + try + { + auto err = e->value().get_object(); + auto data = err.find( "data" ); + if( data != err.end() ) + { + wlog( "exception: ${except}", ("except", data->value() ) ); + await->second->set_exception( data->value().as().dynamic_copy_exception() ); + } + else + await->second->set_exception( exception_ptr(new FC_EXCEPTION( exception, "${error}", ("error",e->value()) ) ) ); + } + catch ( fc::exception& e ) + { + elog( "Error parsing exception: ${e}", ("e", e.to_detail_string() ) ); + await->second->set_exception( e.dynamic_copy_exception() ); + } + } + else // id found without error, result, nor method field + { + fc_wlog( _logger, "no error or result specified in '${message}'", ("message",obj) ); + } + } + } + else // no method nor request id... invalid message + { + + } + } + catch ( fc::exception& e ) // catch all other errors... + { + fc_elog( _logger, "json rpc exception: ${exception}", ("exception",e )); + elog( "json rpc exception: ${exception}", ("exception",e )); + close(e.dynamic_copy_exception()); + } + } + + void read_loop() + { + try + { + fc::string line; + while( true ) + { + variant v = json::from_stream(*_in); + ///ilog( "input: ${in}", ("in", v ) ); + wlog( "recv: ${line}", ("line", line) ); + fc::async([=](){ handle_message(v.get_object()); }); + } + } + catch ( eof_exception& eof ) + { + _eof = true; + wlog( "close" ); + close( eof.dynamic_copy_exception() ); + } + catch ( exception& e ) + { + wlog( "close" ); + close( e.dynamic_copy_exception() ); + } + catch ( ... ) + { + wlog( "close" ); + close( fc::exception_ptr(new FC_EXCEPTION( unhandled_exception, "json connection read error" )) ); + } + wlog( "close" ); + } + + void close( fc::exception_ptr e ) + { + wlog( "close ${reason}", ("reason", e->to_detail_string() ) ); + for( auto itr = _awaiting.begin(); itr != _awaiting.end(); ++itr ) + { + itr->second->set_exception( e->dynamic_copy_exception() ); + } + } + }; + }//namespace detail + + json_connection::json_connection( fc::buffered_istream_ptr in, fc::buffered_ostream_ptr out ) + :my( new detail::json_connection_impl(fc::move(in),fc::move(out)) ) + {} + + json_connection::~json_connection() + { + try + { + if( my->_done.valid() && !my->_done.ready() ) + { + my->_done.cancel(); + my->_done.wait(); + } + } + catch ( fc::canceled_exception& ){} // expected exception + catch ( fc::eof_exception& ){} // expected exception + catch ( fc::exception& e ) + { + // unhandled, unexpected exception cannot throw from destructor, so log it. + wlog( "${exception}", ("exception",e.to_detail_string()) ); + } + } + + fc::future json_connection::exec() + { + if( my->_done.valid() ) + { + FC_THROW_EXCEPTION( assert_exception, "start should only be called once" ); + } + + wlog( "EXEC!!!\n" ); + return my->_done = fc::async( [=](){ my->read_loop(); } ); + } + + void json_connection::add_method( const fc::string& name, method m ) + { + my->_methods.emplace(std::pair(name,fc::move(m))); + } + void json_connection::add_method( const fc::string& name, named_param_method m ) + { + my->_named_param_methods.emplace(std::pair(name,fc::move(m))); + } + void json_connection::remove_method( const fc::string& name ) + { + my->_methods.erase(name); + my->_named_param_methods.erase(name); + } + void json_connection::notice( const fc::string& method, const variants& args ) + { + fc::scoped_lock lock(my->_write_mutex); + *my->_out << "{\"method\":"; + json::to_stream( *my->_out, method ); + if( args.size() ) + { + *my->_out << ",\"params\":"; + fc::json::to_stream( *my->_out, args ); + *my->_out << "}\n"; + } + else + { + *my->_out << ",\"params\":[]}\n"; + } + } + void json_connection::notice( const fc::string& method, const variant_object& named_args ) + { + { + fc::scoped_lock lock(my->_write_mutex); + *my->_out << "{\"method\":"; + json::to_stream( *my->_out, method ); + *my->_out << ",\"params\":"; + fc::json::to_stream( *my->_out, named_args ); + *my->_out << "}\n"; + } + my->_out->flush(); + } + void json_connection::notice( const fc::string& method ) + { + { + fc::scoped_lock lock(my->_write_mutex); + *my->_out << "{\"method\":"; + json::to_stream( *my->_out, method ); + *my->_out << "}\n"; + } + my->_out->flush(); + } + + + future json_connection::async_call( const fc::string& method, const variants& args ) + { + auto id = my->_next_id++; + my->_awaiting[id] = fc::promise::ptr( new fc::promise() ); + + { + fc::scoped_lock lock(my->_write_mutex); + *my->_out << "{\"id\":"; + *my->_out << id; + *my->_out << ",\"method\":"; + json::to_stream( *my->_out, method ); + if( args.size() ) + { + *my->_out << ",\"params\":"; + fc::json::to_stream( *my->_out, args ); + *my->_out << "}\n"; + } + else + { + *my->_out << ",\"params\":[]}\n"; + } + } + my->_out->flush(); + return my->_awaiting[id]; + } + + future json_connection::async_call( const fc::string& method, const variant& a1 ) + { + ilog( ""); + auto id = my->_next_id++; + my->_awaiting[id] = fc::promise::ptr( new fc::promise() ); + + { + fc::scoped_lock lock(my->_write_mutex); + *my->_out << "{\"id\":"; + *my->_out << id; + *my->_out << ",\"method\":"; + json::to_stream( *my->_out, method ); + *my->_out << ",\"params\":["; + fc::json::to_stream( *my->_out, a1 ); + *my->_out << "]}\n"; + } + my->_out->flush(); + return my->_awaiting[id]; + } + future json_connection::async_call( const fc::string& method, const variant& a1, const variant& a2 ) + { + ilog( ""); + auto id = my->_next_id++; + my->_awaiting[id] = fc::promise::ptr( new fc::promise() ); + + { + fc::scoped_lock lock(my->_write_mutex); + *my->_out << "{\"id\":"; + *my->_out << id; + *my->_out << ",\"method\":"; + json::to_stream( *my->_out, method ); + *my->_out << ",\"params\":["; + fc::json::to_stream( *my->_out, a1 ); + *my->_out << ","; + fc::json::to_stream( *my->_out, a2 ); + *my->_out << "]}\n"; + } + my->_out->flush(); + return my->_awaiting[id]; + } + future json_connection::async_call( const fc::string& method, const variant& a1, const variant& a2, const variant& a3 ) + { + ilog( ""); + auto id = my->_next_id++; + my->_awaiting[id] = fc::promise::ptr( new fc::promise() ); + + { + fc::scoped_lock lock(my->_write_mutex); + *my->_out << "{\"id\":"; + *my->_out << id; + *my->_out << ",\"method\":"; + json::to_stream( *my->_out, method ); + *my->_out << ",\"params\":["; + fc::json::to_stream( *my->_out, a1 ); + *my->_out << ","; + fc::json::to_stream( *my->_out, a2 ); + *my->_out << ","; + fc::json::to_stream( *my->_out, a3 ); + *my->_out << "]}\n"; + } + my->_out->flush(); + return my->_awaiting[id]; + } + + + + future json_connection::async_call( const fc::string& method, mutable_variant_object named_args ) + { + return async_call( method, variant_object( fc::move(named_args) ) ); + } + future json_connection::async_call( const fc::string& method, const variant_object& named_args ) + { + wlog( "${method} ${args}", ("method",method)("args",named_args) ); + auto id = my->_next_id++; + my->_awaiting[id] = fc::promise::ptr( new fc::promise() ); + fc::scoped_lock lock(my->_write_mutex); + { + *my->_out << "{\"id\":"; + *my->_out << id; + *my->_out << ",\"method\":"; + json::to_stream( *my->_out, method ); + *my->_out << ",\"params\":"; + fc::json::to_stream( *my->_out, named_args ); + *my->_out << "}\n"; + } + my->_out->flush(); + return my->_awaiting[id]; + } + future json_connection::async_call( const fc::string& method ) + { + auto id = my->_next_id++; + my->_awaiting[id] = fc::promise::ptr( new fc::promise() ); + fc::scoped_lock lock(my->_write_mutex); + { + *my->_out << "{\"id\":"; + *my->_out << id; + *my->_out << ",\"method\":"; + json::to_stream( *my->_out, method ); + *my->_out << "}\n"; + } + my->_out->flush(); + return my->_awaiting[id]; + } + + logger json_connection::get_logger()const + { + return my->_logger; + } + + void json_connection::set_logger( const logger& l ) + { + my->_logger = l; + } + +}} diff --git a/src/sha1.cpp b/src/sha1.cpp deleted file mode 100644 index 363a5c2..0000000 --- a/src/sha1.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace fc { - - sha1::sha1() { memset( _hash, 0, sizeof(_hash) ); } - sha1::sha1( const fc::string& hex_str ) { - fc::from_hex( hex_str, (char*)_hash, sizeof(_hash) ); - } - - fc::string sha1::str()const { - return to_hex( (char*)_hash, sizeof(_hash) ); - } - sha1::operator fc::string()const { return str(); } - - char* sha1::data()const { return (char*)&_hash[0]; } - - - struct sha1::encoder::impl { - SHA_CTX ctx; - }; - - sha1::encoder::~encoder() {} - sha1::encoder::encoder() { - reset(); - } - - sha1 sha1::hash( const char* d, uint32_t dlen ) { - encoder e; - e.write(d,dlen); - return e.result(); - } - sha1 sha1::hash( const fc::string& s ) { - return hash( s.c_str(), s.size() ); - } - sha1 sha1::hash( const fc::path& s ) { - file_mapping fmap( s.string().c_str(), read_only ); - size_t fsize = file_size(s); - mapped_region mr( fmap, fc::read_only, 0, fsize ); - - const char* pos = reinterpret_cast(mr.get_address()); - return hash( pos, fsize ); - } - - void sha1::encoder::write( const char* d, uint32_t dlen ) { - SHA1_Update( &my->ctx, d, dlen); - } - sha1 sha1::encoder::result() { - sha1 h; - SHA1_Final((uint8_t*)h.data(), &my->ctx ); - return h; - } - void sha1::encoder::reset() { - SHA1_Init( &my->ctx); - } - - fc::sha1 operator << ( const fc::sha1& h1, uint32_t i ) { - fc::sha1 result; - uint8_t* r = (uint8_t*)result._hash; - uint8_t* s = (uint8_t*)h1._hash; - for( uint32_t p = 0; p < sizeof(h1._hash)-1; ++p ) - r[p] = s[p] << i | (s[p+1]>>(8-i)); - r[19] = s[19] << i; - return result; - } - fc::sha1 operator ^ ( const fc::sha1& h1, const fc::sha1& h2 ) { - fc::sha1 result; - result._hash[0] = h1._hash[0] ^ h2._hash[0]; - result._hash[1] = h1._hash[1] ^ h2._hash[1]; - result._hash[2] = h1._hash[2] ^ h2._hash[2]; - result._hash[3] = h1._hash[3] ^ h2._hash[3]; - result._hash[4] = h1._hash[4] ^ h2._hash[4]; - return result; - } - bool operator >= ( const fc::sha1& h1, const fc::sha1& h2 ) { - return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) >= 0; - } - bool operator > ( const fc::sha1& h1, const fc::sha1& h2 ) { - return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) > 0; - } - bool operator < ( const fc::sha1& h1, const fc::sha1& h2 ) { - return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) < 0; - } - bool operator != ( const fc::sha1& h1, const fc::sha1& h2 ) { - return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) != 0; - } - bool operator == ( const fc::sha1& h1, const fc::sha1& h2 ) { - return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0; - } - - void pack( fc::value& v, const fc::sha1& s ) { - v = fc::string(s); - } - void unpack( const fc::value& v, fc::sha1& s ) { - s = sha1(fc::value_cast(v)); - } - -} // namespace fc - diff --git a/src/sha256.cpp b/src/sha256.cpp deleted file mode 100644 index 7473839..0000000 --- a/src/sha256.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace fc { - - sha256::sha256() { memset( _hash, 0, sizeof(_hash) ); } - sha256::sha256( const fc::string& hex_str ) { - fc::from_hex( hex_str, (char*)_hash, sizeof(_hash) ); - } - - fc::string sha256::str()const { - return to_hex( (char*)_hash, sizeof(_hash) ); - } - sha256::operator fc::string()const { return str(); } - - char* sha256::data()const { return (char*)&_hash[0]; } - - - struct sha256::encoder::impl { - SHA_CTX ctx; - }; - - sha256::encoder::~encoder() {} - sha256::encoder::encoder() { - reset(); - } - - sha256 sha256::hash( const char* d, uint32_t dlen ) { - encoder e; - e.write(d,dlen); - return e.result(); - } - sha256 sha256::hash( const fc::string& s ) { - return hash( s.c_str(), s.size() ); - } - sha256 sha256::hash( const fc::path& s ) { - file_mapping fmap( s.string().c_str(), read_only ); - size_t fsize = file_size(s); - mapped_region mr( fmap, fc::read_only, 0, fsize ); - - const char* pos = reinterpret_cast(mr.get_address()); - return hash( pos, fsize ); - } - - void sha256::encoder::write( const char* d, uint32_t dlen ) { - SHA1_Update( &my->ctx, d, dlen); - } - sha256 sha256::encoder::result() { - sha256 h; - SHA1_Final((uint8_t*)h.data(), &my->ctx ); - return h; - } - void sha256::encoder::reset() { - SHA1_Init( &my->ctx); - } - - fc::sha256 operator << ( const fc::sha256& h1, uint32_t i ) { - fc::sha256 result; - uint8_t* r = (uint8_t*)result._hash; - uint8_t* s = (uint8_t*)h1._hash; - for( uint32_t p = 0; p < sizeof(h1._hash)-1; ++p ) - r[p] = s[p] << i | (s[p+1]>>(8-i)); - r[31] = s[31] << i; - return result; - } - fc::sha256 operator ^ ( const fc::sha256& h1, const fc::sha256& h2 ) { - fc::sha256 result; - result._hash[0] = h1._hash[0] ^ h2._hash[0]; - result._hash[1] = h1._hash[1] ^ h2._hash[1]; - result._hash[2] = h1._hash[2] ^ h2._hash[2]; - result._hash[3] = h1._hash[3] ^ h2._hash[3]; - return result; - } - bool operator >= ( const fc::sha256& h1, const fc::sha256& h2 ) { - return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) >= 0; - } - bool operator > ( const fc::sha256& h1, const fc::sha256& h2 ) { - return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) > 0; - } - bool operator < ( const fc::sha256& h1, const fc::sha256& h2 ) { - return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) < 0; - } - bool operator != ( const fc::sha256& h1, const fc::sha256& h2 ) { - return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) != 0; - } - bool operator == ( const fc::sha256& h1, const fc::sha256& h2 ) { - return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0; - } - - void pack( fc::value& v, const fc::sha256& s ) { - v = fc::string(s); - } - void unpack( const fc::value& v, fc::sha256& s ) { - s = sha256(fc::value_cast(v)); - } - -} // namespace fc - diff --git a/src/ssh.cpp b/src/ssh.cpp deleted file mode 100644 index 04375cf..0000000 --- a/src/ssh.cpp +++ /dev/null @@ -1,1060 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace fc { namespace ssh { - - namespace detail { - static int ssh_init = libssh2_init(0); - - class process_impl; - class process_istream : public fc::istream { - public: - process_istream( process_impl& p, int c ) - :proc(p),chan(c){} - - virtual size_t readsome( char* buf, size_t len ); - virtual istream& read( char* buf, size_t len ); - - virtual bool eof()const; - - process_impl& proc; - int chan; - }; - - class process_ostream : public fc::ostream { - public: - process_ostream( process_impl& p ) - :proc(p){} - - virtual ostream& write( const char* buf, size_t len ); - virtual void close(); - virtual void flush(); - - process_impl& proc; - }; - - class process_impl : public fc::retainable { - public: - process_impl( const client& c, const fc::string& cmd, const fc::string& pty_type ); - fc::string command; - fc::promise::ptr result; - LIBSSH2_CHANNEL* chan; - - int read_some( char* data, size_t len, int stream_id ); - int write_some( const char* data, size_t len, int stream_id ); - void flush(); - void send_eof(); - - client sshc; - process_istream std_err; - process_istream std_out; - process_ostream std_in; - - }; - - - class client_impl : public fc::retainable { - public: - client_impl() { - sftp = nullptr; - session = nullptr; - knownhosts = nullptr; - _trace_level = LIBSSH2_TRACE_ERROR; - logr = fc::logger::get( "fc::ssh::client" ); - logr.set_parent( fc::logger::get( "default" ) ); - } - LIBSSH2_SESSION* session; - LIBSSH2_KNOWNHOSTS* knownhosts; - LIBSSH2_SFTP* sftp; - - std::unique_ptr sock; - boost::asio::ip::tcp::endpoint endpt; - - fc::mutex scp_send_mutex; - fc::string uname; - fc::string upass; - fc::string pubkey; - fc::string privkey; - fc::string passphrase; - fc::string hostname; - uint16_t port; - bool session_connected; - fc::promise::ptr read_prom; - fc::promise::ptr write_prom; - fc::spin_lock _spin_lock; - - LIBSSH2_CHANNEL* open_channel( const fc::string& pty_type ); - static void kbd_callback(const char *name, int name_len, - const char *instruction, int instruction_len, int num_prompts, - const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, - LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, - void **abstract) - { - int i; - size_t n; - char buf[1024]; - client_impl* self = (client_impl*)*abstract; - - //slog( "Keyboard-interactive authentication" ); - // printf("Performing keyboard-interactive authentication.\n"); - - // printf("Authentication name: '"); - // fwrite(name, 1, name_len, stdout); - // printf("'\n"); - - // printf("Authentication instruction: '"); - // fwrite(instruction, 1, instruction_len, stdout); - // printf("'\n"); - - // printf("Number of prompts: %d\n\n", num_prompts); - - for (i = 0; i < num_prompts; i++) { - // printf("Prompt %d from server: '", i); - fwrite(prompts[i].text, 1, prompts[i].length, stdout); - // printf("'\n"); - - // printf("Please type response: "); - - if( self->upass.size() == 0 ) { - fgets(buf, sizeof(buf), stdin); - n = strlen(buf); - while (n > 0 && strchr("\r\n", buf[n - 1])) - n--; - buf[n] = 0; - - #ifdef WIN32 // fix warning - #define strdup _strdup - #endif - responses[i].text = strdup(buf); - responses[i].length = n; - } else { - responses[i].text = strdup(self->upass.c_str()); - responses[i].length = self->upass.size(); - } - - // printf("Response %d from user is '", i); - // fwrite(responses[i].text, 1, responses[i].length, stdout); - // printf("'\n\n"); - } - - // printf("Done. Sending keyboard-interactive responses to server now.\n"); - } // kbd_callback - - void connect() { - try { - if( libssh2_init(0) < 0 ) { FC_THROW_REPORT( "Unable to init libssh2" ); } - - auto eps = fc::asio::tcp::resolve( hostname, fc::lexical_cast(port) ); - if( eps.size() == 0 ) { - FC_THROW_REPORT( "Unable to resolve host '${host}'", fc::value().set("host",hostname) ); - } - sock.reset( new boost::asio::ip::tcp::socket( fc::asio::default_io_service() ) ); - - bool resolved = false; - for( uint32_t i = 0; i < eps.size(); ++i ) { - std::stringstream ss; ss << eps[i]; - try { - boost::system::error_code ec; - fc_ilog( logr, "Attempting to connect to ${endpoint}", ("endpoint",ss.str().c_str()) ); - fc::asio::tcp::connect( *sock, eps[i] ); - endpt = eps[i]; - resolved = true; - break; - } catch ( fc::error_report& er ) { - fc_ilog( logr, "Failed to connect to ${endpoint}\n${error_reprot}", - ("endpoint",ss.str().c_str())("error_report", er.to_detail_string()) ); - sock->close(); - } - } - if( !resolved ) { - FC_THROW_REPORT( "Unable to connect to any resolved endpoint for ${host}:${port}", - fc::value().set("host", hostname).set("port",port) ); - } - session = libssh2_session_init(); - libssh2_trace( session, _trace_level ); - libssh2_trace_sethandler( session, this, client_impl::handle_trace ); - - *libssh2_session_abstract(session) = this; - - libssh2_session_set_blocking( session, 0 ); - int ec = libssh2_session_handshake( session, sock->native() ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - wait_on_socket(); - ec = libssh2_session_handshake( session, sock->native() ); - } - if( ec < 0 ) { - char* msg; - libssh2_session_last_error( session, &msg, 0, 0 ); - FC_THROW_REPORT( "SSH Handshake error: ${code} - ${message}", - fc::value().set("code",ec).set("message", msg) ); - } - const char* fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); - //slog( "fingerprint: %s", fingerprint ); - - // try to authenticate, throw on error. - authenticate(); - //slog("."); - } catch ( error_report& er ) { - elog( "%s", er.to_detail_string().c_str() ); - close(); - throw FC_REPORT_PUSH( er, "Unable to connect to ssh server" );; - } catch ( ... ) { - close(); - FC_THROW_REPORT( "Unable to connect to ssh server", fc::value().set("exception", fc::except_str() ) ); - } - } - - static void handle_trace( LIBSSH2_SESSION* session, void* context, const char* data, size_t length ) { - client_impl* my = (client_impl*)context; - fc::string str(data,length); - fc_wlog( my->logr, "${message}", ("message",str) ); - } - - - void close() { - if( session ) { - if( sftp ) { - int ec = libssh2_sftp_shutdown(sftp); - try { - while( ec == LIBSSH2_ERROR_EAGAIN ) { - wait_on_socket(); - ec = libssh2_sftp_shutdown(sftp); - } - }catch(...){ - fc_wlog( logr, "caught closing sftp session" ); - } - sftp = 0; - } - try { - int ec = libssh2_session_disconnect(session, "exit cleanly" ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - wait_on_socket(); - ec = libssh2_session_disconnect(session, "exit cleanly" ); - } - ec = libssh2_session_free(session); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - wait_on_socket(); - ec = libssh2_session_free(session ); - } - session = 0; - } catch ( ... ){ - fc_wlog( logr, "caught freeing session" ); - session = 0; - } - try { - if( sock ) { - sock->close(); - } - } catch ( ... ){ - fc_wlog( logr, "caught error closing socket" ); - } - sock.reset(0); - try { - if( read_prom ) read_prom->wait(); - } catch ( ... ){ - fc_wlog( logr, "caught error waiting on read" ); - } - try { - if( write_prom ) write_prom->wait(); - } catch ( ... ){ - fc_wlog( logr, "caught error waiting on write" ); - } - } - } - - void authenticate() { - try { - char * alist = libssh2_userauth_list(session, uname.c_str(),uname.size()); - char * msg = 0; - int ec = 0; - - if(alist==NULL){ - if(libssh2_userauth_authenticated(session)){ - return; // CONNECTED! - } - ec = libssh2_session_last_error(session,&msg,NULL,0); - - while( !alist && (ec == LIBSSH2_ERROR_EAGAIN) ) { - wait_on_socket(); - alist = libssh2_userauth_list(session, uname.c_str(), uname.size()); - ec = libssh2_session_last_error(session,&msg,NULL,0); - } - if( !alist ) { - FC_THROW_REPORT( "Error getting authorization list: ${code} - ${message}", - fc::value().set("code",ec).set("message",msg)); - } - } - - std::vector split_alist; - bool pubkey = false; - bool pass = false; - bool keybd = false; - boost::split( split_alist, alist, boost::is_any_of(",") ); - std::for_each( split_alist.begin(), split_alist.end(), [&](const std::string& s){ - if( s == "publickey" ) { - pubkey = true; - } - else if( s == "password" ) { - pass = true; - } - else if( s == "keyboard-interactive" ) { - keybd = true; - } - else { - fc_wlog( logr, "Unknown/unsupported authentication type '${auth_type}'", ("auth_type",s.c_str())); - } - }); - - if( pubkey ) { - if( try_pub_key() ) - return; - } - if( pass ) { - if( try_pass() ) - return; - } - if( keybd ) { - if( try_keyboard() ) - return; - } - } catch ( error_report er ) { - throw FC_REPORT_PUSH( er, "Unable to authenticate ssh connection" ); - } - FC_THROW_REPORT( "Unable to authenticate ssh connection" ); - } // authenticate() - - bool try_pass() { - int ec = libssh2_userauth_password(session, uname.c_str(), upass.c_str() ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - wait_on_socket(); - ec = libssh2_userauth_password(session, uname.c_str(), upass.c_str() ); - } - - return !ec; - } - bool try_keyboard() { - int ec = libssh2_userauth_keyboard_interactive(session, uname.c_str(), - &client_impl::kbd_callback); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - wait_on_socket(); - ec = libssh2_userauth_keyboard_interactive(session, uname.c_str(), - &client_impl::kbd_callback); - } - return !ec; - } - - bool try_pub_key() { - int ec = libssh2_userauth_publickey_fromfile(session, - uname.c_str(), - pubkey.c_str(), - privkey.c_str(), - passphrase.c_str() ); - - while( ec == LIBSSH2_ERROR_EAGAIN ) { - wait_on_socket(); - ec = libssh2_userauth_publickey_fromfile(session, - uname.c_str(), - pubkey.c_str(), - privkey.c_str(), - passphrase.c_str() ); - } - return !ec; - } - - /** - * @todo figure out why this method results in deadlocks... - */ - void wait_on_socket() { - fc::usleep(fc::microseconds(5000)); - return; - - auto dir = libssh2_session_block_directions(session); - if( !dir ) return; - - fc::promise::ptr rprom, wprom; - if( dir & LIBSSH2_SESSION_BLOCK_INBOUND ) { - fc::scoped_lock lock(this->_spin_lock); - if( !read_prom ) { - read_prom.reset( new fc::promise("read_prom") ); - sock->async_read_some( boost::asio::null_buffers(), - [=]( const boost::system::error_code& e, size_t ) { - fc::scoped_lock lock(this->_spin_lock); - this->read_prom->set_value(e); - this->read_prom.reset(nullptr); - } ); - } - rprom = read_prom; - } - - if( dir & LIBSSH2_SESSION_BLOCK_OUTBOUND ) { - fc::scoped_lock lock(this->_spin_lock); - if( !write_prom ) { - write_prom.reset( new fc::promise("write_prom") ); - sock->async_write_some( boost::asio::null_buffers(), - [=]( const boost::system::error_code& e, size_t ) { - this->write_prom->set_value(e); - this->write_prom.reset(0); - } ); - } - wprom = write_prom; - } - - - boost::system::error_code ec; - if( rprom.get() && wprom.get() ) { - wlog( "wait both dir" ); - typedef fc::future fprom; - fprom fw(wprom); - fprom fr(rprom); - int r = fc::wait_any( fw, fr, fc::seconds(1) ); - switch( r ) { - case 0: - if( wprom->wait() ) { - FC_THROW_REPORT( "Socket Error ${message}", - fc::value().set( "message", boost::system::system_error(rprom->wait() ).what() ) ); - } - break; - case 1: - if( rprom->wait() ) { - FC_THROW_REPORT( "Socket Error ${message}", - fc::value().set( "message", boost::system::system_error(rprom->wait() ).what() ) ); - } - break; - } - } else if( rprom ) { - if( rprom->wait() ) { - FC_THROW_REPORT( "Socket Error ${message}", - fc::value().set( "message", boost::system::system_error(rprom->wait() ).what() ) ); - } - } else if( wprom ) { - if( wprom->wait() ) { - FC_THROW_REPORT( "Socket Error ${message}", - fc::value().set( "message", boost::system::system_error(wprom->wait() ).what() ) ); - } - } - } - - void init_sftp() { - if( !sftp ) { - sftp = libssh2_sftp_init(session); - while( !sftp ) { - char* msg = 0; - int ec = libssh2_session_last_error(session,&msg,NULL,0); - if( ec == LIBSSH2_ERROR_EAGAIN ) { - wait_on_socket(); - sftp = libssh2_sftp_init(session); - } else { - FC_THROW_REPORT( "init sftp error ${code} - ${message}", fc::value().set("code",ec).set("message",msg) ); - } - } - } - } - - int _trace_level; - logger logr; - }; - - } - - client::client():my( new detail::client_impl() ){} - client::~client(){} - - void client::set_trace_level( int bitmask ) { my->_trace_level = bitmask; } - int client::get_trace_level()const { return my->_trace_level; } - const logger& client::get_logger()const { return my->logr; } - void client::set_logger( const logger& l ) { my->logr = l; } - - void client::connect( const fc::string& user, const fc::string& host, uint16_t port ) { - my->hostname = host; - my->uname = user; - my->port = port; - my->connect(); - } - void client::connect( const fc::string& user, const fc::string& pass, - const fc::string& host, uint16_t port ) { - my->hostname = host; - my->uname = user; - my->upass = pass; - my->port = port; - - my->connect(); - } - - - ssh::process client::exec( const fc::string& cmd, const fc::string& pty_type ) { - return ssh::process( *this, cmd, pty_type ); - } - - /** - * @todo implement progress reporting. - */ - void client::scp_send_dir( const fc::path& local_dir, const fc::path& remote_path, - std::function progress ) - { - fc::path remote_dir = remote_path; - if( remote_dir.filename() == fc::path(".") ) - remote_dir /= local_dir.filename(); - - fc_dlog( my->logr, "scp -r ${local} ${remote}", ("local",local_dir)("remote",remote_dir) ); - create_directories( remote_dir ); - - directory_iterator ditr(local_dir); - directory_iterator dend; - - while( ditr != dend ) { - if( (*ditr).filename() == "." || - (*ditr).filename() == ".." ) - { } - else if( fc::is_directory(*ditr) ) - { - scp_send_dir( (*ditr), remote_dir / (*ditr).filename() ); - } else if( fc::is_regular_file(*ditr) ) { - scp_send( *ditr, remote_dir / (*ditr).filename() ); - } else { - fc_wlog( my->logr, "Skipping '${path}", ("path",fc::canonical(*ditr)) ); - } - ++ditr; - } - } - - void client::scp_send( const fc::path& local_path, const fc::path& remote_path, - std::function progress ) { - fc_ilog( my->logr, "scp ${local} ${remote}", ("local",local_path)("remote",remote_path ) ); - /** - * Tests have shown that if one scp is 'blocked' by a need to read (presumably to - * ack recv for the trx window), and then a second transfer begins that the first - * transfer will never be acked. Placing this mutex limits the transfer of - * one file at a time via SCP which is just as well because there is a fixed - * amount of bandwidth. - */ - fc::unique_lock lock(my->scp_send_mutex); - - -// using namespace boost::filesystem; - if( !fc::exists(local_path) ) { - FC_THROW_REPORT( "Source file '${file}' does not exist", fc::value().set("file",local_path) ) ; - } - if( is_directory( local_path ) ) { - FC_THROW_REPORT( "Source file '${file}' is a directory, expected a file", fc::value().set("file",local_path) ) ; - } - - // memory map the file - size_t fsize = file_size(local_path); - if( fsize == 0 ) { - elog( "file size %d", fsize ); - // TODO: handle empty file case - if( progress ) progress(0,0); - return; - } - file_mapping fmap( local_path.string().c_str(), read_only ); - mapped_region mr( fmap, fc::read_only, 0, fsize ); - - LIBSSH2_CHANNEL* chan = 0; - time_t now; - memset( &now, 0, sizeof(now) ); - - // TODO: preserve creation / modification date - // TODO: perserve permissions / exec bit? - chan = libssh2_scp_send64( my->session, remote_path.generic_string().c_str(), 0700, fsize, now, now ); - while( chan == 0 ) { - char* msg; - int ec = libssh2_session_last_error( my->session, &msg, 0, 0 ); - if( ec == LIBSSH2_ERROR_EAGAIN ) { - my->wait_on_socket(); - chan = libssh2_scp_send64( my->session, local_path.generic_string().c_str(), 0700, fsize, now, now ); - } else { - FC_THROW_REPORT( "scp ${local_file} to ${remote_file} failed ${code} - ${message}", - fc::value().set("local_file", local_path).set("remote_file",remote_path).set("code",ec).set("message",msg) ); - } - } - try { - size_t wrote = 0; - char* pos = reinterpret_cast(mr.get_address()); - while( progress( wrote, fsize ) && wrote < fsize ) { - int r = libssh2_channel_write( chan, pos, fsize - wrote ); - while( r == LIBSSH2_ERROR_EAGAIN ) { - my->wait_on_socket(); - r = libssh2_channel_write( chan, pos, fsize - wrote ); - } - if( r < 0 ) { - char* msg = 0; - int ec = libssh2_session_last_error( my->session, &msg, 0, 0 ); - FC_THROW_REPORT( "scp failed ${code} - ${message}", - fc::value().set("code",ec).set("message",msg) ); - } - wrote += r; - pos += r; - } - - auto ec = libssh2_channel_send_eof( chan ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - my->wait_on_socket(); - ec = libssh2_channel_send_eof( chan ); - } - ec = libssh2_channel_wait_eof( chan ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - my->wait_on_socket(); - ec = libssh2_channel_wait_eof( chan ); - } - - ec = libssh2_channel_close( chan ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - my->wait_on_socket(); - ec = libssh2_channel_close( chan ); - } - } catch ( error_report& er ) { - // clean up chan - int ec = libssh2_channel_free(chan ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - my->wait_on_socket(); - ec = libssh2_channel_free( chan ); - } - throw er; - } - int ec = libssh2_channel_free( chan ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - my->wait_on_socket(); - ec = libssh2_channel_free( chan ); - } - if( ec < 0 ) { - char* msg = 0; - int ec = libssh2_session_last_error( my->session, &msg, 0, 0 ); - FC_THROW_REPORT( "scp failed ${code} - ${message}", - fc::value().set("code",ec).set("message",msg) ); - } - - } - - - void client::rm( const fc::path& remote_path ) { - try { - auto s = stat(remote_path); - if( s.is_directory() ) { - FC_THROW_REPORT( "sftp cannot remove directory ${path}", fc::value().set("path",remote_path) ); - } - else if( !s.exists() ) { - return; // nothing to do - } - - int rc = libssh2_sftp_unlink(my->sftp, remote_path.generic_string().c_str() ); - while( rc == LIBSSH2_ERROR_EAGAIN ) { - my->wait_on_socket(); - rc = libssh2_sftp_unlink(my->sftp, remote_path.generic_string().c_str() ); - } - if( 0 != rc ) { - rc = libssh2_sftp_last_error(my->sftp); - FC_THROW_REPORT( "sftp rm failed ${code}", fc::value().set("code",rc) ); - } - } catch ( error_report& er ) { - throw FC_REPORT_PUSH( er, "sftp remove '${remote_path}' failed", fc::value().set("remote_path",remote_path) ); - } - } - - file_attrib client::stat( const fc::path& remote_path ){ - my->init_sftp(); - LIBSSH2_SFTP_ATTRIBUTES att; - int ec = libssh2_sftp_stat( my->sftp, remote_path.generic_string().c_str(), &att ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - my->wait_on_socket(); - ec = libssh2_sftp_stat( my->sftp, remote_path.generic_string().c_str(), &att ); - } - if( ec ) { - return file_attrib(); - } - file_attrib ft; - ft.size = att.filesize; - ft.permissions = att.permissions; - return ft; - } - void client::create_directories( const fc::path& rdir, int mode ) { - boost::filesystem::path dir = rdir; - boost::filesystem::path p; - auto pitr = dir.begin(); - while( pitr != dir.end() ) { - p /= *pitr; - if( !stat( p ).exists() ) { - mkdir(p,mode); - } - ++pitr; - } - } - - void client::mkdir( const fc::path& rdir, int mode ) { - try { - auto s = stat(rdir); - if( s.is_directory() ) return; - else if( s.exists() ) { - FC_THROW_REPORT( "File already exists at path ${path}", fc::value().set("path",rdir) ); - } - - int rc = libssh2_sftp_mkdir(my->sftp, rdir.generic_string().c_str(), mode ); - while( rc == LIBSSH2_ERROR_EAGAIN ) { - my->wait_on_socket(); - rc = libssh2_sftp_mkdir(my->sftp, rdir.generic_string().c_str(), mode ); - } - if( 0 != rc ) { - rc = libssh2_sftp_last_error(my->sftp); - FC_THROW_REPORT( "sftp mkdir error", fc::value().set("code",rc) ); - } - } catch ( error_report& er ) { - throw FC_REPORT_PUSH( er, "sftp failed to create directory '${directory}'", fc::value().set( "directory", rdir ) ); - } - } - - void client::close() { - if( my->session ) { - if( my->sftp ) { - int ec = libssh2_sftp_shutdown(my->sftp); - try { - while( ec == LIBSSH2_ERROR_EAGAIN ) { - my->wait_on_socket(); - ec = libssh2_sftp_shutdown(my->sftp); - } - }catch(...){ - fc_wlog( my->logr, "caught closing sftp sessionn" ); - } - my->sftp = 0; - } - try { - int ec = libssh2_session_disconnect(my->session, "exit cleanly" ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - my->wait_on_socket(); - ec = libssh2_session_disconnect(my->session, "exit cleanly" ); - } - ec = libssh2_session_free(my->session); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - my->wait_on_socket(); - ec = libssh2_session_free(my->session ); - } - my->session = 0; - } catch ( ... ){ - fc_wlog( my->logr, "caught error freeing session" ); - my->session = 0; - } - try { - if( my->sock ) { - my->sock->close(); - } - } catch ( ... ){ - fc_wlog( my->logr, "caught error closing socket" ); - } - my->sock.reset(0); - try { - if( my->read_prom ) my->read_prom->wait(); - } catch ( ... ){ - fc_wlog( my->logr,"caught error waiting on read prom" ); - } - try { - if( my->write_prom ) my->write_prom->wait(); - } catch ( ... ){ - fc_wlog( my->logr, "caught error waiting on write prom" ); - } - } - } - - file_attrib::file_attrib() - :size(0),uid(0),gid(0),permissions(0),atime(0),mtime(0) - { } - - bool file_attrib::is_directory() { - return LIBSSH2_SFTP_S_ISDIR(permissions); - } - bool file_attrib::is_file() { - return LIBSSH2_SFTP_S_ISREG(permissions); - } - bool file_attrib::exists() { - return 0 != permissions; - } - - - - - process::process() - {} - process::~process() - {} - bool process::valid()const { - return !!my; - } - - /** - * Blocks until the result code of the process has been returned. - */ - int process::result() { - char* msg = 0; - - int ec = libssh2_channel_wait_eof( my->chan ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - my->sshc.my->wait_on_socket(); - ec = libssh2_channel_wait_eof( my->chan ); - } - - ec = libssh2_channel_wait_closed( my->chan ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - my->sshc.my->wait_on_socket(); - ec = libssh2_channel_wait_closed( my->chan ); - } - ec = libssh2_session_last_error( my->sshc.my->session, &msg, 0, 0 ); - if( !ec ) { - FC_THROW_REPORT( "Error waiting on socket to close: ${message}", fc::value().set("message",msg) );//%ec %msg ); - } - return libssh2_channel_get_exit_status( my->chan ); - } - /** - * @brief returns a stream that writes to the procss' stdin - */ - fc::ostream& process::in_stream()const { - return my->std_in; - } - /** - * @brief returns a stream that reads from the process' stdout - */ - fc::istream& process::out_stream()const { - return my->std_out; - } - /** - * @brief returns a stream that reads from the process' stderr - */ - fc::istream& process::err_stream()const { - return my->std_err; - } - - process::process( const process& p ) - :my(p.my){ } - process::process( process&& p ) - :my(fc::move(p.my)){ } - - process::process( client& c, const fc::string& cmd, const fc::string& pty_type) - :my( new detail::process_impl( c, cmd, pty_type ) ) - { - } - - - void detail::process_impl::flush() { - if( !chan ) return; - /* channel_flush deleates input buffer, and does not ensure writes go out - * - int ec = libssh2_channel_flush_ex( chan, LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - sshc.my->wait_on_socket(); - ec = libssh2_channel_flush_ex( chan, LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA ); - } - ec = libssh2_channel_flush( chan ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - sshc.my->wait_on_socket(); - ec = libssh2_channel_flush( chan ); - } - if( ec < 0 ) { - FC_THROW_REPORT( "ssh flush failed", fc::value().set( "channel_error", ec) ); - } - */ - } - int detail::process_impl::read_some( char* data, size_t len, int stream_id ){ - if( !sshc.my->session ) { FC_THROW_REPORT( "Session closed" ); } - - int rc; - char* buf = data; - size_t buflen = len; - do { - rc = libssh2_channel_read_ex( chan, stream_id, buf, buflen ); - if( rc > 0 ) { - buf += rc; - buflen -= rc; - return buf-data; - } else if( rc == 0 ) { - if( libssh2_channel_eof( chan ) ) { - return -1; // eof - } - sshc.my->wait_on_socket(); - } else { - if( rc == LIBSSH2_ERROR_EAGAIN ) { - if( 0 < (buf-data) ) { - return buf-data; - } - else { - sshc.my->wait_on_socket(); - rc = 0; - continue; - } - } else { - char* msg; - if( !sshc.my || !sshc.my->session ) { FC_THROW_REPORT( "Session closed" ); } - rc = libssh2_session_last_error( sshc.my->session, &msg, 0, 0 ); - FC_THROW_REPORT( "read failed: ${message}", fc::value().set("message", msg).set("code", rc) ); - } - } - } while( rc >= 0 && buflen); - return buf-data; - } - int detail::process_impl::write_some( const char* data, size_t len, int stream_id ) { - if( !sshc.my->session ) { FC_THROW_REPORT( "Session closed" ); } - - int rc; - const char* buf = data; - size_t buflen = len; - do { - rc = libssh2_channel_write_ex( chan, stream_id, buf, buflen ); - if( rc > 0 ) { - buf += rc; - buflen -= rc; - return buf-data; - } else if( rc == 0 ) { - if( libssh2_channel_eof( chan ) ) { - FC_THROW_REPORT( "EOF" ); - //return -1; // eof - } - } else { - - if( rc == LIBSSH2_ERROR_EAGAIN ) { - if( 0 < (buf-data) ) { - return buf-data; - } - else { - sshc.my->wait_on_socket(); - rc = 0; - continue; - } - } else { - char* msg; - rc = libssh2_session_last_error( sshc.my->session, &msg, 0, 0 ); - FC_THROW_REPORT( "write failed: ${message}", fc::value().set("message",msg).set("code",rc) ); - return buf-data; - } - } - } while( rc >= 0 && buflen); - return buf-data; - } - void detail::process_impl::send_eof() { - if( sshc.my->session ) { - int ec = libssh2_channel_send_eof( chan ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - sshc.my->wait_on_socket(); - ec = libssh2_channel_send_eof( chan ); - } - if( ec ) { - char* msg = 0; - ec = libssh2_session_last_error( sshc.my->session, &msg, 0, 0 ); - FC_THROW_REPORT( "send eof failed: ${message}", fc::value().set("message",msg).set("code",ec) ); - } - } - } - - size_t detail::process_istream::readsome( char* buf, size_t len ) { - return proc.read_some( buf, len, chan ); - } - istream& detail::process_istream::read( char* buf, size_t len ) { - size_t r = 0; - do { - r += proc.read_some( buf + r, len - r, chan ); - } while( r < len ); - - return *this; - } - - bool detail::process_istream::eof()const { - return 0 != libssh2_channel_eof( proc.chan ); - } - - ostream& detail::process_ostream::write( const char* buf, size_t len ) { - size_t wrote = 0; - do { - wrote += proc.write_some( buf+wrote, len-wrote, 0 ); - } while( wrote < len ); - return *this; - } - void detail::process_ostream::close(){ - proc.send_eof(); - } - void detail::process_ostream::flush(){ - proc.flush(); - } - detail::process_impl::process_impl( const client& c, const fc::string& cmd, const fc::string& pty_type ) - :sshc(c),std_err(*this,SSH_EXTENDED_DATA_STDERR),std_out(*this,0),std_in(*this) - { - chan = c.my->open_channel(pty_type); - - int ec = libssh2_channel_handle_extended_data2(chan, LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - sshc.my->wait_on_socket(); - ec = libssh2_channel_handle_extended_data2(chan, LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL ); - } - - if( cmd.size() == 0 ) { - ec = libssh2_channel_shell(chan ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - sshc.my->wait_on_socket(); - ec = libssh2_channel_shell(chan); - } - } else { - ec = libssh2_channel_exec( chan, cmd.c_str() ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - sshc.my->wait_on_socket(); - ec = libssh2_channel_exec( chan, cmd.c_str() ); - } - } - if( ec ) { - elog( "error starting process" ); - char* msg = 0; - ec = libssh2_session_last_error( sshc.my->session, &msg, 0, 0 ); - FC_THROW_REPORT( "exec failed: ${message}", fc::value().set("message",msg).set("code",ec) ); - } - } - LIBSSH2_CHANNEL* detail::client_impl::open_channel( const fc::string& pty_type ) { - LIBSSH2_CHANNEL* chan = 0; - chan = libssh2_channel_open_session(session); - if( !chan ) { - char* msg; - int ec = libssh2_session_last_error( session, &msg, 0, 0 ); - while( !chan && ec == LIBSSH2_ERROR_EAGAIN ) { - wait_on_socket(); - chan = libssh2_channel_open_session(session); - ec = libssh2_session_last_error( session, &msg, 0, 0 ); - } - if( !chan ) { - FC_THROW_REPORT( "libssh2_channel_open_session failed: ${message}", fc::value().set("message",msg).set("code",ec) ); - } - } - - if( pty_type.size() ) { - int ec = libssh2_channel_request_pty(chan,pty_type.c_str()); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - wait_on_socket(); - ec = libssh2_channel_request_pty(chan,pty_type.c_str()); - } - if( 0 != ec ) { - char* msg; - ec = libssh2_session_last_error( session, &msg, 0, 0 ); - FC_THROW_REPORT( "libssh2_channel_req_pty failed: ${message}", fc::value().set("message",msg).set("code",ec) ); - } - } - return chan; - } - - process& process::operator=( const process& p ) { - my = p.my; - return *this; - } -} } diff --git a/src/ssh/client.cpp b/src/ssh/client.cpp new file mode 100644 index 0000000..80d8788 --- /dev/null +++ b/src/ssh/client.cpp @@ -0,0 +1,717 @@ +#define NOMINMAX // prevent windows from defining min and max macros +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "client_impl.hpp" + +namespace fc { namespace ssh { + + namespace detail { + static int ssh_init = libssh2_init(0); + } + + client::client():my( new detail::client_impl() ){ (void)detail::ssh_init; /* fix unused warning...*/ } + client::~client() { my->close(); } + + void client::set_trace_level( int bitmask ) { my->_trace_level = bitmask; } + int client::get_trace_level()const { return my->_trace_level; } + const logger& client::get_logger()const { return my->logr; } + void client::set_logger( const logger& l ) { my->logr = l; } + + void client::connect( const fc::string& user, const fc::string& host, uint16_t port ) { + my->hostname = host; + my->uname = user; + my->port = port; + my->connect(); + } + void client::connect( const fc::string& user, const fc::string& pass, + const fc::string& host, uint16_t port ) { + my->hostname = host; + my->uname = user; + my->upass = pass; + my->port = port; + + my->connect(); + } + + void client::close() { my->close(); } + + +// ssh::process client::exec( const fc::string& cmd, const fc::string& pty_type ) { +// return ssh::process( *this, cmd, pty_type ); +// } + + /** + * @todo implement progress reporting. + */ + void client::scp_send_dir( const fc::path& local_dir, const fc::path& remote_path, + std::function progress ) + { + fc::path remote_dir = remote_path; + if( remote_dir.filename() == fc::path(".") ) + remote_dir /= local_dir.filename(); + + fc_dlog( my->logr, "scp -r ${local} ${remote}", ("local",local_dir)("remote",remote_dir) ); + create_directories( remote_dir ); + + directory_iterator ditr(local_dir); + directory_iterator dend; + + while( ditr != dend ) { + if( (*ditr).filename() == "." || + (*ditr).filename() == ".." ) + { } + else if( fc::is_directory(*ditr) ) + { + scp_send_dir( (*ditr), remote_dir / (*ditr).filename() ); + } else if( fc::is_regular_file(*ditr) ) { + scp_send( *ditr, remote_dir / (*ditr).filename() ); + } else { + fc_wlog( my->logr, "Skipping '${path}", ("path",fc::canonical(*ditr)) ); + } + ++ditr; + } + } + + void client::scp_send( const fc::path& local_path, const fc::path& remote_path, + std::function progress ) { + fc_wlog( my->logr, "scp ${local} ${remote}", ("local",local_path)("remote",remote_path ) ); + if( !fc::exists(local_path) ) { + FC_THROW( "Source file '${file}' does not exist", ("file",local_path) ) ; + } + if( is_directory( local_path ) ) { + FC_THROW( "Source file '${file}' is a directory, expected a file", ("file",local_path) ) ; + } + + // memory map the file + uint64_t fsize = file_size(local_path); + if( fsize == 0 ) { + elog( "file size ${file_size}", ("file_size", fsize) ); + // TODO: handle empty file case + if( progress ) progress(0,0); + return; + } + file_mapping fmap( local_path.string().c_str(), read_only ); + + LIBSSH2_CHANNEL* chan = 0; + time_t now; + memset( &now, 0, sizeof(now) ); + + // TODO: preserve creation / modification date + // TODO: perserve permissions / exec bit? + try { + // libssh2_scp_send64 stores state data in the session object, and it calls channel_open which + // stores its own state data, so lock both. + fc::scoped_lock channel_open_lock(my->channel_open_mutex); + fc::scoped_lock scp_send_lock(my->scp_send_mutex); + chan = my->call_ssh2_ptr_function_throw(boost::bind(libssh2_scp_send64, my->session, remote_path.generic_string().c_str(), 0700, fsize, now, now )); + } catch (fc::exception& er) { + FC_RETHROW_EXCEPTION(er, error, "scp ${local_file} to ${remote_file} failed", ("local_file", local_path)("remote_file",remote_path)); + } + uint64_t total_bytes_written = 0; + try { + const size_t max_mapping_size = 1024*1024*1024; // 1GB + for (uint64_t current_offset = 0; current_offset < fsize; current_offset += max_mapping_size) { + uint64_t total_bytes_left_to_send = fsize - current_offset; + size_t bytes_to_send_this_iteration = (size_t)std::min(total_bytes_left_to_send, max_mapping_size); + mapped_region mr( fmap, fc::read_only, current_offset, bytes_to_send_this_iteration); + size_t bytes_written_this_iteration = 0; + char* pos = reinterpret_cast(mr.get_address()); + while( progress(total_bytes_written, fsize) && bytes_written_this_iteration < bytes_to_send_this_iteration) { + int r = my->call_ssh2_function_throw(boost::bind(libssh2_channel_write_ex, chan, 0, pos, + bytes_to_send_this_iteration - bytes_written_this_iteration), + "scp failed ${code} - ${message}"); + bytes_written_this_iteration += r; + total_bytes_written += r; + pos += r; + // fc_wlog( my->logr, "wrote ${bytes} bytes", ("bytes",r) ); + } + } + my->call_ssh2_function(boost::bind(libssh2_channel_send_eof, chan)); + my->call_ssh2_function(boost::bind(libssh2_channel_wait_eof, chan)); + my->call_ssh2_function(boost::bind(libssh2_channel_close, chan)); + } catch ( fc::exception& er ) { + // clean up chan + my->call_ssh2_function(boost::bind(libssh2_channel_free, chan)); + throw er; + } + my->call_ssh2_function_throw(boost::bind(libssh2_channel_free, chan), + "scp failed ${code} - ${message}"); + } + + + void client::rm( const fc::path& remote_path ) { + try { + auto s = stat(remote_path); + if( s.is_directory() ) { + FC_THROW( "sftp cannot remove directory ${path}", ("path",remote_path) ); + } + else if( !s.exists() ) { + return; // nothing to do + } + + { + fc::scoped_lock scp_unlink_lock(my->scp_unlink_mutex); + my->call_ssh2_function_throw(boost::bind(libssh2_sftp_unlink_ex, my->sftp, remote_path.generic_string().c_str(), remote_path.generic_string().size()), + "sftp rm failed ${code}"); + } + } catch ( fc::exception& er ) { + FC_RETHROW_EXCEPTION( er, error, "sftp remove '${remote_path}' failed", ("remote_path",remote_path) ); + } + } + + void client::rmdir( const fc::path& remote_path ) { + try { + auto s = stat(remote_path); + if( !s.is_directory() ) + FC_THROW( "sftp cannot rmdir non-directory ${path}", ("path",remote_path) ); + else if( !s.exists() ) + return; // nothing to do + + { + fc::scoped_lock scp_rmdir_lock(my->scp_rmdir_mutex); + my->call_ssh2_function_throw(boost::bind(libssh2_sftp_rmdir_ex, my->sftp, remote_path.generic_string().c_str(), remote_path.generic_string().size()), + "sftp rmdir failed ${code}"); + } + } catch ( fc::exception& er ) { + FC_RETHROW_EXCEPTION( er, error, "sftp rmdir '${remote_path}' failed", ("remote_path",remote_path) ); + } + } + + void client::rmdir_recursive( const fc::path& remote_path ) { + try { + auto s = stat(remote_path); + if( !s.is_directory() ) + FC_THROW( "sftp cannot rmdir non-directory ${path}", ("path",remote_path) ); + else if( !s.exists() ) + return; // nothing to do + + LIBSSH2_SFTP_HANDLE *dir_handle; + { + fc::scoped_lock scp_open_lock(my->scp_open_mutex); + dir_handle = + my->call_ssh2_ptr_function_throw(boost::bind(libssh2_sftp_open_ex, my->sftp, remote_path.generic_string().c_str(), remote_path.generic_string().size(), 0, 0, LIBSSH2_SFTP_OPENDIR), + "sftp libssh2_sftp_opendir failed ${code}"); + } + do { + char mem[512]; + LIBSSH2_SFTP_ATTRIBUTES attrs; + + int rc; + { + fc::scoped_lock scp_readdir_lock(my->scp_readdir_mutex); + rc = my->call_ssh2_function_throw(boost::bind(libssh2_sftp_readdir_ex, dir_handle, mem, sizeof(mem), (char*)NULL, 0, &attrs), + "sftp readdir failed ${code}"); + } + if (rc > 0) { + fc::string file_or_dir_name(mem, rc); + if (file_or_dir_name == "." || file_or_dir_name == "..") + continue; + fc::path full_remote_path = remote_path / file_or_dir_name; + if (LIBSSH2_SFTP_S_ISDIR(attrs.permissions)) + rmdir_recursive(full_remote_path); + else if (LIBSSH2_SFTP_S_ISREG(attrs.permissions)) { + fc::scoped_lock scp_unlink_lock(my->scp_unlink_mutex); + my->call_ssh2_function_throw(boost::bind(libssh2_sftp_unlink_ex, my->sftp, full_remote_path.generic_string().c_str(), full_remote_path.generic_string().size()), + "sftp rm failed ${code}"); + } + } else + break; + } while (1); + + { + fc::scoped_lock scp_close_lock(my->scp_close_mutex); + my->call_ssh2_function_throw(boost::bind(libssh2_sftp_close_handle, dir_handle), "sftp libssh2_sftp_closedir failed ${code}"); + } + { + fc::scoped_lock scp_rmdir_lock(my->scp_rmdir_mutex); + my->call_ssh2_function_throw(boost::bind(libssh2_sftp_rmdir_ex, my->sftp, remote_path.generic_string().c_str(), remote_path.generic_string().size()), + "sftp rmdir failed ${code}"); + } + } catch ( fc::exception& er ) { + FC_RETHROW_EXCEPTION( er, error, "sftp rmdir recursive '${remote_path}' failed", ("remote_path",remote_path) ); + } + } + + file_attrib client::stat( const fc::path& remote_path ){ + my->init_sftp(); + LIBSSH2_SFTP_ATTRIBUTES att; + int ec; + { + fc::scoped_lock scp_stat_lock(my->scp_stat_mutex); + ec = my->call_ssh2_function(boost::bind(libssh2_sftp_stat_ex, my->sftp, + remote_path.generic_string().c_str(), remote_path.generic_string().size(), + LIBSSH2_SFTP_STAT, &att)); + } + if( ec ) + return file_attrib(); + file_attrib ft; + ft.size = att.filesize; + ft.permissions = att.permissions; + return ft; + } + void client::create_directories( const fc::path& rdir, int mode ) { + boost::filesystem::path dir = rdir; + boost::filesystem::path p; + auto pitr = dir.begin(); + while( pitr != dir.end() ) { + p /= *pitr; + if( !stat( p ).exists() ) { + mkdir(p,mode); + } + ++pitr; + } + } + + void client::mkdir( const fc::path& rdir, int mode ) { + try { + auto s = stat(rdir); + if( s.is_directory() ) + return; + else if( s.exists() ) + FC_THROW( "File already exists at path ${path}", ("path",rdir) ); + + { + fc::scoped_lock scp_mkdir_lock(my->scp_mkdir_mutex); + my->call_ssh2_function_throw(boost::bind(libssh2_sftp_mkdir_ex, my->sftp, + rdir.generic_string().c_str(), rdir.generic_string().size(), mode), + "sftp mkdir error"); + } + } catch ( fc::exception& er ) { + FC_RETHROW_EXCEPTION( er, error, "sftp failed to create directory '${directory}'", ( "directory", rdir ) ); + } + } + + void client::set_remote_system_is_windows(bool is_windows /* = true */) { + my->remote_system_is_windows = is_windows; + } + + + file_attrib::file_attrib() + :size(0),uid(0),gid(0),permissions(0),atime(0),mtime(0) + { } + + bool file_attrib::is_directory() { + return LIBSSH2_SFTP_S_ISDIR(permissions); + } + bool file_attrib::is_file() { + return LIBSSH2_SFTP_S_ISREG(permissions); + } + bool file_attrib::exists() { + return 0 != permissions; + } + + detail::client_impl::client_impl() : + session(nullptr), + knownhosts(nullptr), + sftp(nullptr), + agent(nullptr), + _trace_level(0), // was LIBSSH2_TRACE_ERROR + logr(fc::logger::get( "fc::ssh::client" )), + remote_system_is_windows(false) { + logr.set_parent( fc::logger::get( "default" ) ); + } + + detail::client_impl::~client_impl() { + close(); + } + + /* static */ + void detail::client_impl::kbd_callback(const char *name, int name_len, + const char *instruction, int instruction_len, int num_prompts, + const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, + LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, + void **abstract) { + detail::client_impl* self = (client_impl*)*abstract; + + + for (int i = 0; i < num_prompts; i++) { + fwrite(prompts[i].text, 1, prompts[i].length, stdout); + + if( self->upass.size() == 0 ) { + /** TODO: add keyboard callback here... + fgets(buf, sizeof(buf), stdin); + n = strlen(buf); + while (n > 0 && strchr("\r\n", buf[n - 1])) + n--; + buf[n] = 0; + +#ifdef WIN32 // fix warning +# define strdup _strdup +#endif + responses[i].text = strdup(buf); + responses[i].length = n; + */ + responses[i].text = nullptr; + responses[i].length = 0; + } else { + responses[i].text = strdup(self->upass.c_str()); + responses[i].length = self->upass.size(); + } + } + } + + void detail::client_impl::connect() { + try { + if( libssh2_init(0) < 0 ) + FC_THROW( "Unable to init libssh2" ); + + auto eps = fc::asio::tcp::resolve( hostname, boost::lexical_cast(port) ); + if( eps.size() == 0 ) + FC_THROW( "Unable to resolve host '${host}'", ("host",hostname) ); + + sock.reset( new boost::asio::ip::tcp::socket( fc::asio::default_io_service() ) ); + + bool resolved = false; + for( uint32_t i = 0; i < eps.size(); ++i ) { + std::stringstream ss; ss << eps[i]; + try { + boost::system::error_code ec; + fc_ilog( logr, "Attempting to connect to ${endpoint}", ("endpoint",ss.str().c_str()) ); + fc::asio::tcp::connect( *sock, eps[i] ); + endpt = eps[i]; + resolved = true; + break; + } catch ( fc::exception& er ) { + fc_ilog( logr, "Failed to connect to ${endpoint}\n${error_reprot}", + ("endpoint",ss.str().c_str())("error_report", er.to_detail_string()) ); + sock->close(); + } + } + if( !resolved ) + FC_THROW( "Unable to connect to any resolved endpoint for ${host}:${port}", + ("host", hostname).set("port",port) ); + + session = libssh2_session_init(); + libssh2_trace( session, _trace_level ); + libssh2_trace_sethandler( session, this, client_impl::handle_trace ); + + *libssh2_session_abstract(session) = this; + + libssh2_session_set_blocking( session, 0 ); + try { + call_ssh2_function_throw(boost::bind(libssh2_session_handshake, session, sock->native()), + "SSH Handshake error: ${code} - ${message}"); + } catch (fc::exception& er) { + FC_RETHROW_EXCEPTION( er, error, "Error during SSH handshake" );; + } + //const char* fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); + //slog( "fingerprint: %s", fingerprint ); + + // try to authenticate, throw on error. + try { + authenticate(); + } catch (fc::exception& er) { + FC_RETHROW_EXCEPTION( er, error, "Error during SSH authentication" );; + } + //slog("."); + } catch ( fc::exception& er ) { + elog( "Unable to connect to ssh server: ${detail}", ("detail", er.to_detail_string().c_str()) ); + close(); + FC_RETHROW_EXCEPTION( er, error, "Unable to connect to ssh server" );; + } catch ( ... ) { + close(); + FC_THROW( "Unable to connect to ssh server", ("exception", fc::except_str() ) ); + } + } + + /* static */ + void detail::client_impl::handle_trace( LIBSSH2_SESSION* session, void* context, const char* data, size_t length ) { + client_impl* my = (client_impl*)context; + fc::string str(data,length); + fc_wlog( my->logr, "${message}", ("message",str) ); + } + + void detail::client_impl::close() { + if( session ) { + if( sftp ) { + try { + call_ssh2_function(boost::bind(libssh2_sftp_shutdown, sftp)); + }catch(...){ + fc_wlog( logr, "caught closing sftp session" ); + } + sftp = 0; + } + + if (agent) { + libssh2_agent_disconnect(agent); + libssh2_agent_free(agent); + agent = nullptr; + } + + try { + call_ssh2_function(boost::bind(libssh2_session_disconnect_ex, session, SSH_DISCONNECT_BY_APPLICATION, "exit cleanly", "")); + call_ssh2_function(boost::bind(libssh2_session_free, session), false); + } catch ( ... ){ + fc_wlog( logr, "caught freeing session" ); + } + session = 0; + try { + if( sock ) + sock->close(); + } catch ( ... ){ + fc_wlog( logr, "caught error closing socket" ); + } + sock.reset(0); + try { + if( read_prom ) + read_prom->wait(); + } catch ( ... ){ + fc_wlog( logr, "caught error waiting on read" ); + } + try { + if( write_prom ) + write_prom->wait(); + } catch ( ... ){ + fc_wlog( logr, "caught error waiting on write" ); + } + } + } + + void detail::client_impl::authenticate() { + try { + char * alist = NULL; + // libssh2_userauth_list has strange enough behavior that we can't use the + // call_blocking_libssh2_function-type functions to wait and retry, so we must + // explicitly lock around the libssh2_userauth_list calls. + // hence, this anonymous scope: + { + fc::unique_lock lock(ssh_session_mutex); + + alist = libssh2_userauth_list(session, uname.c_str(),uname.size()); + + if(alist==NULL) { + char * msg = 0; + int ec = 0; + if(libssh2_userauth_authenticated(session)) + return; // CONNECTED! + ec = libssh2_session_last_error(session,&msg,NULL,0); + + while( !alist && (ec == LIBSSH2_ERROR_EAGAIN) ) { + wait_on_socket(); + alist = libssh2_userauth_list(session, uname.c_str(), uname.size()); + ec = libssh2_session_last_error(session,&msg,NULL,0); + } + if( !alist ) { + FC_THROW( "Error getting authorization list: ${code} - ${message}", + ("code",ec).set("message",msg)); + } + } + } // end anonymous scope + + std::vector split_alist; + bool pubkey = false; + bool pass = false; + bool keybd = false; + boost::split( split_alist, alist, boost::is_any_of(",") ); + std::for_each( split_alist.begin(), split_alist.end(), [&](const std::string& s){ + if( s == "publickey" ) + pubkey = true; + else if( s == "password" ) + pass = true; + else if( s == "keyboard-interactive" ) + keybd = true; + else + fc_dlog( logr, "Unknown/unsupported authentication type '${auth_type}'", ("auth_type",s.c_str())); + }); + + if( pubkey && try_pub_key() ) + return; + if( pass && try_pass() ) + return; + if( keybd && try_keyboard() ) + return; + } catch ( fc::exception& er ) { + FC_RETHROW_EXCEPTION( er, error, "Unable to authenticate ssh connection" ); + } + FC_THROW( "Unable to authenticate ssh connection" ); + } // authenticate() + + bool detail::client_impl::try_pass() { + return !call_ssh2_function(boost::bind(libssh2_userauth_password_ex, session, uname.c_str(), uname.size(), + upass.c_str(), upass.size(), (LIBSSH2_PASSWD_CHANGEREQ_FUNC((*)))NULL)); + } + bool detail::client_impl::try_keyboard() { + return !call_ssh2_function(boost::bind(libssh2_userauth_keyboard_interactive_ex, session, + uname.c_str(), uname.size(), &client_impl::kbd_callback)); + } + bool detail::client_impl::try_pub_key() { + if (privkey.size()) { + if (!call_ssh2_function(boost::bind(libssh2_userauth_publickey_fromfile_ex, + session, + uname.c_str(), uname.size(), + pubkey.c_str(), + privkey.c_str(), + passphrase.c_str()))) + return true; // successful authentication from file + fc_ilog( logr, "failed to authenticate with private key from file '${privkey_filename}'", ("privkey_filename",privkey)); + } else + fc_ilog( logr, "no private key file set, skiping pubkey authorization from file"); + + agent = libssh2_agent_init(session); + if (!agent) { + fc_wlog( logr, "failed to initialize ssh-agent support"); + return false; + } + + if (call_ssh2_function(boost::bind(libssh2_agent_connect, agent))) { + fc_ilog( logr, "failed to connect to ssh-agent"); + return false; + } + + if (call_ssh2_function(boost::bind(libssh2_agent_list_identities, agent))) { + fc_ilog( logr, "failed requesting identities from ssh-agent"); + return false; + } + + struct libssh2_agent_publickey *prev_identity = NULL; + while (1) { + struct libssh2_agent_publickey *identity; + int ec = call_ssh2_function(boost::bind(libssh2_agent_get_identity, agent, &identity, prev_identity)); + if (ec == 1) + break; // done iterating over keys + if (ec < 0) { + fc_ilog( logr, "failed obtaining identity from ssh-agent"); + return false; + } + + if (call_ssh2_function(boost::bind(libssh2_agent_userauth, agent, uname.c_str(), identity))) + fc_ilog( logr, "unable to authenticate with public key '${key_comment}'", ("key_comment",identity->comment)); + else { + fc_ilog( logr, "authenticated with public key '${key_comment}'", ("key_comment",identity->comment)); + return true; + } + prev_identity = identity; + } + return false; + } + + void detail::client_impl::wait_on_socket(int additionalDirections /* = 0 */) { + int dir = libssh2_session_block_directions(session); + dir |= additionalDirections; + if( !dir ) + return; + + fc::promise::ptr rprom, wprom; + if( dir & LIBSSH2_SESSION_BLOCK_INBOUND ) { + fc::scoped_lock lock(this->_spin_lock); + if( !read_prom ) { + read_prom.reset( new fc::promise("read_prom") ); + sock->async_read_some( boost::asio::null_buffers(), + [=]( const boost::system::error_code& e, size_t ) { + fc::scoped_lock lock(this->_spin_lock); + this->read_prom->set_value(e); + this->read_prom.reset(nullptr); + } ); + } + rprom = read_prom; + } + + if( dir & LIBSSH2_SESSION_BLOCK_OUTBOUND ) { + fc::scoped_lock lock(this->_spin_lock); + if( !write_prom ) { + write_prom.reset( new fc::promise("write_prom") ); + sock->async_write_some( boost::asio::null_buffers(), + [=]( const boost::system::error_code& e, size_t ) { + fc::scoped_lock lock(this->_spin_lock); + this->write_prom->set_value(e); + this->write_prom.reset(0); + } ); + } + wprom = write_prom; + } + + boost::system::error_code ec; + if( rprom.get() && wprom.get() ) { + typedef fc::future fprom; + fprom fw(wprom); + fprom fr(rprom); +#if 0 + // EMF: at present there are known bugs in fc::wait_any, and it will fail to wake up + // when one of the futures is ready. + int r = fc::wait_any( fw, fr, fc::seconds(1) ); +#else + int r; + while (1) { + if (fw.ready()) { + r = 0; break; + } + if (fr.ready()) { + r = 1; break; + } + fc::usleep(fc::microseconds(5000)); + } +#endif + switch( r ) { + case 0: + if( wprom->wait() ) { + FC_THROW( "Socket Error ${message}", + ( "message", boost::system::system_error(rprom->wait() ).what() ) ); + } + break; + case 1: + if( rprom->wait() ) { + FC_THROW( "Socket Error ${message}", + ( "message", boost::system::system_error(rprom->wait() ).what() ) ); + } + break; + } + } else if( rprom ) { + if( rprom->wait() ) { + FC_THROW( "Socket Error ${message}", + ( "message", boost::system::system_error(rprom->wait() ).what() ) ); + } + } else if( wprom ) { + if( wprom->wait() ) { + FC_THROW( "Socket Error ${message}", + ( "message", boost::system::system_error(wprom->wait() ).what() ) ); + } + } + } + void detail::client_impl::init_sftp() { + if( !sftp ) + sftp = call_ssh2_ptr_function_throw(boost::bind(libssh2_sftp_init,session), + "init sftp error ${code} - ${message}"); + } + + + LIBSSH2_CHANNEL* detail::client_impl::open_channel( const fc::string& pty_type ) { + LIBSSH2_CHANNEL* chan = 0; + /* anonymous scope */ { + fc::scoped_lock channel_open_lock(channel_open_mutex); + + chan = call_ssh2_ptr_function_throw(boost::bind(libssh2_channel_open_ex, session, + "session", sizeof("session") - 1, + LIBSSH2_CHANNEL_WINDOW_DEFAULT, + LIBSSH2_CHANNEL_PACKET_DEFAULT, + (const char*)NULL, 0), + "libssh2_channel_open_session failed: ${message}"); + } + + if( pty_type.size() ) + call_ssh2_function_throw(boost::bind(libssh2_channel_request_pty_ex, chan, pty_type.c_str(), pty_type.size(), + (char *)NULL, 0, LIBSSH2_TERM_WIDTH, LIBSSH2_TERM_HEIGHT, + LIBSSH2_TERM_WIDTH_PX, LIBSSH2_TERM_HEIGHT_PX), + "libssh2_channel_req_pty failed: ${message}"); + return chan; + } + +} } diff --git a/src/ssh/client_impl.hpp b/src/ssh/client_impl.hpp new file mode 100644 index 0000000..606bd36 --- /dev/null +++ b/src/ssh/client_impl.hpp @@ -0,0 +1,280 @@ +#define NOMINMAX +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +// include this to get acess to the details of the LIBSSH2_SESSION structure, so +// we can verify that all data has really been sent when libssh2 says it has. +#include <../src/libssh2_priv.h> + +namespace fc { namespace ssh { + + namespace detail { + + class client_impl { + public: + client_impl(); + ~client_impl(); + + LIBSSH2_SESSION* session; + LIBSSH2_KNOWNHOSTS* knownhosts; + LIBSSH2_SFTP* sftp; + LIBSSH2_AGENT* agent; + + std::unique_ptr sock; + boost::asio::ip::tcp::endpoint endpt; + + fc::mutex ssh_session_mutex; + fc::mutex channel_open_mutex; + fc::mutex process_startup_mutex; + fc::mutex scp_send_mutex; + fc::mutex scp_stat_mutex; + fc::mutex scp_mkdir_mutex; + fc::mutex scp_rmdir_mutex; + fc::mutex scp_unlink_mutex; + fc::mutex scp_close_mutex; + fc::mutex scp_readdir_mutex; + fc::mutex scp_open_mutex; + + fc::string uname; + fc::string upass; + fc::string pubkey; + fc::string privkey; + fc::string passphrase; + fc::string hostname; + uint16_t port; + bool session_connected; + fc::promise::ptr read_prom; + fc::promise::ptr write_prom; + fc::spin_lock _spin_lock; + int _trace_level; + logger logr; + + bool remote_system_is_windows; // true if windows, false if unix, used for command-line quoting and maybe filename translation + + LIBSSH2_CHANNEL* open_channel( const fc::string& pty_type ); + static void kbd_callback(const char *name, int name_len, + const char *instruction, int instruction_len, int num_prompts, + const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, + LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, + void **abstract); + + void connect(); + + static void handle_trace( LIBSSH2_SESSION* session, void* context, const char* data, size_t length ); + + void close(); + void authenticate(); + + bool try_pass(); + bool try_keyboard(); + bool try_pub_key(); + + // don't call this "unlocked" version directly + template + int call_ssh2_function_unlocked(const T& lambda, bool check_for_errors = true); + + // calls into libssh2, waits and retries the function if we get LIBSSH2_ERROR_EAGAIN + template + int call_ssh2_function(const T& lambda, bool check_for_errors = true); + + // calls into libssh2, waits and retries the function if we get LIBSSH2_ERROR_EAGAIN + // if libssh2 returns an error, get extended info and throw a message with ${code} and ${message} + // set appropriately. + template + int call_ssh2_function_throw(const T& lambda, const char* message = "libssh2 call failed ${code} - ${message}", bool check_for_errors = true); + + // this version is a little different, it handles functions like libssh2_sftp_init which return + // a pointer instead of an int. These retry automatically if the result is NULL and the error + // is LIBSSH2_ERROR_EAGAIN + template + return_type call_ssh2_ptr_function_throw(std::function lambda, const char* message = "libssh2 call failed ${code} - ${message}", bool check_for_errors = true); + + void wait_on_socket(int additionalDirections = 0); + + void init_sftp(); + }; + + + // #define OLD_BLOCKING, + // the OLD_BLOCKING version of these functions will ensure that if a libssh2 function returns + // LIBSSH2_ERROR_EAGAIN, no other libssh2 functions will be called until that function has been + // called again and returned some other value. + // + // if you don't define this and use the new version of this, we will release the lock and let + // other libssh2 functions be called *unless* it appears that there was unwritten data. + // + // the OLD_BLOCKING version is too conservative -- if you try to read on a channel that doesn't + // have any data, you're likely to deadlock. The new version is not heavily tested and may be + // too lax, time will tell. +#ifdef OLD_BLOCKING + // don't call this "unlocked" version directly + template + int client_impl::call_ssh2_function_unlocked(const T& lambda, bool check_for_errors /* = true */) { + int ec = lambda(); + while (ec == LIBSSH2_ERROR_EAGAIN ) { + wait_on_socket(); + ec = lambda(); + } + + // this assert catches bugs in libssh2 if libssh2 returns ec != LIBSSH2_ERROR_EAGAIN + // but the internal session data indicates a data write is still in progress + // set check_for_errors to false when closing the connection + assert(!check_for_errors || !session->packet.olen); + + return ec; + } + + // calls into libssh2, waits and retries the function if we get LIBSSH2_ERROR_EAGAIN + template + int client_impl::call_ssh2_function(const T& lambda, bool check_for_errors /* = true */) { + fc::scoped_lock lock(ssh_session_mutex); + return call_ssh2_function_unlocked(lambda, check_for_errors); + } +#else + // calls into libssh2, waits and retries the function if we get LIBSSH2_ERROR_EAGAIN + template + int client_impl::call_ssh2_function(const T& lambda, bool check_for_errors /* = true */) { + fc::unique_lock lock(ssh_session_mutex); + int ec = lambda(); + while (ec == LIBSSH2_ERROR_EAGAIN) { + bool unlock_to_wait = !session->packet.olen; + if (unlock_to_wait) + lock.unlock(); + wait_on_socket(); + if (unlock_to_wait) + lock.lock(); + ec = lambda(); + } + // this assert catches bugs in libssh2 if libssh2 returns ec != LIBSSH2_ERROR_EAGAIN + // but the internal session data indicates a data write is still in progress + // set check_for_errors to false when closing the connection + assert(!check_for_errors || !session->packet.olen); + return ec; + } +#endif + +#ifdef OLD_BLOCKING + // calls into libssh2, waits and retries the function if we get LIBSSH2_ERROR_EAGAIN + // if libssh2 returns an error, get extended info and throw a message with ${code} and ${message} + // set appropriately. + template + int client_impl::call_ssh2_function_throw(const T& lambda, const char* message /* = "libssh2 call failed ${code} - ${message}" */, bool check_for_errors /* = true */) { + fc::scoped_lock lock(ssh_session_mutex); + int ec = call_ssh2_function_unlocked(lambda, check_for_errors); + + if (ec == LIBSSH2_ERROR_SFTP_PROTOCOL && sftp) { + ec = libssh2_sftp_last_error(sftp); + FC_THROW(message, ("code", ec).set("message", "SFTP protocol error")); + } else if( ec < 0 ) { + char* msg = 0; + ec = libssh2_session_last_error( session, &msg, 0, 0 ); + FC_THROW(message, ("code",ec).set("message",msg)); + } + return ec; + } +#else + // calls into libssh2, waits and retries the function if we get LIBSSH2_ERROR_EAGAIN + // if libssh2 returns an error, get extended info and throw a message with ${code} and ${message} + // set appropriately. + template + int client_impl::call_ssh2_function_throw(const T& lambda, const char* message /* = "libssh2 call failed ${code} - ${message}" */, bool check_for_errors /* = true */) { + fc::unique_lock lock(ssh_session_mutex); + int ec = lambda(); + while (ec == LIBSSH2_ERROR_EAGAIN) { + bool unlock_to_wait = !session->packet.olen; + if (unlock_to_wait) + lock.unlock(); + wait_on_socket(); + if (unlock_to_wait) + lock.lock(); + ec = lambda(); + } + // this assert catches bugs in libssh2 if libssh2 returns ec != LIBSSH2_ERROR_EAGAIN + // but the internal session data indicates a data write is still in progress + // set check_for_errors to false when closing the connection + assert(!check_for_errors || !session->packet.olen); + + if (ec == LIBSSH2_ERROR_SFTP_PROTOCOL && sftp) { + ec = libssh2_sftp_last_error(sftp); + FC_THROW(message, ("code", ec).set("message", "SFTP protocol error")); + } else if( ec < 0 ) { + char* msg = 0; + ec = libssh2_session_last_error( session, &msg, 0, 0 ); + FC_THROW(message, ("code",ec).set("message",msg)); + } + return ec; + } +#endif + +#ifdef OLD_BLOCKING + // this version is a little different, it handles functions like libssh2_sftp_init which return + // a pointer instead of an int. These retry automatically if the result is NULL and the error + // is LIBSSH2_ERROR_EAGAIN + template + return_type client_impl::call_ssh2_ptr_function_throw(std::function lambda, const char* message /* = "libssh2 call failed ${code} - ${message}" */, bool check_for_errors /* = true */) { + fc::scoped_lock lock(ssh_session_mutex); + return_type ret = lambda(); + while (!ret) { + char* msg = 0; + int ec = libssh2_session_last_error(session,&msg,NULL,0); + if ( ec == LIBSSH2_ERROR_EAGAIN ) { + wait_on_socket(); + ret = lambda(); + } else if (ec == LIBSSH2_ERROR_SFTP_PROTOCOL && sftp) { + ec = libssh2_sftp_last_error(sftp); + FC_THROW(message, ("code", ec).set("message", "SFTP protocol error")); + } else { + ec = libssh2_session_last_error( session, &msg, 0, 0 ); + FC_THROW(message, ("code",ec).set("message",msg)); + } + } + assert(!check_for_errors || !session->packet.olen); + + return ret; + } +#else + // this version is a little different, it handles functions like libssh2_sftp_init which return + // a pointer instead of an int. These retry automatically if the result is NULL and the error + // is LIBSSH2_ERROR_EAGAIN + template + return_type client_impl::call_ssh2_ptr_function_throw(std::function lambda, const char* message /* = "libssh2 call failed ${code} - ${message}" */, bool check_for_errors /* = true */) { + fc::unique_lock lock(ssh_session_mutex); + return_type ret = lambda(); + while (!ret) { + char* msg = 0; + int ec = libssh2_session_last_error(session,&msg,NULL,0); + if ( ec == LIBSSH2_ERROR_EAGAIN ) { + bool unlock_to_wait = !session->packet.olen; + if (unlock_to_wait) + lock.unlock(); + wait_on_socket(); + if (unlock_to_wait) + lock.lock(); + ret = lambda(); + } else if (ec == LIBSSH2_ERROR_SFTP_PROTOCOL && sftp) { + ec = libssh2_sftp_last_error(sftp); + FC_THROW(message, ("code", ec).set("message", "SFTP protocol error")); + } else { + ec = libssh2_session_last_error( session, &msg, 0, 0 ); + FC_THROW(message, ("code",ec).set("message",msg)); + } + } + assert(!check_for_errors || !session->packet.olen); + + return ret; + } +#endif + } + +} } diff --git a/src/ssh/process.cpp b/src/ssh/process.cpp new file mode 100644 index 0000000..8794c11 --- /dev/null +++ b/src/ssh/process.cpp @@ -0,0 +1,334 @@ +#define NOMINMAX // prevent windows from defining min and max macros +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "client_impl.hpp" + +#if defined (_MSC_VER) +#pragma warning (disable : 4355) +#endif + +namespace fc { namespace ssh { + + namespace detail { + class process_impl; + class process_istream : public fc::istream { + public: + process_istream( process_impl& p, int c ) + :proc(p),chan(c){} + + virtual size_t readsome( char* buf, size_t len ); + + virtual bool eof() const; + + process_impl& proc; + int chan; + }; + + class process_ostream : public fc::ostream { + public: + process_ostream( process_impl& p ) + :proc(p){} + + virtual size_t writesome( const char* buf, size_t len ); + virtual void close(); + virtual void flush(); + + process_impl& proc; + }; + + class process_impl { + public: + process_impl( client_ptr c ); + ~process_impl(); + //process_impl( const client& c, const fc::string& cmd, const fc::string& pty_type ); + void exec(const fc::path& exe, vector args, + const fc::path& work_dir /* = fc::path() */, fc::iprocess::exec_opts opts /* = open_all */); + + + int read_some( char* data, size_t len, int stream_id ); + int write_some( const char* data, size_t len, int stream_id ); + void flush(); + void send_eof(); + + LIBSSH2_CHANNEL* chan; + client_ptr sshc; + buffered_ostream_ptr buffered_std_in; + buffered_istream_ptr buffered_std_out; + buffered_istream_ptr buffered_std_err; + + fc::string command; + fc::promise::ptr result; + + fc::optional return_code; + fc::ostring return_signal; + fc::ostring return_signal_message; + private: + static fc::string windows_shell_escape(const fc::string& str); + static fc::string unix_shell_escape(const fc::string& str); + static fc::string windows_shell_escape_command(const fc::path& exe, const vector& args); + static fc::string unix_shell_escape_command(const fc::path& exe, const vector& args); + }; + + } // end namespace detail + + + process::process(client_ptr c) : + my(new detail::process_impl(c)) + {} + + process::~process() + {} + + iprocess& process::exec( const fc::path& exe, vector args, + const fc::path& work_dir /* = fc::path() */, exec_opts opts /* = open_all */ ) { + my->exec(exe, args, work_dir, opts); + return *this; + } + + /** + * Blocks until the result code of the process has been returned. + */ + int process::result() { + if (!my->return_code && !my->return_signal) { + // we don't have any cached exit status, so wait and obtain the values now + my->sshc->my->call_ssh2_function(boost::bind(libssh2_channel_wait_eof, my->chan)); + my->sshc->my->call_ssh2_function_throw(boost::bind(libssh2_channel_wait_closed, my->chan), + "Error waiting on socket to close: ${message}"); + + char* exit_signal; + char* error_message; + libssh2_channel_get_exit_signal(my->chan, &exit_signal, NULL, &error_message, NULL, NULL, NULL); + if (exit_signal) { + // process terminated with a signal + my->return_signal = exit_signal; + libssh2_free(my->chan->session, exit_signal); + if (error_message) { + my->return_signal_message = error_message; + libssh2_free(my->chan->session, error_message); + } + } else + my->return_code = libssh2_channel_get_exit_status(my->chan); + } + if (my->return_signal) + FC_THROW("process terminated with signal ${signal}: ${signal_message}", ("signal", *my->return_signal) + ("signal_message", my->return_signal_message ? *my->return_signal_message : "")); + else + return *my->return_code; + } + + void process::kill() { + elog("error: fc::ssh::process::kill() not supported"); + } + + + /** + * @brief returns a stream that writes to the procss' stdin + */ + fc::buffered_ostream_ptr process::in_stream() { + return my->buffered_std_in; + } + + /** + * @brief returns a stream that reads from the process' stdout + */ + fc::buffered_istream_ptr process::out_stream() { + return my->buffered_std_out; + } + + /** + * @brief returns a stream that reads from the process' stderr + */ + fc::buffered_istream_ptr process::err_stream() { + return my->buffered_std_err; + } + + void detail::process_impl::flush() { + if( !chan ) return; + /* channel_flush deleates input buffer, and does not ensure writes go out + * + int ec = libssh2_channel_flush_ex( chan, LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA); + while( ec == LIBSSH2_ERROR_EAGAIN ) { + sshc.my->wait_on_socket(); + ec = libssh2_channel_flush_ex( chan, LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA ); + } + ec = libssh2_channel_flush( chan ); + while( ec == LIBSSH2_ERROR_EAGAIN ) { + sshc.my->wait_on_socket(); + ec = libssh2_channel_flush( chan ); + } + if( ec < 0 ) { + FC_THROW( "ssh flush failed", ( "channel_error", ec) ); + } + */ + } + + int detail::process_impl::read_some( char* data, size_t len, int stream_id ){ + if( !sshc->my->session ) { FC_THROW( "Session closed" ); } + int rc; + char* buf = data; + size_t buflen = len; + do { + rc = sshc->my->call_ssh2_function_throw(boost::bind(libssh2_channel_read_ex, chan, stream_id, buf, buflen), + "read failed: ${message}"); + if( rc > 0 ) { + buf += rc; + buflen -= rc; + return buf-data; + } else if( rc == 0 ) { + if( libssh2_channel_eof( chan ) ) + return -1; // eof + sshc->my->wait_on_socket(); + } + } while( rc >= 0 && buflen); + return buf-data; + } + + int detail::process_impl::write_some( const char* data, size_t len, int stream_id ) { + if( !sshc->my->session ) { FC_THROW( "Session closed" ); } + + int rc; + const char* buf = data; + size_t buflen = len; + do { + rc = sshc->my->call_ssh2_function_throw(boost::bind(libssh2_channel_write_ex, chan, stream_id, buf, buflen), + "write failed: ${message}"); + if( rc > 0 ) { + buf += rc; + buflen -= rc; + return buf-data; + } else if( rc == 0 ) { + if( libssh2_channel_eof( chan ) ) { + FC_THROW( "EOF" ); + //return -1; // eof + } + } + } while( rc >= 0 && buflen); + return buf-data; + } + + void detail::process_impl::send_eof() { + if( sshc->my->session ) + sshc->my->call_ssh2_function_throw(boost::bind(libssh2_channel_send_eof, chan), + "send eof failed: ${message}"); + } + + size_t detail::process_istream::readsome( char* buf, size_t len ) { + int bytesRead = proc.read_some(buf, len, chan); + if (bytesRead < 0) + FC_THROW("EOF"); + else + return bytesRead; + } + + bool detail::process_istream::eof()const { + return 0 != libssh2_channel_eof( proc.chan ); + } + + size_t detail::process_ostream::writesome( const char* buf, size_t len ) { + return proc.write_some(buf, len, 0); + } + + void detail::process_ostream::close(){ + proc.send_eof(); + } + + void detail::process_ostream::flush(){ + proc.flush(); + } + + detail::process_impl::process_impl( client_ptr c ) + :chan(nullptr), + sshc(c), + buffered_std_in(new buffered_ostream(ostream_ptr(new process_ostream(*this)))), + buffered_std_out(new buffered_istream(istream_ptr(new process_istream(*this, 0)))), + buffered_std_err(new buffered_istream(istream_ptr(new process_istream(*this, SSH_EXTENDED_DATA_STDERR)))) + { + } + + detail::process_impl::~process_impl() { + if (chan) { + sshc->my->call_ssh2_function(boost::bind(libssh2_channel_free, chan)); + chan = NULL; + } + } + + // these rules work pretty well for a standard bash shell on unix + fc::string detail::process_impl::unix_shell_escape(const fc::string& str) { + if (str.find_first_of(" ;&|><*?`$(){}[]!#'\"") == fc::string::npos) + return str; + fc::string escaped_quotes(str); + for (size_t start = escaped_quotes.find("'"); + start != fc::string::npos; + start = escaped_quotes.find("'", start + 5)) + escaped_quotes.replace(start, 1, "'\"'\"'"); + fc::string escaped_str("\'"); + escaped_str += escaped_quotes; + escaped_str += "\'"; + return escaped_str; + } + fc::string detail::process_impl::unix_shell_escape_command(const fc::path& exe, const vector& args) { + fc::stringstream command_line; + command_line << unix_shell_escape(exe.string()); + for (unsigned i = 0; i < args.size(); ++i) + command_line << " " << unix_shell_escape(args[i]); + return command_line.str(); + } + + // windows command-line escaping rules are a disaster, partly because how the command-line is + // parsed depends on what program you're running. In windows, the command line is passed in + // as a single string, and the process is left to interpret it as it sees fit. The standard + // C runtime uses one set of rules, the function CommandLineToArgvW usually used by + // GUI-mode programs uses a different set. + // Here we try to find a common denominator that works well for simple cases + // it's only minimally tested right now due to time constraints. + fc::string detail::process_impl::windows_shell_escape(const fc::string& str) { + if (str.find_first_of(" \"") == fc::string::npos) + return str; + fc::string escaped_quotes(str); + for (size_t start = escaped_quotes.find("\""); + start != fc::string::npos; + start = escaped_quotes.find("\"", start + 2)) + escaped_quotes.replace(start, 1, "\\\""); + fc::string escaped_str("\""); + escaped_str += escaped_quotes; + escaped_str += "\""; + return escaped_str; + } + fc::string detail::process_impl::windows_shell_escape_command(const fc::path& exe, const vector& args) { + fc::stringstream command_line; + command_line << windows_shell_escape(exe.string()); + for (unsigned i = 0; i < args.size(); ++i) + command_line << " " << windows_shell_escape(args[i]); + return command_line.str(); + } + + void detail::process_impl::exec(const fc::path& exe, vector args, + const fc::path& work_dir /* = fc::path() */, + fc::iprocess::exec_opts opts /* = open_all */) { + chan = sshc->my->open_channel(""); + + sshc->my->call_ssh2_function(boost::bind(libssh2_channel_handle_extended_data2, chan, LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL)); + + try { + fc::scoped_lock process_startup_lock(sshc->my->process_startup_mutex); + fc::string command_line = sshc->my->remote_system_is_windows ? windows_shell_escape_command(exe, args) : unix_shell_escape_command(exe, args); + sshc->my->call_ssh2_function_throw(boost::bind(libssh2_channel_process_startup, chan, "exec", sizeof("exec") - 1, command_line.c_str(), command_line.size()), + "exec failed: ${message}"); // equiv to libssh2_channel_exec(chan, cmd) macro + } catch (fc::exception& er) { + elog( "error starting process" ); + FC_RETHROW_EXCEPTION(er, error, "error starting process"); + } + } + +} } diff --git a/src/string.cpp b/src/string.cpp index 0f164f8..b4945de 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -9,7 +10,6 @@ */ namespace fc { - string::string(const char* s, int l) :my(s,l){ } string::string(){} string::string( const fc::string& c ):my(*c.my) { } @@ -21,6 +21,7 @@ namespace fc { string::~string() { } string::operator std::string&() { return *my; } string::operator const std::string&()const { return *my; } + char* string::data() { return &my->front(); } string::iterator string::begin() { return &(*this)[0]; } string::iterator string::end() { return &(*this)[size()]; } @@ -33,9 +34,17 @@ namespace fc { void string::reserve(size_t r) { my->reserve(r); } size_t string::size()const { return my->size(); } size_t string::find(char c, size_t p)const { return my->find(c,p); } + size_t string::find(const fc::string& str, size_t pos /* = 0 */) const { return my->find(str, pos); } + size_t string::find(const char* s, size_t pos /* = 0 */) const { return my->find(s,pos); } size_t string::rfind(char c, size_t p)const { return my->rfind(c,p); } size_t string::rfind(const char* c, size_t p)const { return my->rfind(c,p); } size_t string::rfind(const fc::string& c, size_t p)const { return my->rfind(c,p); } + size_t string::find_first_of(const fc::string& str, size_t pos /* = 0 */) const { return my->find_first_of(str, pos); } + size_t string::find_first_of(const char* s, size_t pos /* = 0 */) const { return my->find_first_of(s, pos); } + + fc::string& string::replace(size_t pos, size_t len, const string& str) { my->replace(pos, len, str); return *this; } + fc::string& string::replace(size_t pos, size_t len, const char* s) { my->replace(pos, len, s); return *this; } + void string::clear() { my->clear(); } void string::resize( size_t s ) { my->resize(s); } @@ -56,6 +65,38 @@ namespace fc { string operator + ( const string& s, const string& c ) { return string(s) += c; } string operator + ( const string& s, char c ) { return string(s) += c; } + + int64_t to_int64( const fc::string& i ) + { + return boost::lexical_cast(i.c_str()); + } + + uint64_t to_uint64( const fc::string& i ) + { + return boost::lexical_cast(i.c_str()); + } + + double to_double( const fc::string& i) + { + return boost::lexical_cast(i.c_str()); + } + + fc::string to_string( double d) + { + return boost::lexical_cast(d); + } + + fc::string to_string( uint64_t d) + { + return boost::lexical_cast(d); + } + + fc::string to_string( int64_t d) + { + return boost::lexical_cast(d); + } + + } // namespace fc diff --git a/src/super_fast_hash.cpp b/src/super_fast_hash.cpp deleted file mode 100644 index ac1bbca..0000000 --- a/src/super_fast_hash.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/** - Initial Publish Date: Thu, 16 Oct 2008 - Initial Author: Paul Hsieh - @file SuperFastHash.c - @version $Revision$ - @date $LastChangedDate$ - @author $LastChangeAuthor$ - @author Paul Hsieh - - The code below appears to be the fastest hashing algorithm available and is licensed for - anyone to use. An article describing the has function can be found on the link below. This - function is used by Safari and some other big-name programs (so it must be good right?) - - http://www.azillionmonkeys.com/qed/hash.html -*/ -#include -#include - -namespace fc { - - #undef get16bits - #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ - || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) - #define get16bits(d) (*((const uint16_t *) (d))) - #endif - - #if !defined (get16bits) - #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ - +(uint32_t)(((const uint8_t *)(d))[0]) ) - #endif - - uint32_t super_fast_hash (const fc::string& str ) { - return super_fast_hash( str.c_str(), str.size() ); - } - - uint32_t super_fast_hash (const char * data, int len) - { - uint32_t hash = len, tmp; - int rem; - - if (len <= 0 || data == 0) return 0; - - rem = len & 3; - len >>= 2; - - /* Main loop */ - for (;len > 0; len--) - { - hash += get16bits (data); - tmp = (get16bits (data+2) << 11) ^ hash; - hash = (hash << 16) ^ tmp; - data += 2*sizeof (uint16_t); - hash += hash >> 11; - } - - /* Handle end cases */ - switch (rem) - { - case 3: hash += get16bits (data); - hash ^= hash << 16; - hash ^= data[sizeof (uint16_t)] << 18; - hash += hash >> 11; - break; - case 2: hash += get16bits (data); - hash ^= hash << 11; - hash += hash >> 17; - break; - case 1: hash += *data; - hash ^= hash << 10; - hash += hash >> 1; - } - - /* Force "avalanching" of final 127 bits */ - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - - return hash; - } -} // namespace fc - diff --git a/src/task.cpp b/src/task.cpp deleted file mode 100644 index d17f173..0000000 --- a/src/task.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include -#include -#include - - -namespace fc { - task_base::task_base(void* func) - :_functor(func){ - } - - void task_base::run() { - try { - _run_functor( _functor, _promise_impl ); - } catch ( ... ) { - set_exception( current_exception() ); - } - } - task_base::~task_base() { - _destroy_functor( _functor ); - } - - void task_base::_set_active_context(context* c) { - { synchronized( *_spinlock ) - _active_context = c; - } - } -} diff --git a/src/tcp_socket.cpp b/src/tcp_socket.cpp deleted file mode 100644 index 6b0a440..0000000 --- a/src/tcp_socket.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -namespace fc { - - class tcp_socket::impl { - public: - impl():_sock( fc::asio::default_io_service() ){ } - ~impl(){ - if( _sock.is_open() ) _sock.close(); - } - - boost::asio::ip::tcp::socket _sock; - }; - bool tcp_socket::is_open()const { - return my->_sock.is_open(); - } - - tcp_socket::tcp_socket(){}; - - tcp_socket::~tcp_socket(){}; - - void tcp_socket::flush() {} - void tcp_socket::close() { - if( is_open() ) my->_sock.close(); - } - - bool tcp_socket::eof()const { - return !my->_sock.is_open(); - } - - fc::ostream& tcp_socket::write( const char* buf, size_t len ) { - boost::system::error_code ec; - size_t w = my->_sock.write_some( boost::asio::buffer( buf, len ), ec ); - - if( w < len ) { - buf += w; - len -= w; - } - - if( ec == boost::asio::error::would_block ) { - promise::ptr p(new promise("tcp_socket::write")); - boost::asio::async_write( my->_sock, boost::asio::buffer(buf, len), - [=]( const boost::system::error_code& ec, size_t bt ) { - if( !ec ) p->set_value(bt); - else p->set_exception( fc::copy_exception( boost::system::system_error(ec) ) ); - }); - p->wait(); - } else if( ec ) { - elog( "throw... write data failed %s", boost::system::system_error(ec).what() ); - FC_THROW_REPORT( "Failed to write data to tcp socket", - fc::value().set("reason", fc::string(boost::system::system_error(ec).what())) - .set("data", fc::to_hex(buf,len) ) ); - } - return *this; - } - size_t tcp_socket::readsome( char* buf, size_t len ) { - boost::system::error_code ec; - size_t w = my->_sock.read_some( boost::asio::buffer( buf, len ), ec ); - if( ec == boost::asio::error::would_block ) { - promise::ptr p(new promise("tcp_socket::readsome")); - my->_sock.async_read_some( boost::asio::buffer(buf, len), - [=]( const boost::system::error_code& ec, size_t bt ) { - slog( "%d ec: %s", bt, boost::system::system_error(ec).what() ); - if( !ec ) p->set_value(bt); - else p->set_exception( fc::copy_exception( boost::system::system_error(ec) ) ); - }); - return p->wait(); - } else if (ec ) { - slog( "throw!" ); - throw boost::system::system_error(ec); - } - return w; - } - fc::istream& tcp_socket::read( char* buffer, size_t s ) { - size_t r = readsome( buffer, s ); - while( r < s ) { - r += readsome( buffer + r, s - r ); - } - return *this; - } - void tcp_socket::connect_to( const fc::ip::endpoint& e ) { - fc::asio::tcp::connect(my->_sock, fc::asio::tcp::endpoint( boost::asio::ip::address_v4(e.get_address()), e.port() ) ); - } - - class tcp_server::impl { - public: - impl(uint16_t port): - _accept( fc::asio::default_io_service(), boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port) ){ - } - ~impl(){ - _accept.close(); - } - - boost::asio::ip::tcp::acceptor _accept; - }; - void tcp_server::close() { - if( my && my->_accept.is_open() ) my->_accept.close(); - delete my; my = nullptr; - } - tcp_server::tcp_server() - :my(nullptr) { - } - tcp_server::~tcp_server() { - delete my; - } - - - bool tcp_server::accept( tcp_socket& s ) { - if( !my ) return false; - fc::promise::ptr p( new promise("tcp::accept") ); - my->_accept.async_accept( s.my->_sock, [=]( const boost::system::error_code& e ) { - p->set_value(e); - } ); - auto ec = p->wait(); - if( !ec ) s.my->_sock.non_blocking(true); - if( ec ) BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); - return true; - } - void tcp_server::listen( uint16_t port ) { - if( my ) delete my; - my = new impl(port); - } - - - -} // namespace fc diff --git a/src/context.hpp b/src/thread/context.hpp similarity index 68% rename from src/context.hpp rename to src/thread/context.hpp index fb1cfe4..6b827b0 100644 --- a/src/context.hpp +++ b/src/thread/context.hpp @@ -1,18 +1,27 @@ -#ifndef _FC_CONTEXT_HPP_ -#define _FC_CONTEXT_HPP_ -#include -#include +#pragma once +#include #include -#include +#include #include +#include + +#if BOOST_VERSION >= 105300 + #include + namespace bc = boost::context; + namespace bco = boost::coroutines; +#elif BOOST_VERSION >= 105200 + namespace bc = boost::context; +#else + namespace bc = boost::ctx; + namespace bco = boost::ctx; +#endif + namespace fc { class thread; class promise_base; class task_base; - namespace bc = boost::ctx; - /** * maintains information associated with each context such as * where it is blocked, what time it should resume, priority, @@ -22,7 +31,7 @@ namespace fc { typedef fc::context* ptr; - context( void (*sf)(intptr_t), bc::stack_allocator& alloc, fc::thread* t ) + context( void (*sf)(intptr_t), bco::stack_allocator& alloc, fc::thread* t ) : caller_context(0), stack_alloc(&alloc), next_blocked(0), @@ -33,14 +42,23 @@ namespace fc { complete(false), cur_task(0) { - my_context.fc_stack.base = alloc.allocate( bc::default_stacksize() ); - my_context.fc_stack.limit = - static_cast( my_context.fc_stack.base) - bc::default_stacksize(); - make_fcontext( &my_context, sf ); +#if BOOST_VERSION >= 105300 + size_t stack_size = bco::stack_allocator::default_stacksize(); + my_context = bc::make_fcontext(alloc.allocate(stack_size), stack_size, sf); +#else + size_t stack_size = bc::default_stacksize(); + my_context.fc_stack.base = alloc.allocate( stack_size ); + my_context.fc_stack.limit = + static_cast( my_context.fc_stack.base) - stack_size; + make_fcontext( &my_context, sf ); +#endif } - context( fc::thread* t) - :caller_context(0), + context( fc::thread* t) : +#if BOOST_VERSION >= 105300 + my_context(new bc::fcontext_t), +#endif + caller_context(0), stack_alloc(0), next_blocked(0), next_blocked_mutex(0), @@ -52,10 +70,16 @@ namespace fc { {} ~context() { - if(stack_alloc) { + +#if BOOST_VERSION >= 105300 + if(stack_alloc) + stack_alloc->deallocate( my_context->fc_stack.sp, bco::stack_allocator::default_stacksize() ); + else + delete my_context; +#else + if(stack_alloc) stack_alloc->deallocate( my_context.fc_stack.base, bc::default_stacksize() ); - // slog("deallocate stack" ); - } +#endif } struct blocked_promise { @@ -112,13 +136,12 @@ namespace fc { void timeout_blocking_promises() { for( auto i = blocking_prom.begin(); i != blocking_prom.end(); ++i ) { - i->prom->set_exception( fc::copy_exception( future_wait_timeout() ) ); + i->prom->set_exception( std::make_shared() ); } } - template - void except_blocking_promises( const Exception& e ) { + void except_blocking_promises( const exception_ptr& e ) { for( auto i = blocking_prom.begin(); i != blocking_prom.end(); ++i ) { - i->prom->set_exception( fc::copy_exception( e ) ); + i->prom->set_exception( e ); } } void clear_blocking_promises() { @@ -129,9 +152,13 @@ namespace fc { +#if BOOST_VERSION >= 105300 + bc::fcontext_t* my_context; +#else bc::fcontext_t my_context; +#endif fc::context* caller_context; - bc::stack_allocator* stack_alloc; + bco::stack_allocator* stack_alloc; priority prio; //promise_base* prom; std::vector blocking_prom; @@ -148,4 +175,3 @@ namespace fc { } // naemspace fc -#endif // _FC_CONTEXT_HPP_ diff --git a/src/future.cpp b/src/thread/future.cpp similarity index 62% rename from src/future.cpp rename to src/thread/future.cpp index b022646..ebf68a6 100644 --- a/src/future.cpp +++ b/src/thread/future.cpp @@ -1,9 +1,8 @@ -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include @@ -13,7 +12,10 @@ namespace fc { promise_base::promise_base( const char* desc ) :_ready(false), _blocked_thread(nullptr), - _timeout(time_point::max()), +#ifndef NDEBUG + _blocked_fiber_count(0), +#endif + _timeout(time_point::maximum()), _canceled(false), _desc(desc), _compl(nullptr) @@ -31,7 +33,7 @@ namespace fc { } bool promise_base::error()const { { synchronized(_spin_yield) - return _exceptp; + return _exceptp != nullptr; } } @@ -41,26 +43,40 @@ namespace fc { } void promise_base::_wait( const microseconds& timeout_us ){ - if( timeout_us == microseconds::max() ) _wait_until( time_point::max() ); + if( timeout_us == microseconds::maximum() ) _wait_until( time_point::maximum() ); else _wait_until( time_point::now() + timeout_us ); } void promise_base::_wait_until( const time_point& timeout_us ){ { synchronized(_spin_yield) if( _ready ) { - if( _exceptp ) fc::rethrow_exception( _exceptp ); + if( _exceptp ) _exceptp->dynamic_rethrow_exception(); return; } _enqueue_thread(); } thread::current().wait_until( ptr(this,true), timeout_us ); + _dequeue_thread(); if( _ready ) { - if( _exceptp ) fc::rethrow_exception( _exceptp ); + if( _exceptp ) _exceptp->dynamic_rethrow_exception(); return; } - FC_THROW( future_wait_timeout() ); + FC_THROW_EXCEPTION( timeout_exception, "" ); } void promise_base::_enqueue_thread(){ - _blocked_thread =&thread::current(); +#ifndef NDEBUG + ++_blocked_fiber_count; + // only one thread can wait on a promise at any given time + assert(!_blocked_thread || + _blocked_thread == &thread::current()); +#endif + _blocked_thread = &thread::current(); + } + void promise_base::_dequeue_thread(){ +#ifndef NDEBUG + synchronized(_spin_yield) + if (!--_blocked_fiber_count) + _blocked_thread = nullptr; +#endif } void promise_base::_notify(){ if( _blocked_thread != nullptr ) @@ -70,7 +86,7 @@ namespace fc { void promise_base::_set_timeout(){ if( _ready ) return; - set_exception( fc::copy_exception( future_wait_timeout() ) ); + set_exception( std::make_shared() ); } void promise_base::_set_value(const void* s){ // slog( "%p == %d", &_ready, int(_ready)); diff --git a/src/mutex.cpp b/src/thread/mutex.cpp similarity index 85% rename from src/mutex.cpp rename to src/thread/mutex.cpp index 5d59f64..40e2039 100644 --- a/src/mutex.cpp +++ b/src/thread/mutex.cpp @@ -1,7 +1,7 @@ -#include -#include -#include -#include +#include +#include +#include +#include #include "context.hpp" #include "thread_d.hpp" @@ -15,7 +15,7 @@ namespace fc { auto c = m_blist; fc::thread::current().debug("~mutex"); while( c ) { - elog( "still blocking on context %p (%s)", m_blist, (m_blist->cur_task ? m_blist->cur_task->get_desc() : "no current task") ); + // elog( "still blocking on context %p (%s)", m_blist, (m_blist->cur_task ? m_blist->cur_task->get_desc() : "no current task") ); c = c->next_blocked_mutex; } } @@ -125,6 +125,11 @@ namespace fc { // allow recusive locks if ( get_tail( m_blist, n ) == cc ) { + assert(false); + // EMF: I think recursive locks are currently broken -- we need to + // keep track of how many times this mutex has been locked by the + // current context. Unlocking should decrement this count and unblock + // the next context only if the count drops to zero return; } cc->next_blocked_mutex = m_blist; @@ -136,14 +141,14 @@ namespace fc { i = i->next_blocked_mutex; ++cnt; } - wlog( "wait queue len %1%", cnt ); + //wlog( "wait queue len %1%", cnt ); } try { fc::thread::current().yield(false); BOOST_ASSERT( cc->next_blocked_mutex == 0 ); } catch ( ... ) { - wlog( "lock with throw %p %s",this, fc::current_exception().diagnostic_information().c_str() ); + wlog( "lock threw" ); cleanup( *this, m_blist_lock, m_blist, cc); throw; } diff --git a/src/spin_lock.cpp b/src/thread/spin_lock.cpp similarity index 96% rename from src/spin_lock.cpp rename to src/thread/spin_lock.cpp index 8bf72c6..97989c5 100644 --- a/src/spin_lock.cpp +++ b/src/thread/spin_lock.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/spin_yield_lock.cpp b/src/thread/spin_yield_lock.cpp similarity index 96% rename from src/spin_yield_lock.cpp rename to src/thread/spin_yield_lock.cpp index 07d2560..17206da 100644 --- a/src/spin_yield_lock.cpp +++ b/src/thread/spin_yield_lock.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/thread/task.cpp b/src/thread/task.cpp new file mode 100644 index 0000000..c6c6a0e --- /dev/null +++ b/src/thread/task.cpp @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include + +#include +#include + +namespace fc { + task_base::task_base(void* func) + :_functor(func){ + } + + void task_base::run() { + try { + _run_functor( _functor, _promise_impl ); + } + catch ( const exception& e ) + { + set_exception( e.dynamic_copy_exception() ); + } + catch ( ... ) + { + set_exception( std::make_shared( FC_LOG_MESSAGE( warn, "unhandled exception: ${diagnostic}", ("diagnostic",boost::current_exception_diagnostic_information()) ) ) ); + } + } + task_base::~task_base() { + _destroy_functor( _functor ); + } + + void task_base::_set_active_context(context* c) { + { synchronized( *_spinlock ) + _active_context = c; + } + } +} diff --git a/src/thread.cpp b/src/thread/thread.cpp similarity index 84% rename from src/thread.cpp rename to src/thread/thread.cpp index 4aec978..701936a 100644 --- a/src/thread.cpp +++ b/src/thread/thread.cpp @@ -1,6 +1,7 @@ -#include +#include #include -#include +#include +#include #include "thread_d.hpp" namespace fc { @@ -28,11 +29,15 @@ namespace fc { current_thread() = this; p->set_value(); exec(); + } catch ( fc::exception& e ) { + wlog( "unhandled exception" ); + p->set_exception( e.dynamic_copy_exception() ); } catch ( ... ) { - elog( "Caught unhandled exception %s", boost::current_exception_diagnostic_information().c_str() ); + wlog( "unhandled exception" ); + p->set_exception( std::make_shared( FC_LOG_MESSAGE( warn, "unhandled exception: ${diagnostic}", ("diagnostic",boost::current_exception_diagnostic_information()) ) ) ); + //assert( !"unhandled exception" ); + //elog( "Caught unhandled exception %s", boost::current_exception_diagnostic_information().c_str() ); } - delete this->my; - this->my = 0; } ); p->wait(); my->boost_thread = t; @@ -53,11 +58,13 @@ namespace fc { } thread::~thread() { - if( is_current() ) { //slog( "my %p", my ); - delete my; + if( is_current() ) + { + wlog( "delete my" ); + delete my; + } my = 0; - } } thread& thread::current() { @@ -66,20 +73,26 @@ namespace fc { } const string& thread::name()const { return my->name; } void thread::set_name( const fc::string& n ) { my->name = n; } - void thread::debug( const fc::string& d ) { my->debug(d); } + void thread::debug( const fc::string& d ) { /*my->debug(d);*/ } void thread::quit() { + //if quiting from a different thread, start quit task on thread. + //If we have and know our attached boost thread, wait for it to finish, then return. if( ¤t() != this ) { async( [=](){quit();} );//.wait(); if( my->boost_thread ) { auto n = name(); - slog( "joining... %s", n.c_str() ); + ilog( "joining... ${n}", ("n",n) );//n.c_str() ); my->boost_thread->join(); - slog( "done joining... %s", n.c_str() ); + delete my; + my = nullptr; + ilog( "done joining...${n}", ("n",n) ); //n.c_str() ); } return; } - wlog( "%s", my->name.c_str() ); + + // wlog( "%s", my->name.c_str() ); + // We are quiting from our own thread... // break all promises, thread quit! while( my->blocked ) { @@ -88,12 +101,14 @@ namespace fc { fc::context* n = cur->next; // this will move the context into the ready list. //cur->prom->set_exception( boost::copy_exception( error::thread_quit() ) ); - cur->except_blocking_promises( thread_quit() ); + //cur->except_blocking_promises( thread_quit() ); + cur->except_blocking_promises( std::make_shared() ); + cur = n; } if( my->blocked ) { - wlog( "still blocking... whats up with that?"); - debug( "on quit" ); + // wlog( "still blocking... whats up with that?"); + // debug( "on quit" ); } } BOOST_ASSERT( my->blocked == 0 ); @@ -135,7 +150,13 @@ namespace fc { void thread::exec() { if( !my->current ) my->current = new fc::context(&fc::thread::current()); + try { my->process_tasks(); + } + catch( canceled_exception& ) + { + wlog( "thread canceled" ); + } delete my->current; my->current = 0; } @@ -171,7 +192,7 @@ namespace fc { my->sleep_pqueue.end(), sleep_priority_less() ); my->start_next_fiber(); - my->current->resume_time = time_point::max(); + my->current->resume_time = time_point::maximum(); my->check_fiber_exceptions(); } @@ -185,7 +206,7 @@ namespace fc { for( auto i = p.begin(); i != p.end(); ++i ) { ss << (*i)->get_desc() <<", "; } - BOOST_THROW_EXCEPTION( future_wait_timeout( ss.str() ) ); + FC_THROW_EXCEPTION( timeout_exception, "${task}", ("task",ss.str()) ); } if( !my->current ) { @@ -197,7 +218,7 @@ namespace fc { }; // if not max timeout, added to sleep pqueue - if( timeout != time_point::max() ) { + if( timeout != time_point::maximum() ) { my->current->resume_time = timeout; my->sleep_pqueue.push_back(my->current); std::push_heap( my->sleep_pqueue.begin(), @@ -216,7 +237,7 @@ namespace fc { for( uint32_t i = 0; i < p.size(); ++i ) { if( p[i]->ready() ) return i; } - BOOST_THROW_EXCEPTION( wait_any_error() ); + //BOOST_THROW_EXCEPTION( wait_any_error() ); return -1; } @@ -270,7 +291,7 @@ namespace fc { void thread::wait_until( promise_base::ptr&& p, const time_point& timeout ) { if( p->ready() ) return; if( timeout < time_point::now() ) - BOOST_THROW_EXCEPTION( future_wait_timeout( p->get_desc() ) ); + FC_THROW_EXCEPTION( timeout_exception, "${task}", ("task", p->get_desc()) ); if( !my->current ) { my->current = new fc::context(&fc::thread::current()); @@ -280,7 +301,7 @@ namespace fc { my->current->add_blocking_promise(p.get(),true); // if not max timeout, added to sleep pqueue - if( timeout != time_point::max() ) { + if( timeout != time_point::maximum() ) { my->current->resume_time = timeout; my->sleep_pqueue.push_back(my->current); std::push_heap( my->sleep_pqueue.begin(), diff --git a/src/thread_d.hpp b/src/thread/thread_d.hpp similarity index 80% rename from src/thread_d.hpp rename to src/thread/thread_d.hpp index 5c4d852..dbb877a 100644 --- a/src/thread_d.hpp +++ b/src/thread/thread_d.hpp @@ -1,15 +1,13 @@ -#include +#include #include #include - #include #include "context.hpp" #include #include #include #include -#include -#include +//#include namespace fc { struct sleep_priority_less { @@ -18,6 +16,7 @@ namespace fc { } }; class thread_d { + public: thread_d(fc::thread& s) :self(s), boost_thread(0), @@ -29,16 +28,43 @@ namespace fc { ready_tail(0), blocked(0) { - static char cnt = 0; - name = fc::string("th_") + char('a'+cnt); - cnt++; + static boost::atomic cnt(0); + name = fc::string("th_") + char('a'+cnt++); +// printf("thread=%p\n",this); } ~thread_d(){ - fc_ilog( logger::get("fc_context"), "thread ${name} exited}", ( "name", name) ); + delete current; + fc::context* temp; + while (ready_head) + { + temp = ready_head->next; + delete ready_head; + ready_head = temp; + } + while (blocked) + { + temp = blocked->next; + delete blocked; + blocked = temp; + } + /* + while (pt_head) + { + temp = pt_head->next; + delete pt_head; + pt_head = temp; + } + */ + ilog(""); + if (boost_thread) + { + boost_thread->detach(); + delete boost_thread; + } } fc::thread& self; boost::thread* boost_thread; - bc::stack_allocator stack_alloc; + bco::stack_allocator stack_alloc; boost::condition_variable task_ready; boost::mutex task_ready_mutex; @@ -61,50 +87,51 @@ namespace fc { +#if 0 void debug( const fc::string& s ) { return; - boost::unique_lock lock(log_mutex()); + //boost::unique_lock lock(log_mutex()); - std::cerr<<"--------------------- "<cur_task ) std::cerr<<'('<cur_task->get_desc()<<')'; - std::cerr<<" ---------------------------\n"; - std::cerr<<" Ready\n"; + fc::cerr<<"--------------------- "<cur_task ) fc::cerr<<'('<cur_task->get_desc()<<')'; + fc::cerr<<" ---------------------------\n"; + fc::cerr<<" Ready\n"; fc::context* c = ready_head; while( c ) { - std::cerr<<" "<cur_task ) std::cerr<<'('<cur_task->get_desc()<<')'; + fc::cerr<<" "<cur_task ) fc::cerr<<'('<cur_task->get_desc()<<')'; fc::context* p = c->caller_context; while( p ) { - std::cerr<<" -> "< "<caller_context; } - std::cerr<<"\n"; + fc::cerr<<"\n"; c = c->next; } - std::cerr<<" Blocked\n"; + fc::cerr<<" Blocked\n"; c = blocked; while( c ) { - std::cerr<<" ctx: "<< c; - if( c->cur_task ) std::cerr<<'('<cur_task->get_desc()<<')'; - std::cerr << " blocked on prom: "; + fc::cerr<<" ctx: "<< c; + if( c->cur_task ) fc::cerr<<'('<cur_task->get_desc()<<')'; + fc::cerr << " blocked on prom: "; for( uint32_t i = 0; i < c->blocking_prom.size(); ++i ) { - std::cerr<blocking_prom[i].prom<<'('<blocking_prom[i].prom->get_desc()<<')'; + fc::cerr<blocking_prom[i].prom<<'('<blocking_prom[i].prom->get_desc()<<')'; if( i + 1 < c->blocking_prom.size() ) { - std::cerr<<","; + fc::cerr<<","; } } fc::context* p = c->caller_context; while( p ) { - std::cerr<<" -> "< "<caller_context; } - std::cerr<<"\n"; + fc::cerr<<"\n"; c = c->next_blocked; } - std::cerr<<"-------------------------------------------------\n"; + fc::cerr<<"-------------------------------------------------\n"; } - +#endif // insert at from of blocked linked list inline void add_to_blocked( fc::context* c ) { c->next_blocked = blocked; @@ -217,9 +244,10 @@ namespace fc { */ void check_fiber_exceptions() { if( current && current->canceled ) { - BOOST_THROW_EXCEPTION( task_canceled() ); + FC_THROW_EXCEPTION( canceled_exception, "" ); } else if( done ) { - BOOST_THROW_EXCEPTION( thread_quit() ); + FC_THROW_EXCEPTION( canceled_exception, "" ); + // BOOST_THROW_EXCEPTION( thread_quit() ); } } @@ -236,7 +264,8 @@ namespace fc { if( ready_head ) { fc::context* next = ready_pop_front(); if( next == current ) { - elog( "next == current... something went wrong" ); + // elog( "next == current... something went wrong" ); + assert(next != current); return false; } BOOST_ASSERT( next != current ); @@ -246,8 +275,12 @@ namespace fc { current = next; if( reschedule ) ready_push_back(prev); // slog( "jump to %p from %p", next, prev ); - fc_dlog( logger::get("fc_context"), "from ${from} to ${to}", ( "from", int64_t(prev) )( "to", int64_t(next) ) ); + // fc_dlog( logger::get("fc_context"), "from ${from} to ${to}", ( "from", int64_t(prev) )( "to", int64_t(next) ) ); +#if BOOST_VERSION >= 105300 + bc::jump_fcontext( prev->my_context, next->my_context, 0 ); +#else bc::jump_fcontext( &prev->my_context, &next->my_context, 0 ); +#endif BOOST_ASSERT( current ); BOOST_ASSERT( current == prev ); //current = prev; @@ -269,15 +302,19 @@ namespace fc { if( reschedule ) ready_push_back(prev); // slog( "jump to %p from %p", next, prev ); - fc_dlog( logger::get("fc_context"), "from ${from} to ${to}", ( "from", int64_t(prev) )( "to", int64_t(next) ) ); + // fc_dlog( logger::get("fc_context"), "from ${from} to ${to}", ( "from", int64_t(prev) )( "to", int64_t(next) ) ); +#if BOOST_VERSION >= 105300 + bc::jump_fcontext( prev->my_context, next->my_context, (intptr_t)this ); +#else bc::jump_fcontext( &prev->my_context, &next->my_context, (intptr_t)this ); +#endif BOOST_ASSERT( current ); BOOST_ASSERT( current == prev ); //current = prev; } if( current->canceled ) - BOOST_THROW_EXCEPTION( task_canceled() ); + FC_THROW_EXCEPTION( canceled_exception, "" ); return true; } @@ -286,9 +323,13 @@ namespace fc { thread_d* self = (thread_d*)my; try { self->process_tasks(); + } catch ( canceled_exception& ) { + // allowed exception... } catch ( ... ) { - std::cerr<<"fiber exited with uncaught exception:\n "<< - boost::current_exception_diagnostic_information() <name) ); + // assert( !"fiber exited with uncaught exception" ); + //TODO replace errror fc::cerr<<"fiber exited with uncaught exception:\n "<< + // boost::current_exception_diagnostic_information() <free_list.push_back(self->current); self->start_next_fiber( false ); @@ -341,7 +382,7 @@ namespace fc { time_point timeout_time = check_for_timeouts(); if( done ) return; - if( timeout_time == time_point::max() ) { + if( timeout_time == time_point::maximum() ) { task_ready.wait( lock ); } else if( timeout_time != time_point::min() ) { task_ready.wait_until( lock, boost::chrono::system_clock::time_point() + @@ -357,11 +398,11 @@ namespace fc { */ time_point check_for_timeouts() { if( !sleep_pqueue.size() && !task_sch_queue.size() ) { - return time_point::max(); + return time_point::maximum(); } - time_point next = time_point::max(); + time_point next = time_point::maximum(); if( task_sch_queue.size() && next > task_sch_queue.front()->_when ) next = task_sch_queue.front()->_when; if( sleep_pqueue.size() && next > sleep_pqueue.front()->resume_time ) @@ -423,14 +464,14 @@ namespace fc { } } - current->resume_time = time_point::max(); + current->resume_time = time_point::maximum(); check_fiber_exceptions(); } void wait( const promise_base::ptr& p, const time_point& timeout ) { if( p->ready() ) return; if( timeout < time_point::now() ) - BOOST_THROW_EXCEPTION( future_wait_timeout() ); + FC_THROW_EXCEPTION( timeout_exception, "" ); if( !current ) { current = new fc::context(&fc::thread::current()); @@ -440,7 +481,7 @@ namespace fc { current->add_blocking_promise(p.get(),true); // if not max timeout, added to sleep pqueue - if( timeout != time_point::max() ) { + if( timeout != time_point::maximum() ) { current->resume_time = timeout; sleep_pqueue.push_back(current); std::push_heap( sleep_pqueue.begin(), diff --git a/src/time.cpp b/src/time.cpp index 93aa57f..abf93bc 100644 --- a/src/time.cpp +++ b/src/time.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -18,13 +18,13 @@ namespace fc { } time_point time_point::from_iso_string( const fc::string& s ) { auto pt = boost::posix_time::from_iso_string(s); - return fc::time_point(fc::seconds( (pt - boost::posix_time::from_time_t(0)).total_seconds() )); + //return fc::time_point(fc::seconds( (pt - boost::posix_time::from_time_t(0)).total_seconds() )); + return fc::time_point(fc::microseconds( (pt - boost::posix_time::from_time_t(0)).total_microseconds() )); } - class value; - void pack( fc::value& v, const fc::time_point& t ) { + void to_variant( const fc::time_point& t, variant& v ) { v = fc::string(t); } - void unpack( const fc::value& v, fc::time_point& t ) { - t = fc::time_point::from_iso_string(v.cast()); + void from_variant( const fc::variant& v, fc::time_point& t ) { + t = fc::time_point::from_iso_string(v.as_string()); } } diff --git a/src/url.cpp b/src/url.cpp deleted file mode 100644 index 54ebf6e..0000000 --- a/src/url.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include -#include -#include -#include -#include -#include - -namespace fc { - -// url::url( const url& u ); -#if 0 - url::url( url&& u ) - :proto(fc::move(u.proto)), - host(fc::move(u.host)), - user(fc::move(u.user)), - pass(fc::move(u.pass)), - path(fc::move(u.path)), - args(fc::move(u.args)), - port(u.port){} - - url& url::operator=(url&& c) - { - fc::swap(*this,c); - return *this; - } - - // url::url& operator=(const url& c) { - // } -#endif - url::url( const string& s ) { - from_string(s); - } - string url::to_string()const { - fc::stringstream ss; - ss<( host_port.substr( pos+1 ) ); - } catch ( ... ) { - FC_THROW_REPORT( "Unable to parse port field in url", value().set( "url", s ) ); - } - host = host_port.substr(0,pos); - } else { - host = fc::move(host_port); - } - fc::getline( ss, _path, '?' ); - fc::getline( ss, _args ); - path = fc::move(_path); - if( _args.size() ) args = fc::move(_args); - - return *this; - } - - bool url::operator==( const url& cmp )const { - return cmp.proto == proto && - cmp.host == host && - cmp.user == user && - cmp.pass == pass && - cmp.path == path && - cmp.args == args && - cmp.port == port; - } - -} // namespace fc diff --git a/src/value.cpp b/src/value.cpp deleted file mode 100644 index 3a11de4..0000000 --- a/src/value.cpp +++ /dev/null @@ -1,734 +0,0 @@ -#include -#include -#include -#include -#include - - -namespace fc { - - namespace detail { - class value_visitor { - public: - virtual void operator()( int8_t& v ){}; - virtual void operator()( int16_t& v ){}; - virtual void operator()( int32_t& v ){}; - virtual void operator()( int64_t& v ){}; - virtual void operator()( uint8_t& v ){}; - virtual void operator()( uint16_t& v ){}; - virtual void operator()( uint32_t& v ){}; - virtual void operator()( uint64_t& v ){}; - virtual void operator()( float& v ){}; - virtual void operator()( double& v ){}; - virtual void operator()( bool& v ){}; - virtual void operator()( fc::string& v ){}; - virtual void operator()( value::object& ){}; - virtual void operator()( value::array& ){}; - virtual void operator()( ){}; - }; - template - struct cast_visitor : value::const_visitor { - cast_visitor( T& out ) - :m_out(out){} - virtual void operator()( const int8_t& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const int16_t& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const int32_t& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const int64_t& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const uint8_t& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const uint16_t& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const uint32_t& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const uint64_t& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const float& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const double& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const bool& v ) { m_out = v; } - virtual void operator()( const fc::string& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const value::object& ) { FC_THROW_REPORT("bad cast to ${type} from object", - fc::value().set("type",fc::get_typename::name())); } - virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast to ${type} from array", - fc::value().set("type",fc::get_typename::name())); } - virtual void operator()( ) { FC_THROW_REPORT("bad cast to ${type} from null", - fc::value().set("type",fc::get_typename::name())); } - private: - T& m_out; - }; - - template<> - struct cast_visitor : value::const_visitor { - cast_visitor( bool& out ) - :m_out(out){} - virtual void operator()( const int8_t& v ){ m_out = v != 0; } - virtual void operator()( const int16_t& v ){ m_out = v != 0; } - virtual void operator()( const int32_t& v ){ m_out = v != 0; } - virtual void operator()( const int64_t& v ){ m_out = v != 0; } - virtual void operator()( const uint8_t& v ){ m_out = v != 0; } - virtual void operator()( const uint16_t& v ){ m_out = v != 0; } - virtual void operator()( const uint32_t& v ){ m_out = v != 0; } - virtual void operator()( const uint64_t& v ){ m_out = v != 0; } - virtual void operator()( const float& v ){ m_out = v != 0; } - virtual void operator()( const double& v ){ m_out = v != 0; } - virtual void operator()( const bool& v ){ m_out = v; } - virtual void operator()( const fc::string& v ) { m_out = !(v != "true"); } - virtual void operator()( const value::object& ) { FC_THROW_REPORT("bad cast to bool from object"); } - virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast to bool from array"); } - virtual void operator()( ) { FC_THROW_REPORT("bad cast to bool from null"); } - private: - bool& m_out; - }; - - template<> - struct cast_visitor : value::const_visitor { - cast_visitor( fc::string& out ) - :m_out(out){} - virtual void operator()( const int8_t& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const int16_t& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const int32_t& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const int64_t& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const uint8_t& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const uint16_t& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const uint32_t& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const uint64_t& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const float& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const double& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const bool& v ) { m_out = v != 0 ? "true" : "false"; } - virtual void operator()( const fc::string& v ) { m_out = v; } - virtual void operator()( const value::object& ){ FC_THROW_REPORT("bad cast to string from object"); } - virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast to string from array"); } - virtual void operator()( ) { m_out = fc::string(); } - - private: - fc::string& m_out; - }; - - template<> - struct cast_visitor : value::const_visitor { - cast_visitor( value::array& out ) - :m_out(out){} - virtual void operator()( const int8_t& v ) { FC_THROW_REPORT("bad cast to array from int8");} - virtual void operator()( const int16_t& v ) { FC_THROW_REPORT("bad cast to array from int16");} - virtual void operator()( const int32_t& v ) { FC_THROW_REPORT("bad cast to array from int32");} - virtual void operator()( const int64_t& v ) { FC_THROW_REPORT("bad cast to array from int32");} - virtual void operator()( const uint8_t& v ) { FC_THROW_REPORT("bad cast to array from uint8");} - virtual void operator()( const uint16_t& v ) { FC_THROW_REPORT("bad cast to array from uint16");} - virtual void operator()( const uint32_t& v ) { FC_THROW_REPORT("bad cast to array from uint32");} - virtual void operator()( const uint64_t& v ) { FC_THROW_REPORT("bad cast to array from uint64");} - virtual void operator()( const float& v ) { FC_THROW_REPORT("bad cast to array from float");} - virtual void operator()( const double& v ) { FC_THROW_REPORT("bad cast to array from double");} - virtual void operator()( const bool& v ) { FC_THROW_REPORT("bad cast to array from bool");} - virtual void operator()( const fc::string& v ) { FC_THROW_REPORT("bad cast to array from string");} - virtual void operator()( const value::object& ) { FC_THROW_REPORT("bad cast to array from object");} - virtual void operator()( const value::array& a ) { m_out = a; } - virtual void operator()( ) { m_out = value::array(); } - - private: - value::array& m_out; - }; - - template<> - struct cast_visitor : value::const_visitor { - cast_visitor( value::object& out ) - :m_out(out){} - virtual void operator()( const int8_t& v ){ FC_THROW_REPORT("bad cast to array from int8");} - virtual void operator()( const int16_t& v ){ FC_THROW_REPORT("bad cast to array from int16");} - virtual void operator()( const int32_t& v ){ FC_THROW_REPORT("bad cast to array from int32");} - virtual void operator()( const int64_t& v ){ FC_THROW_REPORT("bad cast to array from int32");} - virtual void operator()( const uint8_t& v ){ FC_THROW_REPORT("bad cast to array from uint8");} - virtual void operator()( const uint16_t& v ){ FC_THROW_REPORT("bad cast to array from uint16");} - virtual void operator()( const uint32_t& v ){ FC_THROW_REPORT("bad cast to array from uint32");} - virtual void operator()( const uint64_t& v ){ FC_THROW_REPORT("bad cast to array from uint64");} - virtual void operator()( const float& v ){ FC_THROW_REPORT("bad cast to array from float");} - virtual void operator()( const double& v ){ FC_THROW_REPORT("bad cast to array from double");} - virtual void operator()( const bool& v ){ FC_THROW_REPORT("bad cast to array from bool");} - virtual void operator()( const fc::string& v ) { FC_THROW_REPORT("bad cast to array from string");} - virtual void operator()( const value::object& a ) { m_out = a; } - virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( ) { m_out = value::object(); } - - private: - value::object& m_out; - }; - template<> - struct cast_visitor : value::const_visitor { - cast_visitor( value& out ) - :m_out(out){} - virtual void operator()( const int8_t& v ) { m_out = v; } - virtual void operator()( const int16_t& v ) { m_out = v; } - virtual void operator()( const int32_t& v ) { m_out = v; } - virtual void operator()( const int64_t& v ) { m_out = v; } - virtual void operator()( const uint8_t& v ) { m_out = v; } - virtual void operator()( const uint16_t& v ) { m_out = v; } - virtual void operator()( const uint32_t& v ) { m_out = v; } - virtual void operator()( const uint64_t& v ) { m_out = v; } - virtual void operator()( const float& v ) { m_out = v; } - virtual void operator()( const double& v ) { m_out = v; } - virtual void operator()( const bool& v ) { m_out = v; } - virtual void operator()( const fc::string& v ) { m_out = v; } - virtual void operator()( const value::object& a ) { m_out = a; } - virtual void operator()( const value::array& a ) { m_out = a; } - virtual void operator()( ) { m_out = value(); } - - value& m_out; - }; - - template<> - struct cast_visitor : value::const_visitor { - virtual void operator()( const int8_t& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const int16_t& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const int32_t& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const int64_t& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const uint8_t& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const uint16_t& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const uint32_t& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const uint64_t& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const float& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const double& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const bool& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const fc::string& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const value::object& a ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( ) { } - }; - - void cast_value( const value& v, int8_t& out ){ - v.visit( cast_visitor(out) ); - } - - void cast_value( const value& v, int16_t& out ){ - v.visit( cast_visitor(out) ); - } - - void cast_value( const value& v, int32_t& out ){ - v.visit( cast_visitor(out) ); - } - - void cast_value( const value& v, int64_t& out ){ - v.visit( cast_visitor(out) ); - slog( "cast_value( v, int64: %lld )", out ); - } - - void cast_value( const value& v, uint8_t& out ){ - v.visit( cast_visitor(out) ); - } - - void cast_value( const value& v, uint16_t& out ){ - v.visit( cast_visitor(out) ); - } - - void cast_value( const value& v, uint32_t& out ){ - v.visit( cast_visitor(out) ); - } - - void cast_value( const value& v, uint64_t& out ){ - v.visit( cast_visitor(out) ); - } - - void cast_value( const value& v, double& out ){ - v.visit( cast_visitor(out) ); - } - - void cast_value( const value& v, float& out ){ - v.visit( cast_visitor(out) ); - } - - void cast_value( const value& v, bool& out ){ - v.visit( cast_visitor(out) ); - } - - void cast_value( const value& v, fc::string& out ){ - v.visit( cast_visitor(out) ); - } - - void cast_value( const value& v, value& out ){ - out = v; - } - - - struct value_holder { - virtual ~value_holder(); - virtual value::value_type type()const; - const char* get_typename()const { return fc::reflector::to_string(type()); } - virtual void visit( value::const_visitor&& v )const; - virtual void visit( value_visitor&& v ); - - virtual void clear(); - virtual size_t size()const; - virtual void resize( size_t ); - virtual void reserve( size_t ); - virtual value& at( size_t ); - virtual const value& at( size_t )const; - virtual void push_back( value&& v ); - - virtual value_holder* move_helper( char* c ); - virtual value_holder* copy_helper( char* c )const; - }; - - void value_holder::visit( value::const_visitor&& v )const {v(); } - void value_holder::visit( value_visitor&& v ) {v(); } - - template - struct get_value_type{}; - template<> struct get_value_type { static value::value_type type(){ return value::null_type; } }; - template<> struct get_value_type { static value::value_type type(){ return value::int8_type; } }; - template<> struct get_value_type{ static value::value_type type(){ return value::int16_type; } }; - template<> struct get_value_type{ static value::value_type type(){ return value::int32_type; } }; - template<> struct get_value_type{ static value::value_type type(){ return value::int64_type; } }; - template<> struct get_value_type{ static value::value_type type(){ return value::uint8_type; } }; - template<> struct get_value_type{ static value::value_type type(){ return value::uint16_type; } }; - template<> struct get_value_type{ static value::value_type type(){ return value::uint32_type; } }; - template<> struct get_value_type{ static value::value_type type(){ return value::uint64_type; } }; - template<> struct get_value_type{ static value::value_type type(){ return value::double_type; } }; - template<> struct get_value_type{ static value::value_type type(){ return value::float_type; } }; - template<> struct get_value_type{ static value::value_type type(){ return value::string_type; } }; - template<> struct get_value_type{ static value::value_type type(){ return value::bool_type; } }; - template<> struct get_value_type>{ static value::value_type type(){ return value::array_type; } }; - template<> struct get_value_type{ static value::value_type type(){ return value::object_type; } }; - - // fundamental values... - template - struct value_holder_impl : value_holder { - static_assert( !fc::is_class::value, "only fundamental types can be stored without specialization" ); - - value_holder_impl(){ - static_assert( sizeof(value_holder_impl) <= 40, "Validate size" ); - } - virtual value::value_type type()const { return get_value_type::type(); } - virtual void visit( value::const_visitor&& v )const{ v(val); } - virtual void visit( value_visitor&& v ) { v(val); } - virtual void clear() { val = T(); } - virtual size_t size()const { return 0; } - - virtual value_holder* move_helper( char* c ){ return new(c) value_holder_impl( fc::move(val) ); } - virtual value_holder* copy_helper( char* c )const{ return new(c) value_holder_impl(val); } - - template - value_holder_impl( V&& v ):val( fc::forward(v) ){} - - T val; - }; - - - template<> - struct value_holder_impl : value_holder { - value_holder_impl(){}; - virtual void visit( value::const_visitor&& v )const{ v(); } - virtual void visit( value_visitor&& v ) { v(); } - virtual value_holder* move_helper( char* c ) { return new(c) value_holder_impl(); } - virtual value_holder* copy_helper( char* c )const{ return new(c) value_holder_impl(); } - }; - - - template<> - struct value_holder_impl : value_holder { - template - value_holder_impl( V&& v ):val( fc::forward(v) ){ - static_assert( sizeof(value_holder_impl) <= 40, "Validate size" ); - } - - virtual value::value_type type()const { return value::string_type; } - virtual void visit( value::const_visitor&& v )const { v(val); } - virtual void visit( value_visitor&& v ) { v(val); } - - virtual value_holder* move_helper( char* c ){ return new(c) value_holder_impl( fc::move(val) ); } - virtual value_holder* copy_helper( char* c )const{ return new(c) value_holder_impl(val); } - - virtual void clear() { val = fc::string(); } - virtual size_t size()const { FC_THROW_REPORT( "Attempt to access string as array" ); } - - fc::string val; - }; - - template<> - struct value_holder_impl : value_holder { - virtual value::value_type type()const { return value::object_type; } - virtual void visit( value::const_visitor&& v )const; - virtual void visit( value_visitor&& v ); - virtual value_holder* move_helper( char* c ); - virtual value_holder* copy_helper( char* c )const; - virtual void reserve( size_t s ); - - virtual void clear(); - virtual size_t size()const; - - template - value_holder_impl( V&& v ):val( fc::forward(v) ){} - - value::object val; - }; - - template<> - struct value_holder_impl : value_holder { - virtual value::value_type type()const { return value::array_type; } - virtual void visit( value::const_visitor&& v )const; - virtual void visit( value_visitor&& v ); - virtual value_holder* move_helper( char* c ); - virtual value_holder* copy_helper( char* c )const; - - virtual void resize( size_t s ); - virtual void reserve( size_t s ); - virtual value& at( size_t i); - virtual const value& at( size_t i)const; - virtual void push_back( value&& v ); - - template - value_holder_impl( V&& v ):val( fc::forward(v) ){} - - virtual void clear(); - virtual size_t size()const; - - value::array val; - }; - static_assert( sizeof( value_holder_impl ) <= 40, "sanity check" ); - static_assert( sizeof( value_holder_impl ) <= 40, "sanity check" ); - - value_holder::~value_holder(){} - value::value_type value_holder::type()const { return value::null_type; } - value_holder* value_holder::move_helper( char* c ) { return new(c) value_holder_impl(); } - value_holder* value_holder::copy_helper( char* c )const { return new(c) value_holder_impl(); } - - void new_value_holder_void( value* v ) { - new (v) value_holder_impl(); - } - - void value_holder::clear() {} - size_t value_holder::size()const { return 0; } - void value_holder::resize( size_t ) { FC_THROW_MSG("value type '%s' not an array", get_typename()); } - void value_holder::reserve( size_t ) { FC_THROW_MSG("value type '%s' not an array or object", get_typename()); } - value& value_holder::at( size_t ) { FC_THROW_MSG("value type '%s' not an array", get_typename()); return *((value*)0); } - const value& value_holder::at( size_t )const { FC_THROW_MSG("value type '%s' not an array", get_typename()); return *((const value*)0); } - void value_holder::push_back( value&& v ) { FC_THROW_MSG("value type '%s' not an array", get_typename()); } - - - void value_holder_impl::resize( size_t s ) { val.resize(s); } - void value_holder_impl::reserve( size_t s ) { val.reserve(s); } - value& value_holder_impl::at( size_t i) { return val[i]; } - const value& value_holder_impl::at( size_t i)const { return val[i]; } - value_holder* value_holder_impl::move_helper( char* c ){ return new(c) value_holder_impl( fc::move(val) ); } - value_holder* value_holder_impl::copy_helper( char* c )const{ return new(c) value_holder_impl(val); } - - void value_holder_impl::clear() { val.clear(); } - size_t value_holder_impl::size()const { return static_cast(val.size()); } - void value_holder_impl::visit( value::const_visitor&& v )const { v(val); } - void value_holder_impl::visit( value_visitor&& v ) { v(val); } - void value_holder_impl::push_back( value&& v ) { val.push_back( fc::move(v) ); } - - - void value_holder_impl::visit( value::const_visitor&& v )const { v(val); } - void value_holder_impl::visit( value_visitor&& v ) { v(val); } - value_holder* value_holder_impl::move_helper( char* c ) { return new(c) value_holder_impl( fc::move(val) ); } - value_holder* value_holder_impl::copy_helper( char* c )const { return new(c) value_holder_impl(val); } - void value_holder_impl::reserve( size_t s ) { val.fields.reserve(s); } - - void value_holder_impl::clear() { val = value::object(); } - size_t value_holder_impl::size()const { return val.fields.size(); } - } // namespace detail - -static detail::value_holder* gh( aligned<40>& h ) { - return (detail::value_holder*)h._store._data; -} -static const detail::value_holder* gh( const aligned<40>& h ) { - return (const detail::value_holder*)h._store._data; -} - -value::value() { - new (holder) detail::value_holder_impl(); -} -value::value( value&& m ) { - gh(m.holder)->move_helper(holder._store._data); -} -value::value( const value& m ){ - gh(m.holder)->copy_helper(holder._store._data); -} -value::value( const char* c ) { - new (holder) detail::value_holder_impl( c ); -} -value::value( char* c ) { - new (holder) detail::value_holder_impl( c ); -} -value::~value() { - gh(holder)->~value_holder(); -} -value::value( int8_t v){ - static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); - new (holder) detail::value_holder_impl(v); -} -value::value( int16_t v){ - static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); - new (holder) detail::value_holder_impl(v); -} -value::value( int32_t v){ - new (holder) detail::value_holder_impl(v); -} -value::value( int64_t v){ - new (holder) detail::value_holder_impl(v); -} -value::value( uint8_t v){ - new (holder) detail::value_holder_impl(v); -} -value::value( uint16_t v){ - new (holder) detail::value_holder_impl(v); -} -value::value( uint32_t v){ - new (holder) detail::value_holder_impl(v); -} -value::value( uint64_t v){ - new (holder) detail::value_holder_impl(v); -} -value::value( double v){ - new (holder) detail::value_holder_impl(v); -} -value::value( float v){ - new (holder) detail::value_holder_impl(v); -} -value::value( bool v){ - new (holder) detail::value_holder_impl(v); -} -value::value( fc::string&& v){ - static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); - new (holder) detail::value_holder_impl(fc::move(v)); -} -value::value( fc::string& v){ - static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); - new (holder) detail::value_holder_impl(v); -} -value::value( const fc::string& v){ - static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); - new (holder) detail::value_holder_impl(v); -} -value::value( const fc::string& v, const value& val ) { - static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); - new (holder) detail::value_holder_impl(value::object()); - set( v, val ); -} -value::value( value::object&& o ){ - static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); - new (holder) detail::value_holder_impl(fc::move(o)); -} -value::value( value::array&& a ){ - static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); - new (holder) detail::value_holder_impl(fc::move(a)); -} -value::value( const value::array& a ){ - static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); - new (holder) detail::value_holder_impl(a); -} -value::value( value::array& a ){ - static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); - new (holder) detail::value_holder_impl(a); -} -value::value( const value::object& a ){ - static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); - new (holder) detail::value_holder_impl(a); -} -value::value( value::object& a ){ - static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); - new (holder) detail::value_holder_impl(a); -} -bool operator == ( const value& v, std::nullptr_t ) { - return v.is_null(); -} -bool operator != ( const value& v, std::nullptr_t ) { - return v.is_null(); -} - -value& value::operator=( value&& v ){ - decltype(holder) tmp; - gh(holder)->move_helper(tmp); - gh(v.holder)->move_helper(holder); - gh(tmp)->move_helper(v.holder); - return *this; -} -value& value::operator=( const value& v ){ - if( this == &v ) return *this; - gh(holder)->~value_holder(); - gh(v.holder)->copy_helper(holder); - return *this; -} -bool value::is_null()const { - return gh(holder)->type() == null_type; -} -bool value::is_object()const { - return gh(holder)->type() == object_type; -} -bool value::is_array()const { - return gh(holder)->type() == array_type; -} -bool value::is_string()const { - return gh(holder)->type() == string_type; -} - -const fc::vector& value::as_array()const { - if( gh(holder)->type() != array_type ) { - FC_THROW_REPORT( "Attempt to dereference value of type ${type} as value array", value("type",gh(holder)->get_typename() ) ); - } - const detail::value_holder_impl* o = static_cast*>(gh(holder)); - return o->val; -} -fc::vector& value::as_array(){ - if( gh(holder)->type() != array_type ) { - FC_THROW_REPORT( "Attempt to dereference value of type ${type} as value array", value("type",gh(holder)->get_typename() ) ); - } - detail::value_holder_impl* o = static_cast*>(gh(holder)); - return o->val; -} -const value::object& value::as_object()const { - if( gh(holder)->type() != object_type ) { - FC_THROW_REPORT( "Attempt to dereference value of type ${type} as value object", value("type",gh(holder)->get_typename() ) ); - } - const detail::value_holder_impl* o = static_cast*>(gh(holder)); - return o->val; -} -value::object& value::as_object(){ - if( gh(holder)->type() != object_type ) { - FC_THROW_REPORT( "Attempt to dereference value of type ${type} as value object", value("type",gh(holder)->get_typename() ) ); - } - detail::value_holder_impl* o = static_cast*>(gh(holder)); - return o->val; -} -const fc::string& value::as_string()const { - if( gh(holder)->type() != string_type ) { - FC_THROW_REPORT( "Attempt to dereference value of type ${type} as value string", value("type",gh(holder)->get_typename() ) ); - } - const detail::value_holder_impl* o = static_cast*>(gh(holder)); - return o->val; -} -fc::string& value::as_string(){ - if( gh(holder)->type() != string_type ) { - FC_THROW_REPORT( "Attempt to dereference value of type ${type} as value string", value("type",gh(holder)->get_typename() ) ); - } - detail::value_holder_impl* o = static_cast*>(gh(holder)); - return o->val; -} - - -value::object::const_iterator value::find( const char* key )const { - if( gh(holder)->type() == object_type ) { - const detail::value_holder_impl* o = static_cast*>(gh(holder)); - for( auto i = o->val.fields.begin(); - i != o->val.fields.end(); ++i ) { - if( strcmp( i->key.c_str(), key ) == 0 ) - return i; - } - return o->val.fields.end(); - } - //FC_THROW_MSG( "Bad cast of %s to object", gh(holder)->type() ); - return value::object::const_iterator(); -} -value::object::const_iterator value::begin()const { - if( gh(holder)->type() == object_type ) { - const detail::value_holder_impl* o = static_cast*>(gh(holder)); - return o->val.fields.begin(); - } - //// FC_THROW_MSG( "Bad cast of %s to object", gh(holder)->type() ); - return value::object::const_iterator(); - //return nullptr; -} -value::object::const_iterator value::end()const { - if( gh(holder)->type()== object_type ) { - const detail::value_holder_impl* o = static_cast*>(gh(holder)); - return o->val.fields.end(); - } - ////FC_THROW_MSG( "Bad cast of %s to object", gh(holder)->type() ); - return value::object::const_iterator(); - //return nullptr; -} -/** - * If this value is an object, remove key from the object - * - * @return *this; - */ -value& value::clear( const fc::string& key ) { - if( gh(holder)->type()== object_type ) { - detail::value_holder_impl* o = dynamic_cast*>(gh(holder)); - for( auto i = o->val.fields.begin(); - i != o->val.fields.end(); ++i ) { - if( strcmp( i->key.c_str(), key.c_str() ) == 0 ) { - o->val.fields.erase(i); - return *this; - } - } - } - return *this; -} -value& value::operator[]( const char* key ) { - if( gh(holder)->type()== object_type ) { - detail::value_holder_impl* o = dynamic_cast*>(gh(holder)); - for( auto i = o->val.fields.begin(); - i != o->val.fields.end(); ++i ) { - if( strcmp( i->key.c_str(), key ) == 0 ) - return i->val; - } - o->val.fields.reserve(o->val.fields.size()+1); - o->val.fields.push_back( key_val(key) ); - return o->val.fields.back().val; - } else if (gh(holder)->type() == null_type ) { - new (gh(holder)) detail::value_holder_impl(value::object()); - return (*this)[key]; - } - FC_THROW_REPORT( "Bad cast of ${type} to object", fc::value().set("type", gh(holder)->get_typename()) ); - return *((value*)0); -} -value& value::operator[]( const fc::string& key ) { return (*this)[key.c_str()]; } -const value& value::operator[]( const fc::string& key )const { return (*this)[key.c_str()]; } -const value& value::operator[]( const char* key )const { - auto i = find(key); - if( i == end() ) { - FC_THROW_MSG( "Key '%s' not found in object", key ); - } - return i->val; -} - -void value::clear() { - gh(holder)->clear(); -} -size_t value::size()const { - return gh(holder)->size(); -} -void value::resize( size_t s ) { - gh(holder)->resize(s); -} -void value::reserve( size_t s ) { - gh(holder)->reserve(s); -} -value& value::push_back( value&& v ) { - if (gh(holder)->type() == null_type ) { - new (gh(holder)) detail::value_holder_impl(value::array()); - return push_back( fc::move(v) ); - } - gh(holder)->push_back(fc::move(v)); - return *this; -} -value& value::push_back( const value& v ) { - if (gh(holder)->type() == null_type ) { - new (gh(holder)) detail::value_holder_impl(value::array()); - return push_back( v ); - } - gh(holder)->push_back(value(v)); - return *this; -} -value& value::operator[]( int32_t idx ) { - return gh(holder)->at(idx); -} -const value& value::operator[]( int32_t idx )const { - return gh(holder)->at(idx); -} - -value::value_type value::type()const { return gh(holder)->type(); } - -void value::visit( value::const_visitor&& v )const { - auto h = ((detail::value_holder*)&holder[0]); - h->visit( fc::move(v) ); -} -/* sets the subkey key with v and return *this */ -value& value::set( const char* key, fc::value v ) { - (*this)[key] = fc::move(v); - return *this; -} -value& value::operator()( const char* key, fc::value v ) { - (*this)[key] = fc::move(v); - return *this; -} -value& value::set( const fc::string& key, fc::value v ) { - (*this)[key.c_str()] = fc::move(v); - return *this; -} - -} // namepace fc diff --git a/src/value_cast.cpp b/src/value_cast.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/variant.cpp b/src/variant.cpp new file mode 100644 index 0000000..90e4cf7 --- /dev/null +++ b/src/variant.cpp @@ -0,0 +1,647 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fc +{ + + void to_variant( const uint16_t& var, variant& vo ) { vo = uint64_t(var); } + // TODO: warn on overflow? + void from_variant( const variant& var, uint16_t& vo ){ vo = static_cast(var.as_uint64()); } +void to_variant( const vector& var, variant& vo ) +{ + if( var.size() ) + vo = variant(base64_encode((unsigned char*)var.data(),var.size())); + else vo = ""; +} +void from_variant( const variant& var, vector& vo ) +{ + std::string b64 = base64_decode( var.as_string() ); + vo = fc::vector( b64.c_str(), b64.c_str() + b64.size() ); +} +/** + * The TypeID is stored in the 'last byte' of the variant. + */ +void set_variant_type( variant* v, variant::type_id t) +{ + char* data = reinterpret_cast(v); + data[ sizeof(variant) -1 ] = t; +} + +variant::variant() +{ + set_variant_type( this, null_type ); +} + +variant::variant( fc::nullptr_t ) +{ + set_variant_type( this, null_type ); +} + +variant::variant( int64_t val ) +{ + *reinterpret_cast(this) = val; + set_variant_type( this, int64_type ); +} + +variant::variant( int val ) +{ + *reinterpret_cast(this) = val; + set_variant_type( this, int64_type ); +} +variant::variant( float val ) +{ + *reinterpret_cast(this) = val; + set_variant_type( this, double_type ); +} + +variant::variant( uint64_t val ) +{ + *reinterpret_cast(this) = val; + set_variant_type( this, uint64_type ); +} + +variant::variant( double val ) +{ + *reinterpret_cast(this) = val; + set_variant_type( this, double_type ); +} + +variant::variant( bool val ) +{ + *reinterpret_cast(this) = val; + set_variant_type( this, bool_type ); +} + +variant::variant( char* str ) +{ + *reinterpret_cast(this) = new string( str ); + set_variant_type( this, string_type ); +} + +variant::variant( const char* str ) +{ + *reinterpret_cast(this) = new string( str ); + set_variant_type( this, string_type ); +} + +// TODO: do a proper conversion to utf8 +variant::variant( wchar_t* str ) +{ + size_t len = wcslen(str); + boost::scoped_array buffer(new char[len]); + for (unsigned i = 0; i < len; ++i) + buffer[i] = (char)str[i]; + *reinterpret_cast(this) = new string(buffer.get(), len); + set_variant_type( this, string_type ); +} + +// TODO: do a proper conversion to utf8 +variant::variant( const wchar_t* str ) +{ + size_t len = wcslen(str); + boost::scoped_array buffer(new char[len]); + for (unsigned i = 0; i < len; ++i) + buffer[i] = (char)str[i]; + *reinterpret_cast(this) = new string(buffer.get(), len); + set_variant_type( this, string_type ); +} + +variant::variant( fc::string val ) +{ + *reinterpret_cast(this) = new string( fc::move(val) ); + set_variant_type( this, string_type ); +} + +variant::variant( variant_object obj) +{ + *reinterpret_cast(this) = new variant_object(fc::move(obj)); + set_variant_type(this, object_type ); +} +variant::variant( mutable_variant_object obj) +{ + *reinterpret_cast(this) = new variant_object(fc::move(obj)); + set_variant_type(this, object_type ); +} + +variant::variant( variants arr ) +{ + *reinterpret_cast(this) = new variants(fc::move(arr)); + set_variant_type(this, array_type ); +} + + +typedef const variant_object* const_variant_object_ptr; +typedef const variants* const_variants_ptr; +typedef const string* const_string_ptr; + +variant::variant( const variant& v ) +{ + switch( v.get_type() ) + { + case object_type: + *reinterpret_cast(this) = + new variant_object(**reinterpret_cast(&v)); + set_variant_type( this, object_type ); + return; + case array_type: + *reinterpret_cast(this) = + new variants(**reinterpret_cast(&v)); + set_variant_type( this, array_type ); + return; + case string_type: + *reinterpret_cast(this) = + new string(**reinterpret_cast(&v) ); + set_variant_type( this, string_type ); + return; + + default: + memcpy( this, &v, sizeof(v) ); + } +} + +variant::variant( variant&& v ) +{ + memcpy( this, &v, sizeof(v) ); + set_variant_type( &v, null_type ); +} + +variant::~variant() +{ + switch( get_type() ) + { + case object_type: + delete *reinterpret_cast(this); + break; + case array_type: + delete *reinterpret_cast(this); + break; + case string_type: + delete *reinterpret_cast(this); + break; + default: + break; + } +} + +variant& variant::operator=( variant&& v ) +{ + switch( get_type() ) + { + set_variant_type( this, null_type ); + case object_type: + delete *reinterpret_cast(this); + break; + case array_type: + delete *reinterpret_cast(this); + break; + case string_type: + delete *reinterpret_cast(this); + break; + default: + break; + } + switch( v.get_type() ) + { + case object_type: + *reinterpret_cast(this) = new variant_object(fc::move(**reinterpret_cast(&v))); + set_variant_type( this, object_type ); + return *this; + case array_type: + *reinterpret_cast(this) = new variants(fc::move(**reinterpret_cast(&v))); + set_variant_type( this, array_type ); + return *this; + case string_type: + *reinterpret_cast(this) = new string(fc::move(**reinterpret_cast(&v)) ); + set_variant_type( this, string_type ); + return *this; + + default: + memcpy( this, &v, sizeof(v) ); + } + + return *this; +} +variant& variant::operator=( const variant& v ) +{ + if( this == &v ) + return *this; + switch( get_type() ) + { + set_variant_type( this, null_type ); + case object_type: + delete *reinterpret_cast(this); + break; + case array_type: + delete *reinterpret_cast(this); + break; + case string_type: + delete *reinterpret_cast(this); + break; + default: + break; + } + switch( v.get_type() ) + { + case object_type: + *reinterpret_cast(this) = + new variant_object((**reinterpret_cast(&v))); + break; + case array_type: + *reinterpret_cast(this) = + new variants((**reinterpret_cast(&v))); + break; + case string_type: + *reinterpret_cast(this) = new string((**reinterpret_cast(&v)) ); + break; + + default: + memcpy( this, &v, sizeof(v) ); + } + set_variant_type( this, v.get_type() ); + return *this; +} + +void variant::visit( const visitor& v )const +{ + switch( get_type() ) + { + case null_type: + v.handle(); + return; + case int64_type: + v.handle( *reinterpret_cast(this) ); + return; + case uint64_type: + v.handle( *reinterpret_cast(this) ); + return; + case double_type: + v.handle( *reinterpret_cast(this) ); + return; + case bool_type: + v.handle( *reinterpret_cast(this) ); + return; + case string_type: + v.handle( **reinterpret_cast(this) ); + return; + case array_type: + v.handle( **reinterpret_cast(this) ); + return; + case object_type: + v.handle( **reinterpret_cast(this) ); + return; + default: + FC_THROW_EXCEPTION( assert_exception, "Invalid Type / Corrupted Memory" ); + } +} + +variant::type_id variant::get_type()const +{ + return (type_id)reinterpret_cast(this)[sizeof(*this)-1]; +} + +bool variant::is_null()const +{ + return get_type() == null_type; +} + +bool variant::is_string()const +{ + return get_type() == string_type; +} +bool variant::is_bool()const +{ + return get_type() == bool_type; +} +bool variant::is_double()const +{ + return get_type() == double_type; +} +bool variant::is_uint64()const +{ + return get_type() == uint64_type; +} +bool variant::is_int64()const +{ + return get_type() == int64_type; +} + +bool variant::is_numeric()const +{ + switch( get_type() ) + { + case int64_type: + case uint64_type: + case double_type: + case bool_type: + return true; + default: + return false; + } + return false; +} + +bool variant::is_object()const +{ + return get_type() == object_type; +} + +bool variant::is_array()const +{ + return get_type() == array_type; +} + +int64_t variant::as_int64()const +{ + switch( get_type() ) + { + case string_type: + return to_int64(**reinterpret_cast(this)); + case double_type: + return int64_t(*reinterpret_cast(this)); + case int64_type: + return *reinterpret_cast(this); + case uint64_type: + return int64_t(*reinterpret_cast(this)); + case bool_type: + return *reinterpret_cast(this); + case null_type: + return 0; + default: + FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to int64", ("type", "") ); + } +} + +uint64_t variant::as_uint64()const +{ + switch( get_type() ) + { + case string_type: + return to_uint64(**reinterpret_cast(this)); + case double_type: + return static_cast(*reinterpret_cast(this)); + case int64_type: + return static_cast(*reinterpret_cast(this)); + case uint64_type: + return *reinterpret_cast(this); + case bool_type: + return static_cast(*reinterpret_cast(this)); + case null_type: + return 0; + default: + FC_THROW_EXCEPTION( bad_cast_exception,"Invalid cast from ${type} to uint64", ("type","")); + } +} + + +double variant::as_double()const +{ + switch( get_type() ) + { + case string_type: + return to_double(**reinterpret_cast(this)); + case double_type: + return *reinterpret_cast(this); + case int64_type: + return static_cast(*reinterpret_cast(this)); + case uint64_type: + return static_cast(*reinterpret_cast(this)); + case bool_type: + return *reinterpret_cast(this); + case null_type: + return 0; + default: + FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to double" ); + } +} + +bool variant::as_bool()const +{ + switch( get_type() ) + { + case string_type: + return **reinterpret_cast(this) == "true"; + case double_type: + return *reinterpret_cast(this) != 0.0; + case int64_type: + return *reinterpret_cast(this) != 0; + case uint64_type: + return *reinterpret_cast(this) != 0; + case bool_type: + return *reinterpret_cast(this); + case null_type: + return false; + default: + FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to bool" ); + } +} + +string variant::as_string()const +{ + switch( get_type() ) + { + case string_type: + return **reinterpret_cast(this); + case double_type: + return to_string(*reinterpret_cast(this)); + case int64_type: + return to_string(*reinterpret_cast(this)); + case uint64_type: + return to_string(*reinterpret_cast(this)); + case bool_type: + return *reinterpret_cast(this) ? "true" : "false"; + case null_type: + return string(); + default: + FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to string", ("type", int64_t(get_type()) ) ); + } +} + + +/// @throw if get_type() != array_type | null_type +variants& variant::get_array() +{ + if( get_type() == array_type ) + return **reinterpret_cast(this); + + FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Array" ); +} + + +/// @throw if get_type() != array_type +const variants& variant::get_array()const +{ + if( get_type() == array_type ) + return **reinterpret_cast(this); + FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Array" ); +} + + +/// @throw if get_type() != object_type | null_type +variant_object& variant::get_object() +{ + if( get_type() == object_type ) + return **reinterpret_cast(this); + FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Object" ); +} + +const variant& variant::operator[]( const char* key )const +{ + return get_object()[key]; +} +const variant& variant::operator[]( size_t pos )const +{ + return get_array()[pos]; +} + /// @pre is_array() +size_t variant::size()const +{ + return get_array().size(); +} + +const string& variant::get_string()const +{ + if( get_type() == string_type ) + return **reinterpret_cast(this); + FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Object" ); +} + + +/// @throw if get_type() != object_type +const variant_object& variant::get_object()const +{ + if( get_type() == object_type ) + return **reinterpret_cast(this); + FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Object" ); +} + +void to_variant( const std::string& s, variant& v ) +{ + v = variant( fc::string(s) ); +} + +//void from_variant( const variant& var, variant_object& vo ) +//{ +// vo = var.get_object(); +//} +void from_variant( const variant& var, string& vo ) +{ + vo = var.as_string(); +} + +void from_variant( const variant& var, variants& vo ) +{ + vo = var.get_array(); +} + +void from_variant( const variant& var, variant& vo ) { vo = var; } + +void from_variant( const variant& var, int64_t& vo ) +{ + vo = var.as_int64(); +} + +void from_variant( const variant& var, uint64_t& vo ) +{ + vo = var.as_uint64(); +} + +void from_variant( const variant& var, bool& vo ) +{ + vo = var.as_bool(); +} + +void from_variant( const variant& var, double& vo ) +{ + vo = var.as_double(); +} + +void from_variant( const variant& var, float& vo ) +{ + vo = static_cast(var.as_double()); +} + +void from_variant( const variant& var, int32_t& vo ) +{ + vo = static_cast(var.as_int64()); +} + +void to_variant( const uint32_t& var, variant& vo ) { vo = uint64_t(var); } +void from_variant( const variant& var, uint32_t& vo ) +{ + vo = static_cast(var.as_uint64()); +} +void to_variant( const uint8_t& var, variant& vo ) { vo = uint64_t(var); } +void from_variant( const variant& var, uint8_t& vo ) +{ + vo = static_cast(var.as_uint64()); +} + +string format_string( const string& format, const variant_object& args ) +{ + stringstream ss; + size_t prev = 0; + auto next = format.find( '$' ); + while( prev != size_t(string::npos) && prev < size_t(format.size()) ) + { + ss << format.substr( prev, size_t(next-prev) ); + + // if we got to the end, return it. + if( next == size_t(string::npos) ) + return ss.str(); + + // if we are not at the end, then update the start + prev = next + 1; + + if( format[prev] == '{' ) + { + // if the next char is a open, then find close + next = format.find( '}', prev ); + // if we found close... + if( next != size_t(string::npos) ) + { + // the key is between prev and next + string key = format.substr( prev+1, (next-prev-1) ); + + auto val = args.find( key ); + if( val != args.end() ) + { + if( val->value().is_object() || val->value().is_array() ) + { + ss << json::to_string( val->value() ); + } + else + { + ss << val->value().as_string(); + } + } + else + { + ss << "${"< +#include +#include + + +namespace fc +{ + // --------------------------------------------------------------- + // entry + + variant_object::entry::entry() {} + variant_object::entry::entry( string k, variant v ) : _key(fc::move(k)),_value(fc::move(v)) {} + variant_object::entry::entry( entry&& e ) : _key(fc::move(e._key)),_value(fc::move(e._value)) {} + variant_object::entry::entry( const entry& e ) : _key(e._key),_value(e._value) {} + variant_object::entry& variant_object::entry::operator=( const variant_object::entry& e ) + { + if( this != &e ) + { + _key = e._key; + _value = e._value; + } + return *this; + } + variant_object::entry& variant_object::entry::operator=( variant_object::entry&& e ) + { + fc_swap( _key, e._key ); + fc_swap( _value, e._value ); + return *this; + } + + const string& variant_object::entry::key()const + { + return _key; + } + + const variant& variant_object::entry::value()const + { + return _value; + } + variant& variant_object::entry::value() + { + return _value; + } + + void variant_object::entry::set( variant v ) + { + fc_swap( _value, v ); + } + + // --------------------------------------------------------------- + // variant_object + + variant_object::iterator variant_object::begin() const + { + assert( _key_value != nullptr ); + return _key_value->begin(); + } + + variant_object::iterator variant_object::end() const + { + return _key_value->end(); + } + + variant_object::iterator variant_object::find( const string& key )const + { + return find( key.c_str() ); + } + + variant_object::iterator variant_object::find( const char* key )const + { + for( auto itr = begin(); itr != end(); ++itr ) + { + if( itr->key() == key ) + { + return itr; + } + } + return end(); + } + + const variant& variant_object::operator[]( const string& key )const + { + return (*this)[key.c_str()]; + } + + const variant& variant_object::operator[]( const char* key )const + { + auto itr = find( key ); + if( itr != end() ) return itr->value(); + FC_THROW_EXCEPTION( key_not_found_exception, "Key ${key}", ("key",key) ); + } + + size_t variant_object::size() const + { + return _key_value->size(); + } + + variant_object::variant_object() + :_key_value(std::make_shared>() ) + { + } + + variant_object::variant_object( string key, variant val ) + : _key_value(std::make_shared>()) + { + //_key_value->push_back(entry(fc::move(key), fc::move(val))); + _key_value->emplace_back(entry(fc::move(key), fc::move(val))); + } + + variant_object::variant_object( const variant_object& obj ) + :_key_value( obj._key_value ) + { + assert( _key_value != nullptr ); + } + + variant_object::variant_object( variant_object&& obj) + : _key_value( fc::move(obj._key_value) ) + { + obj._key_value = std::make_shared>(); + assert( _key_value != nullptr ); + } + + variant_object::variant_object( const mutable_variant_object& obj ) + : _key_value(std::make_shared>(*obj._key_value)) + { + } + + variant_object::variant_object( mutable_variant_object&& obj ) + : _key_value(fc::move(obj._key_value)) + { + assert( _key_value != nullptr ); + } + + variant_object& variant_object::operator=( variant_object&& obj ) + { + if (this != &obj) + { + fc_swap(_key_value, obj._key_value ); + assert( _key_value != nullptr ); + } + return *this; + } + + variant_object& variant_object::operator=( const variant_object& obj ) + { + if (this != &obj) + { + _key_value = obj._key_value; + } + return *this; + } + + variant_object& variant_object::operator=( mutable_variant_object&& obj ) + { + _key_value = fc::move(obj._key_value); + obj._key_value.reset( new fc::vector() ); + return *this; + } + + variant_object& variant_object::operator=( const mutable_variant_object& obj ) + { + *_key_value = *obj._key_value; + return *this; + } + + void to_variant( const variant_object& var, variant& vo ) + { + vo = variant(var); + } + + void from_variant( const variant& var, variant_object& vo ) + { + vo = var.get_object(); + } + + // --------------------------------------------------------------- + // mutable_variant_object + + mutable_variant_object::iterator mutable_variant_object::begin() + { + return _key_value->begin(); + } + + mutable_variant_object::iterator mutable_variant_object::end() + { + return _key_value->end(); + } + + mutable_variant_object::iterator mutable_variant_object::begin() const + { + return _key_value->begin(); + } + + mutable_variant_object::iterator mutable_variant_object::end() const + { + return _key_value->end(); + } + + mutable_variant_object::iterator mutable_variant_object::find( const string& key )const + { + return find( key.c_str() ); + } + + mutable_variant_object::iterator mutable_variant_object::find( const char* key )const + { + for( auto itr = begin(); itr != end(); ++itr ) + { + if( itr->key() == key ) + { + return itr; + } + } + return end(); + } + + mutable_variant_object::iterator mutable_variant_object::find( const string& key ) + { + return find( key.c_str() ); + } + + mutable_variant_object::iterator mutable_variant_object::find( const char* key ) + { + for( auto itr = begin(); itr != end(); ++itr ) + { + if( itr->key() == key ) + { + return itr; + } + } + return end(); + } + + const variant& mutable_variant_object::operator[]( const string& key )const + { + return (*this)[key.c_str()]; + } + + const variant& mutable_variant_object::operator[]( const char* key )const + { + auto itr = find( key ); + if( itr != end() ) return itr->value(); + FC_THROW_EXCEPTION( key_not_found_exception, "Key ${key}", ("key",key) ); + } + variant& mutable_variant_object::operator[]( const string& key ) + { + return (*this)[key.c_str()]; + } + + variant& mutable_variant_object::operator[]( const char* key ) + { + auto itr = find( key ); + if( itr != end() ) return itr->value(); + _key_value->emplace_back(entry(key, variant())); + return _key_value->back().value(); + } + + size_t mutable_variant_object::size() const + { + return _key_value->size(); + } + + mutable_variant_object::mutable_variant_object() + :_key_value(new fc::vector) + { + } + + mutable_variant_object::mutable_variant_object( string key, variant val ) + : _key_value(new fc::vector()) + { + _key_value->push_back(entry(fc::move(key), fc::move(val))); + } + + mutable_variant_object::mutable_variant_object( const variant_object& obj ) + : _key_value( new fc::vector(*obj._key_value) ) + { + } + + mutable_variant_object::mutable_variant_object( const mutable_variant_object& obj ) + : _key_value( new fc::vector(*obj._key_value) ) + { + } + + mutable_variant_object::mutable_variant_object( mutable_variant_object&& obj ) + : _key_value(fc::move(obj._key_value)) + { + } + + mutable_variant_object& mutable_variant_object::operator=( const variant_object& obj ) + { + *_key_value = *obj._key_value; + return *this; + } + + mutable_variant_object& mutable_variant_object::operator=( mutable_variant_object&& obj ) + { + if (this != &obj) + { + _key_value = fc::move(obj._key_value); + } + return *this; + } + + mutable_variant_object& mutable_variant_object::operator=( const mutable_variant_object& obj ) + { + if (this != &obj) + { + *_key_value = *obj._key_value; + } + return *this; + } + + void mutable_variant_object::reserve( size_t s ) + { + _key_value->reserve(s); + } + + void mutable_variant_object::erase( const string& key ) + { + for( auto itr = begin(); itr != end(); ++itr ) + { + if( itr->key() == key ) + { + _key_value->erase(itr); + return; + } + } + } + + /** replaces the value at \a key with \a var or insert's \a key if not found */ + mutable_variant_object& mutable_variant_object::set( string key, variant var ) + { + auto itr = find( key.c_str() ); + if( itr != end() ) + { + itr->set( fc::move(var) ); + } + else + { + _key_value->push_back( entry( fc::move(key), fc::move(var) ) ); + } + return *this; + } + + /** Appends \a key and \a var without checking for duplicates, designed to + * simplify construction of dictionaries using (key,val)(key2,val2) syntax + */ + mutable_variant_object& mutable_variant_object::operator()( string key, variant var ) + { + _key_value->push_back( entry( fc::move(key), fc::move(var) ) ); + return *this; + } + + void to_variant( const mutable_variant_object& var, variant& vo ) + { + vo = variant(var); + } + + void from_variant( const variant& var, mutable_variant_object& vo ) + { + vo = var.get_object(); + } + +} // namesapce fc diff --git a/src/vector.cpp b/src/vector.cpp deleted file mode 100644 index 48b88e8..0000000 --- a/src/vector.cpp +++ /dev/null @@ -1,186 +0,0 @@ -#include - -namespace fc { - struct vector_impl_d { - abstract_value_type& _vtbl; - char* _data; - size_t _size; - size_t _capacity; - - vector_impl_d( abstract_value_type& r, size_t size, size_t cap= 0 ) - :_vtbl(r),_data(0),_size(size),_capacity(cap) { - if( _size > _capacity ) _capacity = _size; - if( _capacity ) { - const unsigned int so = _vtbl.size_of(); - _data = new char[_capacity*so]; - char* end = _data + _size *so; - for( char* idx = _data; idx < end; idx += so ) { - _vtbl.construct( idx ); - } - } - } - - vector_impl_d( const vector_impl_d& cpy ) - :_vtbl(cpy._vtbl),_data(0),_size(cpy._size),_capacity(cpy._size) { - if( _size ) { - _data = new char[_size*_vtbl.size_of()]; - copy_from( cpy._data, cpy._size ); - } - } - - void copy_from( char* src, int cnt ) { - const unsigned int so = _vtbl.size_of(); - char* end = _data + cnt * so; - char* cpy_idx = src; - for( char* idx = _data; idx < end; idx += so ) { - _vtbl.copy_construct( idx, cpy_idx ); - cpy_idx += so; - } - } - void move_from( char* src, int cnt ) { - const unsigned int so = _vtbl.size_of(); - char* end = _data + cnt * so; - char* cpy_idx = src; - for( char* idx = _data; idx < end; idx += so ) { - _vtbl.move_construct( idx, cpy_idx ); - cpy_idx += so; - } - } - void destruct( char* src, int cnt ) { - const unsigned int so = _vtbl.size_of(); - char* end = src + cnt * so; - for( char* idx = src; idx < end; idx += so ) { - _vtbl.destructor( idx ); - } - } - - ~vector_impl_d() { - clear(); - delete[] _data; - } - - void clear() { - const unsigned int so = _vtbl.size_of(); - char* end = _data + _size * so; - for( char* idx = _data; idx < end; idx += so ) { - _vtbl.destructor( idx ); - } - _size = 0; - } - }; - - vector_impl::vector_impl( abstract_value_type& r, size_t s ) { - my = new vector_impl_d(r,s); - } - - vector_impl::vector_impl( const vector_impl& cpy ) { - my = new vector_impl_d(*cpy.my); - } - - vector_impl::vector_impl( vector_impl&& cpy ){ - my = cpy.my; - cpy.my = 0; - } - - vector_impl::~vector_impl() { - delete my; - } - - vector_impl& vector_impl::operator=( const vector_impl& v ) { - clear(); - reserve(v.size()); - size_t s = v.size(); - for( size_t i = 0; i < s; ++i ) { - _push_back( v._at(i) ); - } - return *this; - } - vector_impl& vector_impl::operator=( vector_impl&& v ) { - fc::swap(my,v.my); - return *this; - } - - void vector_impl::_push_back( const void* v ) { - reserve( my->_size + 1 ); - my->_vtbl.copy_construct( _back(), v ); - my->_size++; - } - void vector_impl::_push_back_m( void* v ) { - reserve( my->_size + 1 ); - my->_vtbl.move_construct( _back(), v ); - my->_size++; - } - - void* vector_impl::_back() { - return my->_data + my->_vtbl.size_of() * (my->_size-1); - } - const void* vector_impl::_back()const { - return my->_data + my->_vtbl.size_of() * (my->_size-1); - } - - void* vector_impl::_at(size_t p) { - return my->_data + my->_vtbl.size_of() * p; - } - const void* vector_impl::_at(size_t p)const { - return my->_data + my->_vtbl.size_of() * p; - } - - void vector_impl::pop_back() { - my->_vtbl.destructor( _back() ); - my->_size--; - } - void vector_impl::clear() { - my->clear(); - } - - size_t vector_impl::size()const { - return my->_size; - } - - void vector_impl::reserve( size_t s ) { - if( s < my->_capacity ) { - return; - } - char* new_data = new char[s*my->_vtbl.size_of()]; - fc::swap(new_data,my->_data); - my->move_from(new_data,my->_size); - my->destruct(new_data,my->_size); - delete[] new_data; - } - void vector_impl::resize( size_t s ) { - if( s <= my->_size ) { - for( size_t i = s; i < my->_size; ++i ) { - my->_vtbl.destructor( _at(i) ); - } - my->_size = s; - return; - } - if( s <= my->_capacity ) { - - return; - } - const unsigned int so = my->_vtbl.size_of(); - char* new_data = new char[s*so]; - fc::swap(new_data,my->_data); - my->_capacity = s; - // move from old to new location - my->move_from(new_data,my->_size); - // destroy old location - my->destruct(new_data,my->_size); - delete[] new_data; - - // default construct any left overs. - char* cur = (char*)_back(); - char* end = (char*)my->_data + s * so; - while( cur < end ) { - my->_vtbl.construct(cur); - cur += so; - my->_size++; - } - } - - size_t vector_impl::capacity()const { - return my->_capacity; - } - -} // namespace fc diff --git a/tests/json_rpc_test.cpp b/tests/json_rpc_test.cpp deleted file mode 100644 index 25b8d69..0000000 --- a/tests/json_rpc_test.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -struct namep { - fc::string a; - double b; -}; - -FC_REFLECT( namep, (a)(b) ) -FC_JSON_NAMED_PARAMS( namep ) - -struct test { - int add(int x){ return x+1; } - int sub(int x){ return x-1; } - int sub1(int x){ return 3; } - int namep_test(namep x){ return 3; } - int sub2(float x){ return 3; } - int sub3(double x, int y){ return x-y; } - int sub4(uint16_t x){ return 3; } - int sub5(char x){ return 3; } - int sub6(uint64_t x){ return 3; } - int sub7(int x){ return 3; } - int sub8(int x){ return 3; } - int sub9(int x){ return 3; } -}; - -FC_STUB( test, (add)(namep_test)(sub)(sub1)(sub2)(sub3)(sub4)(sub5)(sub6)(sub7)(sub8)(sub9) ) - -int main( int argc, char** argv ) { - try { - slog( "Hello World\n" ); - fc::value v = fc::string("goodbye"); - slog("."); - fc::value v2; - slog(".."); - v2["a"]; - slog("........ v2[a] %p = v %p", &v2["a"], &v); - v2["a"] = v; - slog("..."); - fc::value& b = v2["b"]; - slog( "...."); - b = fc::string("hello"); - slog("....."); - return 0; - - fc::ptr t( new test() ); - fc::json::rpc_tcp_server serv; - serv.add_interface( t ); - serv.listen(8001); - slog( "%s", fc::json::to_string( fc::json::detail::named_param >::to_value(fc::tuple() ) ).c_str() ); - slog("..."); - { - wlog( "create new connection" ); - fc::json::rpc_tcp_connection::ptr con(new fc::json::rpc_tcp_connection()); - wlog( "connnect to..." ); - con->connect_to( fc::ip::endpoint::from_string("127.0.0.1:8001") ); - wlog( "connected, " ); - - fc::json::rpc_client rpcc( con ); - slog( "5+1=%d", rpcc->add(5).wait() ); - slog( "sub3 4-5=%d", rpcc->sub3(4,5).wait() ); - slog( "namep=%d", rpcc->namep_test(namep()).wait() ); - } - slog( "exit serv" ); - /* - fc::json::rpc_connection::ptr con( new fc::json::rpc_stream_connection( fc::cin, fc::cout ) ); - fc::json::rpc_client c( con ); - - slog( "%d", c->add( 5 ).wait() ); - slog( "%d", c->add( 6 ).wait() ); - */ - - slog( "Exiting" ); - } catch ( ... ) { - elog( "%s", fc::except_str().c_str() ); - } - - return 0; -} diff --git a/tests/logger.cpp b/tests/logger.cpp deleted file mode 100644 index 350cb85..0000000 --- a/tests/logger.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include - -int main( int argc, char** argv ) { - auto lgr = fc::logger::get(); - auto dconfig = fc::logging_config::default_config(); - dconfig.appenders.push_back( fc::appender_config("logfile", "file", fc::value(fc::file_appender::config("test.log")) ) ); - dconfig.loggers.push_back( fc::logger_config("main").add_appender("stderr").add_appender("logfile") ); - fc::configure_logging( dconfig ); - fc_dlog( lgr, "Hello Debug" ); - fc_ilog( lgr, "Hello Info" ); - fc_wlog( lgr, "Hello Warn" ); - fc_elog( lgr, "Hello Error" ); - fc_flog( lgr, "Hello Fatal" ); - - - auto main_lgr = fc::logger::get( "main" ); - fc_dlog( main_lgr, "Hello Debug" ); - fc_ilog( main_lgr, "Hello Info" ); - fc_wlog( main_lgr, "Hello Warn" ); - fc_elog( main_lgr, "Hello Error" ); - fc_flog( main_lgr, "Hello Fatal" ); - return 0; -} diff --git a/tests/ssh.cpp b/tests/ssh.cpp deleted file mode 100644 index d3c0e31..0000000 --- a/tests/ssh.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -#include -#include -//#include - -int main( int argc, char** argv ) { - try { - slog( "create ssh client" ); - fc::ssh::client c; - c.connect( "dlarimer", "rapture", "10.10.10.112" ); - slog( "connected" ); - fc::ssh::process proc = c.exec( "/bin/cat -u" ); - slog( "proc!"); - fc::string hello( "hello.............." ); - hello += hello; - hello += hello; - hello += hello; - hello += hello; - hello += hello; - hello += "\n"; - /* - hello += hello2; - */ - fc::string line; - proc.in_stream().write(hello.c_str(), hello.size() ); - fc::getline( proc.out_stream(), line ); - fc::cout<spS@f*;n`=7c8Z-F5GvQ=GaY1x!nWe%X1UPEsP zgX)Qg5N04i_g(mx`mal%(tRuRN+(ah{6a4F(#s#yjp^O0km%m{=TC2D*`zDV%4ej? zyHL?PRS87*nfaSpR(`=uyGbv9zn?AqZP-sh^u0#NR{V8U1*N4#uk?~Bm(Q4T1u1G57SO` zxw@8?UOe6Dg;aWd6@Pgo0RGXvTTZf%F|Lj&EuD6G>CCIAUNHUg(ivq}r0`e#Pmwo= zsRaUb@1<9!ofa^qrI%02M6X2Ao7Z0m(!HA=>F-K|-qh(AmR>sT(z4Qv%BM|E;jg*# z4%{E}6n}K@rq^AS>kIkCq_RsVmtHujY!V8+{V}nN&^uEh(7oZenvlAdYC`tCX)g_m zUPKY0dzbn>)QF#pCr>V&GHddb8D*tqlP>V`m)%|XoAJ1y(!E<=FG2X3$8SykDxVX2 zb?e!x19YF6zZvDF7tEYllt$kCSWoVcLKhL&Pw^cWlcjEADEG=cu}0{X^mLH6Nbd*- z)=O{U{X#F>r8IZ{iWc1Xlc!IeI(?ch@zSfW6MFd?09O}je|ZmgfW7pZ6}__@kS)-Y z{?Hwb-M~yu7l<)~7$122yLMKqTvlO6T=-;LSxhKDM>#lbo zP+3R-fUDmz5U9VeXP|KRK)`ywXP{|jmq7i2y9Dz04g{Ky+a=I^bSEBr@&G|j z0)xtDUNPwMOD`C7;niwZ5D4sra^fSDc=h$S_8v0l!J8`nQ9tMK$$e19F|eD=U&sdQ z@khE;p$xzN|NE!sLtEm2wP7^vRPhXN@2T9dQ)>npt+? zRS*!XUNP2+%iMx<)v;Aq9`k!X2CBpz;x z#EXX1cLULc6&i|bJlwLBc0y2ofGYoO2+CulnG!usVVVzgFDs~f128cta4M*<*T%O&yZ zI;Y~+7qX~=OXAf{PDKM_RM&6=wXTZ#T53ZoK)ER%2#k!b92F1tCMM!N4?n+KVCk+T zbG)b*7Y#oe7Z%(4X*X)Fx`o?GSStn-N_87{FNu1D! zPcbCA(9U6C#LKi-Iig+(AX;jExHCyXR7t4sBcQ3+!mWkd(30SzANL5%Z3tCAL&}I( zPvoX*nMGlx|5MyiTmiKAVfe5?fL0QQz)V}h{h?u=As7vius%MVP!iV0nC|00FD8JV zr=5pB#-=TP7ah(;!_UG+xZh=0ra41#zy3%<30LY4?o99?`Vy7Lf@A;09n8?N_$)$- zl~+b$P-I`MVsMCqA?HRMTFp>$@#>J%kSE4NKpdr9p=?#6`m1&+A1{>oZf z-TI!oE>+hDXdYcxZt$JKimj?2)hYuLOy$xQjS{jqUTiA7pSsgRG%h}{!#d3nd3!qh4vS8r#FuN zb||sE?Qv8IAX=)q--x4691og~(bwS?E_faenq`cmpFPGMrTyX7K_s6ijvly(`$NM_ zAs8o)-ifoQq}4}n(0x2|Ap!Jk8;?HTU-~%t92E`EL5*<#x1LN>$I;tKBd$353c-Wu zbkyadf7lbCA%t z5q@OE(F2LjR>o1quqflN_d0R((-G88xQ?V>kKgFTyWaPWqu)QuD%3uqlvRLadZr{$a>=FPDH{JN8i3a zHI8n0#DUWiKM6QHj{b5o8rh0C`WE0^akLqS+Atp-yqRYqb#y_uEEQAWTg(-?lqaI) z1E}w+D;d1jRWS)eE-EyE*-Sv-K<_g2jYP*+pC$r5pF9JeqelEiTr~VWT$JDU;BH^2 zm^qu=FJ9e%TRnNWj!;1NFsh0L*Zq;5hY@1&dcun>CU}IPMqJcXq_1+J`F%M$Hn|86 zR0Ka2z5~CZt?uI33su!xR9RE0o}*(6k&o9Bq?(qTA$(SHMNySPi=vYxI_3aW{OXed z#C9z)fLUfUBPdni8H5Q;`Bw9_iJhTFL1 zB5Q#NUwkcfTCJ2;3oLi;Q+=5>SCG~#7>)rjlJoS3;dU0d0F}gRT@~GFt_U~d3b)z3 zA$GzQp!@(+wgb*D*J-mkg;8aP3fZqK3ze^?V^%+Ax)8Uz zmwOTlnpsIzvEcbr*=!gg7Vk@VvBd*GMgin*&Nh|&8FBz@YTNv!5Pxl4652i z*c+wV8iy)tb6k-iAEFYgB?e$N5vH_Q z2+HuEW-X)y5G`fh!Dd5LNfmo?dPUg6?asJ`*}SpNFq;x(HkTd*1|Wl2_@c)}_;m+T zX|0q>GDP^@i7RBqWXwo@oy+D>#}c^BVY&1_SAd&auOT?w9KMEq%J_3MH68ESe>BWt znCSaZE*d@_7ZEh43!6iO67-+KdlPQ8IsE>Z2=F{r#e%2(fz5#tV(~`8i!CO2=)4&h zWe!IxbI9w>=Fs9I_>3YrN!p?bi8hDf#2!RC5mnYV2ht6hLmQEYtMD?N6IkyEt}=%` z6k2zPF6NLAP*HCwQHj+O126~9%ETor6R#$ybWubJAX@t2&uk715B7GD91F9B+fKNJ zIV^v}Fo$9y9xu94N!xuE_Y(F0a_EM|{Jsx(!_dTXacuZp`cg^~){9rO2`Hl}W&>lm zF$$AyOcE+0?u!Qy$?6hrymq2P`Dq?{YNf($O*5oPu7EHjxJlcZ?)#Irrf(l1$~`|k z8P+sHtm$(u8lL^Awx(5CGA41e7^e#e#mT3;i-4?KVn)!34--jmuH z-2DkFA-8P%0IsNG%##yP0hkE4&$Kvo(nn2d7)qyb3WBT(`b!7ndmLx36SAIGxk_kW{zc zZG$x_u)C4%)6D3>J4P8m&CEqMiXMMwfpY6GyEs4^hq@-Y8{Atph*Ym)w^D)ibv0O` z%Jy_O_$k{aWv1#>bvHNVXQjH89&r*yaijE)+lx)z8u`2~$$AE?9SRq{? zW!g#aLzxYK80w7V*5ytM;X0PtO8hK$Z|$TepTExc61>x{^pjYuB_qRXy@KB9{$i(19MvqIH)3L;<@dsIjW995hBR-HMoG`O_;}7XYWr+3_g1yq6&fzV(;uaDnV8n z^1z!bBeC#2+1{Y+1yQ|pb=QD(G9kto@+JJFbYr*%=%*_5=Lwy|NKxP`v7)b-;%FpU z$05l|TIOMiA)_BeqHEE>!UP(ax1y`yf{or7C#+V+q4io_wkb@!zMt{{i?C%{aCUV6fJ3! z#(GL)O=!%$W5kfUvF5dC?AhfkSqn85L1W9|LlAZNt5iASsjh+Kc~mu;`i&c|quYIX z>w?p_3F}b1j#=*HuFJLSxP=Xr2Nw^)-Vsg5=Byz*Qf9TB3}yv!VBLw3p*E?a747J9 z{N?_0J`5#(dQK#olYIv&-S9?nj z5Ye`I;Z30><2Dg3nN;MW4W?Yxz?*@;>}}^&cq7ms>m^{R?2CpH_HtL(+PdQ^lIN@WiWrbvaBpNk;y4DLu-e+OE1L#UP%alBY#EI5NY9+i)SWx&o+u#W*2 z(d5Y$P+}~23InahuQ4|Y_#;#w3m%3Fr+wCp5~2MLTLda0ea$P$_J@5v6Rc?u4>_QI znt2``;%G*(QtsfW_T4lgdk)Jk7By7=j^|F@j{+t8gs+WpSD%hVkJOGBOZ(5oFy6*U z^!rE@`$VJbBTak6&mD1|j~-&V z_s8un^V98kp!?_{mOI6ThXE=|(Y=AXQoG**HZNQfNT zs1t#xo!}c>TRfPW61^Br-LpHI^3m6~=&{#UkBapg+4)aaM?uGRJp!I~MPm)Xmxhs} zHE~v_;AGHGNjm*7@$@Q0n0Bj>LTek8ktaN{O&>ral2WQ#4ACFVwablg{v+mLDG@PP z9%C(oPd_c6$+g8L;Krl>;ZBW9|9hfmhDDj8o7Gvwl20#f+RZLESdB2Nb}x;rNYhK% zpeu|gtldnUo+&sPdTGX%d&##Wsh7C@^c|V!-;w#Qj*O5NoQ~9etqh<0`Y02`9-?2^ z)kZZG*bRG&seL_1dIr+^_4Q<~EuN9u*CW%`4038*{YzFbkjAojiCfNz#H?cl1l3KT z+@g*$p=?nbcd@YzQTN8)n#-emUX#XF{sw$)D;9RwTsUw2N#n$W({Jxaa}%DE(2OM> zywFvmBch6{_kmZRs4X)bZcNQtrlbEn{oymyNv1+s51~wEQp(bDM2M1XMUTcs7+Hmd zgIO)8YoXETD&F@Phcd#lA~Ettt~rx4;JbC^;wVCX)tWp#pY%w#z+XC$zr(4)eCR4Y z9~zGyeFk^L!7GED`Oq;aufA2vcV&5kHz=@s0EVg1gG+cSG?9U5Dl`p2mdMPf`dIKJ zRH$At<*lk{36yuUt^q?h!6wsXx71W$wv!fqCp4Z6vadzr{yNaJ)R=D1nJ?40hM@<( z19y+U73sG!5^Z$b3PqSGl+GaI@LT$dhgmDa!y`sA8ea97lh4%kga(Y$_&FLBfXz0> z3%e)SbW@5iP!=r~NP6ijcF+_Z{VuGb8RTdZglobY2@T0gh;NS}T;!+7IA~$T?IdaE zq-srHWe+mvLW~pJT0w`wte1IT4)Z56r?oUOdPvv+osX%Zi918byQ@hP?M`CSMCGdp zv1(0@GeL?47nEz$ITD?G5AF!E5|DZ-y)VlDL{lJ?AIJ>_XDYB#A{Yx^h+1dnOIo9@ zbFV3&3ehHMHJW2xpF@Z_kvU(_heVOsF0QWec(Vs{4Q+&P2{T{%6m7CCkUflc_hv6B zh}iVR11cgZFRIScF-6&;M;Zlpry_&(<)XPzP};e4Ecee&y>4YZx?06zBbvU6a*qyF zdnbm3ZQ^l(4P|?yHGt|d+uOyXpeF5bG1A28*^wblyj%>;r30Vf2c=&%Yjlbn%|lOuXo6 zE*kzJE*t=?+mq6K@^T>jO%U!Ngnb0z8bNr6R(e)kz5JZ2?<7{Szxeh6;mup3E%Uqfi<1U`Dq^Qb@XfD&37>SbTTDx-Z?P7$?` z?!THtx6R2tU1je`8CCNxp@c||;UmULl+1(E>$Y)4p1dcuRFdUt=>%$Av9xCWD{FWbq^b>*-(; zCQ7Qy%m+8dLHI^~B&H zkU;P_(%OXu!_eM@6hj@FU4ZuJN@leHS0pBpH;9LU#zOWZgjg7KVLcESAXf5tlvrT$ zgwXO9flXLznKI>fxy4ridqVUxHEd3$N;o}b(#rRRoEFK+L~kIX!$6LbOXZIzvuY#^ zQY~{(MF3T6O6;L^i_(rjYbv2UoytH5YFiQi@Fw#2Ui-jVnks?-wq zj#N!`B(BqhZK)q-sbL1AMgH+sOfm_)*CNh~`2|o_l%V09-O)tI*S!e&;g)s3J@SiA&UV{h?funyqb;z(+~qr0ny20g~-tmAjI zY>iho@np}Pc%*g8*R(K+7eicZd{nK7htE% zWyn`v+9P1Bd6exx0CW*QVf}#pHW$h;pg4Js3>H)3XLXRyWtf<+M1ZF#*7Ak(g+pDkf>&;C}KzzLnSyi z{boQBy^zp@)(v`rRC-^|VEwoif1(LxD}KDwj-mJ`v6<$IBZpt8D8WZ?WXG7Sch){5@Wv}42noMv1x6K+Sdo0>*FL2$z6lwa+L z<(}Z6_h}x&VRQK}28brMFqK$;e`4rio7f6}Vs)v+zB3`Q1;a9kf!p+o%qH!C5O%PQ zfN(eVbyH_wFHEOMQzM2(w7pxnw=qB^1ElOPmS?IwD^uk#v(k*p`$}b_Z^+KdRQbg; z5~osOx}x;{h`$$KE|sitBLtt_ZUk%E^cu>*C2n(g?q>svNbV*i#Uc!nd8s77`U6LG zw^2NqN^&JbRf=60B;PlI_d)x2FmR2>H1;&xwoRkIL%=YN>##%X8Y_ODsN=qlEoyw2 z0lH$*3F~AN=aqCgPyR$W!C}H^leTtouqj{&mHUdwEvX&TEZDzY##Sn7wmo2yRJL$s zWm_utJONlC*p&=mWB=n{-1ftQO-HdjDyN&3rth3Cl`X!$Qkbk zrP5#8lQLEIH!5L-cVEKZne7VMH^4+ZF=Qq~Rr;7q?j{46yz@i`uJIV&B|jQ~6h`(D zsy-(CmI+K$+b;HVhKVL1QB5#lWeeNA5lP}EFj2insCpc<$po|`Ny`tm3`Qh50{dOA zNb=G7X(Gu&C`(6@fQj=EaCni7=ZenK8!xnJU4lDG-*yGO-gr3%<$Y;DK>2v48SJOP zzN8Jrc<$GC@uqcW2BJ;tk)TiDpYsM|@N0}1cIFXNIJIWvUBPg>{T#-vn&DXPJfx#k z+K)xxBqQhPkSF|KgkF!J#vC}Vq=vSsP`OeIa__06%f4prshJS!DXRcu)epK?dWz|q+{g*j$^|j7N z6teQ1Df)(Q?XGuE(ep*eJQR=k&H%9k)Ugh#(UrGj2PxHR{(+Tl`W)m-TClO_jw-6U!*B?tNQH@5kaxHJnL%aBG6@-&jnNk7;Uk9M#Pi66o)k}D+l9_OEf z8~}7}yVFdRuf}S7--7L4;%9ZH?fM#(X}iAWO}5MI@yglPyb&y2Aedz%BCcW_d#|PM zwt2w+33+_{NLCn*AKjcZoJ8mK#NA{jez*yuJ#r%J&!IHd1k;pC#B$gppEE&h`+VkW zn+d}{v#`0B>XGl1vPX&}DT~s@T2nX9x{Jd^P zU>H%Nz1$v6WhSx4aw5Z66DMfnWQ+{|a~Y_uo(uiYX~q?;bULk(*C((wC(OLI!HyN~ zfgghhnIwmqBTNuY%uW$F#BMPmb<9$sg^3lJAevZRDraYykZ?u6+}u+pl`Y25O;Ev8`_pJ8vA>GK4;EfssC01OlCN(Qi<`xL3% zSFnAOE%yn)Z{v9s%yz|vX5nh`*(}q1o31yneH;U%agTybmD!mplVTyN*r zEHoF37OclDNgA9K07#Q-MnT*biN+}y{X7=T3eZlUU9!bPc6 zFBhsFXLv7_>hVIgg*(ECB;T9B#Ov-twMqAyxY&ti^L8XT!69HolKI#vc14muo{}ai z90<+oNOGZxQv@89oBQAdcW&-=+)>u)GQhiYbB|KYNBQgE6@ombz(xWLxw%v4a&B%m z15s}7qmu>vB&v@EFG7XuYzhW{BU5MLELaOT)d?*5X`X=HhZ@E*&^ZD7%E#2UaRPP# zG$totS7A5Yl?S8ghGgDEyZDV`dDf6n0`8uN=ZJHO}m^?VNeB4Gtk)zqs z_t0mzffXDx?n=eUy(nj#g>$}b_^+ZZAolQDJp@RZp-Pq*ok?eKa|qpLj1_T}9g?mQ z`$>74#-O0WyP->m#9*65$_cty?r@$5oSp+Vm{ZSj*9Wj~=^ZnP+1#KD&nNGDkv|@E z)?0ByHeYN*+0WT{0@I2-XwT|HyQg?sz z8s#{D<9fV`WLK(iJ)h!UtwZe?3+YL^cA{~`2XIx1R@$agq46k?K)*=bVA*72C`FSA zA;gB;$p&B)R-o)a;8=j|#O{lh+K5Zpk05)1L?zkDJw@(!-E|4)r59@3ftt5FN7~Y1 z9fS}5CkR6{0;bm@#~tM~zR3SkyggT-}TkbJX|=MKWsK zjGba>(Ho_>E6*idrUuqHB<(y3AxH)C;i}eo*yYl5QOl3RB&_}HT7+=MJ;hb~$*FiV zk2{XNi30l_DF31zZYPd$Byc+^z34>8DY%Y(T9WlSjrGZ1((5#YEqQW{I!pY$MC;hF zsN8>_Zo;C!HiME{?HTitY_Ml{ytJ<@@mJk8us_4jmItb;qCMb#j|pNRw24WS&wETz zgP~Q+sm2$A|IbGv`zZs~MeZ+HUAeUbo(H4T{3PBzRTd@jF4WEHcN_LxJrZ+E#n2I+ z(RtslRXxTL&n00!O~WUs*C(`e6if_zGX8pZ57aiiN7Q6ztGT0~0HACUo=7&Kg`ROj z`*_0!Fz9+RxKv?C(3?66zQy#;h|aE-uH}}fR?nFF!sOr|coHl+t`Sf7)tyTlwmomf z6l^JdO#qJr4m^{JhQBdh9VoZvzQ9wMM$$x&f9M%dlRX1EjNOH2KnJQPvc3nH`vI)( z08tNMy-T~OWdQ$C7Dv>xj_3Vu7z zJGZtqu~r@(i=rDTR%a8vb6nU9Ittc}P}u&OicN9kJ&wr86KMUx4)ns$Fn0FHoC`1| zbIbQWGS_t!oQy_Y0Uyp(4&mrQPWrP2T?x^(pz}Kl_I9uep($twGx8{=U(wM`iST9~ zG2-Jkg8-^HeD!}vN6qoX2`Y%(?jt)tKZD*^RM2C%&BsU$>%Q?<^1AOTLW9A^gWuu1_tea3Trca4^;D)t!FBQ*3?{7A^c&~%7#VL1 z>x*~a!EovMwFatx1oi6Wc`|Fd%~ik@=IDa(+%L*Qpta#hVej#8!Cn-`o3LJ{pZZNf z5*X%n6#T2$6(7&y9-tLpbld_MGOjd#mqw?Ol4(Jg2wSA}|R3H+Z$2!SlNS-RO zUp(7H2sGt@6kPJ_I+S2mfI@f)>1lKW6G4x?gK0WHiDzNa)*QNxo;iF#CL>84E3pm|WcBZi1xLO` zU1yAa-{iycTn``j1c(|3nz2pmH}>^#Vq3ngG1u6)FRgsoB-@moo{rd{^@y?WEjvzm zpSnh_!r^uv+dFf60O|DWeN9#`K)qshps=c+lNOa@oGcxxBcf`lFBpdRsu_j5wLP8I z+~ee-`ROCMmpLn8gbUdNP<+vJ&sKg(I52r0otX0gnxA1qBth zE>m1MD@IxXQjR+w{!V#Tk2kso@RoyY8j$+ZF1&iDfrv*cz`{V!{PjA_o@wISTCV|z zeYIUtoW-h8(x=3!`V{z!08fp0)+5{or%*NF0w!$eooA5zj5V#$c}UyGCg%gGSC%=} zlMMEsy!&OwmNAv(kW|h(Fy##kZruQmGhEiUq#w+jGQ5*!E2w+cRy1b_bTnbwAxRyl zb9GOmMPe4Y4jQ@i!BHO#8a>jvQFk3f>b1mRgr9nJ%|Z~XcTzA5$;RqQd-jx(p2P(Z z*E~QqfOvq3A~zhRqgJ>itSl;$)HQ=%&7jC8E7UXPzA<^ck*l7^#T@@J1*4ocuUsD7 z1C6SLbUnMFnX5L^)X%!dwnITs#qQ163-xB9w@QBMUw`@8Ga!Eg5R@Bt$xlUY`5DwD zzuc$D&&8?oBUShx$`68Ce(ZsI<#*x?zk7vWj?tpr^1QVymCBH_r~dV?ROBSh#}J5) zMfcGjtBOS&OB}0j^E=Zzm^xC$A^R*IqT1F!!!i?1_>CLulGfqwb(XJ z$%F=HBNQX@f=l)?&lBjAxHj#X;rCYi=X&~cQ!-bvIttbg@Qg~*7*2A7RsH)X?BD2d z1~?DeI9t$faXS4nVH(o>UjdpUW{mhoAQ3+*dE3@Y|7A{GeXUO@7P5@aX`km;*pRoEg3h^F5z4!>d=?=0~#7QI=wcG|mhUB*~luiMGUhIM{~7Q?WJaGQ>mr*)t}X zj7&Qy^!EU|=rv&tHBo--tL=RYwtI=6)lqC)9WrFN`v5BwNBXjaDq|1KtoCT5@3a)_N{Lh6{MLJJey)dbPR>QXt|&xC|4 zVi_0r9t@3|P<9L~f7zDHaK+bnBhXw0#)5mXk7qau`0F4F7irEtew3-QAyefeW~CV{ zZ;(p=GsBl=svKohx*`>w%v*=~vHzLjXuT2EDEK|hz{Z*3&L$L*yjDnxMHulkVgeJ% z(}bkkD1Lv*XqZU$6Ov*V2FY$FNjmAb`Ct;sYZ}u`K-)CVaauD><5|~!BGwVl^-dF| z*MP3L2eRQN&dhW;A1oo9;3L9lleTtou$RFQDsSLQzca(x0x(6eZO0Sr#X>qF*lkSO zP*}YH93~i>IGISe)XW>#+4afTODsSXmVEo`5LV=Oa)iPug-waGSS9<=(H&D)VA$01-uk_)k63KXNGGi=A-;c@CrfxtiW;shP~rG zu@QjMKQIuT8E)NIz;~tkSnzaIc+W$kz{#r8bRgzBA?d7WvDkE=*0-7~i)1>NXX)b> zI6ZR#f3B$K;W#>_PtSaJIPW0dic3A%3s@)CaJr$HwA;L>Ye0W+VC@QG-})CR92)2p z%~RPuNnbT|6kM2ZX8^EdRwu<=yMi|nwH%t*(Ahgd!(Lz!(99W%EvssCj%u^3eg}cQ zyVuWUYu+~7kS!LTM=1PkEPt%nE>7#%s(T-n;q)7|tT@)3>R!PH-3vBs)yBfD+o7Ad zkPOayex?6jwx+g{&XFEEvK#mIp4&>N={b`h*@L@no9R66p(8tQLp2@M`)pB4f$D_H zQ2;S|+X^A9Xmh~M+wPgHh*CWbC6s~Tck=q~ynUI$CM-hDNI~tq&DQ~mBtbN=Plx8X zb6ab%ogibT-Z?-zsiN7~!&n2WS3B;!hkY|}+*=Y4pkAfqFU58)Z}2$p`c6;xau3}j zJakWV=>jvT{~SiCSbr9KvM$!ShYj9S+IX5Q+Bub` z+nD5OW46=A$v$n^=PV^=U=gRz&W$GWh*Q`%qJ23Y*nY$=ls6;f#mn`q!hi6oL>L<`+qkYn_k-S7?q!ZK)qoQ9cRZgP~F@>53)MQ`hVTqf8 zH7c6a)xXHD3N;czA9K_d12MFm!qF?hOX29qv>bg%TU3gp8-VKO=+|crjxKgMT0%Qi z&gn>lqrtY0qWqu;>#4wxt2)qEdfFZRRWG_~Rl4F@#o0z|Ik`ETXma)j?MTVtti6RZ z{gBC)Ig0@|MPFSra>liav(r7Ct$oJO+2Ian*Hhm+kH0WywjHb7*e(C==}>{AHAwpUqyaV1hnCV*2@^1QQ8kUWT()*o+kbt~8Cd88#6?>Dv(3Bj-PSF)Ou_{~wi39Xn0#e601Ni=`@$HW9_zS`SO<2Wb z&vX=qyvUjE+U-a29MkKe-UG39{h>iBAJMA}!l63o8Q~8j; z9rB|O=$se*xxXA>{R?PLubI%%(JjEhAAKB(dXdl0-VN)Lk2_%&f?6qk0b6QYG|ZD5 zc*S%_gFwoG;2dxW$Hw_<<deS$4Fmc z>x6k-`Y5eT1qnF@wZ9WnoO94JT4N-7g_b$MZN#bAhVnsr%)1$~yuwG3npH_5^N|XHoQ4E$(Kv zm`g3nr_om@cM~|ceZp#a1&E!wfE7e#=MilIPFRabSBi}}Ye>`fpgd=zZ0IbDum%?w z^QCq$F44w$)kol(2yaA35CJNU#A+D^-;Bef?XEtup!X>CQ3>I)uy28}wc#ZGzQ$i` zpmhRua;%yNh>caXpBtKsXCdK3=g!`{s(nCc?jNy}UDZCctQ-y&qDRF7tqZtlLTGLo zLr%E1S5^Bpp}7a}T}5c_1pH{N0uUldD}SA;Y{$xquLEU0&}vq)3$<-Di%ugh@c?}e zomhO|+8OFhiHE8BM;H6hfJ-tfOJ(aA4>Xx*8fJ8vrt)CkqnfL zcZ2j$Ab$Z!BK!sJ=%G*17B#UvUjf_zfU58pS)nDY{m^sajl;rUgdU`)L)MWt9U;3^ zmVcea!nx@5R&+`_mK6?T`Y=F>QJinkR(xda3iL-64iQxz>r6`92< z25RfKpuFY2&jqM0Al^aZVtfDyP{00w?OWE$eVU>V&>H|sUYEY-pFw>h{2?f$5%*>Q zRE0k@#r@FL^O;2+4RqZP!!Tab^F*QQI0r~PkEBdqJhMA(qp4@D7E{_Eo*S!{7{IQ3 z+;<$O8c6y|+F4Tq<2DN$j>$raKU_Z%^*a8rTLI`p!qM^PP~nWp&sjqON5vnR{ehM& zOQN(a09!2)TAK)`A7aXXLTJepDF@~G--9y_k}bsC=X{GjgmCi-(NFmcs|hO~YjCCm zfV0}LPH;b7eG&?6*6x(uQ(7q$+8=epO(l4m52E-R#vpwKHxKny60$tHL@}xL|Ggcj{wq_R9wqqeIJ%KyaPC zD+kwXgk$htwtwpzh*=zq|HVHLTsQKM;bp<8Z|+bKB#(~`1o zRqYjJ*~u~V3YO$4Ra5bQn0|wBR!wrKrgMg-)0;5PE9;fq3$6Vmt@R)@;w0Ilviv8W z!Te;47lL@Sa4YWz)gUn8)0sSBq8V>Ipx?DHfe6MJu4>BwK0)~UJ z={PQrb{Kn}iADL+t5}Uir*qNpa$IE7@vWKEopx)8yxiI>X$`j=i!5plt)k^|jk44~ zk~fbir=|Bh!4eWs#G*Mnr=$T-jCuUoMavP(wqfaOvd*L&zZ2H?^D*?eKOozJ0t9!e zd*yljbQT#1=3L<8F5sWN%evCcDS4PGU<>J4wntTa&)GeyC>Um4wM!C<#NK5=^maKxcS?4_|6QoM@I}V z31W|6kYR+cTDhy01#E7;ow^%VA~GJMf6gvDT>m_;tgrsro86CKL(3_1xKP@@GKsds z%Kes~MHkPWgC`DnY=3F8o&=G)Rl2!Ft2$Tx^!3PjH z9-FeQp*uB9kA{;qgsM-cB}<%~5QDI=`PLUyBxC&auQ1UW=$emO$~2=VT^QPG%5U)a9+c z0B7f9X12;HvT*bA?#c|-K#JDAgjn-(y*PQ6N`tzzr-GeNrQgvFc(twjdMf>=F4g9B zIhC%aQnwI0nnHXgSWdEL`9>pI!-6-%eQm+Zdf|Ovlz~yY3Q{xofsB97W*X>m&c?)A zN5+5=!zIP5(s#m&t1}*@awS3&`Ntg1j@aS;utQ{kI9J5%{)?N0=tFiNx!X;(RU#Qaw&?!%Xi4|co~MrQPCD!Ot`bCG=iN4 z?&~pTkP|K>-Nb-%^ttfR(2@q4>FiN(+O7n)w#BKeNpa&Gn!T&_eH>GNvB%wrVVVHOszteMrJZuf zGCn3A&R_sZtWIfx6v}v~-b9F`8>9uc#Ao#kQMu^3dY0VrB?=OX%x&m1GT-|t4vr*i z?W-9^Bi1Js8f$$>V zcO)N&-xg}%2D;5s?<7oEZ*lEP00Zd*)!{pE5I~9Z(m~3)HtTRaWn+_OnAb;`8rj;$c@Pz)n1LC2dgR zp(Yj#1irxS*8Gh?#QYe!4uahT#cj>s*3kWL!(0Mhx3-PPx1fvN)6`#*rkvV+mc6^W zlKRTXLjI+lOSr^J21-$ReWx@uCW{KAI<(ZjsO~k~~X)Y{tuu&A6;?TO`nI0hk5)Gde|$0cyFz5r;Mb5EoCdoPf5#JlhB8}P*NQTERSaeF z-ekNwMC?MD38V*8_~goXbwI(45kB>87x1Z-*)Gh=rMiU$R_9CMi6S}rl@fQ-^Hj?v2D1gitbiu0-+y6dHQ7Uj zSQ8lF} z-CHLIabp6}87;N$ol3E>i%@(Y21tvBwc+JiptRhi^m#Q@^KmCMqWFPn5XV?--2 znYfyV1Za4*s(y=x5U#0Vr^jx&s(DFj^#0RARsA|vG`dX3)DmPrsjaytijHu1yHIpo z-AAE}vD?>?q@T3UvpU^SKsnB7E=nBSAjvyCt!-}YW>eC>{K-$O0)vuv?4XO%v5I6R_jAad)+ILMDwX#?^vOfyi&+$_c#?~6sY(}?mwIdZhP03=td_=W4WLI2rPLwGN-#eZyxVs6SL2$3f@yLJXp5(MKv42q30N&I=R|TuA_dh zb)e$Gk?=;vVmx?sz;$yJ-^h78eToqjLQ8T$2*-K?gUxr==U~wQ+2l;}yOpZFSngkb zv1L`fvB==QQZ<}tfS$CXRAt+248hYH6oe{l*M<5Npwnh7_t>B9c9;u(EIVP%yn^au)WfQ2T$0DoeNg1N2dyu)#G1?Cl;HL5dZkZ%Up1 zwzVhrkgECHwfV<#^Bgo=$Q)@m3NhlNiQTrPbQDaDMC0B1a9W7VNnSVPfKKj4#Qii$rykkDa78+fV0nao^-Tmq+$uF{@5lEM zzO!xAmmUaUzox>D5MO?4!;1(cYe}|4SExA8BB;y+FTk6DVo`o`d2jBrg!Rl6ti(A* z^9X*~#dqSym5i_>D_aW(w9t|!X}>sIrgz6orgxO4o{tCgOM%c!9_UqRp`ES~y7_4# z-MuKV6&IxCK{kK5A2r7}r-uf|D?A*(ofg{5@eyeuQ#rn6QaXih$;LPLhAF-58~{4? zGq!6OmdmKl0xIU7Eov&d8n?D(9nE!;DLeOd%v{|2!zZHvGZ!-Xdy%@QbUY&4r$tq@-V zqHf(5YYG>VFY*fLcDjuh-KJ3H3JMelhS6134HNC|rIYxFBIAn7$m~dTT}Kmq6x$EO z!W;D$7@%5x*6lagOOj3)vGB_)lpAkgGtwhHO9M?siJ#FHE6l+;SK&Ml91!Aokiry7 zi78xcrrMaPP1kj+CuZ=3!UQ6utWFMUmO9p~BU}PNbgEtRmgAoJ48VfhiCiL83apAb z+IK|3jaQSw>UgT3E6f9NSda5OW?dF$mX%jgkMnyV-OppT&Vuo~-rRf!z|`}Y`_i@) zx=Nkz^JCU;W}yN}xiR2eu*SO+;xQyfpxDiq#Ca4XT4 z>%&+yRkZfH5{-$H^=Bb&*#I+fDfowSTfxg{W5uIj?X+wLXr&x7BJy3=z~N8LIn(lV ztPf8&qCpQ&^nm8}?$+0n>}KovcI!)S(QTyF=Oj?{>hn1=Y}3|0Kr`-sy#XLfpJUKSsy-zSNo?W1 zt(yxlj;qe>5ek}u_Py&J7uJR`97GX~a}VC&Gc&81j|gOjI42fvtya%u`*CaajOi&_ z{Tqs;PbXs6#@nQ_qGH>M(mx4y=@pt#FPjhrp;^G4w>JD;0N*8Ofm8u&CHF11N@-pk zAC0S>75tE@Xe*J6I5Mt75g(u{-xCH=@2Yu4*Q7kxg?s`sTCv=pTcF!m&lbAKg!+E6 z0kvcOhAjE&^+DnWvh3wlsCV#2W9wRGQB`YZ=^Ta{qMQkHs)V0ND}ECGN>!$W-=N4} z!Y_4AS_z9p!rwo!C42?_pe0Pon#`2&Ln_n~{sFrhuyTLl(0loI&&M$2%cu-<$4~QX zj-9F1sN2@|gS&b>`24BbL^dJ+Z$}B!r_>w0D`x{8Q{?n-^!7Kd3q^cC)z79XQ}tJ% z$Y1qDhilTR{`rrg^H|R+x`=TVv&fW7O;|G|J7cPT5*2FIw_z6Jt9o%i}Y) zq!;uU;)?6-8Tnh;hXaYU(T5{b!RmvXm}Xu0<| zXaE3^N-d#9b)O@Mlx9j}3%QFwx7%hU{n|9=MTxD`$WWNRO;6pUJBYCoy0*pSeZa4h29IV z^XeoPjDJWblm={LWh%8xzn@@Ky53iew;lvfdxsqvTpEu2ZK>g+^k(4#hBV&%{+Z*jT^?6pn7medx%Lbd8GgUOi3|st zI0xA{86(60-22V9I>!9ZX~q>}VDMOF#A_P$km>}id(X3Dg?r$~;6dXv2drsMI8oli z#P~5UGx|;RC#FIR6FbwNSY0Y-1tzgHZ+^eaq-VS0HRsxL8Lqev+Y70)l78&t8Q$ld z%>ZfMUY&f4Vo93HH#1c(GAqqsd52WebNdv1&C07XRi0y1x+2y7hp4bPqhPv_flJ)xP($l421C$x~BFP7soAqc|>=_RCb+DO2T_Vjdbb?;amSkP?bLBa>{rEn7s2<2KK)BJLz?m2Ry|SVsP_`SFOQQAX4+JO&ud?`E zwhD`|(V^!#8CMKxK5t05gsq-iXQ06f^n79RlQHl+Qmp65<>Ai0fZf}%;J`*$YT7(w zh-=g48Ox|CiCu<=HX;@7^3c2CEvD_L71;?0JkTws!U^jR6K8^rvjzPY`{hT>T#auc z#>~}3{HRc_W*d6xzs!lNuXR?Vkd@~wH%dzEu6Hjt@kBMJY)Omj_uN(h0ER-0cCrhaTSaMqXR;{JLBo= zB&IL=x-0o2TO02j__`~G8W#vwKmmFB-?hKf7a%@<1X$Ry<3~S@vYo;0N8)ZWY3VRs zO?%`-52fY)lu8&(D21JPO^w<1*~>vS?DG%UoY7;Cq_9r;L?~X-f)WTilhQ^QPS)(C^xe+Ek+ZA_punkwd7<)6RG4Qoz6kRf84;C;$np{aN zQ{}Wwm1E3GGguxWmHv6gUYRO?eU&4r!gNJaT6b5_3e-2xc+iP<_|n0&gn^AbV|ORW z5fqW^FC@hxjCi^soI>)qm#KX{-mp<@9BDui$@dwmQtZMY`It$PG8s=Yus6?mpvkCh z8to_8tr?~<3cFFRD7|c9Zx*q5qL1Lf2!whZA---FWCQJ0B^cykYLvfwol@yt6<;707jlMTiE`M zJ3oW(d??m2pEyg|tz40*^5IOC)n=vXJC{hMf9CC!OqGWim3B4)6HPiB7z}ZB25G;Q zUi6pttxT0KW~#i)tTd(llT`XkJ0VkLu~7;6p2G?R-bvXF9sdVVD0LP~vuzy@t2SbYr4=xKQ;m;RjQxb``1~XLvZ3>PL&&F?`(W+*GOy8Q8lK@S#c7 zjwH_(+rk==q!ad=U6EwiGif5pVF~VLV@gm$&*5h5kyYr04 z(13vQX7CDK9;?7!piPl@ZvB^>XWWBGWp!HtsnC#~5*ZBSFH`&5%)L;7~)hmBnOT890TpL1COD z7?gqYU`PoYCu;B{8a?sDPkTNKsdWbK7^^?&^=H(D+xWe@^j^|tyg;z+D&w;#K;R03 zq%~&)5)w(gg59D=uJIC7{6CxVa~Q0;VU{ntjq7CjPQw-qW*ItlRfxx_*M~Q+zqSui zG9FNV4vb5X;rCB*j9kX=7Ktt{0Rxd}ZGnz)I@n1k#|%UHOhaw<0|=7(g0eDeWfVecq9(iuyp=PNIy26#|I*GS0m4OS<$& z0M83A;U^R5opg9i4Y)09t7n7L!nNVWFpC$FkbNP%HvIgQ2;QNAa-NRzI$K_y5{t83 zG4(z-?#1_xXItsP-?eFN!0U7p;in5pCkkv>H6fMv;BVrzJ_vxd;ZJlea`8tGEI%+( z#U$~*;7?#_LSEqw6}*dqr)mi2;BtIeL~uOts-2^_osZGhM_`C;9X8)2Hop$VZw6XF z>rC%({x}et`#bYXFKlm$tZeCo_i9D5pz?5?tH~*$xvvAkRT2)(U22vLx(?mIY!Q<~ zu2alB8Kj2R1R0n!(UWWa%5P%RiuS!Ox#@`&MU|eN*}V);>@zdV)+Uv}Bji z^0%wLE{sfmJJPQS0Ch7B!-l)=yf(ZpOKYVy2+pde>KC!%ku;kxdYP?N7?~f*3O7ML zS*@>Qpm3^>9u&G|jnjWDNa$AiKufBI=EH&3$&&+PA>90}6t1sTd|U?M=3n6zE?S*vB~VV6`m8Ix?5d7mWS9qdC?BFbXl?jodV~H)th>!!V^Aj6e<|p=fKRe3N~i(iIy4urv@_&=DOBBxA{J&gQYI}VkP0JrAulZA z@VmImibWX3^}op;s;1KGqYSJ`9;}OnIW`~G0`}Cfze4XM8y2pg8IkH|K&`Uk&47*o z_v0R6$VcjH$IM?;Z={C6T_> zbB}jAf=oZfPUwp*x&dWDinJE+RY0r_zv1c(3UMg0ozsJ-LL9%-$Fa#RhPbh4ClPK$ z9|w|?6iH%v&~^K{?uN|X8E-O=HX*EKHDxsn3pZ9M)$Rs-cNM?*T)Tt>i7brfzKUnF zDZi#R$T=^FTC zY7>mEDR6c6`hkbwIP}LWKYnffGJ4fdWyL1}yp}v}ztii`;TX}nu78FqKf1q|Vkchh z$QK!xC=;w+H7XCVSzUmFOmM; z#V#&v)N@hr7n)`22VU$)M?UA$(@Ut?rRYs!(2_&rja;Q49YHxFP0I5!S7QO597O6P zJP3IK6{uI_+K-v+KrDy~8%UeZV-qmSED69_MzWPE}-L(sOBPkn+nQmB4w?k zBs2LZI~?2_pRGc}C`(v>M;-W|+kkft5I1V>N3H#ed(8H!uRtAN!UO0$p7G%uY8!+& zvv;G=z@%_q_{+8UaudH+zp~;>j4Qi?2-riXnRBBC;5T5n=NYeiF2e=xxr|kY&sTj# z{i1Yj&p>GQN>uQLsCvk^&;dadD{3pnOhOD}xXJy4#G&SaN-J>2o!n{Fx)L1!0p3PdlqZb9KqFa?yzsyShArh~h zO@=0NsqQNQFEStM3PlEz7onO07X}HEzFdWxb11-)8_UY)NLBrccQt91eH)%m(t>(HwU(5w3n*1bv; z*rmO_3RG{eD*a+AqEM(yG1tXnF=LmyH0kJtF-K-CL1!>638WzVxAO=PV1ZF;9 z1hCOq!^+#Z@U9i>A4M+Me0sB$g-4xX_Y}$B=O@Ok$F>6I8aK>Dw27cpj`#*Ah>mW+ z>tyOjMMp2htHAJruzBO2o(Dse96*ykJVfCZpVYxx^|yoZu^Y;$sSE~x|6^eJ4tVV; ztpRXOi29vN4=$%KaMDT$%NLG>O0$uw_D-|av7}qX9}v_KRRHud0yQgYJea0f`WW4V z3_UMP>#ydrh#$c$O>j67teV<{W|@tl;it^p#U&iJxT^HeMCw7aK zy>eD2J{rfs9Ag~{lCkjSB6L?}G>muQZN^)7;uSg8L8yQNB$E?v!mAzDPsO9z`WaT| zg>CRCvFUe!krCi&2S87;KsGx1-9(sHV}ayJcpD$u#6$_*o)ZJ7G&{;_gbfT{RaW3r z+icf%heZ^Dj*&74C67-farVT^sDKU6ID-*qW1T{y@;!<+9<11(JhhUW8EY_2GN zAWuD6{)E+XKB%RmV8Fd9#jB#Vu4?Wm$U>FhOuvn!f0U^TnWm0{kM7a1HXX7<{T3sH zRUDy&DIsp}vIxAzdk#bXZfPGdgBNB!_%sy_KNc76DeEV23H}jI6IR0^BugG{L1FC* z;@^67Aj+`shv{}6=G62>6Je#Hqu{W+?GsOAO3*e2l_(7^5@=>HJ?cgj;}Ly9tcScn zOe3#qcA#puo0^Ji58VN5OlyZ!5(MZHhG>iZqGoD7bl>DHhrkkMU5X>1#(pe@#(o zoh?u)dMQo)I|>d0h+!Gly$6$1iRsMiC|H}m_tDQ7HX8=hg}-c1vu`At`866spt7T& z76fz)saCrs3QK1(n-R?gBuVjemEd%_#I}o+5J@P6)4XbAT{M_*oZ>x@<2NixAKew$(>Clc&zJ6{)Z?&K27ig~> z#R+$>pXb%sn%hc0-`Gb}{FSrZ4n^_vCAV%X#cOSf3p^CX&oAF*iV>UQcn?MK^B$U_ z(z=hIcLRuF8P+ogIp$A(p1${$pP#h_KL-Kbg4cewOhNm(!-d!{%}8RE^J#((!`~GF z?=?@3&ILiA&IZ&-q%0jM4=+4g+BD-4tsDiSKv`*6OR%ejpqFAb)3SbZ;KY77HFXhs^eBHFw-`NHr*k$2xG$IWMO=?W7w7Y(Hjgjy99%|4;}r9;t&kt;7p@HT8(kCX zH?A(!Z^FV*zbOr&ep8!5{mNTH{VLi_i!COW@F^i;aAXvVp`t%NN}5ebl2;{g2 zHi^qJT(md`fXHkOv65ddy&OuV@#p=AkkYJXGY+1oLDsJ5K{LzqP%Lw#9Q<Vgy(*Nhk^5x4M(3)tdpUT0JwhRXZi5 zXSDD&IWW&_!DeK&kzu7BR9S-@^%Uz+!CCU_ie0&H+2PYlJC4?Lf z$!)smGcIY|M{eW(WTJ6PLi2yGwf5f6-p}RJOq~Dgdw%Df*U@~Qz1LoQt+m%>ul4Nb zd5S=-f%2nUrtp;>EO7QHfk(rN_Kz8Jn;L^#sKLj{K1WqMVjj@>1p6DI`FR`4r#Vyj z`#yU4Ej=P$*}+nEfj0O7ViEbW-Z_lY-UCQ1$rL`&Fq|$kjB{%Tr!O^3H{If<4vS@Y z_PODDNQicKZ=m8GLFIt#&TDVmnABQeU;K_gNQIBsoQ0d!0YYdH8Kovhl&21D_z(LA z2}M_GPn-azKx#w=|3{~>OV60h(9v;ZtR&hn&)%=$lxoaw7GHX-20CV zUV|dzM)N$u(J(50C1DZsQGuF=5MDv%zetEf8X2iWw`i1Pc`j=?*|D))?0Tj?Z!sXyLNfbV`xs?>{s8R29~V%4q)_s9R}*A zfB=c_>(TV(OOn>T{$k_T#YEZhTuqykTpl5ERN00`HPnwBfv*ha@>AgCdIsTLwH=$Z zn*l`sFhs+g(NI-2-Y93ZL*(GpxX)QBGkE|P&Dvg{r z|AnE{UMKSoZ|vx&?9n^LjGh`Z_4D@NrjbUOs*4-^q&>JQQqn)*re7q}h&FZU($7b! z?`aH?N_s%rbZ>=BHX>f}&CVLWlYl*d*E({114)00OVz<}7eCk$+8dD)=R$lW;ZC4U z1qTa045$e`F_cbpnT$V};SQ!Du{U2*-ZQfwQk%=S;UVYBkSSt-Td)@g1*#y0y6wq4>bX$SGA5G}_aSfo`09v@S zzFtNjl5=iciHP`a1JzLE`$uZmv!B7hvV`E$`nWsE7S|{l;EUycs;T6?R_cQ3CirO4 zbk#i{Gpnin*Cb1SG>p5f#|)iC@4?C6}T%=KGCycmcY%zKoH zntNU~DAF)W$(wk^S0b5pUI)CMZjeac`8w&Yf80sm38KS6t7&xybN)JXHLiiWXW4Wb znf0#Y{Fq6qR(f?2Ayr?|NO8AdD5MlneNKZ>wjh);`_W=K)u2Fs?mk4paw-sK3Dfmuitsw$8u_(BO5;~g#t~o3IiE7HKb5JnQrQi%j!8Ib98XhjTHQJ(J3U`YP z+65_SLMVlTqZ&ZLD^#iWWw7REkpWB6{hY}+GAqlVxkbT^lwR60xROu`1gafI&3W|%-luP1{ zIa)rVmdyA9?`KYce88~DRl%b+2NRA3TqS}7!Sg8!(PAl8&eT{^xJK!%RZ>37 zSKFHJVAm#aS35b=P#EH-rEmjNN01;^>@3jo945n}QY~ea>`E}K6(5kHj|J(mIi)v; zoEeF&;qw)5U_SdPM9FmxjhM!~9bT=GNPsB-A#ev3MS|bJvfz}&loJGm)(v|$tY^WN z+64zZ7{y{z5QJm-LvvYg8kcjO1XWTbZ&|1@-c0Q4mt9y?l+1%@d=qC2b&E>gP9rbk zNlc^Ah2C~hEGxG^N~XrU>B$!QQXz(DQK&xH9F0_YRwL+n)d0SQq+en(x0CgV+hpzV zIZY>KPa!Qf??7L`DdJg#l0d6eoz1dkv3we}~8UExt~fa1m6zg=wZAo*GYQ6GqfU>(M9x|6H#<6+1` z3<=5z!Z53JI^T0hTz4f)O=6cw;uCNV^PWaKi&%MH$h|Dj+G4$?26;IrSKt+g%rt?*+u*ZT(;N>vdkkjy8(y;-h`cC*4r2ImL6X}Bx&KP zNGCSd5?1fb0ypa06U4@A?k3QwC`*`v_K=o*ov*b7cBI~L9MHO_aO+Z8!ZcFX7)!YC z>Rc-~m3y@%Ty{lh{WlBnI2eS*Tf)wuDasQ5PPbWu*51mPT~=e~ScTill^9U%Tg1^cb2>5gaw8D{@=optkd2-j zCKeD6YIM&jP((|CZ6CoiIO{d(XD=#zdv5Rfgj zPRgTfI*XOcJmfO24x1LRpzan1(zvxaWMiHZo3x#p6luNOUZgCU&h#$z-i9wxxP9H# zMSW$`$B|nic}4q;Pm8$w5BiO@Er3P)jTeYw-*5Po5f$me?>QFu>#nRSCBh|5PSR>k zvDUV9lW42j1T%#+w+sXQ6Hvgk2}Ucc>gbaeX;sHY)Ao&)p`vYN9t(|i@Bz>rWmV^( z2oj=g9tJwJokLuU#ZRTGNe-*(N^B_YYYW(Dt2z_u1FDf=IL@7L^sh?tIM^hIPX3^A-sCI5?YLK?PXxbjv(p6S; zm9{EK{#2sP5BnxIb&8_x&>(G{eA@a2XbVd8ZUR+SREhPBwxYI3G;QgE!hA^5wxX{< z1g>MPXgisReZ)R4cgBhiqY?*X_oe${w$rO2a{4K8-Pqx&p34PgkiE2txQw`B5 zMZ@O{R4RD|Tf;&;qMRByJH-zU&IYOqjGKeMmH6vDpQnJ2iUzJyz}29%B0Uge#^EdT z)dN$X3?SkCj7a$+O!eZY&eU_%TfU^&mx-!Or%T3{*REN*~dZq~CsUx*lXFoZ+ zIt9v%HcSB+UD1R%hyRvPHO!Y$YK>mMa{&|GGYwc(k1gLnNAizi+JNLop($v8zwv4` zQ1Z*8fg2$C!8G*-C6AD6_PxJCbKn4IDMDi3;#V#9qq#urTBNe557x!W{YT%{HbU;O z{IJg0lpm0T^1dKSir#;P^%=D&A)8K(dn-NkE$~bCj^S=t^QuVXyxqrkggIk3TLYhL zMi;XRlb7~u?;b=%<8lI>r;rN}h4EpjN<7Xz507)t2GXk3IGDuH3iiVj=DF^5Kx(b{ z)>FY#3Lm=2lwu7070feTx(c6rNG6kh;0&?G95t@1CHE1tYGbyY}!AP~qL zVa@=DzA!gdPThWS|6OEg0OnkU~1@mxH>E-0xXuS70^R;{V*LLF!&o6_RNWa4=y6&aF&j;TDn{ApU``O zY9D-wcb&+L2)~3GGoy-x;KMfnsq;mL?QMum49Zv!$mr?S>mA7 zqe`j0?plLst<61TQp(u%od7iU`aVbbtA85ew+n~}Jn=#)x4XU{vnI&9Y*zos(g>~Z zd61H`zVl=duWyCP#?|^BMso|tw~{{PSl>Dbjx{=6IN^*&tnao^I2vcIZ{uaw0m@~| zEJf+JFSE)q#0Ji}iYRL=n|O%DC^CEIhiIAo3|nzzc7+ULnO$$H1WIOG_!W#(NVc}j z6lbZSt3*_^Q7xdK>7lFesrK+8E0`vM*gHGD2i840;lxW!C>jJKfxXF=5O5?^LqY(6 zv)&A71gZD|ba5Ft^CpoR(BnHE*Rj?56VHGcCcN{|;TY;&Kn=nq?}&*<(RQh)Dcaq< z6NuXV#L|Wt7hZ9?Q5Xz0`LObexE)SW}Tg>kjlKQZ$HzRU{vab9y z>#brnrZvra9+>bF)Zxq8mudLS+%&OA=sMqmAi))=J4vfo8_8cc(v^I=aJ;ni!YjxM zoMUtuze;o+(Pc?4KnHDp&~Ke}!P_|KP$m%p#2oT2`<95{Gj&)PZYr;%ro@+jA)3sI z5+0W>tm0OF__AO@FRcxHGx1;Cr60bm-9c@eWwNZ-o@NrkzD_*&6&ybwnuA&9keE9F z_=OUn_s(K|DGpMAL?_eu9m$TGa25;CnR(_i>%GikO4C%P7sCw!GTPwt zNN6NLYnxL8a1^1hELB6Z?}eYH)|m|L0PupXdb|sh-w1|hmk3D%4*^sw=1yUgB!^Uq-BOQB1OU%^S9}Lu=ft&)7gDw>NlYtm>e@!|HAyDs(9}>7dNCJ0lEfXr zus@SX-zt%@to-436F=C&i5&3X(*7j02a)Wm=~H3k2Lt_1it5W18incQkt=3 z?|Oq_x>Gln{ttyz@|nW|mRnwtB#56N0?ZfbGncW+ao+}g=HnUj~{fuBtUww?WJ5sqtXeZD>}}-+hI^BJ*^U+DFN5Bsybowf41@jndlhK*t8O zb_g%j#%k>&5Q=E+fnWPtdkUs)sMa3CB>Gyriy7N6t?gwfSOD3u-84XJi!`;a)}F5P zDn@JPz-#>ht^H0D2(754h0G(Z+>xqNuGaQSRYGr_V$V=2pd)0VbbhX+-iF@&n_|7}idV3JW-5mObyF4kli)cI(*lT#$8z_QbqUQDz4 zaFMk1qD?RjORD?xKS|EQL{Xk@-JvswUpk;<5G9dx;r5|K*csuN;_QHphFTO zpmbq3Zgn^4I2=J6;VrpKZ_rtwpl3EFP>j*hY%ORAJ?owMsp-QV4F3aui;(E+Q+0St z)OKJ)B+w4O0(6S*?4;Nrtdrf*ZzuKWSMV!xbZ6KTjr{E^qk+&q-UCOaiNr%4?Kyid znn3&II^Lh_jM6@Nqiz9D^zo`{rhaA;FA2pHfB1et??q#W;yFv$rF!P^N8yN)sXT1p z>yqV*;4C;hc|p7gYRgnM;HLYiiA&8{Zz)FBwjzEiQFWQ7wUjs_dvxv+ksA5Y5n_OI zD*{U%4PQ?BiFFCO;hi+V?V@+`f)KOmT_8Crqd1ZvfNE2qmRld(yq{|R0fNza9H5F- z^9S6F$6!jmveYNZ)Cxi|g3#J;5g`v@bA)o6Zxu@Nt>F>G8~E9);%){evAKO8X-E{e z^npt6X_6e@ellz>v+4~;39f!xFsIVuf##+ze`TuqH}X@dg#r!c__jhh)t|PaHg}$L zXdXYCHC#FsB36P)HN>o|;bDtEAr49`=}=iyc77$i9_r0x4}Bo=$(L#s&-f1*Fes+7 zUQ<0YR)roD{gK+!B_+tJKE;=ze+;}`xD`A`>Dttw63f8+0l%0|;RZO>G*PibV$|CZ zZiM5(KvcFi-9o8AF5CH3L>E}> zD@h5Jg5F9HpyM@=ZQ0IMs`)AAN=jgWB40|-_})EYdclI7-KsRV-lO& zyO3x^aT{klH%SeaeZd)m%h=9Cp9mu_Lj0C*n68>DxH(`uhXG%d?R2AgEZZSHvh9Z7 zgBjS3=zhrZYLY2w1b$z^@>RBQ*L&!|>e5^G5DDmQno2)m26lZkez!9o{6wqkeTvhu zK14wOj1RE1wS6pfgtjgQGxqv@K`B5kZTGTiSY~YHr2i zGuk>{HGj{%2DJ4eLL1Unsz~Vyd4#9miQSqm-4@w#?QKkAb4xi<6t{8O`k7R5SX*xt zTt-`;`AFE_ni($GPu7UF^+A@e($??Z5q{&fmF2k( zuTM)2t>YI!(2EFwh?0%xz>4fo~Rb^#;Gyc^R(Oj$w_Ys9R0mNWb{{=Rzc74UVLJAOj8NsDv69ws3721nZM@C70E7(l5`Rd zJL2*QUX%R0DyW*04`-yu9S_A9hsS9C>7qHBm2IfRVqS<-Nwe{}I2H=MgK;`g;zqwB zqcaTvIZJ7~<&)D+H8135awwQhZyl3ZrrIkt2Ci(-w@?(ucX&d)1Kh>PYlK0>c?TwCk)%kKD#fDSBEa$`-TBy>*KG_tO{v@zbcP#9_O#hBWmcTF2>tbb3*hc!qTp#<+WC2 zC?k$om9q)3fvXY>>Z&}j9jM^6*^SAmaX*$%_%UxBo%5!=jm>ggH+4n##+uP@WNh?@ zsvmT!INc;Y5SiZ4wUoo+9v@H?SSWCA(m_G@F*k%l?=_T%FrS{nq*>Gson2rtdkfl4 zr1(HIJNyzd0(|V0Kk+a&;jJM(QRm9WLVhma%uRVklI-&oER^civ!_djIUx=+sM*Yu zLIY`Yfh=HL4dK}HZG*$wEkRg3L-J3U;f=R)&9KOyf1`Q0!k>X~$g4&o_TF^94^@7= zIEc2>9q`Ka!2|Ki_5H9$c(2Ye_>ET>Wl)gx`pX*d`h0D$(+;K=marN^MU0hi*C1}Q zAP2vWWmCU5slspgadr7A*CjA2>wN)B31#qMx}Glc>3SBwL0A1c&^4C~jr19)Zf_V} zPZKSQkkQK>x(@g08rU$pcC_f~D0E#wbZu$T_0gNwdb=9WI*8DnCLJU$xRO*4s*IAm z0~D(RfRZ8@2EufB&@71C)%_T~*Tekzc6^P7hE@R^^-KG>TX#tL&Ij==+=xOqRXGgN z1#H)f*e{p)YcwYsDqXmBc&3V&nNEww0otZoGaY20tjb}cri2(WNrQeaTRrc-h(XA$L}3e`QG;pU$$i!sH^UH$I143jLpAyu*?56GIipQ?*P2ay_)|!dx!Yn0-6$L zf{{S{J;6jI|7eflUk_c!dA9IRq6qMR)?P9EC&|euJuAaNi~l|J7@PmT{tQ(SZQoKKd!K+@9EPd| z4xCOGf+c$}DtlxPxp!q%uVm_{m{nD2;bT|Z(6s5qk9$JiDWoNd1sJPHdI8XC(pzOx zn(|TlncjLp^ULrZqE-8tyJW@genRaj(i7<^AzE-ba;~n^qD#(SbNbOXw>377XDW z>EN`iQ$%o>;c?h7Erxt*lT!+9p)CA`T0HN$C80YH%soSIK=MZ8S1s~9iYqoYQWAlGAPsegoSCjvlMwV`(^B4tHNdm%SIuURAJR zj-wa|PtYSEt^8Vw4fB(kVPiCwJpmx85M$X5m-Iwg7gemNz{*u9hA-uyhB=YE@+VLG zBh#qVh`x}Vq%!&Qin2_{0yJYImi3Mly#Z@O#^6(+mHdr~6?iE>b+(c)$$*_KKpR0D zt38=%ZxH{)t3yvB0CDPds7obnK)Rp^_ih6T%&C5#wFJNY-FbiF zQ)1C!w0^{p*c0*68N5)%5_47)qJv-`AiJHu9!@mCHSMSywibXQeZ7wY2;P;ZWvpgX zWFG^Yk3)T2|YoUmIku!K&UIwY8 zO9-4@zyZ4TwWVlP5YycOTmjGnHuV-^ij`BWIZs#MOdR&e=!f8e%c$iASmW9OLVeb| zoB&E|c{VW(rmHhikQrACWmm6~%z9mEp~}}b746u>I}}4}@wE;T1KvPQS9$d7PI3fN z-<7DOoHXWG3rW_YAg(fD<8g6_p?t#U1>^Pr44giOS9GU86athB4BRlfi`I^TecyZ$ z2&BM~S|N$Z8Kh0V52j#Y-A|@dx}W~4?kDqe00}N;wBl%ile@mA6=5jIlBlp3i6Joa zFRZs*lwG?R8nRf2gy9f2#|ZC461xrwzFg9YZo9WKl}$U(ha?vOtrIOF4L?FphVQW> z^piw{e{N(CT-(qHeGJcU&P+8hLLaygbEo1WbQ1@s(HFfI zUl|^KEqIjLBtqZ0C=j7v0do?em*JOL4z4Z^mHlBatTkeac-3~4-8MWz@5xj95&8|v ziTnutHeH4y^ur8$} zqU{{K$}K=ULZ4%`+Y$O`yM2QZI?I&=+5`C!dTR@V8=-&Zm6zymhtJ1Yova9bO$Dt% zbcCKueSru)%R(F-p?^~)B&8$2@MR!EuOm^r5&A`j%X-bh6C!jTvDSbHeS?{;lALRr zE~6v#&6v}B4CIF+bPBD32)(but0MG8fbb*qCAjh<^a0OfP8FfE&*HZqq3B|_gz z>z6x1FNHnY5qdrqz3d2mmjD#O{x}TXqyQQbq2~cbI6_ZFYea!?<-F%dd%T-?cqR-{gWsMrZ4+VOZ3CeP$Ve^NaD zjIah~eu&y62F!%Q`tkT>kSX!_RT6SkJifnUY&<>}Xr0*T#N*k}2|FI&O{U_<<42#- zbZ#&nuOJms@wh$o&zZBq@wkNNZ)`lC`!tCzE*`HECR7$4ipOsn9{qTH2ervs+_xYQ zj}HKI5|8`fmsyV3csvQ2LnGqxwmh{TkNeSZKOUFTWhfqR&p=u41ZZz$JpK*4eJdXS zg3Gvgd>9!i_Oa3N_;HMkh{x?&p;clV%$VO5ZRdFWgD4mWZaW^oZ?)U;c(L8S!FaqM z=iP2RzShFv#^W=r9y=cYjn&DD$J6H18brtA_5>V=$89ad(ee0PWFFS4p2e4ecziZ3 zsvD1cG8~>(!vu)O<7u7-#N+i`QKAHn@xheZnv8h>0fgi66TB#HJYGbLW5wewG1QO8o6{A?e!`B&`$M!6j}IgvN5$h!wvUa+!+=)BMpa`7 z=IlCMR;T3-m`AkHZBEMNxp;NZKdCA4_Z?forp)a)VW2S0t?n}_>JHTy?%Kc^zHP82 zaL(|3@E97bFZlMNJ^e$Ef&|$_kECUDOBTVq>l@w;-FtDKR5l{}R6YuASap~?~ z@=e+qNnE8e{qb*q^|{)#`dn?+>q5y04F9U~=Ln$bxQol5E5VPvapxs{sCZ8QL%GJrkg`G_G`1pG<<*$7t@36(ET?toBal6WNv<9tOqS!c__60H^^f=637R(%iafCgYTlDFsF6tx0j5Ok* zlJT@yGNt>TXO+(qr~rkH~tkuqG{` zf~j?OPrq?Vo1woOz87;%Ev-jPu4%&03DuC~-^beFodn|o`Y^V|($ac-RjO2fn#->! z!WO8~zm|4c!H1}+4e`Y<%hU~Ds0>Ks|4fN_8e}}!rqW=-${~>vh9@L5wPvQ65kE8?con=+kQjV zqp`NV9CL+jyB?Bkh;28}7B^+X;6tNoM650D!Jv`0cr|z>WxsB218niV2mh!oE~F%5 zgSL1-K{@J?;uftQ5w>_)Xvnb&T?|&?C&Ho74x~IZDg4u zz8hwXXFi~9@laWh#@gb3SctGKQqKD)+TwUNj0V}_4Bv)u3)hK@7lK!^#aVM=Z4tfI ztTc2Nk@vp0+;40W__}kPbx)Mwb(ht2@Poo{e>^^to`9nz9M`K$Qw!C8W);m1027ak zZA?fRD0*YgrSAC>bkKc4l;oJ0L*YfHIcS7I9o9j9>ORdJ700882Whofh_Ti!0Z*H_~@5FlM z7RqJdFh=sx=TbXG4!|iOhxK+0Ob@(zA|_1%jN&x}#Bir8z@3kF&5{vCbVD~Mj!At}$ZXuL}VO3kwG=Z^)k_1%0o z%bL21c!d83y9s_*vFa*PHv6RRQh7v*&_XJMI?Jp)J6(5I*Sf!#x-L?hn@bj&CzdtN zDKZm@58H6f!DjCXm>jARi@B#H$&ROd5u6dfV(i(!b8n)+)GFY4Ku_X_d~VSs0%M{^ znt+1b6A3G^Oqxb&!qK!qn#QZ9V&R2c(|EXx`EV%nkl)Oq_qXG8-ktqZ181T@TY)T( z3bmE$ZDJxX_bH<2TlqlP5+^d%iOBKQIqtD&-oSgFVHg} zUh1v{zBDW+aOhom$l$VGGnjuZode>l(}2!=x;&p2!7b555W?E4DP{Fs7_dmK-$w5O zzDcpNhFD1_Cbi}jwsqx17Hr}S?kRyZ5Twc%? z)mx-`@0Q*@Hs?7pmQ;u|Xgg`?E-hpli9Bht_3Wp1JZ_|dQU*dRa3++h5=vD8rGjz| zoCl?v3#FO^Wr|j!Y^kS|sfyO+YAh(wR;DM+Ne`S0vgbjWDtu+?3TqZ++DgihIH|bg zOsz}-GyE%=K9GI|LB@n1wFslxNl>gePdVIf2F0t^o_~u_t%r$3qgsWyGOD#;76{r1 z)fxpPzUBU5A#cyz#tZpjur5M=jLK$4-|Ze~!tkYBnZ zLdXYVR$s_7f!PRo02U=EWZ0ruA5GKC-jt;VE`g3#=)KrSM5Ef5J&TF0ec5fO_^2xG z?IWB8pw0iR<&pfLaqwIw9Jc0lPB;U7M}@3qA*HQ65g zGwZFU`R&22G1zNPy_QO;iX6NkmDF(PE{|W96~Fy$ ze$u}wa0F=CIKe$W)21Y>aG%kfHt%nsK?FA&^LzK>9}(Q&d~%-UpIPrp`fCrKfx+I* z)Vh&^n+elYJ_2#y+GA!CkK(&EBNoe(7E@P#hMGL zOre#bjimo_`~Gan_y8;b2c)X3I{ z^S{G36FvW1_(r%j{}F-t7mUa3D<^0fBr}Q4-q{T0aoo!tcQ~F${Qd3Cnt1C`+0wO= zo@lIi1C1w>XV3KcfB-(D(pRR?>#@Ebk68X4-H7I0f6Zfy`kXrxX|$@Uxnp@`bZ?UG zl3dm2I`6`@^8)B41R%GyQiRS|iV&`A1GtV3;u`Pc>Jx`c-(;Yd+)M7eZvgFY&@YF? z9euQ4B6n9L8qE@e3FG~ULWsrsJwd!L5rD9M!v^qzR_s6+o(|o>f$(l|QecX{!6`=h zQ|#tXp>@)xoM)I4nxR8rhL0)MY)c-9slay*{TW`Oa-P3_Fgho$T@70@vEA=ciZK(2 z<9kb@$I83lL5g`+n|=>SEiB6<7T~)uctZI3Hxf-2Y)2s=)AK=Y>az%6(cnYe-lgZ% z<7Sb>GMn05cux_$qb$5b1n=1f?~W08LpynpT8E4g+hfkX@<4NM!QFyz7Yog6_ybOT z+8W$1p3R?_s!OV;(;1Ea$Rq~<%}GOM%rg2mH^1)BI9X=A6QAA?DIMK_8N2IkiU@y- zpzT3ucM(SR5VWNR?Qdr>BXGia zTrD~dNWBgs?-jhg2=8u!cP}AwfWh0u;N|rf84$5vFCrE%LTAbg4CRMIO=!~#4)BCy z`PTr$gN`rDa}V^&oAL>3^YX9B(0n37VRAPi=Aq>vW=|pJ9{Pw(rq8qZ^oFeOMQ7@T z$Vp7GAqLM8Q)%=9&_aI);BTvB`AX2#D%tcq_D##{t5#mEh!IL2=4spPNR;d)lx!=M z>}@Dnc}9aML8Mj-+5j?q`wr;nC(uMVh-t5ZAf=-zZtC-Qd|^XGGt3awU>&_d(Do*@ zN=Nq=w1*qCO>MNi(lI(ZP>`)!24qS{zkm`^_{Ik^gvKXEX`z9}Xk;NBZ7O)D6JDjG z8Nqw6!F!^?n^P_RxQ<@SGq>4FCAu zg_=yC8}N+`p`^57lx&QST2DSBt%47rL#cs9MT_!cSk!9Y>x^JJ+dPY-eG7Vvc|F4) z;py`xzN;amUw0Y{5hz%Q7_I*5Ydu+{7phLC*$d%sj2FT#Z-NIel#(Y%0jTjSCN>T) z?KOZaAP6CYpZiL+hwG*Ia2|8q=BbwJCCp__zQB!6OMS(ZAjBZ8zBXi^v$^%5B9 zCk&iUUyI4~nShUj8Bm*0w9$QK44PSr6Hu^HjZDv>cws9AK1gFna_%w!aasJ8w zkK4vz=D5urS>HBphZ15b|4HAb#p2@YG&sg43i78IZq_@W^4DnF_=qQOvl-E&Y-3ZQ zXD36?dw+?e=l_6h>@Ex(zSOsk0rWlNOrMkSwGa_#(MB@RINLy`Rm}Tum4u4(d73`^ zl4*0#i=Zzlw)+4#^;w9I=n8$~PhtVrC{K;Nk{8}Hd-4(D%F$qT&?Y0&l>>}J1pdZ^ z2)$8#f(YV`>YsvF=b(9G3`z_gwo`^5i9sJ ze|4q}9go#3_!T$xsjp9{6@2o<|5sM9A6Lr%-&nz+Sb2JJ0as}zTn{Hmx-K`VYmky6 z#B$dl)g@X$6|c@PWb7lxRbl(^4Sno7)24bM)_?qSv!(5_()gB;YlSs*L>g_W;4;=k2Xp@;j=n3Duf@r<$+-`qdz1e-X-h5M})0 zf=thWLfI+5Y0BD%DcfgleLeW!^WpEL*EquLTMe{>lx* z%FV&b&Bj{eFTS+BNfUZ-raOc_&%9V+7OgmaAdP`|y*5iz6Mg+H>rD}bn1h3vd0rh| z;2CWDWpiRvFgsMX#7S{k5G=Bp{+#E{xva`%0o+X&&}WVShRL~nGu<1!kN znD#kUqTw?VJJixIem~OzfUfN!n$1G(&Md>KvR)^JNlknqQ_4M?QIGR&-2yBqmU>(r zNUNj4YnBH!KtAWL>!~3PK&^u`U^l(GcQDV+;$VS5M|HDVHU8CSANl!dG)cp8cC)@AS*FPv)X-~)jY*tv*TtE(RApof+)U+P)I?&5B2z~>G&_q!YjTP-si!; zN!*hOYlFlsPn{47UwTWJCP=R*5VG{vF}Lu`qU~=lW9iXrXSjO{aJKS#S|3}0=MWkr zz$Zlc_nl5$*~ zRgrOCI*pHO@C&p|2TbnH=4dMj~|f7Xq24H4v6ng;VpQ$kqoC!nHAhX)|<}P?xA^= z%OGmzUbO=^o*Ie9Ou^j~%{gkLVbGvRyf9C{qZ##v2L`3PHYnAEZGD__ETG4wl} zFk8@BhIW;q2Y;uB{&FOSDlhiH)dcT2xwYU>ci&3g+Duo{#RiuXgmlqn`U6p*y_RpL zdruOqwL>Ikyqv+c6KnRqfFKgPzOQ4(zc_mEM(Yg)tvL9Bkct0!o_YfQXXDpqJjso! z-Ok#a!P0DV%@YuC4-xQ7KL9Y(=aV`u;F$ycwdwa8uMKU+YG|!`5xK6wuf2+zq`Q+6 z4M&ynbkPuj_s{~rnq0XE9L^qZdp;i+QYyRUu<$HRh85MaKa%#+j_jWtO%REP-qW)0 zU1Q?)u?kvIdkLwE$i5%-Sh9C4S((JCm>BMhYcJx)$TT8rI_Tz_4*tSkP%H`Dd@RR( z$J;3Mp?*R*o78SbKh!H&{kv}k0k1js|92W_H_s%RCpxJmlQBRdif8f+^=w|{=WqiRso}rmA>bMO^i7(d9fk%}V$Mp^fJMKs{_T{MCuhYO z!JlG@WeEAAmE8~m^@uzkkw5t%nnhuGWIauV{jU06_nD+cDLTd^d*Cv;o~N=u-F%od z*VG2b*UytECG~*-|3T|^XPvTo}W$9wwu@ElHXa~96zV&a_!jSNFLX{y6 zrN5Jw%!aJ^iE2K2CP%-H1y_cQzkU?ISMsL2 z@Y}YKRHo-`=uV~+C2x}h%6eaOXJQgs_4Cr1#1`L@9jPhX*cYw9wuTd%`{f(AMQ7O% zCz)tU{`gJ_3rp?v+HX2FgIJzwrZMI^?*fZAjx7oYZ&di(6aMEw4?9yWQh7~N_Q3 zH~QeJyzo~Ch@?HoW5E=8zhR$fy-&N)j3J5VkZ%czC`vYrI9`0v!)886G73vk<5ub4 zOo_GD^nx;a1gJYR;MZg4k1|V7FHEOwj=+i;Op@P)7ds$kDcku&9j!SXo87S1Tt)jS z`V_Qidq8VW=H8Md#24r}%<7?v50B@U;qSpc6X^j7SJ`%e-FBueM5YAnI*)(6bh=SL zVs~3WuCHdoY>tZ(bPR6v1Z;{z>G9)~rVGE&b7s;D=)qYDK8US#9My zf-7$@obw(Dy1Tezt~FzFdWJn@pBA=i*Ed9(o9i1Q-G}QNBHf4U8zS8Y`3B#^U`fN| zcDF$Gn92S=4Acui4fZkrb&|2X6%?Mr`Ls$MIDLn8$4SOl*nuCbPin~4^YXb4h(r6*7@E}_qo;llrB9!|JO3?@h<&j~OZ3LyQ6fKajS`!n>ua+~Fq8ARz zHZDqhR3Wi|fu{vjqk#0*XUC|<$P-MvqZ&_K>Uinrmc)4JgP_7<9$9aqJ7!Ycn3~~~ zU>5E*c~do%jo}nZ)H8|QxYc2@J!k~{C*=-&)maR`Sr~qW;Gg8ew-ERrxYfZwQ{daV z@FziHnDzaMdREsAGKq!M6VU%m;-Sda8Ii45MYf)$T5SW!B<`3bv$?HPB3nmGt2tGK zV5X{G$QGMH&i;9YB6N9JK=W+Y!sEfVx=*zSMCLr_)1G7~1;$V4He&p9K3_sHSufIs zsnislWDe5$+|mFY%#&c4H79&pFO)O-f=zp&># zm^qEB0_@1Wu~mR~j*GU$t~`~g0-R70V~P8tV4*E>4U#o$kJZ79$+=%D_e!F+AMS1` zatYksQsh1diq@D_`ZrTzt+mcMy0h^7&A>m8HA`=A28u<-?6Q{m**<|7r@EOx)N!hR zL9!dxnn|yaeZ*A(PUYUHD!>4%$My>NP6+qJQ~|oaMAL<;0E>qj_0!2i6NYr^9`F0v zzQgf0{%D8e^N^KUiulO0(N%!Oz#Q@yjFqmx!?iyRrS$l_>BgDi_Yz%3LQi@bD*A;QtmWk`m@7I_u&OIW0E z659Tr%)L=nfWu;Y_ONFd|3+DR(-+y0L8Y^s@dk$s`CaV9 zz>h8Rc_SSt!uJ?Ml|bqaz6Znjt`&T?;1~JXzT+60_@f=cAA{`PatzC!(pDbW8;tsk z?-`2SF*lhpIiuQtU9Q{Uz0iN1WGru`6Zgt+u07*O<10v&b=eX-5>o|uhte+D77~a? z7EuKl9*s=77T!g4^0RXr+3YZ79b9BFRe=56T7mI_;|3a{9aDUX69S2`#`+TPFD9Rn zqYAKq0b;5Ef6LW5F<0lQZl~)k50%d7DnOT9ovoct%ac-meIxeA(N%y{nd2tu-pDBo z>{J1=NFW0!4-}LURe)p|Wxk-am7>7U%SkDS%9S{s11d!?92dQbi;}7U&oXeZ3eesy z7Z}wTeuQDbQH@8C?^#}Y^%F5(`f#YQm`B#T%pLQ1+?W-IV@#&-p)+)T&Bky(=lY3z zxz%BEE6@n|6I}QYC|%7Yri9_&68yi8a_|=j{CQ#cn*~1Y!k?mwV*?8yu;>WJ@&$Jbik4HNJ!@C(Pc0!qO?HDesTnnGW*rd&m0v+HLTe82(o3 z$KE68FH3oJbNf=<9OpWNe4f-fMXK%;tedr7z3n}6#sWA}@07rdZJ))Va%;u|{TVk2 z&*L8TLm!tFSX1)X7(7sMs(7X7AqhZ6PvGfAVKqXSFsGgw1Z8?ZtD zDK++=!QvIkagHOhJoE3YkaZ}H-c?+LOe`ef#2(LZCITu+*sd>4C-S*BwnFwq|L7={ z$5WXK+3^p@M5(SQQpm(v?=7U9R%F}WjLDfxlzS!rtB_Sdomjo69b%T=-Y6G~j2YxP zH)S^)j+On)P-nx@2WezjYewVCEAbVw!Q2~FA=}UDv14O8u|4<1RLF{+r0GHxvcD6} z{w);R3x4}ACd}se6{dcZ=L17huT$DrEn` z6|#Lxj4{}D)ZMb9EskN?26wA&yD#OUX7{!m9hAHvo?Y?0?-S07&? zJBoXwDr7xld$zNBTw86*J-P@MsE~dBI1!>dEyJUV*6PRDkjDfnT1yXt2z(PILw=DV zoeJ4(N|${o!grV88yUbiHH>eZ;Ijq)PfFf>d`9pe^)c;^;P=M<+Hwr9+@r1BFsP36wo$DTDPpU>*o{DNu6R8adNJ4D3|Mo;u8dB9vVPWkiK+moUoT=hFQ8jtnbBlVk|xy9^aoA^W12156dN z2N^h6A!|)~>$782qnD4sQH|@7cUm5|&)qRzdVi`eDK94amOk%JQTBWsJ zY~nbukIo*#at(Jn^|CKz^cFH&#B40;DNaKZYaZfdtqYI7RYt$f0MjNifEoQEaz4yG zUqHU?17mkHUsL%taLJ1>3?+xbAWV>+vdr;WmQw%jRLS1(5=@=bZ=ZOp)RJ<{iar)LtZe$<98ll1;_i%s-YfHfz zFoq|?SU;S@hEcoai%@DuoVoQx)#pu?>U(ze3zir;t+G{J#Z@3{PZC<=s_BUu2? zQI||rC7V{zTMif2G*33IRM7qt>|7DVG4b=uZ6m3V2#!;R#rOr3V&Z808hI!X~*zjk-W zOfh48Pf{m$1E9QcCZeJLtJB)gVR?I)rMJ_yVv#XBw_T}(A==>ttG@nFXDMeOg9>ZS za_nTGH8}rCCK{~nKgPXLb=upk9(R*6fqP==wBu*fbfG%!FS{G{BVH&YIg%lrlZ-w6 zvWvsHjHSo{i9D!V?0_H*4`b;J5FOEVH7dtFss9LmEbZ6TRq&1#@J}+{(A6;# zU0vdD-rOR<4EZGWfJ+QU;_^{6}9kU^!h)!u_PZ$ekF{snc%i zXXYd*!dHI>a;geUBD;KnBqenO}k@?^-a;uV?LZOA>jb4}gyT=I45J(&C~c)UJB)HaK`DCSpzPzKq?*m93>>V} zUhG#lTv0F*@!7|W7 zu#e8^+&Qs^O~GOLAQ^p;j5dZR`-vSn4NV*?qwB(>zul41_mt5S8Gtt5ysJN~J9iez z=!nAGEE)at45Hkr-`xuNg6t79nWvcsZ*Wt8AOpmhM~7UU&2n{qAsWK-qWtUHPNj54 zS1upQ)p>){8LWjQMss%#PjRG-*JME|qAdLGmA!IxZkem|XIUVP*5!7EbVhUgT&~X9 zPA66~A4yAKofkmCEVn=gzY=*0d`N`4T;9O}ChL5bfrEA06_hsm&W5nwB3L6-c)u{# zQGzvK48?nfu=WwGHM|gxS^cns15C6Q2-YgSYGNe2`_&4^lN{$J1T=cD~MG3dJ#*bx9jop#V-uG3!1 zKvbt)o)Yi@)Spg_L`UQ5v=MbtymOYTo$OfFVI^wK+h1S96;XFPUI)rR*pX3*^J^+` zng)8OaTUKLaNN?`g9I5W&lro+X#tf^3$QTW)5V00j|StM*~i}L(_EyBB9PvUHxG_` z*e<4?2P~?XO81woVruZDl+>XI5uJ4?Kes>?+LD#2NRr*;gsF?FLPh4_|IX8xH*E*4 zhZuuZzAuo}gtNo!O=RhD&nrK`y|GokU1+L^D&J*1m8tS=H#x>WKHrU$Q|#kVcg)Ao z@8CK`%C{t{IzjSf#8AVS$GzQ3Nn{y>DkY7mar~PpQEN&LO4k&+GmrlMyxF#9>Fv#a zvB;Rs_7b=3VD{4|Y-5HxuI^FX#tmytD`dFP8c2;6FSsG7MJ|h?ToU37yd&v#tH%v- zPjOF7mG7U}c12YAwji4Q5JSa*sSN2<`KGuf1jF%JMP{_a@pDMht!?7@6QiqqOLz5k z_d0jTJ{Zy<-TjZKiZ#Ll{v-H_u%j^nJDRhVF$UX?#N1@du*}U~wMC8$U>XyRX^>@+ zU+m&cX7ux=LeuW(=k`cX!WOwnnk`Z|30dSy>^5LPW5O1>JhtawR*!3|cW_TkmG4TY z(=t!0%B7|%I^3#UFJjd-Sx<`m}bh#zfiwRrw;{TJ}Xd zsIu(&Y=>21xtWRB4qG5Os(cSdBU7%0cM;2@kA&HFQOu*$d8Ee#mec(AQu(@~A}xOr=N>FlL3UiwE$GF9&JvO6XnH>NA* z1fjK8vz`Tt2<<>9I$z_?s4Cwu8U3(~7BQPT-38n8=xH*#jt$8XSe}d?Eu$xDOOxHm zZS8sV5E&g&wwd3C0rp}5r^@%GkbN8LQx4m?SQKt1O&r?SAD^r9z+9aj+)meann`DL z-Rld{t?155r!!RLdq7l;nTbqcrpoweZqLcpd1S86z1&Wh+byLtnxUU%X`?$=IGs?! z0mwjL@OhU1-!yEUJ2O;Nm2bvo#<<8kkae!Pij_W~cwH&u^qmd4k!1`xF+zn0hq2BU ztN~*f6UKUpV69=jcMPLV80+DJwTgj_iCy7WD~KuMNk(pJcyK()6S&)Jd6MTYj`1Y- zvFS<`W1>4|62_=1U)wQum9Gh|s9tsr;O#13HTitBmx()gZ?s&V4lq>t&VH1ue2+5_ zRr$IAKY^c0{prN*=m=G=>i$nurGCwWkg*=Ys?{f^)>-bb5W^r?!8RbxTW17J_v{&qaV80v&=?oC%8_7U)ElKv)esy>A7RDHCJL+!P zQKu~&5RGXhgZP+MG@a2Tt#>GksY>;x8ikL~m|{17v}20p$il-u@Wrv@U2>UV?Ld0#vtv|aOCN!w8fPM-wLI=Gqhh>t8CQ8Em+aw=c`k0u^j}**VG;v{ z&_L3A7T8B;cVW4Pb<2_BA{m`8qmAK7UFjvH#u)uQrJR~){W=2#j{vQ1#iO5) z(GgXton-Va4B%8N4w8D+FTD6UY^PeZV}DFxF;*HDC;tVXW_+%Z3qQR+oga&Sl`> z;n27IYK61We)(s^tm8>`K;me5lC4jR@g(cnbj6c=jjYfb^Zu!(Dm7+=U6ncoS5!`_ z1H4_8+Mfaf+V2r}aDW0^PRVAb@U1(!DpklpRFx_Rega>{$!Ov?M2!EVRjJe0K*&&u zU{&gAWIy3Zp5_INt4f{6y|GoPbw5R~=aD>>IV-jNq?q-bjzyCX(%ac|v9&qfm1;4f9gb;s^M^X7S&q~#tToHdA|DZVR_amijjBq`uzFmV zd^z{TRHZIHgQg2rrM~*Xs2}md`!9xcs!~0v#Nazlv#sglk9Ih|3CXYJSav!gx+--s zGGDE`C%Hqu8m{$y1G@Vkaki+z8DqKkAHk2M{koPU374OjUGZI{9d)mDAZGRq7Z#z4$QqMpdP5iS4=6>TzxL zFWeJTmFnkoT82keq=6Jg>CBc}MQTl~`X)+-yfZ^ORjExWTlS#{-|wd|K1ki!|G&1{ zfh2ryGNk)NBrTzj&p3vT{%A+=JcX@u%m8 zQJx?uZKXInjIyVo6uodz?&hMTs#G2W2dh#SuX6}BUi!+FrrlAEH;~aA6(qbol$3{b_c}(xIji5!;`Aij>xUid5ny% zV?%NT_JPd3kBpwk0H)-87!qrY-bzMCRHd$$(LbF?lsi?aTOnTzJ>f6R(@cXmxP{oC z0b+t8p892o`_s3ozZog2Xb{@?{tQ$Qs;4Z4o^`g<26~33WNl4bN#wo zuFlPKb^as^q|v&bqFOqmxqT*A=PaiatJwxgOJJQBxWyYXc*;}YLn74WtS^mmQ9L2* zT)@D=s?-Wf8+~U(SZ@-n5h~m%jP*3Z8Zd@pzpg;j6V?L+YYi`iV;G-&;gCSIwiT>Z zdey|lcBjIKPpk1HJ$wX?Cz*=d!j>nwU~r6AIF?OUJjpTcn4TD;&Pu&;xLuW6f-5Q~ z4F|kkmAaFBKH7g1gZ`TW>kTker4G7|t5TOR5LKl<93?PjCF{Yx{fObF=vR*zzD+4Ey;Uy$8zrl-Qes`sjOtq=)x^p_h!yvpb2noY%&CgH zpU0|L@0>dxUCx7(6TdR_>UYlFe|p5TlQs{BVvORUU6_YhN`C<<0ZKjSx2AL|Bx6zf zD7qX<-+_7u-i|lmxD8NxC&nmB&p;lSOWHVO0b4L{s5_L1Ew3nudFLECD;Z(lP`3+4 zxX|9yg7tM9oSW zmd{Y|t1g;mOq(qsKTH^E2-}Xd&fDN^3dl-b z3&6u46XwGL<^kh;#c-kioi5441H<$3%WGuHd4wY=Qm6n>1+6J0P|X9-_bE-Df~^oT zTz6#hN-JxRLknBbeaN1nm)gpUfY>|ya~j2u8*8gMju5FK>Nh6D^UU(-ad~M~5#(G= za;^f2l_KZcv8?kUiwec~BuoYfTxPxIV7+!bnmY9*J=47WGgjtW%$)UR;)e1x=yNaI zdpK(nWrxhrT}Z$Q#hdtRF-EK8U4S_hWBMyZo%eCSLX;FT2*Va2B4AUov;Od{%)0Dj zXVwCm^;ax+VAk`GcE7ar20)Z0|BVU&0l%p@Pm12@d{?(ZkFo3#t^6iYF=fEycqe8w zrUqH+dWd<$mb#P|#kbT7(M!uxFB}SI2TLu0eyoKCMOfSVyWLE1BkO! za$oX>060^igPwX#!|xNI1=pI*`yI2S{^?ADX*f2T$yh{$%{uRGcn7Td?`?RH7zfiA ziU8nAK{zDVkoPv6k1@_GZ=1p!sO5pX|JXaYEFz*q%rc9-3?lsAhJQf`m2;R#X`=5O zq9dyMiruTE&LDl#*PJn=H<$M&u1(rsu`6b4$(F7qi%OPH@S2S62B(ckWxqX_qe|90 zlV+EAi`5{YL3y>?zR(#%y)wHGK@sl@Ck4_gOFtVFS|R$qklmBmWu_WhjUBj&bQY7E z52odrRsa>mphrBESWYOh2QoXFgHRrFcQoeRzVU@0BKwY$_Mph#H?1Nv$HLt08_A2UD9R>vY{(QI^?fT@ z=)h^#Orj_C1kRvj5*;F2TSd11@Ld#!4^^w30A~{UKM1Vb`isKrwtgn9Rz9~C5~OsL(i|2ViL)3U`8N$JHXc*5F7tiKy0=zB0 z@OeuZPeB;Z2p7-p$ZsspO(uKxJEq;qWS_^L(aL0x>lc^FvJR5?vfg#>nC(JiGKIJO zrlsu`i!zA`)DzO1Ga_3DN46di+1g39y1H=O?=qX)+BdRwH)*w`N9+9!wfcHP`J)BF z>$ILAob~SiwgW|YzHsr3#ZEMUXP+>hwqZQWTs)OwJnu7vLr?Wv&TMQCE}l=36FCWh$h|DR$w#8(#w!+C*4vzNboG0PJLb)UqsF8Qj~GC;ry+3dvR#D6O~sB< zQRh(6gfX%U(>_bhbvBMey=a)U2u3kzOyQz z)%Be|(V8B3PydJ-`mQSo{@9y}5%hNy?SbXB`!c+$zSDyk?$Bz@G>B)SUcIB~jL=ri z)socE%Cb!2+2fJQX4+he_qZ(RNbxt*bHGq)>a+3~b(`3m{n&bXA5|q;Y4MwSM_FZF zHFYGsKpD4*H&omLzaCm)s(WW|Morj}4<)_0og zkLnI_U@L@5MhdU!PYtZfmi~qn$662lO@u6!hSzoeawt&(>647N8qoZoW9sq0PTTHp z=x89uFRL`hA1Pz8FrLX6=l5I4FQ|7-MX$G1ATunmL~& zr|f;fAO>j#5VJR$Pn%iGA54bIm`xGJ>n_;;@miY#dr7Ql)*Fi*xz=$Qdrt$a=#c%F z{yu|QURd_0Y{qS-;h3AY?9qeSvh(qW>GzgC%$5yp$a+nXc;r7>gyn&PEPa9K_r{XV zVFTQ3DoQmlSxq&}_3=KMTiIK(RBU^lhZH3LNpiMzQ?bz&$~L@V>sm=SSK0gYsu8R^;KGRCf0ZQ84IsxXgr1m zs9D4BJ!omqeA@YGZK)#=5Il z5I+1LRq9kT%>&H)apMK`-pTAomcGE#c2Lvi$$RZ63pYkSqn9tO;7Va4h2cXe9eIdN zdA(7k@NvM*`x+bpJNN0;O9w;W&On#1>fW#jx%MS(=^Z&W4o1jikH%X15`*y#+1VQ3 zArbP+eHx4L7=w}TXIU{hUCi9E@(+8)^1Ac|p0l@_GcR2@4W#=Piv4pI2BIYuTqU-0#_%%~j;uV7tUSHB zj{!D5&R_`GxTe*z@WBSQ!4|&NQf=Y==)RU^J+cR$)xELy`00xpV;$X4vM`E;AJ}M& z7aEMS0vN@@zwg#q8V@oU%K{k1!l!AB@fMx|h+f$Oigw;PNEo%^!@{qJ;;7wUaOIVK zo|)UiPp~wv@fehax7AdD!uf$%{-E|_q4<^cPJ%UPW)Ry)YkwA>x$n-o@yFiWPq6BN z%)M8RnSMk<=-xYWbIeSl+2QOL#^TW@y#u(hl>I_C{1LzK<=_3xy_uW2b10q;Jr88= zr($CJXu~-GQR(o$!b2!?pSo9$HHGh+8p_<;Gk4-Sv1d362pp~PJ*SHJwNOp*1;FG0^B**Noi522BJUv@S=4hU_YF9De1xgXsvi^#^OYg-8UO(z@gZIO!2 z#wdSO1NR!&FVucxKHV6y{Dyd<9=jRYHxT16gK<;x;7T0SD|U#GJsJ$(bPs` ze8ON{ge=nLT0GG%8e_aC+8H3C6~~ZumcSX!Po@)-cTuOJ@~3=>(1?}`(Lxcr1T(3V zQTdZ!Mql4&@lO-4<*{@Fj&A2oOwv{}TmOdK1FljPm(R93pl{8hL zv{IGK46I3}kdt7FA~MHB9%?dZtypjnQ6OFSqO0$-atAE&aVH_^aooN|k$3)Sdc(EL@$a)F% z*EW|19{l5$egk9pOgEHH{(M|MaFrLdL;GQqtOE>e4KhJ2}x~eun|x~zjHYapj+`3s^xo1 z3UFT(jj$4u)4&Qwf)#rcx36&<8SOYGP@T{BOJ~V(nv*|Z%7>ZS2J*$*_EfsFLAv+T zbZcs-F|{CMXm#p!{5yx17ujfo8G93jD3`Gr&utWAQz_#sUt$RIQu5>Qt>c7RD!Xg#1Z-_st zyHS^%mFQ^;bX zThbJaef`^U9BP5YHyHaKK$nSq@9!WaJw+SmOyRR5IQA_=nkunxXj|aHH2>m$iG6*k zO~t;R^1F&)y3p@*Vj2(5dXw`5v9A^So!Gawjo-i+zS0dk_8q9mYt8%mYMP}3{S3vv z-JtHqKjw^m%PCWCOzi7XNdxTIS4aE!#>c+Xu?@FF#AS$m<-0bN?yWW5e_HH&oHBlg zu`V0O*!9?U+l;B$cNeyLye8ze<`*GU>&;3H{1bLHDl;uGUQJbRW`Yduvl08Y2B=xv z=-4-k2*-`SCy;f4k|MLcK=G%>_gkTv_T-s}j_7PAlh~9$R@COCbuCQnyA9tL!5!QE z@JC|bx3`euOYB>_#EE^xwRb1VT7lU2044w1_-AV`0*HzO2MG_M*f+@cZ5AIW2=g6s zzM0q?ljE`uXZrHE*?;QKTg+Yhh*wPf+@BCYC3qni<>nw%uLa`go5t6v2uSMzyBt@g z@A@*w4?bl$=DWULNB6GpWb`X`kD_#ymdw6EjaWN)$LLibS_A6zzO<`wRiha8a2zU6 zZBT0$LBiXT*cm+QZAGxMe}13#k)kH?YpAkaxmx6L$f$%DJmaf=Uban(IK%HJX>X8H`WRj@sf{b_BgN#`qmUPkH`CG28J9_#J zporv1NIDG+=v0B%1BX*KaLQFll8{jn8vD(%obtJjGYs-wT0SJPc=-$u!QVp?V}_KS z#K~s_BbF6*B=5-Q1cT1k1-VBdTqX-dMD{t}rj`0B0SB)y%~d-zTACX*&*Tlx6UaoR z7P6SKXYA5`=D)`G&gILGsAuPv2$sI@jl^=8!m{Hdgw0^-?qez43u5rG=;&>t5tgxv zW_t;15PZg@4GcUGjypHOPSgs=pU*Rn{836N{rF_Zi_mOC-P!orlDmK^Fx%2S-Dr5R zKU?4MY>^WBPNmZ-wv|0gldydM+G4}_)AR^BsNOa#?_w37rr;4K;}HEM6)#VdM~QcSJ_E%zQW`!nw(}k&2YCo%KHnliNzyz? zMG~+c&3MFCod=+^Y7a0L8|>hd7Y*WHN)Y^nR{ms%f37Nke-^6CKdXSnKZ9EQi+n=- zD-*-nM~DC2H=6&4eg2U-1^Fj!_NyjoD%g_e;JxO#q=zWwSxrA9Jx``bsHUuU2CHhd z6ce|k%uEhS1wCvXMVyV$)=4~{iD?a4tt(0Jk=lA1FA1Li6TWP1t)+S7F+kSNgJt!q zKr>%&FW1&;@ji6OTpAYA){_aFdblsFtwlMs_1A~YYAr=B6kM$a@lV`E^UsR~{!s@C zSZgh(M838j%%HxuZZFp%{y}aO|AcMh_&|6JNyMw7bQdI+UGmbMXxX)6Gz?hJUHAnU>$71ibyc@>uNB@;gk1*Mr|HUxh?&lVtPpUiy;a^4FSr z-6=yWUy`?2!JpU>xzL-*)VUq&%2KCw#OvZv9-i_>{^XlzcqTD&j|2kXkIC|N&2Y!$ zI9x5D`ea$^t7K-6KDbQg_w&5(IXC(Ut=>xP>K3%*!9Dk){!|tc_o^6TwKtr&NPUZB z8+%c20k?jfOrP5kbhht^DO%7JbfTaveOku?ikvH_18P)$hyLWp0Ykv1bMZ9kk$;Dl zrCvNbnfieoLisAhh%JHgijKv})XT{(-zQULm?l%!aeFVHx3XiY2eTjRdEJSUbbmBt z#^bg_pCMc4H5u1u0pH?DeY~`P#}4}^Gh;h;@HSzR!9dnqk8r(!-WUL~hwRR*dLAJz z$78J{7MH(VUzfjd(Ap_)T=f)<-ND<3Zst9tC|c~@O&efT9j-V0^*yfdv3-XQNd4aT zm;tG`uvb{d+>pyl4~89Xl1vXME=!kot{*g}EIpxDS$bUefxUmupZpIH3My9Y2H{a$ zBD5nwN?B@MS!xZd$2J210>yZ_*PW$8}F3?>y!zCbp~N= zuCQ*xz~dlC;Dr9-SuG%ibiHSIziQ$AfF}Z8gYXC-9FT6&aX|0>9rMNxvBaCdDTyfG zn}aa}(xqVFqXFqHJC>zZ4@hIx24ZOn!1RKAAp^WN2UXss4Bo#ZPQ;D(nv6RtnQop; zmw3ta+~#!zIpv%D$v@%8#0kBcj6FI3$bpG>oURSjf=uCe(22lN=?@4|CvY0hZ z>074frCn)ZKjwAzHs$HYVmc+dU%+$ibpTfOmRjxgpuhy3Z-(61hdWrG1)iLKn*X-fQjWndi(D-|zSTef@r~*Z;hl*4k^WeOYU-y`Q!B zv!CbT8L)OZb~4(DLgUFU`GAT!k&2W4tf{dtGveZjtK0VRw)AOulTCMk7`jm8?rTYl zjhfrF)Q}!hkIk7PpS?ub_mi|2NsnkhF#ID`#?aq1~-CR0)scM+f(Z5L1(nJ2>$!*2fb>+j9OF!KpWd;UZtdgZ%!QHT%N!ocq zvdf2uh~Rt~Sx=}~{jMx2)^0o^qZ=>Ls3c`C66h}FPBXv%=#Qu5QdqA)=Gv2~A=A2? z@K^Ii>|GRn@{%59 zWAVK;*ne=P(?n8M9ckCiY~=S`2;j+u^k)|A#M~>w4`c zIClSfB{Zjm=DYzUql8bx64p60y?LN3VUd*ZrB4gm5TS%f6FU!b(1zJz2`@P5cSPDQ zzz%_He0_3lJIDJn$B4{h88UB#GU64THj7=%Y@5d|(?>1N|Y>^!rTH%ie58bNqh!<1p=)e98Q!cJ;0XQBrD2WDFwb z72zQIsD%uoqp$@X)rB(MrG`Q)T%omtsDyN2sXOG`c8s9G(E3#VSlVY-GvZbnD?=$# zkpRmWPOU^&a_=dyd_n%e3yRLKHy^f_mIRlW-%%p&eH(l8!!7-OnDWqq{McOEFt+9U z*xWUZV#DTHE*iy!3rb@C8z7btXSxeXvdfk>uA#3}M4I=Y)VTO%gZ)+GqB`?u`hr?M zf&NNcDdqSV-WUCHMoKvmM>>VL?*bV!29GDpdtaky#QDm?FURpo_^X7sRfh(OTA7pd$vG{`t!Pi zdh7Ie^+NkJrDyhJ51o)DLRgP{y0a$z`T0BzlULfFw6gB}T-5(8?NW}CmTzkisc6b* zx@o`iZ4HTULCd!_Dv4`9IX};;TwJ;_o;Zn#nHT9aj&UZ$>rXc|JcX&F`_-Ha38&aN zX0*Rc&C<_)e$AWgaHd?z5_`szZB9^Zr;;QRZCmq^-JYK%0YK$bZj|qjbnV!BM73HY zLnp~)BHj+4i5E2I8e-2-lV!{uqjb!KbH{y6rNb*+sh=I}I$R<+8_R6*1i!sch=jKH zF2(+`y>Y+2tz5~cOM9D&Tj9XcFEMYI?R{Kse`L;e^P~??)j?fG_S*G|-<~~d+w&)% z`q@QK1onIDAhBO*44?dnJb{bai~qVUx%J!fPif0+W`@W?S++grm*R=RZR6gm;)cTu zZ1ofuNYut}_4w(N$vE_=z@KgP_`3PipTW=cV?;|aCyovTy zS68QHiN^x$xksDeV)D|T#`7gTDNLsgqQO#7VW&Cs>$LY5CU4)s3Sx=e>zl~EdDeOJ z2psmQ$N#VL|1!T$bu4$+=6Ku6PiR%rhCBD`SI|`NWvkBdMqhv&r<$-4#GXJ?hfXNJ zDJQ#hS>ohYm2*lzVBqA`tG}vuqbyc*wf3x^F1xu=R%sK_%8$2`*X1Qn?6frf3BAhv z{g?dL9N)!h-XAV*)00rY*@MI*E}`XD1_2q9nnY*B0QK6p%ls>)?`D#Xk~RQ)u=#5LoCJWD2omQwrB*w{*Flb)|yB~XR&RfVcD!BL1?nM z;hQFm^hTu0X375~KIi|kSzq%%iRU#j-6d|+#GR5T?O!%_NLJ|yWn+)eDs5XfwpCV1 z^Tb##7}vJ#wA5CJO1rrJC&qR~qAwB`BT>C5F?KNNF{ICw^s9+kj1Mj{uRR8Udc08Y z5BoDQ>t)AZOa>Y@n87Qn~3b%e~w%Jf5U%zijIHlKZhWZ z=|6i)dME$cF86!?#(%zs|9AfLmhhvQ{!!O|CJX;>{AZl-L;rb3?))UXjOMGlvTDPB zs{c^`dCCO-^QPV$s`Z~Mh41^%g$`H$>F03upWY5v|LLYU{&TcLy4rRQX<_pP!662@ z8veWfvj^g}{v-1j`+Yk9)$aGTtytQA zOZCpd)y3sfy%giBU*x@?I5F-qZ`qhs$Ywx}I^2Co#>&U$WR>hy)q~EQT<7|f=+}zZ z8O+#LQAqnAanxWViBni@biV65V3Seq6oQ z+poFvCDl}(L?62`-catBCA%EQm!!0h=G)%CYaeAba(%SY?v02O{!H%PB)cq;&)-Ui z&bRv^Tus=wP%gzE>dl=Ewi;Mn&Gkj>M-Zs?`+~hj*)sjMXJp2AaW(=h$oifhcuB!V zmdKn*_dbhz%Xcd;x)~;lNiaTF*5>@4T z5s|jYzCzrqv9plrw6s^{W+dXt7i5l%JUWjCzazUy?AF;yNF=VsOL!9)Bz~Y00x0UW zUi?{;tjf(dMY!<2!M&rN-WL0^+(W8dS8}Xe_&TZ_+Z7!<)kwOlra`(3VmBhIj`ba> z%}^Vaa-!z^f&t>TgT-wxkAty0T2e43o_MRE47u1X3&b)KKaHbYuC>DpI{Jk-kgIHW zxLNi-S9a-3&N*gsCkp4doe%YDH!QR}wx}n~$PPyP`ywK4u)*E}Pb_r3$Ryo$%&WFn zXqIsWZS7zm%eQCySe}jh82#&GIku}{INxZ>b`9z18uCookP?;d(xJ8?JrMCP82f?B zfWM3(QC&^z(!39q5*HHRrY}}>e)?J;miq8IA6^g4h`;*bx%n)#%WjsSQI}h6ewL2W z&Awip=0s+6)P-zhMl3tgw~_sNyBH|C>eD7!x``9JB_&~?jngJ>@l;O6%&|m&nPhHg z5vwGixj`xHYg2AbU*Zpz#X257-i#kHFz7pJ!9XIh?&KvRiYL0~F(Z`TIy)<@CQN62M2uokM|)hactF4#k-1l`^X%7fIEB?gsO-{R~&N3-T0 zgcigGTWcC?|0nJchmLs!i4(=2<=tq6Ad5vfSj-Y!z>?HnXzIX|V|7yNSAoKV0#V{liWB+=-n6#AnqDJS7 z+qu~$^FD=%eRO5Se`w=$6DAueJsc32!_v{OxezVvs^>23mei?rMv9d z9yDYxMEv<;&9nc@`6BaviHk3O(ff(sj@mnl+{}_iB2&7Z^m9#3#hj8}oi;OR9wjZM zdrAhy5@eYl?-IUDfx(DvOeZLDnm5x zJ)`5(pL-UdpRlLOns1NXq#d;C4`-K^_76ld^dWG`E`79Tq6hWQDZM}4 zTc=5l4PKMNP~k%$_flPZ{$IpbqQ(C#zB+s3U&L2^BqsQ~_-Y(=$>_<5ubzBbjrf&( zTiJz7t0^8Yf9&_bh%*pz79Z_|M})#}B3v6^jTAOEOaNVcRrs-YY)N6vJ0~aRo!+9D z!+c)vyy8T6lD+eR#7n)~0-5N0cLe4GyGo4e+dpa2T32uGPnwo|cME=t>ep-e|NHX2 zu>4mXnpu9*JS@b@&6ss#%saO1gshS)ioK1#-xl+#$fB~YS*4qc+ifh)-WaP~jIJ%> zUhkZeW6&727L^rdl^pNOv+b9;P!iuxCM+t1?g`@L_=R?%<$-l>r*DciI5+$lIscgA#;DVa^= zYL9yg=crsqQ0^Z_xa6$-H)PPq5`BmtO7qHp7w07$Uu|14F3X}(3S|a1|J1_gl{8_0 zYF>8Pabmwhg49Dx&Vie!+{@n}MN;=T zSghpONV}c|eIxDS1%o5)`WIXsX*ao`4Dm?2rwS%0e6ip$h0_bDR>2&g>;u!n zO$4&Zih^&U5W?oP5DtYCL(xhoO*{IOJX^s)ckxbRIcifOJ4Ld0mx$#g@2RQzv!?v_ zMxzf&v?yQGsQmX9k=uTioXIX_yk~CqQt(c5EC(iQh@YG7F04yh-4o0HxaPYu5`+2c z&R;%%kMZX`)A!G0mqLsYl(CLxI7Z;#$u3_u3;9cS!Jm}DpIV=vh&82|^5tBuBGI=6 zEgi4QmeCZ^Av>e~5%u%$v_G2c;_G*REc>&XpX7eQb~0_FEP>zn@CD$lJ}&f;8Mvf_ zzn;*`x9t|WZ8jln;_4Pf-eSL@O?xJ~x9T*<`}4Dzs${AWhlXNKelGRWORvg+$Mut3Pko%LNs-~TuDy`^brzGbqt0v zQD&=a`8%7xLjDfmFTuHS_F=^7#A=DYzRTOyEKMA9Rp50Y^W9qJ?K?B4)-v1g%$!im z{48*eu-I#BnYZlBJR7EO{vV|8ee<6flE-C`+X^|^a?R1b zo=aLyh-H7oSwME$vhw*`&B%Y5zw7wx&R=8xK4L0*fWN`~9nPP`%CGZR#$Rv#n(_A? zO?;idXZX9Hzv2AZmnLiEw>z&W>@;Wg5+NOcO7;Qh_AOzue|EpZmG%ukeVdlYTY5LGvVt~Ypt1D}cz;6u`c7~KJWc^NUSIs- zoy0fezcg=@)b|k6jh^%h^tF4`FW~&03V7HR&`Ik1`oVhU=&+OcxlX)+)F*dK(ueV1 zZG8{bFJSH6_4RAu3Ya^J`i9pRe|snKw;3_$Hxco)>^7!n@Lz3x?dumXZl?k+b_JXv z^=+S2Prp7piMMv*he&;=N_{71);Ftu0Zn%*U?Fn@4gT&L>btYP_&0aeH^;3`{8hx$ z%ejoCKjXhz{Z6f4z~r3@_=hXt8maGq`r;#Y5?@FBL-S6O`mU7vhGy2c{NJ=M+2suh zl5`j)B!cSo8zXFvV@;@KdGlZ$0ZYcsG~qHeeFRMJMUi@AxSyRabp4h>s-&eIN2=3u zdy5KxF>t=UQnC4VB(QqzgtF))iP=l`iOeuxyw)Tuyxr=?4=aW1C0r*|wWpCqVpoa5 z*hx?SO1Peko+s>-=}l(&rOa7A2Jy@gy)Z!KPI}4=&}23mnB76&V927CX$H<*y0-w& z9OOX0BNhutnZp1~kgQS;2Ll`|z|o}vh#V>uhjt85&+H3Iq5A=>_W(vpM2G$)D&&qo zkcZ|8wqJ#lgo7>K2j}if#_e%u4>?a?%nGXCEN!vez%INnFH+grFn>q;yhX*4ihY>) zV~Gx9DB}&rYE7(gVWi?zm1yrIeq-8?C0hSeYN=dax?g%3S={=dM~j)F9;<|seduRq z;QUzOvQa<953st=wy3o7e=<G^uuY zhn&Gsng@;@-V@-NPaRn1h=012lnF0KK*}tE=&bSq7*<&%z|s9iyekxbNPq65_JsR% zDDD4)+Tr;9)ec?Y+LPeacSa1*ZYI12@WcRHn7A;&!yDBA&0$gYAJbelDYJW6;cg+i zSAaSLG}WXU;B9gS2AB(u0p1nhnNJ+})Dd?GNSUtyPUYobsJu*oqX&8l#i{&bfO=*L zD209iu+e+f0Q-Hf2I#h*8lbaqir}Pk(J(xJA^N`|`oj|a-NM5>yus-YE9SLsETyN+ zuTujvG=ShYqQ)o2obEXR$1`)`pzl`#JoAGCKRRMFSK{}ive1~qSAsg#zZGJY=0kO% z`&E4%qUiwj%u-OXC%~RGQB^zL#yY<&iRBXKNbir$u* z(^Ej*F6Bq}P!19O?(E+FBX(;oF^^cKwM`E0oAd_8ss=7?0ZaWnd~7t!RF9a%L( zJ5L496M;UQ56p>F)VNuFut+hh7o=C}tX?Me4E9?R|Fil1kN;@>{`}s7l68L1XMS(t z=J%pOT(f%yyFRgQt>??!+}sb5`Tas|TQI+$Ny@gTjEwocYOT8Uv9NHt0R@!a9FPa$IX8c;F;|X>~O@x$U>P70nWD@Nf}k8s{_9|;(=tL%s)suJ8TET4x0ryx-ey-Z#Ea6-XCw-L$>!JT8qY|gtL*R)4*17rp z?KO?F-qeUGWm*SSCZh*xNS3<~lni>x>=%eQ3mh6Gxt>3(TK^`%Gk-czI1MCG!HNbISs{sbG)5cWQUpN=RN$*jA zelI2nvxmSE{Zq1UlQ3_m)d7x@c+YEnxRjnUtpM^%nL~UG;z0rGRBsz3J@ef&~ z1$d?*3_v3RNz*|<$}~`Eo!@H^bE;j&~XF3o{-_#@hM)Igw(1UkI!>zn4X4N_Zs4_97K8iQb9a zFP?6~%PQ3yE0>nU=$;u+Vu=CVXXuglTvk?14JTm|R}Pk2+|7D=-|`S)FAh^>mlR3V z{9Lxw#uE!tYa;g!$y>R!^bI|NE?Sgt$SIjZQCn-|B|f>s5UBoF?fl~ozEg(*hY9`m)_z0DJsEq!i-qmIBTXqo|a7Udo&r9z%AxAOFgznbg4POV(Uv(H|u4 zDe1%-YUxuHUAa6`aWE}oT9$ZE9_gzjDXSpf7{sHX!TKJ1K8Jw4l_FVT&Bm4o6H*kp zpfP32C{2FI-GW@4^Sw|q=qYn!AmWU9Tafh3iJ%yBfB?^2lrr%UJ=aI=oZHoy4}Y%4d?%vDeEmr@T%erRuYrqsD!;?7 zLnq9ZV_5b);jy+%n)ho2YgE9qz#2t__v;d!A+EIV)vyVgFymG=&Pw$d<62T)CXk;7 zp)efw6#9YL%^BPjVomYc8J6j=EX+EkFx;7zY zehkr{1JpBLfl~f*fIUUS(&*uzsnui6)#^pUIZZjOqavK)e3{qBb_8*@0dg6}c$n4G zY~L6=9`{?~MgIiF6Sokda9s=NT)zU;8KWV!Y1=*XmgX?a1bAkJ11lXdM;etf-;nZ+ z@fD~u#&RLD{t>|XM@4ize;%Sg1}N(vP|E)RV55ZEjOYE9sWG}WQ)6@%P7xe@qbto% zuO?3LhxJF5;&U79-mr_#(UIrE@U!~y;P@?T^Jr46kW-V#7ep#%x0bg+a41iy}f@yBvSD> zcNu$C)Kr-tAaaN9O7`U=Gg>FfMfQq01n%tM`~;Jygg=ywP*0;_@xtFC6;Y&#eDJfknBXejqG`igx9NFG}%84|fiNC4{%;8sux z+@JyO>!GRca(@*z7p-{|p#~jbS9AYE+B<;f7fW)rgEkgL=5mXhi&dnes~YDmZJImk zx3yfVdP^HF6du9lIA0D1J)W3KOxKz7tJ3F}BU!N=M~GCu>gEQC_3ST@Gls)mL;*p# zxc(7wSIM2b0hHljCD=*k{!EH-8?rYFTTPL>PEf9A0{CvFJh7893j)!U`8Y&BP*h{4 z_dvxSRpxymR+%aRDI;`kLdq-((PaVZnRh^`ZZ^OkrM8Ifu~dh{kxg_sv=PqHaLS_X zB-DyjPM7hJj2=MB{&uU={xPBP{>_z|wWSoAGV34qD^Er@NTB8A=4frXy93ZaV2k4H zTLnqayaF2Rh5QE`L+qwGO~io~0#asSkR@g2DXO-Z4eD$$M~GGCO#vw*bl(qPf(MmwkqWdD$(=(%WP}OfLAA=1}Dm5{KdASIbF{t7FOY3)(ZL zzL2&8w+fW;R0jMHRXRthDELU|Ni$pvt0=INOqf!sLS3n%V53U-l3qoDm_<%_92p~# zqX{!kv-d0*W2mt(0>8=#6r>9O+zP%SYyS}tR77zRWhhVlW+5!d8 zwXqzzPaH3A;@I#IcKd2`Lz$@Z%k52nF#m~Mr1E4ZaHa^f_XQepuARD0fX4iJHwC3cKe+x*OZ2;ocKqO_J3ei_Wbef_%CSCx=#teoRg;-^t7LYPR*J@Jc*%19t zfD-qDGCw>Du+7m0cdcHcBc$nWIzo(a_JmUw-CaVvNabtXkHzfU31IB9o1FTO3N2x- zX0;Rq3m;ALt4`*A2O9ID?+Qpp=S$?{<$kTi+;0S6gp_$5Oxx<22`XuR7LYPe2aJ?? zEks{dRJET9>a?FG#47Ww0M-X8f{|GVglI-Rk3mKI#{sqls-XS4_f`AmMzwD&oK|qs zZ*Se{d{T6q#8pdgbSCicJ&pKE^RNFm$J{k+N=BDTbmMh-4-$I+=)fugZf1NM)K~lg zp(f2%0D1@XlzB2lUk=f!imC~o2X!WRL5Qq>1faKys0p44(dhxo`UeyfJOZ%IPz4jL zc~4c?qmi1Rk#JhVVbn;RCL{EHj6qLslTd2uxVrj(>GXe~iN6d)e+|iUt0Boa5Rfvj z090w6%bHD7rg=aB`UB8E5JCSCeK|y@D(dtH_4OAb`U^mR6><89==1M+MzoFA#I4$9b{%Df^P#&setX& zpA#fKa}TJydU)nv;F#hk0r*WIlrk?Xs#;G4by`moBJ-aB=06p2^IwR*9-y9i3>2*& z2iO*q zLqp+>4*V>@Y5OXu-`P(JHE9}A71zapo-!|m=vyH=Q&ClW2B=f}bs<)nR|KSt(6wyr z6{2$j)HBb4qW1FuyDz$+_U0;8d!L%^cyyN*!f6dB-I>8ItAqg>`*auygRo%$pkjGR zCtY&wt`A(@m|wfH_@1Cg^0biE2rG-`*ZC`p(hnIe3*g#^A!UROT|d>@XHLX|v;5&Q zSwbf-_dn18GX$i}Sb(aA72{s(G0HR-2}qiGfRwp95J{O4A$miIUZ<#9umsduuvCau zW~6|W5xQ@|YeMv<0QJmepjhy7fc<>5T5$S8)nVBVwcrQ$z*!E5S#v2tmRvPHaLcOs z5<5Zu7+!AZ1#8wlL$*@ERw>q0f_97QbC8PHshY6mC26#aL{R{{# z5gnmSbGCq_c^!~4mj)s!b8(1{4AJ3=swIYjI!jz3#40mHK*|W+x5Us8y*5BSb3Q1R zxBy_^=U^Oz>ACr8iFf}{OU%C;&PQ;{qA7{Oa0I#al8nA7!PUJmMEy5~mM}-T<=IQ* zDGDwe6OoI19TLz`|0xHi2yk=BP*826XU-97(!2pknOb_vToQ<2w-6nnsH%Sjs8jz+ zAy%171*DA7ef2L3(UJf~Z&1`91h7ju2#5O5&r|i^`(4#va2K49;iNxz>xTIfP)&xA z(d);4JYs#K=FT2@qd8*jPr4*{n}jT|J$7ZC*gbr2j~Bophw((gWi>i z&Le3bf+Ysw*Qfe8AC==C8w zT2ZGzsIR{e(O&@itBBJ-L~jgG^amCF0rs zxeWr{W=Q7VhDfl-AiEA@bk{+~3)DB%fNT-y4nx8mA;tO|5HDj59agYkMoyk0Q8ChU zH0^IMEYgJe(@I-<7F=!b9EC+QwinJngEZRYadp=?TlPvT)~m{T#S=`bc0R> zFG<{W`_<|amB+Xp&xfFi*HpU5<4zH|)E7C5^9&ev3^cX_zDzjDu41iZ^kR|h=1U%e zLP(zG7nbWpP85+m6)D{d_CH8-T`!}c^r0@QdCDyW+d#ta8UW-+@ePs1ArBCSm)jaZ z&XWP0i@77iJ5y#|kYpbY^bNhTduARu-ny3-U|cyy%Aua6L6(&HP*HW$_d%VTE)imt zNeM_9p=+yBW^ssq=A$+`QXO-@chqgVZC1zZ4A&OHLG7-@T)d+OcO) zTr#>BLMVEqFudFjfRx!IV7nQ(QIPb^GA~s0OK=oDLUN|e7E*p=e^pdf`x(@!wn>Op zX03pf5xOtEK1BZrP|y4b$_QKqu>G%6MLWH%ik|tKDtfAL2Ea*gce|HM-MX%yWK5Zk z0Ih&mZW7L++9|^DawT8Nv91VvGNSR{-A?&B9YS;nPX?TUxD%N^$ zMyFgp#;?(^VYRH)ybV=7aD}cd0%%zSN;EeUlZN6ssAt(mwr84F;2Tlj1%&I^tWxfy54I#Q#QMF+j z)Y)*25UaFY$`HD5!=FMlsNbG=vSXg=h;!RkvoKPPgVl ztTH(QQby>$ZcRdTp8)kt7AXFa4X{^Vp_=yL`iQ1i{j8c^Mw4s_oOEN?r|aE1ZY1>D zmDHKUW-OLYmF9c7LmaqNfK%}>P+!G;gqk#C0G!(n=$zXQ(T*Y7K~Yul2vDbDdm&bt zHUjW_712R{c!+imP|vgmMa2UFHaSdHyy6X2F~Oi_Em~0l=N>re?N)nn52xat(1TD( zVl<+mVUW=9RtL%jI1PJ(`Wki-YSP>fNSRuC$`l16%o`zks-mi44Af~@EW|3)LqN(1 zUCU0HULksBfO@7IC>kCQurFM$8s7f8YWUm+)$oaOI4{9TZ&|I;z~d5C-2j0RURg%r zY(6ESr5ETsGbKlYW?mIn&&&5Yp`=Ad@$`dnuk5r69YzWG??bTW*b3 zltYoj7e}5C5$miS8XSmv8cd%47_x z)Zex`XGpMZ^(s+sGr0CANEwT^TXe-2mB0-*U3s%}JmOv-gSaL{w*;sg92+$$HZ+fe z2JyxeaGYbB0MEScz#ESEoq&{i2jB+5Y%m7FOaYGWd;Tn;h^um6JV3ec3`(J|0_?%4 z!lL!hS9M4nRINiIPdIJhltmAaIE%Hi&62qj-cQ?5j zQ)YvYL0lW6+XB>Sze$s-{ga@9_RoN${mTM8Gt+@L9q|X3k}~0~6Tp5cz}ez8Fl;eZ zfTQ~ccu6SE7H|2eJrq^YKFeu;@EX;AKe+aAIO05&^9h>k_zTY*`Oob*|K$D;QI1`D zaUGu+FeR=Ecpt2`*cGfz73lp`(? zz(*uqpbFZreMz-% zW>x#$gtHf%^!w~y)$s@VUxJpUgX{LcuEC-!B&?zT#|9So(#Ifv7NS1{sNesZbo~z+ zSl}LT>3;$AzXMM>;t~P$Gr;eEFzJ5*j_#}dj8L2frUxkf4=Vi+u+30K`hS}1|JAPl zh0_uaQ)CWW$(F=7ZX;`(gfvSptgFAS(4s3O=t2J*YW4Rq(LY3g2vA>tO*;KSYxM^g z{RN=E15Y{P5&`H5@bw21{RKFBpubRj{R0&JK}COnZH6kMKkrr~OxWWmr@wGo!V&$^ zD*Y`RSzM18hqCdbkLlx2gMW_ENr@wGo z!V&#xzV!c{TlK22O(LkJ7u40C5aS))=t0jhzW$tlMwBxEDJU6q^bbUQ{evX>gVO0! z1fahIFFE2D0?;22=nv}aFGTbgfc`4t^bgVL0gC>hqCdbkLlx2g1*iXyPJiLFgv0!Y z5(sn{1}Re6fPjK7{gt@LE+HJu2n;S~k>>6Ma{awd8mXd-5#pFr?0;#GO!y`10dPD94|a*tt;p%I6 zfx5BJ*yov z@>}hg%V~!#g;N$CE}>m*yn3O8a$RAFTl(?pCoF?%pC&k(oLYA>dJM80K|2x(&%Xt9 zo_`Bar+(KU>6xFeRZW{fp?P~b&`LnkL|y7+2YL(O`DuV}jBHS6j0QriGTSMPiiNHX zN|`@}!jFu5_*6S;fU1A`Gphd8D^>kr2-?wbG+>=az^aj{zrNWyUM-eT?hxcN2J73? zrNrn_5(cKs{(jZ$|Avh?EJTk9P-l}PHL2I@Z$^dJ>+irZ#To(Z7d!B)Beo_B75z@i znc)vG%Ai0&3vvjHjvZv@y2&sOb^pQ74d@QrGJ zws0ki4`URCHqpgu;({OJn8T6FdHxO|qI3!5&{KeI( z?XLnnv%`Tu9r19)Fu`_Gz6rL0IuraZ#402Cs7mO*2{wml!?2pQP$_>Mz@C4WnxOD0 zHNknjVwc^Ne!>|Hhe`4rf;S0Rmb-v8Cb8VXurdtr)+-nwxLoZYRLS{oWZ4+bg~GT9 z=qZyIpw0jX2T7ho8L0;NMF7vgIk7~o9dTnGmPoK5tW{)UKk0)xC*Lb*d=WR8Db>_v}) zMf>*mYh?WU7{tRu^q2tk$G;}s_`fP+{DaH*7r^*;;8#a%O%}@hos>WR!DRdkaCBe$ zEkfakbfchJ`W-5Tt_Ro)`nmD{gd6`~x$!TYi{POB00Om)c(qtUxkF%O>aWYa=uxml zf4@%j_c75wM2`tjUw=(H{YPZz4=(x(Kz|2*b;QnDjPQo8_@eD33{0855tkp& zh5H!9gG2PF0Ch$kMTze#|j z`zrq`6sLW5P_1XyK&8-XfIY9TYJcpbs{Me^Rr@o9GYAet;4FeC;>@QZ1@Y>Gg8!HC z>H%cTh*wL=L^*>1_2Sh{5~J*Te>I3#JJOK%5tH%?{CIWiX_@irG`M#B>2><$5Z0l= z#C+=&z9o{;azt52jDwOgwe*y^IS_Fjb9<2VOc5xZah?FrT;jkGM@$Ofd>Fu=m@fo% z{W4gHRho~ggzk67`5`(iKs|FNDCPG9*m-D2xccbB+AnjKX}`=I2B!*6S@dm*Xd;#W zaoejeld>KR@yf^D_G*EyLZkn3@zSkim0!wC@G%;l4ABPz)G2?jCenlV zh5*l;=fFTmtZ*qQ6W(0{Ql=lk*`hxfwm40Iqx-h#D-?c6U*My5K_Aur@yV+FyiZm8 zS(l^aA~+hYE~wpJ4W7T=IbNMa;A2OTL(JmGE6rG!)<*HeDN^fBMn@n^6h9OS=bi#O z=l25C8D>B(faiJvzE>23I!l})#4624RYKP$q|C`7+Al!4 z?*~fxQGk6hu6FSrQoB6=iQ47K%iz2Wr!4x6ggKGQxo(5?K~nZw7^41Ex53(+g=w(8 zbQKx3YA-qxlneajDG8E3MaMJIw!J4^#Nk%6T z^w?4GGA8S0EC7T3r4i)S+LO_%B);;xTn2@6zX6@|ivj8kaBYxey$4G7_Y&Zl(;PV6 z5yuEfnLYsD0H=UD1Dqn}v~7l8gMqNBfei1rUq^amCF0d{J!)BoR2|BsyhLqvZ# zqCas?dS&hY>LikO6s%1Bb+H${36{J2&pB60P&0U~F9SvYfZ&u4`Q}(SDBV|pXU=ut zJVz`SkW!wOhW=0j{Xu>Gg^2zF&|gKI{vp~wK+zvm^at3fF{l3nPX7;`{+EdUa72IN zqKtTT5=lD>mgpbMe=PTE*K5Pct8HceLzea0P$B(fcX#L8=x4}8Q>HlGXDu+{!atK&+5N3CRdargT?=o^~-OT?I zq!+8M?qu>bwC_>F&Af+d`E!Ne7-!5CM zwckH1i(W6Gm;c$fNX3gZfFlk!BFQ%f_^J)w6Hl5;C7qB@V)0S0`PF-}IacA?Dql+A zMI*c>vTy#VpCh+jDfX7vI(FytJ9A2HvG+Ca&gnva-gN-4xbW+e;Lk@!tZNCjoxXUIFTQ z_DUgEX+EkFy8Mv7EJRBJl=J_fls^bym-Nt{eSV_$?0fHO&n_4Q=VLhOK?JrL_TxR* zV&cS@Ja<2xw-f9cD?BHEbT3}x8B5$OA3-YR9nb!2GWi|^FN2WSxbTepQG3U{_hN}+ zWT2kqQ?FeEDX)5&E06Od)z63Z^(kBssq89}$!JX4G^MK?RB6*69PNq#@`G}UqxAME z>7Hc5llCW#3#EV5eO9`5ZBAMAHwkr0df<3*$(4+D0obk-jqN)LiG6f{{4mo$gyNZw zj?p1t5c&k3qa6L>~xH=L!=vsY`$& z&|nGB3!J8%CV=Nf92nq;w+Kj?K>+6q7lPpn=L&Fi)gxsF3Pn^(nacyzGiQKO=$QaJ zw@7{AkqPPxvlpo^ym3C9g>cgEVN*ZwuZ{oLb}fraI7k_MPOIcVd1nAG$B2F}xmNzO zQ5I*YxnEEUJp^Fy z>8|#=>Tb2y-6^%#?E~Tb3r>3DPWF;_BYw(9v3GDFYC)Ntz&e1B>m3mDKC_Si%o_~G zb(GgNMB5N}@v?*U`$5|G1=LGK_jII(_J;IRCwsp4dYYUt+lg4p zqPfV@M!uR6sdyJ9rBCuP{b|y&Q@b=mWRnCtdVnxtUI*7+ayb_9MuZ^80g_{1ayY)c z*od!v#1cK_xLVJGn5}+4TV7ODc`uJB*cC_9`pP*s?V~S>v3K9jVa0caMgu33D2tAj zYI#kk9{*}R^gK){@0wbsFJCZ&;L6h`hq2qhvA6@geq$uL506&Fy(i1)igr`$eOz%P_o|oh zRXFwz5l-YDOUSDg%KKhY?iDX$n2x-0A$ZkGdF^{%y4sq@@1?0+Ub2_^BCk5@ z;okBxkIx&%c!Xq(d&NtxRxyq@YlQE2DT|&j5m=;xKE@#*I2R9P!YT_cK|Q5kqJkZp!6p~Y@cIIkbjIR_n}ZWQeqBt7%q0JdZ5H>+<)`y;l78DLEJk;4-HVK z{Q;WPIb_K>;T-ZYIF|TI0PlZw;73PnMiz)tCSV@{Df2ZvXN+&aFvjNs99{b(Wxf;& zKe3CC+CImt`bQ*G{Zo0J3&BZGxb_S>GrNqE)(QL%^rVA{jFSc^87 z0FL_?XS-VI_ptumLUgYHb@phgNwvq@-qW)`3qQafblja|Lh~SPn+p zmkDrmU+vF@;w|K;uRwkMg^2zF&|gKg+dmJ{9|IKqK}COnjUMOp_niK0D~bNXDS{*K{}L?{ zt=mD8NwQ)N(`2Ob6Sw=Yzl3zZ7S^%G-MVs%W=THIx%PM3;TJvzachVg%2n;1G5%DJ zdc#Ygfj7Jcj$z&s;F*OER5{`X0X*jgaMoA?hBZjDBf`CvZ-K;fO!<62>t(_CG!@^^ z3cf$aiR-?+rB7D?yyD9q&1XfJNq%5`_jfPmn?;x;*Q8&#CULX*sebt40Nwj2Q$^VS zl0a${b&Egl1B+6dQR+MX`d|cEe9@~k^y+dM6yo}TPW&FAt_!XWlI;J0qEIgZ?Eg4$ zx+9KpsaqVlRY1y|2=Kl0cu?0LQ6W~DV+Ev)(6vD+Qy8Kr`>36ItoFbiw`mW&@Q(Jt zQ)i;&E6Qp87`U4LxUCuCp_`vvPaG$L+7mBM^LwH;e*CNccw(CNM?V&vf7c%pqe*{U z;`*Z%ZAs7M*}$OuWOR24)V?PWmHsGjj}6{2+{cg>X{co zDSs-!9)KM=12m%qLc$V0HtoW}6D7~_ z?f){kOSh+}+6zvZHjwo%<=KgZgv9Uv!M8iHa11uL@9FF7;YBBcGCL=bPMKPI%G?!* zI8#0lBt6qtbC_WQJTuCHYaMa2fRwog;G6O)P-n`KLafq!R3&t6Df{RlIwnAQk0>bR zUktDxcUDtQD_2u~I7>~r=yW*C;G{p=iq<-ia}ObTG005}_535E?W72xQ;4K5Q3 zKcq_nl=VL-g$@GPCC8`@p1)OX@E)%;;Ci#*G_ejGrq)G-H|Z9&*V~yS?L=6a`m910@T-E zi0Cf>{Z&MjzAQvb0u=p0MSp-@a3PfSn}^G$#cKN^P%k)ZVti4iWPf{!)Xn0kjkY0p)~1M* z-IM=xp(7hqHJzl5XUSJ0-D5)Y?Qkh8k-NV%Tc0{Qg9+L;C6~Ws(VD*?V|4}1updYf z?0#)jsPFNgt7vug4>Tct1>NUAV05$6H>596l9ZD^0krztp%ZlDj;~vmMPHF1$*uWs zkO@WB{OjXbZ56AxSfTkHoVBidMvW~1KF&c`6&Eg`F(t>r#g}$*<~gf)Hn<6 z^Fnd^alZ&!-eDF@w;#v4xuY(K+VD#pmTmHK%GN2pf=6nnOSgf$WH~ZUU6WBBQ};6bDbdNJLH$3&LO`NVwL8j zDxqtE#5p1QLx6hbeNf6@0*P)_qsadF~aE%Cw(`QQaHaSb8mrDT=;3E z(w&&>a=jGA`vfGzrEPS#>?$F#{{xU8yJbThvr|319o11h3{U>CYo^^9A=7Rqt2t`rv&OOYk8wq$07x^YX7;ZzmD(QcW=8{UK1v6L#5BSEr=N=bF7aBg1|=>I2+jvWzIh!E&HG4z zXTEgcD@SZ7c1S5tTgEwg7`{8a3+mkAJt0<^g#tK7ts>~bIqDGoG(d?XK&k2-fbD=P zxI>d0)g9XZN8O=7IGx~>McYcCMpqpSiMN~4kr<&BM7yqoGeVKj66SVRRJAvuR>!23 zYD!DY#7(I0pz!|FfX;iH1JoI0U6Az5)1Vk+wgAs8a$vC|ZW4fA0N)A=K%Es93b9J_ zQI*iO2`Mu-L_Y{no}&Y${5JshaCE^6jmD`J+Dum~94MUjaMFX=Byg{||MW-%HP-Ap zMKFCA_fD_j?tF+8m%D0gFnh{8YCq7tIyX*Hbc3A>%AZbigUZ3|LTaK=TCU@uY3NueC_$_>w}&@n0eNIs(H2NUr=;|O#vq`Z0?cZP%Pm! zo-OL@KRuRH!}V~d@9laU>wVAKWRK6xPdqLQsoL@qW>P)AS1)~iy>xb+_OO30 zfm=p-_tY!@mU`)H>ZbLM4WC8}bgG?z%cNWC>(^<{eE&<_&g=X;KL6kIb3Z1Q;N#|r z>j-YJajIs|PIDLoIrI6lsDC|zdm&%3rlmYa!L>!+cU{s(f|+mHNk^~XnQoTyHrkdH zS$Q&9KT*I{AtoPO-wGkYmvNQN?cERr?5uEG4wAlr}Wd?s0L0|pye=ZC2FWd$H7Fj3y z_2#$!wojpRbcK_YB>p z`Wy*86Jv3anvz`lbD$fh8T0o*?n0?!`+)vCm+|E0bRFaP*yXbvBcA9*>hcHx*fq+LT(wKeKbFx3%k6ya9zoPybn9fpBE>8Z)soQ!eWp7_CPUR zBC7G6%o>dfin)`;pqJZOe5wPu~=e9BIS*-%@_uTcak4)SLlcV@twXzSTQ%u8}l-+Tq%kpXkk16W3>muUHF z7I#Z;wA7vG^38RPvpOx6mFq(gCWP%}JnhbWw9E0-R`N2Q2Bv3BYUsb!!3nPIC~w-x zk=vp9v38qc$#}tmF|TuhEhNBkyH&W_ZIYnB@?*&{Hr6d#Ho9?EX)9{%T{{CdME{Nh z=a;`*!;QDTTPv5|{HG0gK^n5(H4>4}^hr=9~YbJa=H=-=2QEY)|d{_N`jre=@)M>-838(QFCoVu^ncuezJB z>Ens99M`jB?3o=Q{SsJOhk7TFC;wAdY?}<;!S49@^HC})9UM6nIQe~Kgawnk~g}+R1 ze#b&5*h?y+Y+vjo#5gP24GQNz0(#1v5TIgk&OHT5p63E3K;2gW_v;-v)Dhz@b(RBX z3rLy00REb#1*nT$TMDtt>>(g!gsu(ZJy0RKpO4yG)Fq;WM&ba;+?$`#SanP{6s%NE z>k@F?D|cIqS#E!PKka^50^j+7IOgAcKPd5lZi^p}k^W{|JhxRZ*9phV*A3``)_)u) ztHa@Lb-1}FE&31_%-F)aLRVJN<*+ctBE;p#eua-g{3Jxb4NzzGFEy!4ggZckCBj|c zDD{8<-q+y3UjPgQF;CyN(Pf{~ z@1T_b2*5T&6_j5yT$SHriYnhoI4zaaItx5q$Vqhn{RbzB{;i$<{`u4qEUs$L54_*C z)&NV8<@`Vu6z)s58LQAnBO|C`FT^U% zM^!@CKHz=&A^KW?^8R>G%6}MOo1zN_NMET2X!4XAprLSDD5rJJu}#<~$wHT4VvAJn z#aD)KhP6eAEj*x(F$S|Vti3rjo4neRWONR)+#H$-h3~cmbnfp2s58dGAnBQ#K*j$B z;QtOh?uhRS;63pG-x!lYoiQF3A_qVO@cwueQE!+OqE82?XYK~2{0RVCv%ebS>nqe4 zJDyNuZ2l*lhG@xjy$M`rpq7oY{ORW*$)j5)&F&RUrymzj*55eM>$KhNUY&$qAM>}9 zkh#0NyP`ZJyL`O&o0`+l>Alk0_)zA5r0hvFLH8@%{Zff9YPYJ6C!gO1QDoVw`X?0b zTLyIQTL!4>f|G)zXa4Adx=GUt3MOjpz<~mirngJ=b>IvEJl_uRJ7f<~*C9=XSY>t- z!1)pt(GJN8(Oe(3X~t%lz$_@uFcc_SbUlG$C^jAKYlm{ z&PF&yKC7b`V>OpX)*t9k%DxIGePQN zNP1?t<}j54cwWnayB+Zj0o*48`0C#Q>eNpNu}bq%mC&^bDKkDq?+Z}$2BrL)0CwFz zs{Xq}RsHHmRQ(^1hVwHV)VD-0>GR$7f#jExY@m03yNh;5J+lz%b6e!REZX4<7{n-3pW+brq?XBnJy zbBPGtixsaFN!F9E0IRF3)BdUy!0- zvA0=Xlj5IZUCU`l4(>ldUlb=!W+P^fE~g_EBcQPV5>Q(3p}V@2JomA(44M2$#Rv3n z28B&=`HWvYad}=Jz8*WOPvTOLA4^X2w_#+J4WXvwFn7HwPF%+}#s=FTdlx4z)K&S* zt?0VS<;C90(r;xm1mbG@kRz5DPP13fEKXbib%U)8sozxJD~r3fe8-jzf|R|&XEhU( zvo-NW`ZDnjUH|zay)#AfMdWB-g#LD=6l99Xw^Y+RBqXO4HaDF}cBTkbf016~i{LO$ zWW`>pQHi#N?anXK_aai97=#jA>>S4}_EtnHhe=irU(1@S=mOm~sk7ew|6_lCyXP+Y z^F2qb*Ps6hsrCEwL7(+E{drxc$gcadf2PQ;`?FJ~$gcadd8Wut{kf4yP5t-3)1PO# z_q@7&Kz-{bQ}kU|F~23w>F#d>%U!CTvh&puhr+>wk2H_U_(-$NRqi9r<7A_x(d|SS zz#+6n-dNgQZt1=yuPwd0m|dH}_K)3!QBu%Wl6m$|l2n|Oikaw(Jz`3B=A9eP&)6^G z=mOt&j#ON(Bc+FY)OAhN*P$jpy`vlJw?hG-r6-=8SaB`BN5% zQlo2;{jmkDbo2Y6<3+*h>REO7cbVvP?yhUk6QrE~l|855=Iq&u7VOfVFPJ*^oJJCR zMyZ(DD^MUbY5Kj0Y)w1u{x8_`fV#~&$Ter0tT{96c^{4N?fFUNuI(9KKjO*D*!b2b zA=cuA=g6S}&QzQf2aw zp3|prRmqTEoob2;FW_~v52UJF#0$SKITK2(+j&qXre=4fP4*%(#mcvSi}RI4iW9rV zydL>n1sTFU+Qz-_+|F%J_H0))6U)dMhVou*Hg_6Sz+n=pg7U1MXkB|uyY+x zbnBBSrBRL9Is8lk;PVcmZGU{XXt(?n!r!KqStiHTi+T z+h$jH9Xg>;;h&M)4#&RfrCb^1`bAIq?`jS&$fv8?suShoL~ZL`N?m#5+fZKh z$F8Veoz^)k*DWnlc@jced!f`WS>*mjyxVXr@{U@ht+Qf#Y);eprahfi!;J_E*3PQB zvA2_SMp#AE>5P!_jnF&82!Hk@61W_ZIFDsz7$Mz}n*ADjb=vGIacz}aq_0XJ?Nhj6 z^n=wCW$fg{y7lJ12v6ZP!(i#L6*CbGCUq=4~Dx0e)b6pPA& zX+W`j4ZN+)Es3M!-A3m}${&(xgBu{lg$VUF*gtvGSYSW|iz4=X66X(V)2S}aS@@ab#fGx^S14@xEOG8UdlQCoQZplkvDM~EScg`6lr1yIQcwof1|$) zr*C84Z!#r(A!EwQh+{yNxBFvGak%&=wX?4fyJRV6Zi|OWAN^76Er}=F z;BlYGjvo^PJ z;{~m;A$M}^7<7*@eDaAqVu`b@ouuMA!FQNFfbdc7#kH;#Y*Yz|1=qe7u-`FCv4I8oJzwX(-_r=fmhT_GJRX_%`+e`Z z=bn4+x#yhQ7l#CFX9R5LMi{z=iu!E!V=Q}(o|64{&}`YuOI7yUX0!MCjyo~n?qW){ z!^VEH_!}eo7HeRO7mF4@p$cmThHL8_r0 z<;_N4rwq1tKN8h?MJ_yg%|^iaxFt&V72=qktgcld=zHx0?X8)@_V3qM)Fi(NJ1AVy z(DeBQ@zi+?ImEu*jghRkb~Ne1FLys}!)zdPx*eJP;Btt8P@YBS%Tv=duU&QHekJ3+ ztxd;z5N|$|ndR!H3G72mM|%76)|^CDgJes6ru(lsMZz<5Io?h3f{f~rcoT8lapo0}dO*abCOFEDZ6_r#-mS$Ks3dwJAUsDIN zv{k`MgRMq&V)Ar(hmw-U36;FUC`_^>Px zvY*M-e(o=zRcDVD5}9!kSwKa-8cNgbjcT+2g7LiU{xsqc<;X_?92a%Wu1U_SX_`g- zR8l{puU_qXbZzpxT0ZKGk@T~9A7gz3b_>8@`abS8b}!VDGnbh}jtO%XOnFiLua*DF zVgBA~#FA7N*ncj3Gqs>Zc1jdv3RJl0BK*yFL9r^Yshd(I)$_qW8 zC_f%rNn7Qof07zUZ)ma4(X*l;$JcFdWaNMVSAEX^$>oG;`9X1M z=DGRAbfm(vIxJvuoB8$qxAI%Ye3mrA{%|5R6#H-Ne)$ta5lwS1$m{)+nb&t}&kei6 zlzkvlwVbd2b|NgN|1v*NdyNwY;AcK2g_bVc*wVb7FTVxpKSK}XrGL_Dzt3_DUFND! zZC_$WL+v)*|Cb<3%!HD~#K)sUoI4YzP0rgY(Qh_IdU76K<^XSrEo1(^qQZn1Pv82x9<<& z^*5tRv9hG7aJUm@k2!ANM?pN2l7iF=5l<()i^LgCgtf##)Zx{j@v%qY4xEQ~f&?h+Mf}mv}-2`~I zkTAc5P@@kTqWV4FXS*jLO4$Rp6vD{%J2%BZwNDBr-SAy5^>2f@+|ZAn6&M8axW1~cD+K&JR<}ndIz)2JIIz!4TC*D zegLzZY)N%c2K9(%&Vu5Aw^us<`|Homc(?RsQ`bC*@xV&L>KJCAv>w9d+);!Z9y6s+C2A zW`0fU@C_;3zWSe`v|9&h|1PM_fXc-;Dt@~l{wk}Mb=29wVw#UJ=p42qi(Z#(E>;4&wta&427EN=~!7I0g?2K`lo-d*!b(W$7LrHCI6~S|87G;L>M( z_@)Y^fpIn(HGLlEJm{XZ{b<5pTyj{&rnRY^M-fE5Ja9HO zj$>QuHX#FT73xapxTAe&x%&q63hhSd@j+-`x0uiwRaCCK11{I5$Kb$~tG`4M7~5Lr zo&%sZeJ;%K{Wdq<0xrgRw6ky4xT!*%I=6Gn-~r&_bzr<@um;4LqaR#u&*W)vn-16A zQ1-;H6_eEMc2Lp|s@-)WI7J@lQh{AAu)XuaHW%1w1~wGXDp#AjGqM~ArhlV}CA3o+ z1X<&$dXGLfq+)RN8R~kO+u>`Fqk4MknL3wQ1K)S(DQry__bOo%ZOdQ{GqEh}yB@~g z_GisFVnHU zB03qV)T1S`4-fshFH~9SvMe0{n03!Mac$hCl7`U+3{Zsn~QZA^g`0|KGrn!>`8u(Fz&O4i(P`0Re03`ep_J zrST#7e0RK4N#;4_doK0I5V(4-an9S2Nv^WzGBGOrg!KbnnxRndR7&)6Z`i2HNg<|-}xi`&pDYFEPhVrC7yv{3LZ`SwQJaTPzcBj%BdQ(mR;tef{DxBFaK5%ef z4Pu^Kui?`?6*&n}xCuaaB4ptmwYVp*G+9k3HS53hU_BELlcj2_x3XaunXI0r*mP_F zUZ)#MOzXr+xLDDNThlnSS79dk_p*?oLCE}IQ$-}fx?ezcciG~3e;-v9_6)k=_BT{? zbDgLnX^Umc+LxpT51=@e&n5>CIR8}+pzM{LrHp1VH3{a(9$<}5oCc{1eJaNMd_)r~iEF%AitJY2 zqK^$8jM_kxxzP|L!bb5l+lfD9yEw9$OecZ<8sq&A=-Zl7e=a$@X^FOT#JkKEjea}F ztI*-COg#BAXU)Z5&NO|}F5YE@Ko+p$V}VTzwUM4O5~_xv%Bt;_VU9P&`kN-DYcGP9Gs&-<2Vs zvmwOfvq!VZ=SKu0pI_*~eV{z_=WYWGUHaGaO+H^zY&v!$YvJ5o#Dwz69jit1*}qsm zKiY1C<@0xe7##G)dgb$Kutq0Nh0+4~e4xiVDnVZ;U+*U`Yc$WY5`3!Zf6= z$8E-1fsjA8{Tg3EUtMquQG9m0+iOP9Ur?cASt3*Ero}d$8cP4d862 zc&g{&gqae~<#f&;O(TA_mJH4+mcjaMvoZ)L0)FQB5$eZJgKB>1v-QefH!wygYMEbw z{O!5TI^@s6Ws^S|9pz|SKi)!|m%sga%agwW5G4J$kDi{p>yx;ag{Wc+fz}qfp+xe%_VHpKA}Ra3R8Y)^IrrS=b)_ZrIyy z51+zbbAVvQ3#BUN9G6y;qCMQfv-MN=93UQlW9)7~wEyp`hAnWU@8#?0LVcSg$Q?pL z^zFOuo=c5?4Td-}L64TmMLdju{ge;)pPys(alB&Fv0h)ozy3x+&su_xrt1>hTX9hK zl?laS*M)d`fW`aQ|J!fYU{wy!_CGU+lUqT5bA9;ZEo`P2X>3xnrf4l2r5s*MO3S?WWBqo|9FN=uCL&xy!vI_}^lDan?w+W62In zq}mN8Os?SnLGBVajoDoK7(iX{kt1D?Qr%fTx_mRFI@hy>E zLMZeH03hrchO|U>4PUv3kXLYT$-@m+!%UaO&oXI$zdbSOm`s%$PE2MbZ}N@m+^A_f zOZRy2O6G&{=v3JZrAQsXN)Z;)=?qzV+jl4|x!jIWSNkqFk7PvQ`8>-TI>syG<>wtA zPkvx$?rh4eZtO@fFf3F>85ngomhcjYEz@XWNO|}YNG@I8FvLa)z){`Kt$2qrHdXcI zMANx-)^cy!l%fy%)a+kkAIb<1zt~7T{E%Nmk&ZP01P|W|LpVP*d`(7P;uRh);^EeO zVm$0{rt$DEis8Of^q*@_78yG)HXTV5p4rOyY3u3goAxV3Up39GM_E}%J5ck`Qu%Ec za9pw~&Qgjj2WeKl;SFsh+P)_er^e?#iy z#M~(`wYa?L*t~XDC3RLM8(aaRzRLK?OI$Bh$-(X1ac{#io0e>;3hJ&ZsJbevxp+%e zkgm#-@jcp-SJjuyt2zOvyiU{N@J{``1shWh=X~tz(|V%mNKXi6e=WcI1L#hGsLw88 z2m<*i#=h5Ks%586j1X#RKYFA9P8Z$w*K=&UqA1A{!LiZh59*{U&EJt&wgHi^&wC0pW`>+ z=OX~Y&uzjG?x_o3laVN|@UxVM+aE;mbI7U2&v#cFKlfoG)eR;l^RnmX3xwzEFXa7T zazNe#emqZrKv!=hwe8ex?LQO@EAbUp*)j`(p&AGJ+OOyh6sv=`li(8YvUoPy?nR`cAHD-6FIX zKc~-EHE`Zny!`xa6K{{ZFf@Xr=@g>De)ypaol0=!S>DBj{qHz^{%ah$@^-_OWZX;Q ztBfVT+fYU~d$H&DHePHwHOR4meKda{4EBr4vt z5-TiLFXRL*34?fddGE{f-dE+lYn`zEl(uv5J}*&Gs#l(y@oeWZufV6|oW_gmnZX-u zlLw3x3>-Wl+9ZJ5RG%)t)a?V~dQ~@05ErODLU(>8M(-mPd1qfuMlc|DIG z+T@)Tjbx(9&nP+F$UA|LR7~Zm0W^R|lPi}aAaR)^G+&sgn5f890ohemVdHj+bkA}wfoF|oX&B+?8`tQF83s+@M4QD;21-7v5HZj8Y8(iQ#(5S!_#47f zk?EB@@>x`e57s7&;>mk+EJ{>NqnueT%^6j|r8|XGTzW?^Kf|R11Q^6WDA+8c5*0J; zJ2F2&J>P#`Yo9hz6uCEeAK+TwEo9e|PYKr}6~ZY_9ni&d?0Vqhm(5iR3g?V8e~uVe z%8mK}9}f;DI5$!LQhKG@cN4$*187TtXx|rxA?<U+MqwO8Xwm!`&)pFp*oxeqBR7*WnOQ}f9KHBZIteR%q z8I2umTI&fc4gO!f6!{5t(fx!U*SMVt&3tGp>te&@m@UVV6s{}1$MENGRO8q38`Stt z^0?SP9)`3;CWo)=ALo@Czl4XoPabKy?4f$A@dFft|Gu0W{|7OdU4);Zphi9@!rnm< zF7`#}KoN*7D#B4hnTl zUi@8c#GjfM-&`DT)!0}Zqo1XJRsqbU|3B`Zo}wZY?}tzMz@q)r<8qt^M#@=7X?MqmBLWD_%8n{bqNXe;fPZU(5%g`U>~MKj>pOct3pg z;kKT>w$1&izcxGeAMHO%o+rE-+>0k{9o&~EH86MpPbzD070+Hg1>cuv9nS$gNAs-W zS#KL$!`(is|49xkwqiy$yTP@b&V=9Knixi3ANC>+#|&f0RFNC(ARQhLcaRRY z-C?+!Y*-)GmnS`Z7c$musyq z{jK$HEA#q{{ba9X_mf>6l;?7x3ii7--A#$(O%vEtrjkSx<0+JT69`|y&o-z$@g#Mq zHEc=hPz&3V)S(u=C8pP{_vrG7In*njqQQUA}^#zX1M=sx!f)jjP> zwbox5WJ@_TOKw2VNbO$}LAHPG#Qz7>i+stJ~@x!@?-~)8==DXzloge{x`w@ zzu*r$65-EES5`pK&Kg)hCdiXTp^R~ohyW3yPYe*T+|IS-a#(EK5 zrTF>i##kM0Vo5x89J|x6P`gQ$J@6U6ss_Q-5oS^NpY+Wj*j9P#Kk~84`8mI5MRDhND$d;0#ypss8qpb5TvgkC5NFH|>P}cZ-hKp)ivQHux_J9@XjuHG zE*Kqee^KAY3r-;4i~2?rX%WH}1B>-TFgUntG8+47Bn~h?{$nF;iwXZ9j{nTTX_f)b z@1LO<0i=`IPnGF8#%??_()eu))HyYul@j<3=qAM?_3bl66qL5CL_xTr8lyi zhuZ-}^hPS^XfnI?v|`e+tv*5we?d&9W46KiQgS{Mg}JD2=9kchy*b>DG!BIZX`#Y2 zpLrBg^BJTx#=1ZWTJZ+pCNZTaaa`8hW`pJuh%1r-0g zTD@%+{E%o$M04UvP!(e8MYEm6GG50wU{#~z?FRL=GuAZ%n62JmK8pLYR>0^y!<_{p>Z{=ptFNw#Nykq4fciR@ zn9NNc|LRZZ;@RAsU$6Z`xMUlH^$p!C=s%Pe$O#3!1t(A|K<8&+SrtXebUXvcVim}D zidp5Rc>pjwox&W_IjiZl=Kb7w;V~7C5k%#;JkGJ%+MuGf;#mH#En{|yWb7MtrJ&(?=G#*QsB z%<9=GGXzk!h7m=&&l;hKC%15)kWBf<|J(cz^7&6O^me*VoGVq0gv{QG3&_~UlW{>I z8OH-bl?C$GtSO=&eEVyR-MbWtV}DjEw)e-9sh+#*(Yz)ckKdXT-Vf=#=7U^%)>Dzj zeK}w9+n}9%r`~JQ_|K0Bjvd{uWJb9}I2l=>fGNPinWuU8mo23>j<-M9rD!?H(qtT& z8Nojn+9c!RIH8f7fNhEViC=SzjuVD-*`a?k$^P*R9^sv^kxP`t86M!AgZ%gjL9~Dl z$h|w8n2em{oIPSjoR#>g$YDEERq5D$hE8L#kYcGMoik zKMnhmKaA^=J?6eKb}A@J8n#aM%zW5|r7~-`_Zk4)>=xtKTkxy$9wCj~4!G-jRE}Ra zDPSyc@GH&xhVtuFU|S-;$nxtzWfAiLgAO!)^&kjFyo%L# z)x>1>hF_jXeKq!*jwKC+@o4D>q+fxrDIRq)Jh9IR6OV3wN<1pq57ND9O}mDkO=~u4 zxFFCXYn{jEZx*>oDARq;y30_-)9Np^Z;W*#XH12YJf&jST1Gvu(u3y9Rp2z`>?wcT z7vi;3wgMVSRx+bAKWpnHU|Iwt>7PbCuO{gH@7`d$n<2uZn#^NM1Fdo z;8REE>gXEd(7>uhH zp{O*uZkBJ)PI|~FSpR=rW->5Hx6dxvpUQkTxwzScN}f-Yc1cJ2OFMDC_IpHiIXqWK zHz?qAV5y@d?;Bc2zXg{0RDP|Fb`^$n*$%fE@8`=Y%Id%o%A(Q(>{nxTv^7E0(IU-S z$B4;1g;;0XW0K@vyV0HLnQ{C;bLX$W%%Prj&o^5KU;Hh-GtB zZza?DLzt9mjEy8GM6yNFn2OAN2gIp3P8L!&0%?nvN^2)abf$ANB-Ljs@yVXI^UFNP z9Xzy&sWvqh$o}IMn*6kS&Ff7+aIYP@r)2z&O+U21bi2mbr}!-7vKha0Sw;YvFI|XMigIv7kwZ_<;9_(s{dWIzX>_9}`Bwr)sXZw%%Kft;# zakY?#=HGO*qJ8`}JMtDk2RP!)wKv9g6bW$QcA;w4 zI1W|XRd81XaARRL=Ldg>Qv&(qce(ioE)mgQu$S?ioZ z{D|QDc=*K4UZ|%?r6nU>Nah;YAQu{$5(T{Rj5W%y|Fz*ly$INr$cy}%P~RX7>9VW- zLN2T)hJak7d=wyerw6!us0sDu1OYdYt3KUSVlrA}IEj$&iXj=*j^02b%XCXlD2@f!1h?Vq4f+*L)TDJZSF`4?@FcjfkRDjC~m;TW` zd=%gtX$J0B6|w~f?u|DMZjxrHR}+(&rZFVb8jZ0UQqwvyLM5r5&jOiw!H!Gt{gK94Zy$dW z!p(Yvdxa|1zBX0Q`C$F8&{uNVGn>%>-TT*2bZtqTSDXB@dd;hu?QJSElDSntkwbuW zPal}$MU4W=MQExl#`}iyVjEyvB3tuoym;?P|GaM~y{7_;|Ie?{yN4&|7oOhd zaa(fq9;hs09$=8Cw+BJc`>N)ft3~e|YNvqS75R2OXP8WjowRyAzgOvO-9Fd1@zvcEYcp}x@zO^X#_!Uh3LJOn9OH5qXqQ7B?W{3 zr?mIg=IE_dK&hv<5APdFZx>+k|M)d}U&IH4-Z?iK9jD7R%C?QAuaU*O9^iv2qxVUI zptoTe^uA9_X7gftdwY7XQ`*%Bw^DV<$cwKMRhd_Y zXBBWWu#{ms?;Bc%8-Q(zT+gqS;V5B9mmTycqivNOlx!I;QWmFrfHU_uo)0I8GL)zc zXAqNVl1%&gAI3{b?)D;B_Tyggqjvg}qA_+0F?^Z!i8hb-i#^QWYVW}lV=OFko)lv; zviKD+jTn)uvey-G-{V%?=Xl@H;{FxbmdKs_T5(SkhICo|AFUW&3W}Rj78iMdOZT(l zjwXoWZuSMmy@Z&|Y(y;RRuR4cZ^jKGT=wH_Rtlnn9+h@TMz$BSWKFIBWeWHl$B+8z z!uy66;NyR)03Y&e1^Bx#q|0u-!3c{(K(4-?1ISJH0MEp%0DmF~LhC-K08bN>=?|5@ zzTA_$LvU(LdFK9a2*dtIzLTclegWZmf#pA;@jg-keLd|XdEZdldjrdU5`K;LrH>lz zA5J!!{($e3qrIE5SnUBe^0dGGvcXMmh4yx${eH91u~!t17u|f1m>KzKb9238hR()P zZU?~KC0w}PPukPE#H}k^zsa??)<;?&YW+Cx`>od7TVKojp4{5fns+~3>-5&kTOZBE zXU@hW&-33~Z?Z!!VXn8onS%@CgM%rDgyRtzEx680pBcq>;d-CjHlt|P&G+kluFZXC zZg`}4JV2lQ=B69X|LrrglX!lCtJU#`{-1Nl{SeCcRJ+N+|H z*H6^aIV;rQ?(Xo1ATj-)@61rf=NYcH&*zQN=_$csi0DI zbg-G!N*&_j$xXN5yPWS{@#LZ8r?A>Bc+sFUcR4_hg>~4XhGn5#xHeb=SWwg?l{DokJc>1d}J2i1dUix49K8vS)zCXUWVo zk@apjE0I-ph4}P%j-K)R!6?z}O6h>~myCSeokpuTnjB{(*;`yq$mALzB7P zI>F_{2WcV=eC9{n+4QU=jk>{#J`xer$=b|o@A(ho>bIR$DU0Ljv7Oy-9#GLehdG_% zFM>$--_DA#%LASoQ53gKV1X2Jcr(Z{||z837d=w9`0OJlUzW<$BB@w<*CsUg#TGs|tx zkpYZV?X9k7@?TZaXTDKk+SfTwSZ`YLXxGkEEnQ&OUPWVW!={aV`_!^VRsdy>TkE=u zdz>ODxLbIpP}RiKIc8x>5L|Ga=`Jp*;1Fk3$ulJ-9Q$%I<-!`=Ff;nt%#4O)xNA4a zPiL&JV2wxgu`lE8<1SU5qp-Sr=7jr;+q0ifvSlSUt;1v`pD=xmz_4E-L= ziDuQwrP0JtQb(_zQ_fh%>W!j_PoSo0b$jS**xRO(vig$6rOGKB9k5$c8-WhRgsvA! zpQ=~_P}gdDom`nSq+)kLa02X!TzOra?s^iB^ZIkEC|RAy079OAC9r)o@khY>&E&n^ zxT~3<-S*{o%MK)E=d*zuR-nVe7kGuPcXfcv*dovhTk)DG3W02VAz-Pa=hoqjeOyfi1EjC#gl+TSTyi$*+j&O${4ce-n#|n~sk%x89TY3-b zCX@!M{(8dI#1j(){BOy?(NL5p1D+9~znxEy7m_Te>qJiv(UX&hht)VzcLws1y4S>^ zrs?x`0lucyh(o6xOG?tZEM`w6PeK~K^5tDX6NpCBv!zL&FrMm5x!of2x#MLJa~btu zSa|0z+aP%T^*2R$PJ2`I=GWh;)E`I>$wQjc583+5@;qJEOOUD9!JyOeujwtBWA{vP zUBS-j{v0*QnPYWUZ9TjE)R77~6kq5tPVYr!+uoGKWfdC6tgYZAf1Hqb<^1TCOE~4P zwlWh$K)%7ELFXN0W_ru?0HRIiDn3J>(XQ%H3X!0di z;Mtjj7zp>bzXM|jO;)}eZQiXn*ugMX7GD5a(D z=>VcW3lS4UDpXt8#6(4j%8M5OGt(9MH8k0_H6h{BhwIiaB`;Aw3ttBb@@>eF@6JMs zd_PRM+EXg_){E+)G*lexjz=S!)oH$gPCbU@nZfj0PQ6gxPK(hAVfOqy({5sQ>%mDSuMrbh)*f^^zOPZ=f&YoY&i~1y;WL3$gMkuLJ@v zwGUD3qzQl|Tnj3ShXf6JqZPRc1~kK(!YmxlKndNh4tDmo83+Z_UqWYbM|Wm8eBE2JY>f_V2gW8MvHKxlyK3a`kNJm7fZt3 zLAYs0;7vOMe{B$6Zj~2kDZ(!#JliIpk}I6*Iqv&5+hm6w*J_isJ>Z4f7TKTrg|yGz*x0JtD(3PQglCSk(KGL4So>-nQE3jzPF_fOZ&a>MlWear<1c z$m1!NoVN%!&*cl%XF9T@uHZ(M8C*KDMer#dO6=PcyOfMbZAm@gG#;}p9Q974msOm` zI+)Xze)Rq#Q%yaEK2#fl)spko=;bNTKKZ&0N|uV%&zJmLDH;$>R7cb==aJ4W-i{?=uf93*ENvENtDt!7D*F<>cMOF|{wueecdR znLFh6TvPjGf`H5J>Cr)wk5oUzTRb{+QC<%yn)n-sLbCjnN$Ui~exx(zIUDpvX|_4oGk6tWHLKgYtuwioz=G`V{S51Q7b zXMIvDZrBO|nHZonaUt9^2jOEaJZQRyk~r%X{FSkI+TZbCw%Pu^feXd$Z*!=SSFoHo zYk$8`qe{2s6&!qXQTuxbUKh2$)wkrgzgpUI+wHHva22$_MJRy$_P0dj>GY7KRA+P=IK!UZ}A8kkNENotC zcWQ@fkLGp-}~_h-yYA`bueqU#}h2rx5sGW4_oB5IJHS@as9yDrhk%aZ-+sV+MBnx z4E9i&BnkCps2^zQRu}1rE76@u))85xicd%0AVjL*O+L8=4PmavQL4pLnMp{k+?mCY zmtQ{a^Qf`@$U9pp`==_fYlh=No^9CMVBoB?vY95(blH8RB=g7`WH_hmrVz=w(a-=# z^ZlnqTyMx01x8F0cG?0(h$c?k47gO!N0+Lla&j46+4`E)aNnhV8JcTSN6@1_iw^ao z=#`syr8JeFH5_hD^dZ%ny3kxBr_MBub!6|)H7tKWGc3L{{iE+ppKavOndW*(ZhlZ_ z`lvtWH_;@`z3nD?op2R2(HO8b=^6F15Xq(P>;RxXYawqi1#_hbm~9P{GA}W%MJ_7y z!sNS4*3q6MmbKxpC|q)Pqn@eQgEMHK7qeKcEwApRAbg6!PWI>rfOvv!+ykBOIxJoqxQAdu+@+o!j={cTUEh}B4fDxPx&qFM;dk8Ev=Vu6|}Ue zWol`;VXKY-M6Rj54P`~f@IeWq?;^j>ZPi(cpdoqT#~2O?wQ@oK*w`5A`BbdxDcaj6 zb3KarcuMy_@=cKwgmaB#r7r6B)goxuGK|YvuRbG41d^`y?Np; zvaG%e?9)h{3gJyuG%;-x;U5Uzn@#Q2Cf|%EMi$|JvxehL(~)W1fGs$$4-@A2w?Tg} z^7f|MW?~5VgOPxls%;s#$0*a<{q=NYIQZ3PUyprbeMe70$}G;dTNAywaH^x03j1#U z6w8dkw>mN_93S-KZnq)Mw6_6BVf_QSrkn3OxgQc^TtCo zUU%R0_3D#}Aj;~K`)wp5ZNSK@h$u2v-$KmH#6MUlN47ApE8ve0dPQDhR(U2$#U-8<$gq@ZxU6 z!9jSja;zjg+fx{yG3D6*lQxy(pQ(;Q<#@#(BGgc&iza@L2$*ur@DeD;mclXpT_zPN z$MX@TBIWqXb@|G1H>N+^R*stpSAlYz7cEqdnQJ^mPB{)S-Ci)JZ%p#aak?(iMnFTY z=M7QVu(RzuufG>Unq^MK${$BRwgx7snES5~p4pxak4Wvx$7G+wsZkwaiolOHy%Q1_ zj4!XgE+?_=@@;%{JjQ6*l`F{s49 z5NDOR5jEX*C7yV7Q6=8hd96z9c5QwoZbikkU5UeltDq9ELU{5mTtxtptHeD7LAR$~ z3`m+Eg8+vX?(2;UE73PPb=E`wW!?2x|0wmh+tc8}yD*%z{;<_Ppo zer~@#C1Y;?2R@@$UJOj;9)9}G%q#&{k;AsU6R;XNZX{98f6mTtXuc-&*G!in>n6GB z$fSU4Cba3u<-w=5fOO=X;Il+!Nk>i&K0EWNQQE{MWSrw~Hb3;UpY&h`k@G%c?H*C@ z*!Q5_+$Y86wTD0MB|LEEu6@MUL~%<>TGB^+I|YT60sVP4;h9y8(4&qTj+7MdP=yKE zMdFz@Uu|wy9a*pF##AWDL9b{Gy3Ev3u2(d~6p_ zBu&8->xi}UA5xG%QwHlQzw$qwb*xtY(!Bhi%jI8O{^I=K=n(Kful#?=FMs(u^ZzkP z{@>g8` z;{3H3smL78m5gKuuIuCuwJCo;PNe+za_ocU-$C~7e=~ylAS7o&_F_Um z`>`;ei<~en!hgvnzdWwt;RpZHoE9pQ~U=ub6b~mTbT& z!tf**iuJLQKZ4T<^w=!)fDrL6v`k_~Wn;D%o^x|}h^)*;wo~LNB8$rNs$`7)%~`-V z;jj^YCvAzCZ#6z|_54g2(@CO`j=htOxl=Le*ureU^#tUvLN7B~8!C=>PhSQd9ry!`A=$)-F|DUaZj z8wGa;lp|@ibL3G4A5fI)L;3ucUw1{n%4enmn9yHtoxOJUOKA+5H8i38>_0HE72z*6 zg6I`K*G^eaJ6t>Txi&+8g%Zrq;Am^{%HT|8P|Ih2bRwJoL5d#7XQn-(oDcJ=n!gox zH^Ds1XJ)a<&X90?F|*5$`DrFaui3$xsq+2yQWBN&nU8Z0tU}J4lky`}s<%1oss!I3&-D*Cmv5&#%FEDn$f?ypyyqqAc;?UP*Wfx=T z_kO)&iJPaoDSx_^fYtLs}TPJ0fQMs8x=)L?x#6JrQvAGIS$!BIB zfNK-3eVv(mghSU{t{p#gF;OYSU%?Od@6tBGZlQ(e6Y!3;crp3fOCaC{KG()QBm-slR(PoNkrAkDzYmGc$9~K>yYS zpx}GRl!r+DWCE~v@R=p`w`$fq)2vTuI~3cWh0Usf127kv(TLsJQ4hA6;Qz3hVf(~7 zX^RP)8^%>|tX1V3(aAF>vMc1x#$U9{ZuV&zY-)!yO(ro?+VBQ@Alz^SiY*(HwPmCA zh1~eVe~NF%b>L&s?Ggskb4uT+)eC}?gdWoUfMPSM2i&>T;N+rMVLOq&b0KH2ed zsYsu9@NCoPvi)miyv^-j9RMia{xxbmtuomDwIA4>o!odZDp>BHglDHhMh*L=9;v^fEVG z;BcZz9Pw47-Ca|_+WH`>xb?N*6mRV(bTl|dYIFi!zXf*w96JCxE$VZ&5nehvp1M-| z1>={s*dtZv+-9KRuIk2@RGAmoar7Tg?sTIml)85ytKWie2eUgWb#7flhj{8h*YBU2 z6`yFy#8O)pzHHoOs~tIAue>(JZQ)GtU-7QI z8I7)=OpJAq7YYPZ){WCe`+cjMElNlBUaA9;7hHg-r|VfU|5H0QTtpM`8ppOX7-eahyqIAJ+( zS-gJayY-&D`B9@To<7%Z=eSa6-xZ#mzpvg*r8S#a>9?Yp(zrLpGk*^MHKdWWT!_?Y z{R#Jre-ncJ1F)R9MX%9S;a=q4K98JkENY!6Wuu=`^kIBfxA^-LM<#zgc;1j-V<~l| z=GvjJ5gNFyKPl~rP@Fl6pVmya!_Y`&KUGVwS1OJa_cWW~(gUjtHquw&Om%Z!QwwA$t zgZKe@x|n#${_nturplg~-?5}+a9rLbE2+FwK)N(XDs$evwj)EDi+hSnW=yg1+K{AP zBFQZl&h$iCVYW>%KB}U1cb$D!-d-=m9XNDh$C7!?W57^CIa`|R^~T@4=2P`X$k-sn zlhG`UHM*a)rJ0sze2EYyqsR@i?e_Yn=VhKWhf));AwxU zbC*%+AS@S~hvFt;7t-S+r36uuPVPh>-MJPES(6&omrY>?6L?Kq{1e8TODJO>9tm)R zFZa+=cf>j3?RYlAGdsE!xZ;?gzI5%5Y9V2z7H%0^n{R~Vc=EK-+z?6$s~dmh?B+Gw z%xqfHxoPI6`rPK9O&@e_n%%i^e8ny$>~MC=&jwrbO#B*l>odb+c~UX`zI6|iD+8?u zsz%dY4_c;dW1V&6K{|4RzNm~UdZ7JzpKgboX$F(qCr2jdyS|6WTK3=Z$&MvM6Rdmg zvt}tNSb(gA(IKu{t1i-I-&tta%?;gQ8tbdAfcnd&22-&);!7&>s`)}?odDwED<`JQ zj%)sH8t+=*xSS_(^DPch<$bEXGcUM=7jk|;Sz-6}Md&I$Q<16Q26!T01mEiyNSFf~ zUgZ=ZAju-Zq=%@5`Q@0BchMHWPqFwQ9Uu?tI~9rLfiwmnQ}hI65>MA~CX^vxbwm3t z(1`!&i9;&ttEU-D*}&Zy81lv6=r^;aLj|ni>ye5^J&7K}(_Y5v#T_vVMTDC&Hs1V2 zLv$L7b9$?~3sku~SV>~`$tLF_5?=C{dB}u8+4l@6twEjx?1BpWh6b{7dIJr01y?gAg|9#L58 z2oC$8ktgS>B51p{W!Z+_I*s7ghtWi>tZf=!F@`s{F@&@}LMszhk5ZAXSG2wx`2W>M z#M8s;hbCKmN3uHkyw}-mAP!VEo;1RAm=<2*sk%Ky3baa%q|3?Q7a~DDl26k;bFcewpi+AdS|Z6BSeR z49&n9W1#GRWd`b=%rgU9Wc97gKs3>$Y%v9a6&Nz{>9);4w)^D!j~Y`x4@sd)dgF1) z9@rVosmS;EA;ebC8y4Dwj_wf2R4NvILQ&FZBfrER97Skm&-K`Y`a*l)kBO=>i45$) z*1reMZ?OloAZgx#r-llBnfuf4l(97aYC;2zKam9ZDrX-gg~Hg4Vx(!^TOP(e3V`(c zbo?`G?0mFg1O6(Q+hha&F{zb{{{l169+$KAR`L=to%uk>4?j@L**>P^=kg{Miz01J zDs6%@ZzzxNkA4+gi?lizVri&Y&X9p!i&U*M0#0WT>9Wt|w{XPKn5Pl6)Udua3mY^XLkMniQ zUSiYR>cs98)tOkIMw`1D#Tt!S8ji+v2!N{m$SFVzpqud{ZlyBUmTQt+=yvlgg(W47 zN+)Jcl+x-7oziE`UrW4`bbF4$M#~jaxA%hD)V&pr#MGu9F?Ua!m*jro{fM_3@0Pb- zX+A7GyI(pm;MqU*z8kExg2~B;9mYQ|Xxrii6mYHKB(>xsj?J|O9&&7m>SWy{<$0nv z6KX0#dKj&7U#D{Q2svw*8^8RmPVh%fy)wVy0FqEEUyHy!XA zT>S1cL`6;V3OP^i2xzTM{kF8FN`5l<%1)SpM^m+_zG{;k63vN_+D?|lA(dA-w6tLx zuXC%Tv+&?e>$1reEJUaK5Bi{e$rCK#75Cjq$}{z-`flbAjB>7yAUk1;0IrkSedl@i0BRlzN)}gn;dY66+RCqSJd!_@Q`NJie zIaQhVb1$3-UETT2kM?(+D*Ap!zpAAdjOBK3sWu^rC)>>%(vAVatJW29hw!tG@@}XU zk1snac=GL@@g+oCyMqZ=2_IJwB2h}o-8AL-BW*|@=MvNUs*R6jKDKr>B%J?keL+cZ z?B=*K;ZbvxoTmn%dzcidNp8t>kql7-j1(Cg3E7n-X#JG?ibDNwdY{3qV03+a#j5Hg z-mML~V+^v&zt3rphsr-Y(2nl^Mv4U8UzCqTONT)TLv@y`W;l}3hJ3j)wtuA{NYv{xqDTq}%T)i=;>m%jJFZa?9p zvIq>0KV<0yA?mPaRsA*rP@w7=$=74VF@ZLh2ShxYQ>G@o0IAJXgeT3Y| zWxyiBp~0$_HaWB%xH4~}v7VG`7-OcrOl(VC#& z>-Q(bN=C=>_4_BHHWg__OHqIGngjJt|0PuK^O{Y&6Oymp(Ok@YM7Cg^B{89P=QY&s zytbv?<4Fdt32BacaOL{eI#*fqs{cX;QAK$NbnFJyi7jSb~BR6qn`c z_ah0;^vde@IQsoY6j>-A`p(zyCarPwyK-qcmb8Bax=6qG_WHdJiVWU$ClfS~(!4|( z3DtChyngSU1zT~Ps2+;i$_?0{--qU__aJs{^}e^%uc`N?$3RvEpZV&2nbfvLzoh6T zffg?qW?A|0uwiQkN zwsKq(DEB`S-uk*t8&Lk%ce46?s1iz_n`DOy9TBI$ZyNn}W8E^>R~ROHjb433cB}_& z&Z2>DbbBE#Xyl=Ps3F=sxrPnW7j%~ouZhwsy4}&lAT%WE8x?+LFKO;8R-lY*ZmBad zHl27DFXnODTxmRgOhr{No%oldp*20)=1R?B|CLm!&6QHQjEPma5n@Sd(~9`OuDd`A z%1KL;>3*1}j;01%uz2WFVGGrFd|+(lgM!~vxu+(e!ru$M^-%#}l})e?jJ;@pJ6lP{ zp+y=h%7up;XszX8K2_{H1hJ&-3oh0F6T}b$qk~0X`GB{6}X-b5DbV_&kop}+FErAPX zPEuv(JwPhBiO7scx%d*1$j_s=PDWZ;9Z+7aSwxemwp)oSQf*To$y05k3sf7|S*=60 zb)dd#=uJtrUHL{MKv1CC7U!w9O9+;=PHZjTf+oB8Jq+2#eB|`i z$VyH_-Gv|tyzO`4cyllGh&om6#dM{+XEdUallX>Fh0=bEvBadk@_tG0ca~>c(ta(N zGF{DQHhVj?LB+FIBGY-ujsLx7nuJuvhf4%?4~0ZH`H;HZ8L?MxlO=K6Y3~ zzrJWo2DN(#qH@)^48@kPw_97zqs?EUh(Ml@Eks)9j$zYN-Z*@A0H)F6lRspJ8)*SN z-#eQt5PXY2-X7r59zn^tVkplZn45E-R9`w)^}1LHyz6|V+8VQKi`@*;sBZ2i$lHT$ zvS9DSsdd|f_b6;OwtMC!KJyj+tgOO+Zxm!b#Akl=!ff;mML(razrx@j2a2M_Zfhfw z^XF9ae23xx;M*+-jxQvEih5(+F>!9@viBWIxv1^}~3432~W?1tU$aR7a2t z)LWDHN?-G#v^MvoaRepW>V|>MmQ0hPl{+S@N?Na43-?r30A|lK_VcyXhshW)S^E`^ z{6tlADsuZh9ZM!2RiU#R$f7UEyGD;sd`N?P5_HEH!;i| z4~%{Dcfl`ayH=4Ce^>xm9{@gYfRnVZ3rBt(GGCK^=0=#{EC{B72M|sC8r?Ir-xqQhFi|Vr4AKFw0ZT3s}TUzNZhW5N}{m~n%R7blL z#m992iAtqn3G_hYZ3EP3iU7SD^FSx%1N9~>58p9{?-;ka2OW?P`V(}9pgObrSY>^z z`_%lLTwQm$TXo$DRv@K6PGxw=+DOw(+6lJ2wO>B}a^?O21)Gokcws-@CBa^Ul5F_3 zDn?-pMXYo`9$Z+3bzv3mCOysKt8W`sgPj^~@&2^-Qq7dZlJ0-<%K?w1rgk;r=~o7; z=u%@{ZSSS=-LRGJ@8sbpxtqTR7lV8gjkEdM)$GlWI4stzHnSXPR)MWitAN=34=HF< zxy3GP+}Fx~V4v6iCZ3%t@oBR?^#McX9yD=w>&y9hAFWSk^?x9!nUhga(l6CHN&W>v zQ#rBw8&YPrT04FoT3zv4R+X8~kJ6{=Rx!de@pHJUR)=W0;jks1I)GmGAN3tiU8YA( z^2I>|cHcGH{2AzLnx1WEZMSyd7@9?sa(oDkr%dww%@GJOdTTV=hjZ4g*XPcohzQKZ z_?GaDp~HW7Jn=T))6U`VlOEKyxe8KRL)5PPSLwcBEK=V)Rw z6%x+p4Dut3E2&{?j2TH58_6?$s4&^d3tyx5wEe>LoUgznG}WfZ;>&Z*!Akc;oz>k8 zxtagLSiz@A|9Zy?L4xaVV(ucDqDHtUXqr9U$ zw6nYOAYVQJDK2BTJKqW0b7KWrNbgcJOz?=MC|i9;flKX23u>Xd$fZ6U*$wJ%!$%8- zqISa3f??02)OyOwpwtd0bK7$f_|*tA>xnP`dyP~%&~{BNrEUj4GTX^dLQLqgY(!HG zhhZ&wWZR6ML(Km|;e~?<7YTj0RcqFmRr>^|2A8ob zWSXWrIbH>xi!}tDIGI)%VYXmHmKkK9AMyX0&xzA@HfN~yE zWw+f{AcLkf;x@3QZXGh%*HV;S2wYyb&dcC@;?&&pMyy``Ya24i*lpg372XLInw^yx z=2Zt*3V1op+(N9cp)uf>cF*;`OWovJtEQV!S^t@apFwN-k2QQRRaQ?=LPtpWFEsoE zIH^CQ;rqIV1FWRi0GHG7Wy^1+j^R10?(%fJREEtPU1o{Oo&zddUE%D}Hb!^Z9!ToH zukCg7l&>=yw6C(e&=g+VUrS`R*A*X8hLDG3q7WC$TcsPn^tRR z>U&`!vO9{#X=74Yb-Wf$&2hI8qkala8v|UEWUhtX zD8ZadsVfN(T+P$2^&w3wQ*?9O6om{|*5q>~AJV(W3!9#NyPFlL4xqp*iSfNd8LsgW zBkOj`EAYO;rM-iK9IlUV&GgP`eM{JT6QWYI3rf+BZ?_*m!ahK0-ripyK`HvKRf>I$ zuPfbr@mmuEnIZhFU00X+s?a6qbKDF8+fu#coXjb}7uMo&>=g60ST`KNgZRw!LB|(D zMYB-53aW(9np8&$6WW>Oh}tl3W1cWk^O4;%_e#7ssrDyT7lMvAoRWc z#M)qSm02>4uu7f=#eJGZJTrI5gi(8+sBj-B$2|9wKy z_rXQq)%o9S1`Ag1h5f_G**W}~p=4Yf-!7LvvvV8q@8fF(^kgD!#Lvo${}?tG6BrH+)3sAJa=dn`{*9jvneLQ3Z{9-_Pxu(4Q zWlX8#^XSqxxn~>tD1rD8T+5W4?S3md{9+9nGSe`S(B1DxkPOAIV;{%je+&Oz5R}6o z`FZ^A+J77W&;tB-85^8tAKRjTVjh00FL-i1M<~4=P24JvFJ&XOY@)j6CM3o0-HJA+ zEGp7NwI7Zp`!VEIm{E-(hr_@rmeL11zAjLEP_&kC2J!CRAuuBqslM65N5{h@8K4O6 zdLwp@Qu!34-GfR&HH}iisEYzwh+boBbxj_&V20Dy>gGfxdd&q=g%d(8)Vx$&vE#}1;o zmCDbr7vv|t|3A!+F}@#Yk+i+Y!MBGT?G#T9j|T%}_xy=A)|2R66`j6#fMxkt zgKVYZgy%{6;*W@%EP}8pK^T4!iY7Qr82OTH6FoJI=KaCE_i5p~brYFzW%@;Wq`o$} zr~9R+A}UP`WmCvf%ihN-Z@paLUlJ9Kdf`twX|P9sMyP)!wR~%q*7H)Oa!mnaNF-@A zEU7H5sj`Fsk?Apgo!G6YErb;T`iZ<&IBCSQK z(r7S0pz@&Z_kojA<#i304(YafRfo#NhDsL?Ao^w@Mhb$0cnCV)CTQ02Vn4SQ`L-WH zEwkNW%_6ZvaM{EwjMlPk<#iWT+qbvmRh!8fRV4&sc^1L79>FXDhf)&)yFVGRL%obq z!E*vARVs^cI@J5>^z!R&74&6u)oKc+W~hztSwBJ=s|{P;WjyQsyKp$C!P!z7+eN9nXM>#&`Y`tG?Ox&#fwx~1IARVgF|^L z625VRfQg&I4b)W#=(ZQbm}m-=n@L)rY!4<%JnaLYT9di5Uiy${!(9Ujx7Ekb!~LjE zInFdfW#0X}nq-mz!hjCP()anzwGw{a61HsI2*%ZWg&&7Aj>O{OH4Su`I<3(au@_^C z*EDP&PaQ$xPVuB}ggpWkUe`HwMCW8(cNZ7s#ooZBe-~|0*G075l1KBcK77T#gkO)L z>x}c~R_-MkS>_G^Rd)Tev0}L--JHh8*t`=t7cZJNeWK}}*bk!xw_Sz&1I8au_ReMIgGvoeRl%Fs zk-)p#sa#ZV^L92O-t%2jHOBT6rXZ7XHvzhbK+iYOhNN4xs3d#&^JEgZy@{dTC-Od{ zvouj^<9PdnU1|i%w=@}t$0PVZ1fE7t7g@=;*xS7&aw1<0!j!lbaFNC09k=RI^2~h0 z(C4CSRD-djm4GFtU?O=;U$&$vGKg3A7RAA*_$v-PuveZS4OtHDN0ym48%>4*dZa$uzrnki@apy&!l(z3T3M7 z8s67e@N<=4w&17oWd&b_m{9PpWx0Z1cC{7eL?y@;e2Bh$!E1PRO9oiM@B2T4y}Dk= zBf|xhjKp)WBLzFx=dpm9XbS$pC}D~%WZ1*aC#EU3n2^rV=0C!Uoc>x%bb^g>;d;Du zY#TClCxSuzxk`L|96J#5=VFk$ZIyGX>@42b$Dcz*R+c|Cd>MbSq4h_>;DtMeNMug*>v0fRd43IoLjez0>D$_e|r@?8AjAb`KqS zHC*+X>1eA=_=3oyN?0lcc3p1>2pJ-26I`$F+9`1Q! zGF>PeDwVJUK;y0!G^XrMOBGveThQjXJ1oQ4Onv5QPR=PK#P!$%P4_fdTEAe2U^;ep zkm?Md>Z%|Wj*j$gE7u7O;m+ZgSPPtvO$cDCJ?wD-?41GZ&8<@dd9%(I32K7`r9MF) zpMV3#%{(cC%*nh?%ABs>y!Pz-U$);Q(6*zGl}_D3=%IFc`uk9SnY zblHm1ob3PhDy#EhN|2S0Ui$L#(T7(z_g5w#*Z$F9&pAegi|i(#WMuaoY(K$H^?BU) zw8_W3Lxd^z0K?(#USe{me&z83J}~_unb{iD?kHhEX2u$(*gZnQ5Xo6aMC=dxERdPs z6XHJIEh{sDzeSe^d&mXd$5bqlNyIMt!IWN&vHOoUyQn@`Q>-89J2%7|V>c?a;S_A* zF3LnUk?vEfe>;68S;T-@e9av?r$lQlng_zt#@NXo(}CE?d6AU|o0$tMSw@oU);UXs zs_vCLfTt0KFRt_^tvd&2Pxf+CZ!hlyMPsa+um%J~n=h0oreoh91^8eOp3umFyKzBI zM2;b$`@wirR>%ALMC4b%AB&o<5lMVPlXeFkT(j+6D^ME%MaFfqv;*%yMx77iaj$QRFMY@uh%tUM>0bNw! zLkN&P&><%7Z`<_~0w840|a- zw!mBR6&AQV@9u$qR^aj18}R=}+?#+$Rb=nOS!f7~c3fKHf(DIB6cki60j?4O>DG>- zvN?$Bh$tW^9YEHGbd+n`68C-F$8i^R5R@e$KtPmL5fH=`>e3*aB8!;seNWw`6LEU{ z&CLJfc}Q2?I_FfKrB0n%Zry$oH~Eetj_Er(1^74uKd5VY3~Rd>G2h{fa|z=KEHkS| zQDX5s^$qs-$UkVRD^X7V|Hkp~mD&{kK|~!yy5Jw_wEWB4dX7&hMo#ljy(I$cnx*i6 zx8|P+9{{3EU2Zln2sQ1h=tq@#!f{!@UDBk+T|mdB=R{`m?Y_{Vi>>QR(f)fhDz z@UK3a@9{bw2+d3~DjI=57KeG}V1>NS*DM+>j$yUFq z`3=%)BnEf*iLR9bd@9-r8LlUe>H9hb_hUUl#lW&khB2eAbW3pYjwEHL`xJ>T8)MN5jq}4;M zg~{vnjH5(HQhQMXCikTP*AaNQu4VL8Ve(-@A&%J&CP$&fI$Ar!mjt^;4G_{s1+(>r z!JA0y>jJjeSb``<9ZtF!M_USggXJ7YPtydt*aYU;k&(n((-?Hk*74NVA>d?A^5DDWxn?QF>V6a1A6UC;hT#sa>b$kQ-!;r5R&*4@% zJ6^!K26qZwj-VzZ(jsac3(6V(*pbrj8cu_2D$$gy8UMTh@gja(qV`pL_BcC)l50iq zf%lM3XOE8o#2 z`9lNZ{e#YWO8trC?^ahBR$CjuusfhQ@z!*P9$9D&^z)SJTjjRXcOu(4ON10S0_k-6 z`K241=QzbJ$ccW&kU}ExfX~y9Z@lPd0})*PEI`iD&nHN$n+iogZQ=ran2wr0CXVS_ zlmfhjz!&RUF2%ub9^xca!YIWh$LbQ4ShGYge72C0$KiO!_~BMOR=3Rdcs_%)K0cil z2Tnvf9naaU$mMy@#Wv5ANFfn;rjf_1|Lu%f{S!8ry2*+L)i%-fwPlsk^>mjnV$-*RJHCMpbE) zbo^d-C_8E_LMQ@4?eyYZFKJct%k9>jgw`}z%S)M%>i$x{ zn{ke&8*Xp>#8eJX;SV_zeYR{m4PzSinsex`&mzTw0%eIrtUM-zAlwUr3`@|M_F zE};^}9^B%ucA><&L;94+#fdkB9d)nZwSG2}WT6YXFbMxL)CLz>POp_PN{|ys%88o| zYCXP4&XP8pzp$=V~MD4U+SdeIY0oC)JLLGWFL zA4fpFkybwzh=4v~v~T*Z(NO*HW4#A61EPr_M=ggK+3pWG|2QqB-N}o{l?XYo9_e)L zt^thK?&-)$yMv^F`>irO{Vuyp^!qLmT>UG$yU`8CAKTVCC%L%Z`4p_b;evDwaOTe`5p`PxSQ(KM&DP&sK<-w_h7w03 zcT)*A3fUM<8I@fLTY!BoQ?F0;bTtH+>QJ$gz)eV}(^WUA$s;9I= zDGS=b=e89{+=-1yy|tuyNp|_%B3pkUhE)&3RG_~XR1#lpbNbrb9Z_92gZ7g!4zh`}OvEeeIE9qLSf6aP`-RIo;R#A*p_9F6yh+vH1%U8~OSY2;-m! zdjnxtQSewF`@3jwR|iru*5hj(YAs5vT3360K}P+J(9qudf@N$aIJEbkRA?+^wx0Ih z!V`5yz|~&;{ROZ8e4f&Owj(-`{`0(0*ZpUHcBZW_Oig7$9q~USo5Rr(=|2N8syp&O zi`6cMMiKj;jC4BrH<6m0{<9zPrpW(3Qb+`z-|h9Ez?~xhT?|QG`L9CG=|5|cR>QD6 zjQ-O}PZU}(+%kP@h-3P`OaWd`;9k0xzAuXgB7{m9{qPA9^%s<+^qX1r)VI*bQ_;I-PFM0F2kSS|BI7eTNhhfqA>UzEwO_bbBlj zT;2X!M162h@5@Aidi+>X?agBZ_F@T%e02meeHp~mus*_$(RECCQ8fFcP%_HDf@Y&A zkyq~^BP~z9-pUK3;G<0d^5_?~X9i%s^hRWH*aLer5Y*?0R;*R%lxj4NFgf;qAwbku z4Bz5`bC6CalcNFS$>b2^L?%y502r9^vnP{Nh6taHiQvjao$vCw1xXbLWHT5D zQDZSmToL&zzMzvz7}E)#rQu^Wlu_@uJsBOx+CLQS1^h^-lhMxe*nY<+SjdTtMv?;J zpPxJ#W!^3_`j!Z;jOH?D$3IA_>k)9kCA60Li*YEL3gOfe2=R{x`zc|&=sH5ri;QlR zQsdIKU?_+ZOF>4JYV=zkZx<5lE73yW9Hi6nb~H)4yd8p^);}pE0#kN+yqz*w>z@cN zZ>k+~nzt=Ts@Tz5|9W0?wggeWB!QrR4|Y3Y2k1HmKd1FCrN)pisehDM$553L+a(!W zoJnYSyDoxdj2D_UsM;SR3oI{U&mL=%MRYjH3!}Q^-(P22gVt4PKuw^laWrlQQ7DH z2(KNZHofyJ`@Oi7J-V%-T zCr(07qR+;0D1HV5J{uqX7=(z2k&V|LtbYJcy$hjXe4V2Xe#5i3CFh{zb`fWw2I+M6 z_6lG;dwT{svA0&FkO-7)x9tu6`=7Uoy*)|<*WN}V=ZvpokXA<^qCjW*dbj{r>&Rvl zaZKOn6yWg$-bKwM0{gJrgc;P4gi09uSHa@;qNGFf!|}v_AJ@~hr1jsZaVyAX==I*H z@$1>lR1BBHWtX!A?KIDs>e zPNx??U_8C}kQ2Q;ObUs>t6M$2G{03u{aafgxO({-IY%$wBdtaw&VXKmdXiCyc0wWF z636s?mjb+zz}M*XJk6?wa4{VB@@cuX{Bm!^#=<(iSfbgD01ef>k+jzVyq}BMth4*ko zfLk*VGkqISf}f2kz)1q%sB5_emsY_hql7|#!`H!7f0W32Z^L+tPJ#Ci>l;mP7G*0ETW5jYv?bh2o|2Dq}=f0iwa`$z%t?-oxMfm?*VT>$Z9u?jiI z4%Q;Ah8-rd=%gnrjJY6$HN-*un*zL^z`b-WeV-IrLb zLWtI=E2Ku_c4q61cwtttu!%e3IpawZuVxsR+t^2F>^3&`0((89D*1`)?=Af@j&Zz= z^0l8V8v9%83Lmji63HjDf3$*nKVUNfIR0t)Pc^(hb_0v`{$wvCE3IqsS0XzbU(QD- zj5lojp&CEo;J5Jbj}rV7__zN2@oV0bqenwM3OYxiunzD#B9@FuVYzWOC}#TaKmK2h zdfGqV1r#+0qQZDrtB%8~vyQ#3Z-tU^BE-N7q|@2k2Y~VH?M>vw-a3*(B5=hf&)(+U zB=+`qBDnT82|1@f-G{U~84(Tq>NXvWFOwL>cQ0{FUpxhPGJzZGS`L0p?5%)McprZ` z?Cl_wlp8JZB-1~6YkmJ3HSPl0j7YbrkqZEfb$^jz=O#Y&$C``yTK{+ksPUq|_<$k| zc(u%$Yj9ATBi%Eg=-LzNECi~$6MBU_Usa1<^yE1icTzQ6e#nVD zH&ZN$K&Iu%v+PEZXD=eS@+?Bmk!MGw)rw{!&*yaDK0!h_Uwh)1z78qC7ZP}?uH~ag zM4q3W4yc4Nb1CHcAxf-IM2>t`3_5Beo;mYd9IKxR@ThSDN?f`5E9L+N@J$JSrG}63 zG_`u=1y4o;fvFB+-8lb*bUGPzX2V<`SB#vElVA)VjQ(l zj`55q{Dzz+$f6n2>cxXZ7DERK@D&m@`3@qE={q4c#6j>w| zLl*a<#M%g1KsfL7IsE2GA#FUuY(2+53{TXyOt#oqkI+M%M7kImiiEzwauPUS6X;a{r!xUd^cHB$%c6=h1j2*7465f`2&sSG+A)%;}GP;KAt88 z%zwZ4?BkScMdgi&;M#{e)w7SyNUQQ3%FowbPhQ$eH09fb64*yF1$Zlg`|DZ;J|OlH zBUHi|{0Z#iHk6bb6Y%6f{&_WG67kPN0pR-Q8a{RX^JS!_{c}tB=hK+|L;q|7RV{~7 z#Xq0%H&32hPeIB3qVB+VNT-u$Enqx(&O}b+87759;D+x!d47J4$a5+YTzNi@oYUW) zMp~VNcn0#!(36gDBqZ@YNgTXKk^=lJfsfL)99JpwJeN=jqxmAp^H`Lm_~$1;M|}%b zrTFLO0FN5uP~ytX_0P8w{#^~P{d1FNJQ*!2KIJuu(M zB^2V#g^AHoyaJ~L4&|(__Q|N@T2WfyJ*3mg;xWK@vPd8&vN&G1vh6pX zEMESL$l`7yxUv|4oFj`tNULn0$YQAu-ls6+F@3iY2j{<1fQJxx0|kfqc|v5-h)`H> zUI1BaLW$#_j}+`0wW<+G8$X`}uzLP^1)iwxzh)8pLe!`xk}mx7<3itHIsNlvn!x)u zfj{M+C)+fx(lmzJG#dElTWzS;8tM`amDWEGD)<`b0l9jFi%>pe=)4W9NnB@I6~_J< zU;4mH12-WA%80ZrH#W5pKh68%xq6h()gvq%@x5Q9iuj?^PFO+;+Q(=hl|n{OcS1Gr zFSFI6Cp>$Z3|i_;QCgrJ>2&sT3t&8Z>4%)y%Vsi+_;0;!FIZ10>m&BkiwLg06fr07 zTKfzn)n{4Msqgu}3hYE3({vz^>FemhmJoKDu486gtYu|BDH*fp!&+vbq}*76C-Bym zj(xkp7whw)IR6Z~@XQE%QCah~y-``*w@wIfce2*^Inw+Gfwsat8a(`}A9jkt@^%baZSkFgL&banLOp3c5J5v8M0ige9$-A3y^5UZ ztcVoweV=un&Z>Kf9$p}VtFst$T4yGbDxZ;1+_y!?_lqSY@!dlp(>KY3O%S$`uA?cw z_yBKrl9U<;&jUj_D6z`GH_x-0AflE-$Q%!j$7}~OI|RT{<93v|qVreG1_I!(Cj1K; zKK44Esb3!TE!beU_AMl$ccRNNFfnuz1EQr+DS-PFaw#>f*FdW zYLX#>`Ai4(|CGqacRPVh-w+QrLfE8)lYwoML@-UI)Ywr2PPU@N`a;5V*B)*KE%h!6 zxZd_4%2bmSeit=I>20Ewz-*+`@%tiRJbs@*PWWx9n`C_H@yjxg-_guzexpdLqwC;u zcq`C>wkQO!Iq;lp0y&w+E@NJ@pxyM$NPBZH19Da z)p5TG@9H|~Fbf&#n7)YwGJWM9>?Fe0QBH|KqkBZx&85_6JO{jIllNTc(|ZZqKN-8v zuyMYiJz#$pJ`UinN+pj2u>n8JIMx3NI9nj8Qg)3p9nk znu0&p-J6bdMba|x$D8js=jl7z*clqTxr2SUhuwt9gmJhHxsqdi+}L@nFr!aa*%Ksw z0^7C^Yq6xeIP2BcH^`^VhyGx{=Vu8&DE5Ka@lVd_`<(Jctb*$nO%IJP+pb_^WwIj)_}M;!@srA@4{xS_>#XB|m>( z7U-0b4u+;7D)|%?`tZ6*z^QiQnq}{>a?^{x5MtdOgy~IXnI18{w)Yym((cf5ft2=AK~YzEJV* z$Qhx+Punh^br#yCEnENfPi=Hq$7}pu=1&r=OngtfEEzR^Ld*e1Z--Wc^1^`cp*+YM z*Zrhi_HLg)TFCh1a9Ah(bCUk~7F-eI%!$tcp86Qd!FYWl(&>CuHtTWc#CwjmebgjU z!1?#jZ6Ag2`5kt-xSt&W@m$qs$b}O4O0wx&jieg7hc){QJ(oFwQ5DX;6UFqc@?h5y zwui3c>WSj2?j#WIF_;O4`iOCj#}f!802Wi$7iB+WqdI3@U0u|ep~E2FUJKl}kyE>2 z864Tq7Mt{)3?lxi?H)#v-8VYLaOq{k?%}WaQqven8t-cwv06M+O(%QO{q!i54iei7 zR3n{Ex-SF9lkQWRM-mA8pC5sty(qCZ!_(XA-;AB+;2G^{9PR1o`#p}o z44`zBXf?0|>2w^w2N;jzSCJEri*##BS9ly(hlPt5h~RP@L(b;dL{jDdA{=kg@%>^Q z-`qnK#D5-ag0PKr9ZfaIClM%N988XLP-5|WUlRW@Bw7wh(n>xN*Lg^D09)9pp%vZA z@^_tb>5+%*KN97a>hciFAJpZs#(1VS-sj2dbwH|1L{EWdkxnPCa=>`k=LC>aOKqlIa^*=BdNA=#E$!Ba@v7=2XuVYn<%EQj|bb2u%A)3iNNY{ zVj(+@5P5w$9Sp5PiFF1}BFOt+45?ng6WYg)Jt+PKch5Qg<|Ck~zlfFsZzG+K--lR@ z>u*ftgx@^fme$KWexJWYc$i28m*2l4XY+e2k}5;<`>CEwyrpBJTZm%%26(W83H$vn z;nx}~{ALj-VI-%4A%zm_Xs}kPj!WTf{o%kGN33{Y1=8tw`v5Q=Z*L+eymi#|Ua{2U zZC*%t`#TX_-X@vazbseRng}?p;!anX)@E1mjbv0d&oR3<>=;u&EBQzEZ zNf_4&%^G#GRA_W!w%(%E39RBNE34l9BZW5B7JNtwf$l*z)&b8)?f0|QHL6;}e#IkHQJv+=uY{J{?XSzf$efMliB3V&1aS0erfe%Qv( z)%dL)d~Sc*QT+Fe)UD0*>b2b?2o;J3Z58_{Mz7jPoMm;4xdR~Rf5G%xe4*(azXZh}?{(Htsm>a-%Br<|G zHJTXAoKyF0m%7P**UnrI~I$! z9MUvnI?&PftuXnL7E4hZ>$Hn>|0Mwn3JI4zH z>QS{7UZ0EuR-GN+P&@@?7Th zRJs^Rwe&~o)AvkwfgPtqr}GJ9`ieYQgRt-GI;M}1KDoRZDH$KV3x=kl#JZ81!;@l0 zTNCkw{Bl81eG&8ceF|u*Jt^V-E2Pu$JB-!1KIm5Dgx}p;h2KL`_?^&Mc({=WF27xv z)BJ{zR9|lqe&5uw`~8fGaQ_v7OkdE0EhX$+UB|-V!tb{SlajG$3K&{|66;X%+qZ3% zDB4*+i5kVAnc;PtPFR7WYlln5H8QW3r~F#`95Q4?+>*%K~%jSbh9{ z$WEsKG>PFhiQ$?=mkikRbd7%wpiqC8`uNR>56U+Fc{cueDfkSzQ2#l)KQyY3zwRL5 zqx;zSyO1RdyD;47`5g7nSZX5dit%JCeA$Tm{{Y1PKS?{%@K?~)0KO^Vue9Mi9!ws7 zMl6C!{UQyZ7_79_0I?5fPu>AsP#Hf zn-Vdo!-(J-)Xt_f1FlW`b|a}KC&i$y(bE-!L6qs+MIh7niwFBFVTb8DMn=S-9*|OF z)Z1Wa1WK&6&;sPKhw;lrctH6zgFGO=v4F+>A1FzcpN3yZ_`_}Zr<+lJ|0E#frvd&! zfbIB_6Fa25;Cb-`PkslnWv`+X9rCxF^z!=_FrNHYAt&;?g%lEjG4nn7ZM#t9w~Pp` z{N7_u%WoQz>het@zvK1fXFmfO(>Iks*az@nXAt%rT}RO{k>3?kYP5d~@;e_T)>>F0 zAsL z0y0*@9N&2aGJWTJupJ5eo~~osP?6syK#BFVwx?pyP!sWh@`D+IvDPyI z3;&0bRQYN6ri8!JhW{1575)!#2IZ##6mqJq28fNoGj%uO9%sUN2}mnTiTo}=I-UGZ zVzb==H4i!M|40G;Z;mIwHXXJ9BZ4cxosGz~_J2sK$s0s|*XRj=!SD(Gk3jH$9_+7# z9j5CTIYj$EDK$pD28KqU#Cn=t>-8}nYeR^1sAlaZq|>q1jTBwh4CI8hPpD$N|5@#^ z*0Y1Kb{-L2*7BIstTjhcz5j!-Hldrq-l&73;|OH>j`v_&5cY9h$1}GJYg4mH$$0iv zF!VG^tU`=h5;dwtqdop615BMM1{f$uIvszvkgUsJKjehJ%~S#Qe^dA?YcFl?MFf|> zBIY!I29oNt?}fkTFBaH|Itc1OAngBouqA|@rt6qFSom9+MM}o(e}KOkD3SXhHGj!b z9)E8GOkE}h5_l2mbo|{zvMzsPkrV!!>AG7~dHQ>#SlT?C2rhqpnA80ALsI?po$y!P zRbXFWBxCye5(w{qdaySTb`^Dv_df>-f4eeC$yomi_*;t-tJs}SADqJ95`d}O#YzG- zNT=iP6_R!Ndj>h-ua&O51nBl9w$1-pByE0_2rhpknbZ7@MN%E9`TIu4`Ew+$@r@>s z=^Nw0P9W@V>KgNdfx_QWQfk!w9sK=@66+Xv6|KKB?(+1vH3OLUi6E;uR z(OmO)o|GCVlE350U*T?tze`7Y{P~IbmPiq=Q>5o_V_i-Pf9sGF{sxf(?mw96@%Qt2 z!rw|Fxcp6HPV+YtN!8;U;je|Bw`6JlJ|YnAKk#6y30tJ=Fm4n5^^#KK!k58cN0eB{ z;HzX>e*;H&{GCP2#UjPP$w<%U4%WZ8WVs2+y7svr_c;iE_mKkLf54YI9s3Mu{&oSx z<8Kvnn!j~Os>s*EU&%!xi<20x;k^d}nZC6i>^Fq%qwDB*tME5mN{#DY0)N+_#IkU& zp5`w;+~e)8QCWxq!x{k2}guh3n)ENIF_#1-~>loaTsQG)n%;Rqe zYdKW&cN5a-`0GZpE`J7c!rv#<1IE7(J^p&0EBu{D1ed=&=CuBrBdOm1O8A@5Nnmx{ z!j7KD9V*YV6P!r#<8Az(n)(L;l>uJhFiHm$42!!#^gDoNK zG+oEc{=(l%TqVKr?|JYy10|NZ12Y9#kE}tF>hw8VWSj+(>P})}ZE})OFjx*qb&phT zyu>V44&C!`$!W={D0kKqkbNb&)mslsK9T$;`AABB1?m}M(>zDh?5=70V}rfL!5f)O z7+r11rW*282ePvVS%jq327g3f)=(#<=l9n2giIK};xY!ZQMHybG}bZ88{GDC%C6sc z;nHHIcQcEP&ujjGKf}h4YW!y${0}{RSz5$B)iz`=4LQt#tn?r&kaW%;43~5lXP4P} zhhSL$w5jB3Dyop>U{kZ!<>OYpnx_&>Bl~&^h_?HO_4xD~?lw_A{F1QSwYNCEpl?|b8k?@aNx8;Icg+Xc*NfBPwt>aVLPD_>hZ zH#r>5gri+VAngBmu*(P=)OD2JApW+$lp2>m4SyR(Nz@pICzv5Of;Z6}%a&hX>*I~k zfVkp!>Og2G#SZt|R0tYfNC|eCBW*EGVYc4ZP&S^Z=n{8p2sa&x;n_cOF4(>=cdqBACS%AzZh+jY=lhuI1p2}MRL@g3#1Nlg&Q+Xr6 zcq-qE>m5YpCMhHWe|y(fIgW@P-bz%y6Cj?-KSwU4uS8gbq`G6JsQdywojDQBgsxW+ z1?OWt*sloNQ`hmA>qO22?+0alvoQLFO8>9FrN7qijnm_Ev)81!22I4ab@POSgMDj zTM7TJhL6p_Gu33EC!<9>PkrWA^d9wdS* zqX=@gjP62G<$fkITBqanSrXp(Mi9mHjr3s0680yF$^v_?5g8p$poFpSF)*|nCDu0_ z&(s;WdAx1KjST93(L&%mq|@w0f^+vDx?mRkQraCv(iIY<9Us&iLp z{cGO7mAJ(B6j7jm5B7P&=IJ_`Yu?Ty5cE&pjwf%tPsE;I;9M^+*||%`nG9=Q{qYT0 zccCIR2Xcjd#GXL0I{H>mCSPtt=_rwUUjrgG~^&k*=d@U(xqT1j6~JN5N1IN~~Fs z03Mtz$Te!$GEz2CY~bb?0e;2@puA)Sb%#hHOupLGVZDe=Zt9P8pnPee&7gZl&c&?&z7 zdZsf!k^5KNorP1mj17^44G+_u65vz63>h|Joi~^W|=rhS$1q zfBFeVLEl0u^nV?(J|8tISVz3|`JjLy77_s1odo+xgT;b)rgHmx-QY7^2BC(DXaft7 zPS*|I0F2iSUO-N|L0eKt1TKEv?FOfOSRmctDI&PtU@UUZt6me3R(Xg}FgE_8%{TvLY z`*Ak}_J2^~O5a~GMvo66!au0tV*@xoZ2YSysMmq1E@1=WfoG9UCn(%?nj)yXkP|`W zkOI#Cz2*t(fs=*zJBi>5st0n8p!y)KwtgytnsJr@KO^CduNQGlU+)y)z64%QsU`wn z^b$dBONyXYKLD0iqQr{JC~Aj;T3%}3O&+hafuODx%>>>yBJBY~Xodc1B$ z+gCkaUp`5ie>V|aUI!rO@Hz--m92SQs)O+<41nye4}JuZ;+W z_x~!v>n4;~8)aO;T{dg=c%kQDFcx{<#hG6NCxm*`gTUcc8NwElH#oBzX;$pbC4{)ynqqz7`2O!^?Lwl328Z>{yuz{vFVA`bMQ z0^FCt%PBzUzlYX8E>r-2t0z18j1_qLM^5Ws zx1#MU9T z^^X#(2^6WPQMWR7dV|my^X3Sav0srW&cA(3=^9@#TW`>ufhVeXjysKV#tXTRWwwo7 zuCbr9vH#V5Ece+c-8IT!8|4r0W4XqL&)4vVhX42PV>#Z&|C-}I?tj@R4Ekf~?qiYh zQod(wv|wDe78?(IZNVNlG5!Qj4yJzZvwTiww0%a|FFkR?`-vz40lZtW8H1bgwL~Ue za3vXDNNN+rcY8ZMFD}}53;_9ZWRY5n7v`hJJV0hdIs@ko!C5oEQ9&l&`J2`)8}F`M zgT`Z+!&wV7CfczeBXSrZClV5bbJcE~06-i2;MQo4k9VO!&4Jvoe(Q~gq5=(gL+(+F;3|wm4;OptKiY>3? zeLfGWyB49C_r~7%n0{ODLl%`Wc5Sd;6Tgsp!YvSg@Re5U1=Q;4XJ?JAIQvJwKR-bA zyyv$%)x8g7Q#>bVB5q|sE3YRrm51*(uz#IJ0KBf(CTPyD2bE8#ma5&%EW9^p{Dz=? zWWIE2b&WxL@&y?5VGXDgqt+rV5qA9Ib&;0!*0+N34&=wDlJhC7nmmA%ZPHlyP&?YR zUM)q@Ea*04Hsn#K_FzeR7E^8O)D|BesH<>S{G7H`vE`9m$a?_fjXGjL01x{*vUx-E z>3tN+E!VY zkS8BY`C4CX9X}6SqawP7bL<)(kQ%;XC3oAE-HG4i18NboshI6G=8B7S+j@JLVH>ju zzZNH0tmrX$xL!?{U+m-9`B(7^n`ziz|NqXnt-@?AW&Z)TW-@Ma{71v~HS|{v%YnZz z6~BB)erCP-VBA-jS`PRpyu8(JZUcXW@;!`gbbG8o!}5|IfcOOvdL2lc zsQ=PGuD=cIN9ED_m1EDZ6HK#LOMXmx8Nc*iz8gL2V|0yiEz5UjM>?19Zd8U3$&J7Z zr_0(_1>@s$gN45YieKu;RWjak5qXLkamRQm*=2LwtfWON?jT*TpTLi z=AU>Wx>wk&MN|9}Ta!xW7kEV#8(wEJQ@95R#f$wFdF+K1yKvDD68@=2mlPf5ugK=Z z@*gwtrfOvn#9|qEfDgU*$kZ)6vPnca{G&hA^QYl>Hw;T7;6s)K3%>{#&JQLUogFOx zE$F|PjVxRy)jrQ~fz|#U3IEiCN{aB^fPBv|J!pyW^JgtE~^w0yuT;y0hswA z^GB}k9hpqvmzVJS(MWd4c=7=(Fe2tknxGM8sPhYITHKZyOQ(h9r)%Q0O=4hjK2 z4@fOB2x7k`Z2lO`Twk}8UxIy}jZ1WH(-6Fk3yznQ9q_W@01Y+-4Z5ItDWI3aPhB4> zpNs!nGb8;3Nky9S?sI_$D7=+4A{G`~pIgNF1YSHS=~r@X$#tpvA`)&ePAwGkvi(5N z)dxsJ@`bA$AqU}YA`lfE&2aq9jNGCj>Jtl@n@h^S&!ljmBn9D=R(y}JgCClL(9l#Z ztUl6CgeL-+3N=VWeIBcd{LN|$Fq>rZGl4}8L|I4Vgx^ukvZ?B?aG9!qW%4`M!9}4T zSdV-ULw}Ei-}#&6*q`%hg+B4#`N23pL^nPMZq~K3`N87qVfpjBc7l0b!$53ML68R4 z9pdZ*FQ)xx;?7LKnZxo&^eq1^GjdVlBJ{ULo$$Xl9KRlND4Gug0tw%yTnuZtO$b-q zz%bdiu(=@!J5$%bmz5D8mLDpf>wlzcCwLH$OWv!^5;-)1Pjocv@DrNm@Iji}>>G=C zIg!Ip;*v~rrFl7c8;|ip`cBCIHr(d?5u?iYWJYdgQ{#cF*sS_3#vCh0x7x&ls?%EO zK4`Lf``xSzX=~M_u0ed4pi%k2d>FuiWYh_-mUj&%*LeP8e%D~83`NOLWj^D2fuOnn zD*7e(T7L}R48g54{UN>+QWO^N2RZh{6$U?q3fG0I_h*L-*WhXrc!b}A)qCj~@TH~Q z!QwCc_XNZ%^u*Azw6t(l2!11MRs&!$M#m8YFHf{e!u^g5hZCLArB@?b4JC%<(4TgR z9~3f|!>i_n3fFWon}*DV!Sd?7%i{%ErG=}5_d50$tXLj7Dj3fUnpwek2`aw` zLMy@WbrC}OYRuQbNbx6StE`^rDtw*xV5*thDJL95fFK#xDi^OF;ip(8mPu5N-mI(oEc+RR;SW zoNN6c<5CyL&30|OrEA+=$!FEf=`ud_gyq_6BvAb?kyG66>%=E^{B|(ty73$3%+-nh zm9(Fb`CCcPkohxT3e>A5=%}~kgge}ltG|Q?m*kHfhb50v__%GJ%L~;uDqu$pIW}I3 ztpmkeE+0d0;lc&BKU@k)_+u;i`onZjdLR4m!O8KAaH8WpjZvp=2V+u?CKkUvCzM%R zTD*V}We9@~)QAgQA{T_skAtwuiiOnQ*+H{yFn%ZGdk5ruC**qv%(<8v?qXzoYHjzs;OZCUo|093FL_ZZQ-_l0N2VG|u zF5D7C$47Tk!HO;8j>me(u%*HBWL`Ldp`QVX?=9NNmdvsrs?b3@g?W{3T6e=ElHCAL8>O*BJ{@N=+m z9-D+-=D+(F?vA*P4c69fBOx}{>v51*t_raMG=`u#2l^aL7d!_Jg5!ZdhR=PYwF9Nl zqjts_K`c$MsP-ZmKkzGdYD;7u@cprYY{G}0g)a5qb6X=kLLbMxTrHhSLBOqNV!ECs z?!vqcW8Y|~H5<`>^P1tB0wrRpfZT|w7O8Z2_1-jwF+FD_t;%9Pb$O#v3@yGU|@uAtyz$IZwu;NR9Y&o8X<2UDo&$t=PfdTT^+2*mc z@F>zZzs3kwD{P(%Ni<+{2oOWn-@}z{RMtOXubFf4RYt5ky|9-;W)oX{CCj04L9wB-vuupzndB8rx#Xm$&a_ucXR>mlwI+jfa3X01tno-3TE@y33nJj=K z$KZY~jIl=nChLtM^eg4_W$Z{H^I}+Mz3%PM*ZrGEJG7f>y9M3-TXg)e`9s&Xb;w+X zS0B)=^;@yJZ=(lq3MM*+g7{)uE^bT8wmLYwUV{HR_eN%UeQvw|o?SdlK(va5Wplk4 z${AXusa6*7)cXjhu#iNn?ffc}>(yWcgq)F`#b0PsQCUe)q9-myT<0eo^XTBEA$ zqHpE5R=p%3puna~2AG+Y7cAahwknwD1}oYTEW~p4 z(qOg9E=@${wh0$6j&#N2u({ot4|2Q?$FssFJ}h?;JZA~K=0%`~n9_|$J_fz=`TRa0 z;}K9=nWx9q{_h}y%={s2o*XuZq3Hv2t!eCAiAM0dRl^bg{2Z*ECxfD^L{C=AS_0sZ z>%~fomyY-}lxP(N8ldRQ9I2L4;#`F(nMHY{S6d$;r{h687{u+Zh%W6}MZ8;XbbJuK zipx7EXnz|lUW4%x14+DVC;!wVWT}kj8)TX793*5sVZ5{@rceIZ zjZFZ#2McmpNT8Ru3&u;)?aJ~Y??_8WKkX0m#~K3wgC!=4i_5k)h;K2Giu4U9#k6ibISLEd^W;LSwX)Ip%_BXiU;u6d z*R8IOT*5^AE9%O2z=31EX>G{tmr*v2VR+jrr-yLep)$5S=%2OMKWQ#VV$wVBXJ1CV z%e0Qw>X7oUGcj454dh5|uzYNH@F@3pc(QMUW=eZjYuQ&^N7=_qv7pkm2yN1fe`wcH zcDu0b$1%=s+m9b2gSVFP*PCzZ_KbvLe8p~C4n5RJ-Y|ZuDLR=4VwKh$a8w) zt;Pr?J>Epe!;UKW6}I`^pqYv8K;-DhV>fbBstS5JZ0?Y{lR-_-kvFbKrM!Fo1bO#> zyf+^w#ekBi%>u5D#>6TR=gO$qk6{ zU}-QubGvmWG7zD*KSw?EwQ#hzc+%wLUIG?jUt%&fg z7eqlR%>Bd15P?K5Y~_zlV64K0+zKYl{Uy<{8LhB`Q9duTwD`xeZKVi`Yx%jKIz47$ zTGR$az)6>aA}7&F5{R8s{adNIJ5;#4G!d-3EODeCi%_NJic){K_1uu*{qCh$rq3rC(KpgB_$4F zyn;& zqF{$eK_}d|OdF`!6*-o6g8-;8e?j+Ru-*lrG6}~l0Tx{Ztw;Wq zPTyK~Y$+}wE^k$kiPbtWh*EREbvVoe{SWpO`7Tsm3&Z)XYH*D=^XGBi3{4lx{|LvdJh8`Guxb(=Kim<1=1r-O2SCxG) z%u)srL560!;$Wbs+9Otcz&mY0jei2iLXK!qF4Bx#jrj@*K`rP!eek06FV-49pivc@_J3M%okjS*Zh?A75+FOPB?S)na9kFk_rmlQj<|O?% zWPTouH!83=;z(n*BZ2nQk)bg?_2Gt1$jPkXc_c84!Fr?ZR?(13JPQ^th#cd{t38$; zp5a4=!o}5PTg4hlF<3sMpbEd4{))bkI80JZv4OpDM}}>Mh0;Y5fo-JXMuu%aEk2VO z3YNapny-g+$ln?9J`zOV%L=2Y%#S!HffI`jf&pox{@GtaV}+0QXCz;@+u`8rQP_90 zi_iI0a#khxV9l-8Td;l_7M*a#t*9NHBE*#l`dtv^Lf74RTq$l0yR;#gFlPIE)uKna zq62%j{*EQAkhzKE-X%Fc?AmsrRe|Sv>|OVq9P-vvrVBw8s|-@Db*2om`G`HH117nq z)U>eegG#?drN6VMe3%hK?oJ4r`W?WIB0<;?CZl3Qkq(ai>?lo)#e7CfknsmSPP^ftV(}*LO@k2o9*%AWj6$uJjfXRoM0TW0mkU z!UsOLtNA!oTtTHCg~?0RV!{~=ZUa;QK8I@RiLDF%Bpe4@7F03Ihd zIs*HSUNr7Is2&k^O%n*N)_0~ZDK)h2-mT8{;i-LNKrT~_Q1n3kU$k0wEow!Tq zV{Pw67vY2wzY0Tx`_XkuSD?ApwRo%rHnJ;(weCBIb;pkl1C*m9QQ>Ozd>aF2)_kwK z7>=+y!CS-;iaLuh$!S`EBk(M_$`{1b&A_&|D+tPY8DGOrck7 zLUWu3?~*3?K63HMFAc$m0&55Uq{b5t7PlWDrHbEST@AS=?{mk0EutPzd1A9JLgo6g zk@~njYSQL@Djp}7>h!Tpf9cekr)%}QwL03Y1F|C=(dNONz1iM&5iAsKUHy$C8PVth zr&xyDxbH)^*d|)h2o1Hi<4;OFrdt(zGKHTmP=e-XFdpOWN^_n>`ErOegd?BFxrd-P zAOw>gHXeemf5>wYi{ifHfAJxf;;b97I?mo?fuyc87b)v1S9Y1HP1pl#*HD{4Cb?0k zze3tERw{HB75bxyIUlw>8^x8$uVmaro3TQ!S8-G)6j;U3BZ5^7iG{e!2q}Q5izcJw zM3zWI`NZR(Q2!rTFn56knNae)f82K%)^JktILnFYz|nG6s#8wg*KPn4g_?eM9`ASO zfq4W+&OpLZG^y*Ji$jlC&2-N@p}yy_CSuoTm9d4X_KR{0>#Rn2rgNqmDZe@DIr(iGPTbsQb}rhkjsP`?X?7kmi0I#$$QSo-#y&$= zJho3(u?+VgJ_g7{U@;(q<^asS*VlI9F$X-vWWBZ%7l~1V0-VlLx9r^y$BwO7>_$g; zDSTbsHh*>J9G-eRR0NREX%vJ26T%MaddS6vY6hsXHO}+AKO{_y631N`f+l#>Y!8HgR8{RdlkP$pSM2;itrolezChX;c zedO5j-P=}S`gr(+z1%>b2E)UP0Nih>16Mg}KO#9y#B!{TctU!c8QNic@ldHk+P7LB zv3*uwq0ISUBxl0jZ}408-ZTtyb;&6yCP=e_mz~-R`%{bY{zkCwYps6U%y@n@mj)U) z3ctb+jypL!`6e%k?3|CCeJT@k{mw14s7XRlNy~fj!+M;zTguOiWzP01!m1LqH@2KJGhxMoxzJ{)U|guQ3W6toXxdNW3?y!$iIC<8WaW z-eHL}@ju9;*^ta;Oat(?$`bVf!Ws&yTAfH){b~FW{~`YQ2f~-LViPtGMgRRHvF>{S z?T*9P%15fq5lyiULg>CV=*Z^A>8&Azox#`nO4pP30x;38rF>d`qZ$lJ;y4jBwo$D} zAdTPgasJjYIniViZ_@zG+h4%DT3j6bDOk7^j%_72nbE>eao{iulEl$q)XB|Xypis| zpZi3<&Jp@!j6Sekj&C?AtnJj4E#f2)2YF>y{3Hr_h!<0Nox=S6A*Rfv>|Ygs74gg4 zI<vKZNxp|>|G_$ zvXZYMW%~or1&cEq{+`3%#9uP4 z%aL%0Gus}u{6Eq1#~hdPUn%mRusI6p)>nbZn=0V z2l-=@Fs=N<=64O`pHKN;fCzwFq$j`snX-9c=k?Ny3%CjBahK+J(_e7}QgET+_yBmWHVDvzh49f2 z-p>Gm>R7sPjOj>Dpyu)08cP2iTCPU>n~nAzC6OrWL->%5 z_cKAXC*EDo=@Z;SA|cslOvzzPR5ym>^OLKw8!1CHY)=F zhWBaEeyr$8JOO*(FK;b`6Ss82@KPir;K_Di!M6$U9%CHGg`6QrU5i=T{LVR<5@nnl z9o-_MtkL|gMKI&9=-UxffIsJZ#qi@r@>%fu@w|uu2Y@{4IB~}jEl-Wd%q%)OCu4r+ zyv(xa83NZA*d6HiBFze0nh>Qc%^oO}yJ`Ltefgal4y3Og9I^io`kFXV^p(pG(nB{r zsdoA@q(2fpZB)02lEn0Gn?Mz=SJMFYpX%$aU;d~1TC)3J>#G`l?GN?!5(uatNU z(?)xE`WG?Rsgzct-TOIOwtJ`|JLbBM-2^f|nBvzx{m>|r>(w<-v$o3Uc${S%6)Yd$ z9s3>Q;SsM2PT2gM^uqDzk(jaOaC~Va<5Lhbe9rLl>2PpJk#QdjnQ5t>BJo7KW1FHW ze5wXXV`Tr8*@e`x6x@YI+y1oS`)oTg8xV>$>W1;Uv2TNn8!y}PVGE<ozhl&gcmXGe95yAPB(SOJlr{)d0%2V^$ibT6E6tFb@Q94l0 zdUbZE7&rNQ5&T!eX|Zj6JvN>kr`b@z!}$2$llK|AWv|KC?Ad@{C2DZxeYM-Nrf6Au zd2b)98+suc>dO0o{t~_t^STSvSsc3JS0RAN#<@um9!(_DXj>g$o59Iryee=WEmUS( zSPVF#WCn2Rx|m)gBZ+pm`5eohAyI>CKgURamY$2Yq_>|bqqY6ifsAWEf3Ck)!bSXt{WYMu zdbp9p)dq(}T^ z|6zZqXa1}GbrA_C+Fjzd>}hd` zuDtiqf~CK{3LetS`+?!Qq3c1$mG>Xo`@cQDuB2J~@9lew-TD@6y*EGpFWPrs){tno z<~K*It;AKk@;1f(X$i&9OnP~@DAV#D0y3_=|D1hiz!(09_FchNB-%A{x#}fu-W`wL z6ZLhz7Y-cyF@hSq_M zEAKzFZ`+^qWQ7}l)$uD2>Eg)^G?V|mz3;cVX-jVYC-y#&H6+??+Q%QtzoR&CSN=~( ze_%lfno2MKws&gzj|Ul7{(sKibK%ndLwkROtw^*x(&ehZIB?hAYotGrt6|{(0QP>{ z9h!}4!27S-`#us*v>UaTKWxA!;=o;b7rHH54Ia|VyLzZ@s2>e=<^8AZ-H$i7(%Snj zn#up(-Vd?G&ZzQ#WACFWFT}sQ9r=gFp}X>bRr&)Jb2ZwMUj8LRwEQPCE^yYn|G?f) z;Yva0gZ_A>;3y0!V)?i0l>%JO@@H2Ho??5j{^9aBNF1nZ`3t3IkiWYi37fy)uNQD5 zRMx+M{ol2J5{CW%!XL4J32e=<^SjGf6KpP|1_Kb2lj7^ zy#zw}AK5?U1^fTmk$+emyet1#rGJS1qb=#>UouF`e=_5SH1_`o>tp#CSpGwQ|1w*V zXjkBJHC)`NYxOInSCFf6@P7b*KWd<6V*&8~tM-1dZrQy*Ir3gB0go&1Vz*@$Ak)ix z*=@R^C!(RQy#JKFpSbDYu=mC^#Q(j$H@C%pg~S%vS<~ym*eKi%AG#uF?!_t@c8s{U zNN>T{4zT^$?xRXvT6rehh}YxWWJJdCR6jtB7f`@g*RigT*BQ7N7*rWFoPpBd9J~?8MM|5F*>0zxk!^*FStqUT5>7WIOPd2pXgEG$74UX zgMQP3%O0WBYkEt+CC=gV`#~E1^T$)*;qFu5N7?ZD)QS!N$RESY7q+-ys`p1V{hq1q zsZamd1JMtp!q;#ACY*zk1=&>kt)KkE_J4RF_<4_|z}KgL?}6aU{+Qpt)Pu+UktR=y z;I(uU=QOGzuj_;6xdqf8cGcu2g&i>4M)$)sM$qPQgbOG7aQyfI?*GOEPcHRgS2=JT ze*6_YLLH0~-B_MLlVQ(TU3Trc4GG|)0iI7flI{a`Er;9=u&y0|(9jgQyvjR2AyRz7!dBr#Snl zR_snA^Z2eCMwMdT3IykXJ!#w|BCUu*hH$64KcPKsKvT|COVIJ0(U}Ne4NkC zfHiEzDzDlHcKTvjeh0dbecNGLafX{KdNVNtbyzzqbufD%}u+U?h zzCaMZaKmHaBLGj}oJb}ik0}d|Py%Y{Qz((Yd4|m3T(_|Ay2B6du$OsOj zqaX%8{dq4++U){KwSpxyTeS$|kv?Rgt++-_m$A&4MYsus1KW?`7vF1Ih-aF=rEJ&% z`1=Q+lfP16*!;cZ!Tu}$64k=raDo0q{zh=$Bw=&{l-f!?#*J$PF|g$);qN?_>=egL z{*vfM_4!*Z9n1LbVZc34IPmuYek<+q6<6}P_X|P=^B>YGK(A=NsftaM-YyMnBMOku zqG4E|%@(PZICrTJ9r7e%@j8D+v21bnfD+3`sSKXtZ*754IB}!GaUp-j&#+;8W2zG| zgWgqzx+6LEkZ3o2v!l0jFjnBUkq*%40Qcbu`r&y|<3ezk5hB>M9C-OL5vzgT}d;F z8%t(WWP$EGMLDk$suxP+Q#I_3xoT|}lJigIL2Wt;KljR}f)i__Ji&p@={Cqz2ZTNK zA%eWbC)jWnN_BWbZCYBx9jQ6=&>6@k*SQ^bwGCB+$Mxl_&ucW$|4|R7=zrF~p?{p) zNUQ(tAoPFH|JY5g{%>*he}nt*1pN^DzZ|Vj(f^eApU{68jr#-r?|Fdwhn9b*|I1N> z`b7Mtv4T)n(iWiqnOgtbMgN6_>V=Y2{a)fxF-1rW~xVi510vnjyhaaY`YBQ4FvBRd|e%8VA_`xYdW$3`T4O>~9%fNyNW zXB-edN5g-=Q5u*FcnrQme;d-jr@tFdL4S^h&p@t`4gd84;gyDeT*GezEQBTWmmUy) zm4+Xx;lBnf8Yu8p2ZUds;e#4}DPaFU_TB_Osv`RrPY4Y`!466UnBkt9Is0|L6-%KV8$$Br*OO`dT-=ZW7FZ$J}VYDWs0*_CdJTz|u?+ zPD~`SP>AssECIFy1{z}t6{mc{5@|b5CIY}4R9j~Bj$BY^vYU+`xoJ5 z6Sdc9=rq#5hCXT< zAI=0-6%zH^FS}42vaOcvit|3F^)PD9#~lvn``yPdw>bj9k?^uF+&CeoV1#G-r8@ak zN-;dW;4d(x`0+WE5G>*1elL2`lsem%%)HdsCp5+4(?4eB*X))M&= z(<_=B2h3G1P_Y+~7{i5BwNPJL`EU&6*L>C~jR$=(57L*vPX3ymO`lJ-+jEbRAj2hI z3I3J${M44hfA~Xh`64}z21#l>ve{Som%H$`d{0;4WsXqv12wV^MPOq=s@hC z{Kxw>h~z&$x5$%zR^}P+=~Gu}>cTT16fT=YD8s#<;zl%t*%N6R5;Mbb5K@b0@fN%w zz84!mhC>A5h|*62b%}Q`Cu@A}R02IqM53x=7q3`t8SGdH^L#ic~R1_PCRObXj4~Y(V z!2p$qTOWg`R$`inD|dOA)V^J{vH-W4*Dd322hOmm8QDZ0lw+Hu`Yd;ntnRk z!sOrXMDE^O?gW96!+VR*1`Z?X)aTjHIHR$LQ3TX#sq_mx5m!b-)2=jhnNP;fL0I_d zeHsVOh9(&|4`me*L+A26AQ?2<$PqS8L@wL7hEgXlZWU4X)$5BID)et5IH1*lo+Sr|3qRti@$DQr73A zQc%iDijH%0)lPI&2~~Qm8Y$@JoA_&CK;F<+^J(l0@l-XX+EcZf75n*F1@{SGTFH9dad-J>@%PCusCo^)8RnX zFex2gT7zecseJ*N_d;Z?Z;2WLuGq(o;$H&D*5zMlbGLsf09gnAWjm0#{D<*Bh$}X3 zz)^O5Dj>i?OW&uF;6G?p{-e)eH{n0)t{&@onWUnRS^lGl{u!?nH<38vX+R$QoV554 z5;F(Of1shk4dAY{g>137xe@*Y@5^)G4dE_uc%fS1;N6Y53p`{?-5*kM8zK9s_8;~o zK{LTXx8$u47@6=Nkg0Fou*8xI&*qOY{PjZ!BsX8SSmGQY84 zug4_!_YaVRUFIKEKa@E-1aY+8M9|+GAx#YdA^Uq1fat5zqpU`ROXb<$`+~x53+V5( ze-xjKvSzEfYN+&cXL&zmFGDXbV7VDxEGX7}wy%^Sm?wSq9<(yKt48a9=H1JXS2~~?~@*HRf?VjcdMWn@~){cGG2&~S9j|w zFhuuaK@l>@`)OS7>W)iJaLT(8GDMbzIl!!0&L1ygTLWcWxk{Eetln&Awap)*s*Br+_}4C`xw+D|j| zvl$jKwJ?$49?dYFsBI&p(!aD=mA;;-ZK6Bd96`-6f~aMh;Z2*NoTfxfLH5)7~{eqYA)Ou02t)<&E!%Cta&2PZP@r5Sc0%BvZA*$i8+MQU~;L)&|z z*0+fINJ5e9k3X_1{Q^@z6Ww_Ze;I_F>%tq!9GJfm&o66r@;HLHTdLMtF;7{}jXD z+gWsq5FEadvDfvq@|8&Ej>)_AV{AGqeDFcnQBjFD?kM%!B~9vKazyGW0D5miQg`6$YMd@J$AO)WEY1Jk!844Lsez zjRt1G&id3Ec#46?8MxNK)dHK9&ng4R%4eAY#!^h70jde)8bGgn8bDS)(+uDvSu0g6 zs}=xS3?M6?D-0kjpG^kHC(mpH4I{;0UyPw}J!*z!!-cP3`wES`Wg;ZWN|&b|k7_*WCNFM;G<<_l{0o*0-%2?0GdB6i&$5fad!&?} z%fUQ5aXal3&OUL|y68hGMr;l5ONLiouoCMp!(|1Aujh{R zvgOKA2RXul_Md6%%Z_&<*~MlsDFK$PDUHAQ3ObV`+1EiRyLzU+=zt3EUGT9Bf?8b~S)(2q-%VY1*Nu0UK3SESR_ zgRilbz!QV(T<@i*pgc^%9u4!x!ZF^8ErUn!^pui8TOe@6r;+T2cUa{5yk$VhS}}hk zo=ce=$&S6DvGWXeCVu@PTuR%%y&e?-@KpQ_7nfZ|#{!RJ6ggWY!Ch%JFIcNJ(THRi zXd+TU&O7|3$Rm~(@jR2yuvDXFijWEWBDEq5o(jLfPSx1!fCY4`hQ@2?HbAr^>(Am$ z2doCMD?rc8oH~^Ghc!X zNU5e2sJKcK{r0XXe5i)nG<2edzSYn$Kon0cQ2a>1Y6#+A2!9%V^d$_Eb`I*>A=)m5 z7{#QE;e7>smGnJsyJV?VG9=+i4uGMv4dQ{V8F^LG-KOP@WJlZc7>dZgewJ=tB~o4V zG7JwO?qr6#LL{qeFsic^5MV11RiG7gX^OW3rm5ojy0=l77@Ztq^l@a38$CPYEr^6M zvzU%g^*HU9!?cK}hw+4I0%o_de?~l4H*3aBVT9AeUOM-ORw&D`= zG+dj6$4nG4Es(wykGXuLnzw?TYNr^&tso~XnR0ItkD!I2OW)CoY9Xbp=i{P#Jj2Ra znj(i3sM9)~+Eb_YL@H={X{fV?dIMrMy81XG09dUxYL*k6t0D!L%$!u;{^&@1L?Bc z+9-nR^B%PX)}l~xdfmU~i4mlKEt5y&GF@_k$1(zD8_i30z&8Pg+83^p{&gIqFZ8cm zG0e{nzwSMnMA?5sAj5)Bk?JP(uUaIlKK)5LBaeWLTr4XLKitv3 zs2=t1Jl(%2Ozcb!>0eD`joaC?iy4-xkuLY$#rwzP*O40(JeDl>Pp8NuvhxW){HA1w;f|GrL3H*Q?f}Eyt9b4=QhXs} zIH)a4+j}OZz`~81=qV5ZnyR6vHFT?n9?;NjfGC~{U~Q)ZRzK3`MT*b)m&4x7K|LVO zaE@drZd|zZ(E>hNM+@+*ZZg&?B!XiibAq+Dz7+4KOjG;5V7ws+wKtRp^vZE$jaw^w zmM9gWAk#6fIs6%lp2^gR=XLRXa8U?eo&7O@bjwWB@>+-m(^mOK2d{4j=+FR6|}3ov5Ks z8X5+O;&qkLya1~aN3 zB=a=vBTIFY`Xd@on!2G>=SD!rJC+p|UdrLkM3+>LszB7k=#s+3!sL+tn3ZT@&#y}% z5?Y)M0#|?ByhNksF*lTUru=r;9}ysO}>gxCZI*{#+&k&_A@G)ctv0+`h}?5n_Fk3;L}QFx%KyvID*e zFzkEgn_}Pn&(-#Afxy&^{ z`&)USza?wjI-XfZ^=U}=%Ke27{f}9w?UG3*^v7152%=LK!essHKnM<(WD(D+3p95N zz;^rNL=@K=ALSADP{I$@OLizT5LBqnzCN!OFzog0>te6)+1g$!APDxFNhz>Uqb9l; zM1ZDh=oSs#s-f#Obeo21G&D^^V>NU;AZAVVu!T+stX`)7j1(86VcWK3?&@4|tTSZs zGP$n~7E34h)kf1-r?aoVSPa==&u{QaYz^zEg5dHhY^Wx#p%uXivn8XuRK!8k_${|1QfDjFoI+Ud>LTczgg^m&zai(O%Me8S5pcs zUZsg{1`(j48oEV8Cu-<=4GjZC@w(FRFM!or4t$Z~lh8eE8#4!Wy^M%+@(9pEwNgmw zujBY=`s+kIt1}MO77`ltSE&drl;a#dnOoPVj5h_B_NMYcZ%UbQ3wd5Ks;@$NQh$Bs zRc)7%WI}%}liv>etB+(6&klyW5MaCgb?bJlx6EHMQF7@NCBlz&0m%;i6f{(*&K{iy zgs@j9yx0hp{*1W+6*n8)96u=q7Ru5@A1%@2r-n9YsF#LTX{a|Kil+)>`~BE<$(g24KFU7%VG+%ked_JHPv%Q?lj5aZB&*?t+TsLc z{G=*i@jEzN8V^nNsO%@S#VJfIP7aBes>vF+cy=drDjGA5>8|lJlW7spi}OhW#d9^@ z(I1aOdVKtBAr@3y<+q)9cwXGT%j6LZiVRS=C15ry1z55Jz6mhwyVqi|@BX8;eP=@9 z96u=q_FbWge#5(cfL3a#O+%|R^sRW_PxqXUluNfS28Z-@PHI>{oQ>rheJs}^9p{Shxjf>`?F6nO*#H)E(kGE%@e zRuiz!9_fH#ugeySy~3w!do@B3$4^Rug&H-{@gM>;RYNCe=vECKqoLaXQ9M<^?4|=& zchdDmig$xgvF*hi)G^`{&4*cFuW`a9_NwNivDa8UtKAQR5R7m_1A9qDV6Sy^;eE32XX$Fh-R|JO_lVaw2J{PI?+ifKJrV0~#6zh_ZE+F}?v-FNztG9p7x@_~y~^ z9o>)h@f0;`$CtxGCkG>0NLEAlC+Unl0y0r#rZ80{7U(R;$4aVy{X=GWcVHdv)`u8Bc9`)#SiSKgdH9UzlruM zAVqk$yG~88-_~xn{W4i<+Gd?d)-njUf`&Sl9F6_bKn(kBk9Qe4&Izm7FH0k~;Eg%U zem!;4CM3ary)^WRhI#{{Y+Y^47Xhnn2eYWj_G>csTSohxDn{{~f3vn9=9a1Khlm2- zVJe`!8F>U`;9`YfzkZL!?Z-;0?)T~yR}>=Aev~fuqX@BIn#+Eh=V=4XWFFQuBEf!- zO75QM^CW~1BIp>;E<$>IJgXHk@Hbjq@_eKPYM)2rY5%xP9wBy$ zNO9VW4*ysS$!ah0dDyQ4z--4!A+>+xqvap*thU=v8%=09o-rqmXOF~<#x(WFgT_CC zOZ!K8z<4&BGUI*BbNdTg^<_v;8qbD`2gHP$Oz264^4sBfRzk9f=P7zes5cj2it&uc zgU6XgQcG6Su_>C&B$JuKvCB`PJML0He?RuX=f=9Fk}^TiyJcg zYw1H+1;sj{?rinY1)lBxgxV=0Bc3PcYRjw;F#A4&5zj79G8LORA_3h3zlr{G+Y_Di zK!<)&g36cy&&Nl9dNWe1B^CN4b0CDT3L0UBQg?JC1D64Y`96A)JM;5(Z6aDVuvnGG zE&vwLPz^2A(1{v)UPHqG(SEwx80-j#JwKd;PK?dJET4G;C`Y{@<`WNU_65U1?qf{L zTR|TR--@##s68F&#=f+iCnuyG={y#i1EIU9P_AP|Z8pf%0eNIaMGBHi>Zbd)FFVg2a0Xz<-OSuvUj~vx1q79FJFsmM=Xzd@OyQ9W2YLV zs?%O9jRs_Z7X73y6YoL@!c*|71UUerm6@7Y-GmXHEtDmahQs`%;mpK?-EeCAkD2R1 zgX;k+jKI?r&rp079j)V7`NjD|JVJ26*UT~UWnZgVJx@1J zdINuN%GYGz+YMfJtsyVl;N|oH;3WoLA)Egw|4bvF&4T#@&*t(dv|icpSuh*>rTEBQ zxpx8ljC{1_HgJ-HW=~CVzfhdbkAU~Ly7U;4GT;i{c9>(+Kz?=ZsYj8Y4K z$WV;LxRsjXSwq3GE;U6HD0susIA2{1x2D9r4f~>G3}ffXXo&0lb+yg6{k-+B3I{&p z(hh#P!P6DmLZ9xVg=R`Tn=JHo!?dg&q3aEPWIOy(gO~Xgzd_(C^frT^*A9O-+8mXh z*baVYgXjF)uGBzNsT^6*NX~Re!?dm)p?L;B(<$`LY+aJE?Fik&Fv${Hikco|@La63 zOS-`bUDl4!{S4ETcJN0Se3Mh?c}8ds`)7)h6dR^>?Fg+f_!Ul}zx2}8pV*GjGQ-4e znN*op8GMUVXuT1-tR1G~4AYc$@S_aA)hTqk5t<{Lv&q&+_$*CoT{}XtM<)0*^l#fx zxmNYt5jw^&m9&E&Z}3@8p&PSwPRrV1!U{%(SKfy4m zc7)z&@DtnN$7OPosT?IsA^#DBFLV}aqN(Y+c7#4)n5MUbf7al0_?sfrg$A$M;a??q zTnC0D-d7C3&>jxv<*F{bGB)xQ{Zog4g(M0saL(VX_oKs@5E2_HE+IEwJ}wb(eqJtq z)jbqcrvaRYoRODL?9Llg6;OS~ac2pcwA|n8h6O{3ef@RpfLe;#w`@u(*gfQ;CowwNr{CAOg{M z_mHO%tRc@;6fk))4@v9Kx|N?%KH7f2*dJ!l_oe;8SsAhU$ysm1@mmqnS?HYT0D$K< z+6m?ZwGR5SMEatR=#NXJKdK}8{)zMlc0_+rB7JU0^m``K_Y!*RD#FC?@p>Ef0oKCh zL~}^1*DtK^^URX~2$6tRW}gK5%ns>yNucl1A^r9V^uOXeU%y|TpFt5X|HcmKV+r&h zc1Ztz0{vSZ(!ZHN|4N7SD-!4zc1YipK>uuq^h*-xU+9qj`2_k$I;4Lof&PgO>HnEP zKchqXrxWP!?~wk!1p28R(m#|ye@BP((-P=!=#c)d1p07?^q~a$t2?B>If1^mL;C9y z=*M+PUzb2%(;@xk3H0Z5NIx-w{(=ta$0pF9+9CbL3G|~oq(41@{)7(cD--AkbV%Pn zf&QQl>5oaEKeR*ogA?fUI;7t#fqush>3b#6ckYlrS^v1Q0+-2Hi@)kMF9Rhm3_rOO zW2Ftawk8nzTs8i4B- z>IegjBhb$PjTF6~5zXZcwX?yjAX#?<%p_TcA>%5C+PZ@-PA-9%0cMlzgFYI=#SgW_ zU}_1>Ge8r`o;PGXRix$`%nFh{W&tF-*^qImL`^W5LIM{UpoL`TS(y@ZtijY0=x=~l zl9gGRB2-t!2D5@>`3B$|MeS^5O0pddhUb=5R|9a?p}x&FH6`ZD9vY}6@SXuUk5F$K zGOo_32Mnf#WVaiD>on>K0~8Xt&jKjmCL@5$H)@Q*G!i(;09g!RFEl_4F=r59v---% zi^=<`!=;_E5k?U!V>yYdebOk^ej;D5h(*T%sosGCUd@8W*y39G(gkjGnD zkd*V$QMNZxyQo9-fxzRub*$CU?;mIF7k@kmk9GkF80sQEI;3Ar=>>88?s$}VJNAv? z*g1~eCH}Y@9&Pyq4D}v-bja^P`8&n&-SLo-i9FU#xLX5b5@72S02sb=pf5dd2)YM-8L*|?JK^UBcI>IZB= zl5aMNq5uM+Hnly7qet-WVP-nTWIDl_>6y&*97zGmIfmpyei+3n*8q~7A}Js_#*l3J z+Cj1_Nj{boknCYd-gZja24@m|#gg*NS6TrhoFr>VQXwg*psu~OYoHEC7WV#t*))jC zRqGM3svgnzT0yWPwBxO;DC2l3jfsz7}+YQMwOA6cBr6ieaNx96B3-jaZ2ezk}E7J-3&>VljKtjdePr3DPJgE=`v^AY9h&jNQusk zclrA`{nl>u{`ljA@yA(sgkj``@(t=AXjxDo#@49jY>wUu0{F|5v7R;dfJ}ULy6)?- z7?uKuaV6>+UTV0Kr+0FF8OLJ9DS%t_Uu4${4>C6p+{Upsoc+NiuyJYj$@uX$ESEGa ztHJ8MA(VT!`HmY1#zVsI-avqN_Vo<}@%Me@n#~`W-c82U7g+F>S)9rf) z@&wX#JA8jf-Kwajk?MB%9Q)pZ2Fj9q2eQCc)D-PTZmrfuYEWl-F1+=J_JR8bveJT| zNsh4(&uyeV)?vxtvd2Y-wrh_9x;(c%0vC%tp1;U#k2(l-+vDS||Fia(gfgg`kSUip zZF@Whb%+|cn-;f6QS~3T$0G%fx*2tQ_ zHT?r8E_DCMQFozT(H^x!wk^?jf0` zhd{B5)L!Y@B8MVymM@q{4=Kcr_3R(>_Kn-)q9SdN6#l9kE9UMW2O!vnzv_n{Z^N4o ze{~jwy8Fihw9NlWe>ECqP#4fUIQz#VP)1Rc^bl|TIBkrhPIq;Vk)r)F^9h-K1=7yy zrhOb0GqzAPv2{sG>uFZ!=nXb8dZNFY)|M{*>S1`&M1R%Th+{*gXF{cNGN|h!z(a6R zYnr{@5B&KI1LAnkU1ul4+gxx_0)50Y_2N!Wc|*`+tZ&GaVT*r64n92;%xk3^-dY)2 zQJHa!@|CU$o?KbFFqm2Ho!hCTOE9yjiJy=uOY=vLN%w~~W3Z@)@o|nT;s?CYSNeuO z^m=g5KxtF(9i9R5&K=oSvU9Mds42Eok1YCc?WBC&FKV8yEL}0mJFRI^qZ99)+tu8J zqf`IgF!Vb`!R0Qv$OZ4|f_u8)bQioCzSCLW zk6kbwwG+R<1wZ40?{~pdUGQWVJl+M5alu1faJdUEa>08h!jtfIur_`#sw;!9wwA>6 zdt19|A+rf_Qyl80uYba5U&)COdOy5r)ao# zQVzn*uEEYrhu|UXDH!FTv*IBM^PUy%a8K3?x=-xT-- z4!kD?zR1`YZ6W&kFUj?@>`DBR6!_A3`-;v=fnV>yH>ALyf3n?%aM=c=?v3z^`=RXQjYDVKl6{weS)9r#%(@Xt8#4Jq(b9r$xn;Kw`g6)EsT9r(Vf@Q(KF zNr89vkI%Oz*WcMcmZZRMcC?>aDex;D_=XhtXB_x*QsC2v$Ms*40>9o-zrHE(D;;=G z3Vg_c|NO_~`j20{)D(aAN<~>Z}ZuuUtjZK&dEjK zOm!A`@ztJV$c8PL@X1*4x;8fu?w5}ge}r%0g$9=S!WH-(mg$dF;`eGSYi^HZEP8v! zSmkKI7S6z&U>8hv+p2QFfJkWrw#IUgrR0J6NGZf`VYs3sG!S3N^{hP}hzLkSz424! z^GrdZkO_FRdk+$(GW8RxfMWp=<&Urk8EW}==~lTmKwg=8QAjqackydar}cVRAiR@5 zosRB)0 zgzDEV&atNHKAcaD)RalZh|)x5xuj`p(ekms^fTonpLeaV4CnYm-*E{bw5F}9q`s+U zr=libc-K72&*Z0obtd5F`B&`8qbOx4%6e>Z@wGGR5tL-HsiRqEa8GQjFMI_M{V(uC zVWqzXcf;E1(fb9vy|_0jvE|`l4=ynb;wxhO>yMP>V1>`IAEo2BuF*lz>bZ^X^$2VI zp=)%%_VAgUpLdOJ*ACwEalnI?29@YFQ{~+v%dexN>+pd4!u2NxX^Jq7u*nx5uGGOK z3SSQMXm~FT=UQ+tfd@kG6Y;s_on8`)g*IU!-yYpNv+~Q5!LjLx5fGR_87if*6np}?oYy}(9qk^E!CIk46)b#VE%!` z{A*19yCMH{=CAYO>)9DPb35Ou%Ou}5cD|P~-)1vwWPNS_YdPQiK=`~|NZuEg!po7F z$c!&XvW9p;lJ!0+5I!r%yf9gFK7cF>7+~|E@6z`|1$MFMweuJ06CT@|rCf8RTs+;e z_G^^u5smynBcHR8FA@2WM!u$zAscxwkkJX)ygIj$hF33s2@`}ijEX+|jbnflGoy4X zF|ws@AFp8-4Ft1g{Iv`^Dq1a4^!RAnhaL>kI7VZ&`h9$-FucFCjwAcMU+#f_MeeEq zY^fSTnlAnawn09^d7;=_X8x|nTT4C%ThG=ZG{fk8QDnpW(0|Z754CM;H7|Y!OMT(f zVII6CdgN}WvH-_{Z8HZrX^3Kg3IJAvbdF~jKQVYFzHd_Vw2Z4r&xt)Gho_EPN^70l zIO$I@b5E;<^Uu9^NT_L=pWu}>FZllvdqqXYxL zTJ4b?@aMsz1hgQurj$y^ld;YnBSd?ladcSU#qs*S$WzZ4MNy}W1`+Km^Dm*7?bbmLj(h&S2R2OS5F*hLCWJM zT5~EYQI>Q3hvti*`9C$D6|yN<<1uoEjMLGCo#RapkXZhDeZ`-YzXFHnZ21tLmMGjk z-jDgS^2fR4&x8UTg?G!}jL7>>=_ku2zwGzr-}PtZ&&EkJTR&R=A3_I?Dnuh7vGhOY z&&scI%7^}I6NS6=Q*=z+-@EY!pPbAj#3c>o(=I_1))ikLjh5aX(~;zc)QIBbr?>dpub9a zhXc@F1;Wy;^4i5a=noffR+&>@>K!-*sBcvCUY66=+lPSEqxi%7Zm6$siXHinhm0hB zT|~ilf&Rhp;}7X;$HW2+WP!q-F3wb_Ecz?c?eg_!`7)(^w!Zd95p8|#?ksOl6h_Kx z6>pNvuo4>-UN_)Jm*RP>M~>HE0(N&4RRW2e5)+93MAhM79!zfTkOjr9w>BO^-~FUlH(EGc~?lY6ra zc6qKZgzwu#eT*Esv|-H%hZ%k09rNtFdVJvv3$g5l<~Xp>*RU}j4Od8S*;=N>hK4~T8#2(;!AR?`|*GYR)HE5A`bBfO& zT703^3~`k&azQ3z+*SsIi~vVsUGZ-Cwg47BpoOFIYL7r6f~Y=Ubohpgi|D9>@^WiN zs2$P3muBFqfzv>Wt`;c$w8rNPAF9J(e%q(uTlE^OVz17Xu)~#cPUd64R|Q>+jCXfk zK6M*7V*iwwe*~6jFk^k35&s@AswyUK1}YiA^z~sH9Epu+262Cc^LW0Z*PFZ0wvusW z!zyq6(Ex{u76aiEN&;s!;e?$({q^HR-4_PJqf0_vD%0N!q^}R){@>7>zJg``P?LYb z)=rf;NPBa4@Ya^*dh36N$l5E@@zjk;S9Zz`PO7~!Be$k7`gfpoudcnaGYIY=>BRKh za~r+&cgr(~&#s-AksH7%zYBel^3MJ`g@bzAB5#>=_$c_$`-}jU5NMDr)P&UXzMj*7*TOY!+FEY5ZuPzD;HP!q}%+o~k zc zmg$CL+pDTmYync^a7OHzMEgCEV87v>*i@FFyd*7%Rgfk=z-}v|6Gi;OD39#YHe>lq zV~xgx#qkk2VvCSrbQdJ!dxQAUVCV;KJ8%V*I}SN@zomO`z7zF}3~qZF%1wg@=q|n^ za%rZk{RP6;LI-VX4u&+`9fpnytEwm7Pfsg7Ew6jf=hx1(3Ukn_(gR0MY@N_G?AzM# z`gJ>MYIPq-ZK9=}vvM^MsZzcpvwy>TthlrUMW|bp?yFmpIjD3?&EF0AM8rzX>8j+z z^t9J09ft$16}F^!X;$2S-`!lcl|+HiM0L#4 z&LwHlY}kbFDAjy`dSF0-Bi^8n1)w5KK@HE7-wi5+U&dE@nH+=G6<8g*I#=~Z5oA&W zMn1#oX7Mnx>7~Q4uMzsWc0gKw>D*yV|2ACSM7mpeGkDv{_yCk%E+Zv<*&j%ZT`{^Yj%pABfSzL1EEjV zlkcUcRhE7ptU{;&|F<`zgwFKZVK8g_h+YVh77-!Rn+zZ=vyYq4Be%HHm>&;L+- zsnFtNiOpJHv(|eLN9cj|-kg4aa=lmcb+F#s?OBN?;_JO%u0eY+>%Ct;BgpuA?;Av# z_1?ENGQQsXB#>sk7t@iUhoaPa?iXFMlC8<%pMgKcfuEHEKlu>X{L#~f6f?ao!^T0G zx&&;HmRSYZU}t&dhI; z#@9bF-~CIUf9bR4kF=M_1jG>b9&L$l@*=KX@x9C}bvAtlhFZiy8`KhUETUEH-5%Mm z|2_z9dig@@I2A5rh?9?itVHk7p7*#6LLZxmWs|A^cWjl2Wymsz!XWe?80F*b-OH0H zBd|bmv>Yrcc*9rlo3HfSpa&yC8G^=D!LniAxjUEaQM11WWCZ zDgB5Y(^0U})|!nvb~C3?5GuyLlN9b$Ltfq2C77fk7UV=9vwVMOSs@Pgdq-nql2%)Yv%=|}XexhGJHS@eRMPirTYn3v<``%9PA)Wx1} zM0pVh^PN4G_e*0Ku1+v;xAM(VxjNr`D_={$m;v!5429s(5$uc8F1W}gkhg;`wA5Fy zP<53dLYrGo!sNS5erz60z8&fWovp*+7TJuy<}opK)He00%VFyGY*W7ukfweP!V=<% z^5K5x>}>MaGuiOML#pLqjko?PTtY-Cg|g17_D1Ra*rThKG@KEezc+?59N59xEa;?O zF6ve_LWLC>Y&KQ}NH6W-I1Br9IH5*gQyOC93X+}_G?dsEFmzgJE4`IOacxJ(dM zZT^m%DOl+pEa5wt+Po-*)W&GI98|9Ok40BM!JOnqFT`TgkGOF3&Err@bOET>v(!B2 zt9_QS#)n|WDYZSFvN8L-Q}V#a*;yp3;Pmsu^66Q^c>!)qD57~#g&18a>6Il zUF?Vl&pna>Idz_@p3IXMvtL*fq($-d6KbKWrNgeqKs8{AHsTs5%!h#QVc~li9iL46 zIOta6yIc6~hQFBj!^J|As$asD_b7JpDaYdaqu1U5<|5vk!Aa>2v)JpsxBN@4lagaN z8&ow(UXm1$oMlKpHTK3yoeio#Nmfbb~}=2}>}04W9#du%t?Se`V>{HQCXfq0-85ULGd4 z-umtU;NQ7!l7$rjbcm}|TCkQjo>fWnUgg^_!i@`q=1;iYF-Xz|vs#zXDZSX1loojY)#_f@Qs z|ELaQ|3HU06u;C&Q4@91@FP`Sx7cU3H^+UmG|kz~tX;;d{H71!wyMI|)7JQcy7+vk z3vM8D*5w)Lh|*zoNmohb%u+i}*?hMfMwK%~`_V>Z?~hE%Qu{op+t>TX^m}l%APu6T zuOmf9eRT^23GucEH1XF?;?*c>^gSUq@id#%av_~Gm7PNt;-3In?0RF_MQRsO%Le6v zI%Cn;myY%Y_YxceS0mdjKZ?a8p7WW)Q?l4tQO_=dcCaI9;){r9P!fHqlm2=){jN#$ zJ38r4bklz}*j=9WOtH$dmz#c068&RN`fu3*o#n4jqQBBfztBy8QWCx2Nq?(FFZT0= z52I_2E`$Zl`S)!c(#`rq#R6-)%Zi`E0~jBIX#^HfhpXTYTN2Ml@I?8Gupj)=v?kOe z(^?tS@fJc0EXWVe40gerb&Tigmcqq1=S06pP7>b@5D($ZVtdKLv>(bpMa#cEm3&NP z*I`?iOF=C>bB*~l_5-jv#ZyV>bl1pC*XIil&h#BQB-2}e6M9O~`@SPR-4II$57MD@ zuB;YvYYA&fh^%=ose}%sjQ!H#|9O8x@J+06!f9QB|5__GFRJIE(1xa(*;s%>1#w8( zTmL0;^3KiT^0Jk*NRrY@7J8>Giq)h30UXaPdcQJUqbeJI@YZvKBoMwX#~(gHagU<@ zbO|qz6Rt3V14Ji%r-|MG5MAZbKv$-J6G-1yS^B-V{vd$<(zm_!```hGuez3(R3H?} zVRB?hdLV?m33>QrsUH_i^z@Z33wDR)^<@!%3x4V^eK&Yi?X{?($5*;Jm|OIIIqu8I zM^)CKOM?fcj=qUUY(8-P?`60{j6Fgk??;~iveQNou ztdr+braRY9=IZo2ZTgh!KS}c2kfK|(k$;Jn<8{j)uG0_y9rxvoaH9 z9fgf~J2zB0m&33%kE#a#MsC7`ce7tK;+Oqm^E83 z-f%;urcdlV%bt4UDLqiSB{*!5_tpKquU?D$U?Fi(Xj6G;vDyQV<)w>*Yk=HakUa$X zC8D+rJe4jQ<-NDbJGUt^D6P#b;5+=&sG=q-QTuyL<_lKBg_kb(hgJl$92<(YVg*i3 zL*HWKQjM4&_u~1M7x%sN_&@bO+1bOkp6uzBz^|kFK~BW6;|ebeDVWb<9vwitS@2ti z&-?TmsKFQ7F>g{~^hV?*<~IZ-go z+9`4pPC4){x9~ApzEaFuy!G_NTDs1MKAKA)MZPd+3gtL{@RP5g)mOSu@BWHdZv%Jg zd7y)Rqhu7FOneiC<7q|FMl@J|2-;p-vv2eYcu74F8v7$8PWNNk!H=y*M8)3vlf+ZM zdSJQt)d6ZR42q#mu=LJ&C|wj>iPYT%lS#}5+?Lt~_g}iiJEJMu2b_&8i!1>-Vn-Fh z1Y?2PBg$PHth&^q%(g%I%bx#(_B`=5V^2RG66{$*4DERkF&)_R6@*BC+4KK`{&_u4 z?MeT<5)TRX97_!CIhvRb?74An+@5y#)bXx8o5lc-3H7@?KmjjTJgu__V-JQZo~A0V zJsL6DN?AGD?bKZ{-iM3N0)bAy66r`d)lSIQ38i)dwzo*(vlDL62?OkeVkC%r+6LEw zLm2k>hM4jwc+Yo{d{j4YJ(u#1+Rj_Q1i${$U;N&|zxXjr$8yDpHecz=;4WCnB|Y(^ zf5p&0kKaIK3{HO?;t&0X!vUG#uEbTi-of8h7JLuK>xUBS50ol;&f5i*4;S)25DT*- z0t^H@=KzC=HKLjTTs=cG_-=$TzD%{(^E|lVt;fZ!X|>nF0X961r==C?=`!J1T9Jk| z;Kf;%-!!ut9sxm7ybZid4(BzZ{qQRzmzmGtP!B4GbvvX>5NsQ;7Ik7_)INxdF&(OZ z8KE%B`1;>a`bhR$B|M3RC=Sbk*$V*pLRFb64Ybi)L1@H~{|mTp@?W6&Cu{z&lYf%M z-vrudc_RPAhJR z68ZNr{1Y_)W14?4SnT@Gv-s1IKazc=FyoN$uuRni z+UT!XAhXMl5cfwF*5?))UITCRHxX~6ZPo&oBS^{_}$ow`R19mp2TpKF2_Fqv-51n`5!!+ z`dIO?FSOZLunlMW{5Vxt$y0S}p|wG{wQx{LS8x4N0wqImRBoAm>J%IeIHP8-*acEv z0G)%!4k{^64+inKQ}B5Fg=w3ExGD1loN`2W3oWa`6d(C4@YQYW6da4c89>)Zm*IopSNPEehR+CNpUPgl7mkQ zumNHzM@}<>Dc$lHn4h)E{LFggEqp1IhYh3j?|r41IbE7{8QubCu#CwW&P0We%k_oU z`U>90yW11?^rhpCDbBP?zx8j)lg7>k zLWss9$k|*3xrmD(L9+;=+gJD!Y_)Vpw2$v#h0jH`xGqt!pq#IPDSST`iwc(=5lH_S z>tW1Z_CACvNB#1&G^Jh5#B=SFrq#!8jIXa()c+9d&XZ4l%4?6x%MD_8GJ1}qeM*y$ z4nvBrFDCHlq?nY2ENRihfJD@*?alo+HfSiGuf`k?+o19&yf3mND!~~A7Lvn*b1;4I zm9DsKfG_e@jrfgZVbTxo_2!sc-gJbHoz?b1ufzqYH9$XB{#A;P}Nmg(_)5+nq ztbT6klNkD;=rEK>*7KS$achP#O#h0E!1#!-G^`EwNm^eD;6~Gj0tE~GkpnOd`{s&c z{Aio9K9=v7Sr}GQ*fD;ZP(m}5uDAlX$e)BJ>GXA`p&NhiM?8e)^?mF`-5&h7dDiMM zY8b4>EOL3klCz|^$F%B2j7z?2zf_;mv-UVJHQmEk`m_7I-mmDFh?o8koY#9!OR~=E z**@QKUZ@5BhJCA5R)nl&AoSF}yLa)VE$y1NbVz!xuX#ubx<(p)%lK=~-g6h5H{5!T z>*YbeVfz>7#2s#UhR~3FIs2+g=xD-+=9v?(zQ~1DI0w5=caMGewYiL+D?v9{2>qiu ziKu~Pl20IVRyEvI75)2sAKo&a*-KG8_8vQ8!DG0FylqlL7C;2diO*LUlh>>R7+y9URdK z*hDs3v*#b$XXw@*EWm7GVFuo@Yee-h9od^I36y?cvzt-Huh2g?`C8b?>^3V$6;@7R zX(z?s-+vm;GiJTN9}WG}RUXfk+a<0S^X7xIKm`-6fx$2wqbB<1gEA)iQ_vrx=^rM& z%#g~!4HAY0Uo-?jC8aQL|DSI zh)(jCt`@qQ3OS!$i9_IzV`reKXq9)ax2$A&O<(Oet@ycgRWJ;EuqPtdh1ePBz7vRo z3V*!!EsWj5GboEFtg9et0=9kWOHz**sgeAWo}?6;Y8}8J&|0~6=khavB{J$ zV`20%G+IafxL?y^{FviKq7uaaSAO3a#xqmi+9T6~197%@5IU)h&zscCkJ7s@_C+c% zd0ZSkkDjNnUH4+@M=x>%3)sRin(j2%m$93~N=Sg+WgS!CQHX)#vYUdpdgt~DM10s0g26LO-l!=^>|cS> zWthm)=5tT#f_(6L3EEUz$s57XOIC6f^H|^<{)lf9IQRdeF}%XyYA>w`@ix}(5!fAM zob;}3oz3+X7r?2-TLb!~xyPiuUi?w~`iea;sKnk%HNNsAGYB8H`U}33n+~}Dg7XdV z6a754pLi`3omgcuH>`YM%ls4WzHm=yiP{gMF$QMJ#t~i%ml0EaAkHa!CB_q9Xsq>8 z3FGcU^JWQ$MvUip+sztYP zjYqVx*qbcU1OTxGcD&~Bf6yX4T zgXknR72Eb}XMF2Uc(L`5=@23gHRnN8=TVe(+`e3q*rW~z z0dDos8j><2@d+eqH;4NEDy5J&lhlZKQTn7RiuyrPv!DFYD#hh2#c*L0BlOb}lpnwF z?>t}k8{9$UlB)8P%IBkTw_zl;j@eyO#r+UHXTpm>I)K6h_Z4ySaih0>Kg?%zN%ddZ z!9pCSnCF}9_&dy_TpMd}01NWvOCFq%`@$pP8Zj#HXbPv| zt!)D{B{K1c`uIaSs*Y?)W6&B7c;XbloVJ$*m0X-}epSJVX_eCMi5h*x4d$^bR zY902)u-5jFNH`g-1v_v!LyE!i7!0r!$$c9dkHWq6+@ly2YO(WfI06Yi>lC)Z=x+k& zIxsoWUVw^LvG~n{*#*{QLo;MCk#H{QaH|BMU8(#`(4TQgfR-~GWVe-*?E4Wm|V3= zS}bQZ7~@W-%4zlFPqAdff|P=2#pz#v=X)$zs_4z?oCvE9%FB$sD&-dCS*lZOqz1*s zc}7#}ky)&gbqG>*X6YiuhuZiX1y6-N$SPZ!cnIf0b$!#z}ch<;cbxoHbP;9*;SG!^1m5}I1vK+jEI5gG??w?zyrQ>_mO|9MDz z35(HSLSSAzl^w>&eu3k#`1px*n24u9(pX5|rGwIQ6KZrTlPC{NJ~05!YaODwW4JG=d;|vk^5H06 zl{q*p?koqT4}>S7qStT+**VW&+U%{bK&l_>3tP&)mkz-y^~B!>?TWA43R6t z`}nbek47ZN`@+0`Nh*VJ4Q-j9ZDZFG^-Rl~&RH%%YuELa#Q{mSsx=hcGH zTYmui1w``Dvd$qF%d~w>hBZji=aIbimkA|`00M9Q*#fbw^sy#CDHXnG&pgWfh`YpV z;SY>^QXb-f1XAe;=6VW7qLKM|Gf^fiu#ruAh)y9~qL#_{=DF|(_!s(rG=$^!WUnzq z#>J#Tr)o#G8+0ODsG4v388}|rSGYBsii!i`nw=4(rV6P+AAPqq5*q&p-+Txox9z19V8n(1x0pCqL#YZP^C)Kt2{*gzc7puBOc-$ZZ2 zlc3e7UK9L_@kg%rH%C^62Lwuw%JVk7jMaL*1~G?KsoUBbgf;tMw*)N;XXkmQpen~2 zP%ttg@|kITUM74Ro2E4+;UJ~$f)fUW8cbx32aYvZnqok5z@5}Ijx(sErsD~IXB3Pfi(8<_BP%Tv{x@63Y`i@$J!a^H!<1z6Tfs;6XRI8q0*o z6{7d!&H6y-xGXLfT5ryu05b2~VfxMaBLL_(=gagH--m}0^qce3@DvCwj}_?lcEs?` z!BI!>-T7OAIHC%)=gWhBcOIWgg8Jj{&ZB7||0ezJ{1PJN-TA5d2~u9b6YfNXaJ~M> zQ?)2$Td7=*IUBU2&I1(Jnz6f@Yx6cG_$<<3xHvdC(3)nR(p&;{`n z`CT579gA&3JR_T2VWKl6PCLW3mf6 z?e6s*Tuh)Fp4ETqnmR?-!o>i=c-4>nplCB-gAYUod!jGIVbluEm&>tu`XT?4ANTFr1Lc70}myE-O80n-f znE)=%9PtFM8Tu&$S6~Fs_eUn0y}Ye8|B|Bo=BxV+RNcUdC&>N`^mt0IDboci^x+bU z*dg|*Kg$5PJA!?);cT%0cAR-r2_El*keP(fm6n`a#+4PovjNqa(J*iBE78S6{-&EJsnl|eq!x?%k_4fj zV)a%E$C8#t%)`4%Zn#ZTeiy~QF}1^@1)4}%Nny~-hv@d`LPW)IKj}g_Sm48*8%3P9 zpk=%b*Q4#rqloXS28bq{uWp~poKerOqPq$)@v%=ia$SHzF}9gN9fv`TbB>6R@DXEm z4!ELw@pHyFsR;KI{X3r9RrRG#WKOgipyhAdhs(q`#yi`np8= zAizL)FJI)+YBUH{1LMe1S1c1OR9C`pyoiAUiekK-j}XDvyb#)IQ#0T(Fs48+$8V*I ztI~^pU|f74SfWQtlK5ZD^;fGGZlSIr^1bM6_E3)KT$%`CA;L>LOkT`*z!`m@O|5|X zo&8v+s3#~aQvB3Tx=oQvUB$p4GDlcw!G|c+I8h1QSF7;NNYZ6EK)i$&hxW#HaWSyb zPmylfC&14Lan^&#DSWgn7XHM=!md~>#JmruaGQb$V=31c8K>9qvPxD4ca7y+{8-P` z?{{L^ZpXBel{Gu?9nUBZ^J}+?MZEj)9KT;&?}z_C`+hlQKlWxp{uWFr!OWFb8&Asc^j^xv#|D}a-tUkl=T}cDN(++;oL;}5dmA&L$%$r(P+6n%$m1q83*ue*r;FTQ_7bmZ!Bx;|3RfdH&}JrJRi;qaHJeq;cpItoKKz1CtG=$6F3 zvd=$=et-PCu#Ach2R?Cq-r1fX-IQ4G8+1-;DSyMBor#XTJX^+T?!mECp4)7uI$~6Y zCVog0*V@E&d{m#aBw^1|n+Y=N^p2UX(y3%;mCm|}W!|JV-^O25N&6eAPqtN`8-Pr# zPbzz^_$IMlPic1bjsA7Dn}cB62MlOr#?_4T~Q-eEJj^|c@KqP`9ZQBRxH0*ORyeL=L}X6_pO7+N(o(fS0w z0C-(18nvr>MKq7zm@lFd&o{CE)v{ua{&$A7KHMvy3;USVyWRHti5AcHdodYU_-m%< z!gsa`Z?|8TKb~FmkW}Rd-dTRHRsOLO8oA4lE32C^IZrd25hsuc-+{;U(6t$ZjhXHk zlu=cE!a?6mFU|#HZL`{wobch>*={sb9WGfeQa$B&gE|DiiTeI88XwcXhED%2<71zg z)dDmA1IEYsY~4Ji@}V?yj*llxbF;_C?iiqcXMEgzBfAHBa^+`6s57-x!zQVC45rmhT*Ya$RzN!m)I^;lX4Nd+t)G zR?_&>+h)@Kw2n++Pacz#{pmRxJJ@D&`_uPGK$rAs9W&pg#>*gR`%@Wz#y1cLdvpP^ zV|(~maEHI#%hc-<{p+&JvoeZ^T`GlOliG+R<3&=9Z|ciL`3rUN)DC3FxGj2X*B_s# zsp*eD4YlX1fBkHen)xIl^L zI+^kx&tKesMl?#*PCRt07SHnUW|jW{Q~o)UV^Tb{NNfxH4F*2Ze$MvT_(h^#FVH!u zx%|bsaH5miW1Y>U+v67I74}Ti#P0F^U5%YEv{ck2^`0i_~U` zR&b*v;KcIk@zD|QyUKGPIm6k%eDbHuGoGBT^4uupSfs|7^3>rsReAm^=CflzgHHb~ zmiX6UOV^+0{5+50E~`@p_gtH+#H34I|R;jMwMXLIB5yFW`X_{YxtUT}I)K z@nIj$?iv@$Bvrx4#Q}npzU|^RQ-6%lV7@FNtoy{Jk_a$De!o$nrmNwJ!gmN#&RLA$%>-Xdg@A z-8*g{xvuhcG37hZ-|0k*1|H&i#AH@Fw|2onof4`LSYvb~3jQs3m z`Of$=%_Vo$l~QeW7}@dN+V@edr1&$#X43KJf9PSzT91S1l`MxIzM`cQ-TfQ$1>l|jI2$zL{g%PqJL{Vj7bNq5Pc)$#tP6S9 zd#UQ%+h#KJKQdwd$K>Sto};mYZ6uAtUby5t{l~gBiRFGODBVF4!Zs>yPX&xhc*h~CWTLFSpLPS&nYgsXBfF6AL}1PC+V}! zW-{v^EIrmgG_hNs?`rH^o5`)uW0@!QIcyv&h4l{(2Cn^}w?)@z-&X+HQTukqyC=xt zlKsvqROZjcyL*z;74IG{rNjEa{9^qdzyG!IZq_@{>A%H)_gQVV`2Pg|y^Kwl{yQpd zSl0igx!Lh8=GmvQfpw@Rw`@6Y8C>;Dk% z@~_GB#jt0JOa28Z$wY9sZFX}7vItsM6a}S>>6#j$gYV!-aP}nbG#b^8qw~fGTykyJD2~y zg+$@(yth!TKj**4kkjSACrFly)KK}|pf1Pnf35${Uk;uATm1KMT1y(?e}e!1icOpT zdwcN-^xwDti_OjU-vI<5zvI7qNZ)|JSOZ7ivA;;8aEHHGe!g@Fm!BvUq2ed{n!dLL z;{SmEp7~~?{7X{GUm>X?e~CP9Qs*SgclslrOKu-6SKYv0tfRhxY?J)=Fq=vHqeWwd z_-rO8`|nvAdxOp7_D6qXUi3$MpG&1}QqSmN$nrrJW!k$C5a^3#B zMq`KDOm2OBMFQ$;%h{~dCN)_X-_jREM_CSC{pb*AHPIj9ely^m{#$Dv+Ep?hb>P3> zmJufVsAgpH=lu8mYZt;cQlB<#Mg+jR<39p>V1xe+v z%6T6wNw1SDgLqX4zx?=GHU6l+lv%eG+>3Dg6wgUUYVx5wA5OyM0>*oA_{JUPMXZYG zYhWRgaYS-p34U|&Tc&oW3kg>;p%525MBd0mqb%Z9v2M6j z5oVN%N-&A=e2$=^)>>O!YTfEusS5&O3%G)c0xHD)jsqr$LQo|C@AusMW=q0iZGX1^ z^3l9E?{4RwdzO38J@?$~%EIOT@NZkAduc^)*i25-z~}ftU=inwyaDIT0>-`YMT6&; zdG4B9fzx{LBNGk>;|0Gg8wdVYcHq!q+d;u=k1xC^ZH<3?~tovVvBeH|D_2ry!7zf|#=vY2nT8_}u|MPweYjrF|}yift-4KkniLSx16>DF$s3^IutEL?^)}*kKSP zJazCjGuB*(L9x+=qhy>`$pNe{)K?;G=96^gQXAews81pDtavfdu{#eU0_O@!Z;Od84cMO1~_{ae8xX=6?w1k*8xFNGd z>IoevRDtGMes|qL9JQmrU_vM5Ug%YNkQ54n4I^Euy(Rljq9CWQ6E z5vJATtCxSn-)snHZ1!d%5Z+TVLEzRb7{lRm<9i`gjiSQ5k45H@e?6d>h6bOVM$5xF#12RK=Y;uwYqpTs_Zz2MgbdX35zDAuv^@*R*HJZYlnGBP6#cG&@cD?bg^&b~ffjK9zULy=fWTFs zt1BTL=ui&b!F#uH3lWcav1YCBcr6InA7^VJOS3`bIgH+QBx#zbR-Ka7e`8%7sEksD zkS#J$LBvKYd2k_8cxX?}8pZ6m*afjdGEP*Cc52yH4hG2FbAllPKVd*O0vysT)swmh zN1Y;v;7!XbwNes;52_=OaN)G*J*o4xCN`l@hp^Pb>jAQ_`m)hxJns#{D*tC+TT2r}6{C=aK4hy>mRIyuYy3U*DP$@I3jQ2rUnV z){8FQa7@WFc~^W2gbywC*MEi+!cA%hM}&7ohf5JDV9}6p=0txua}hDHmtW3f;gmRu z7Uaek^ba`jeIG2h?9Bm$$$)-A1SaUkPL^{evW*3yUx{2}0X~A!*UZbad@B)eG|Y&2 ztK^oUrB=Pls0^1cDw0{AZ$+>S2XX`UJUKrl_4TvtBRZ~+@k?vwBgEtiQxl?xAZ(E* z02ab7IOJJ?LsFUkZNNrEC%Ym$VE;BpuF@!bp0NQCRlcI%Mxj~N3)$oI6_-A+4x`NQ zZDm9TKn@Pn7my$v4dTt``F)tnG7=0Yx;gRkJQ56=f$SCRIlu;jnDL0XMkAtP;zxni zM-GkSyqhmGAJ>6kR6I2=p}Iu+2e$ptiS{yQY)+sL<1YZCe%u9s0dB_iCf5T??!Dx$ zz9W74YrX<)B~dSk7vmQChyn;&0f*x`KpeAj0AnMRj4wcifGC}wx?-|&OsvR##$Zk} z9~K(mY(~1FfAy3OvTmGsM!Xv5RLJ$FJmff*AKl)9jH1WH#Eq^GQ&diF{(`Rioi2VG zkuSiCehy?AbZ;46aDV$2R_Aw)W*Q<^TLX|BTENr!*=fPc5KBsC?)~16Vwy7_vl)FS zfHeSOH&}^y|G!PcpX1c-=SsM71o`NSH()-9$>!{{b>c?ISBW^j4lfdM9Dvnb1Y9J^ zC-le5s}wLa7(MA7M+JS&#*bsm@RAdG0=mh_Gv1cqscjTx^{QN<)o)$2cO0L9Rm0qX zIG=}t7XE;&yvRbXDL5Cf$VC>5)CjzmA+qS}p4t0IT7?Vnv3L>WBR+1sBjXA4^0CMa zoMTL)?_$e`_}RgHgsc4(MFoS8q>K;g8H}HqUx^5k7zAo2NCe=YZ+T^S%fSmU!RbaH z{IcxK{OFM`z5K}W&CCxil#3>Umz&Ye!RYovyu_sO-8VmY5^!OL_bAL+5KSJ$tqSqV zdntl%#s@f;$qXsqorw%7&jIE+yoB`!`vJ*?{$Wfx!y+f6%51#k3pMf+*adv!sawrq z<;4{ygd5^xr0APOem*(d`qBCfVPoD?lh6Jy(`V0pkf6^dpY{{zv!!SK*XgtMXYQ0f zD@XRYK1$;E|LHTVi~o!C*`PCAedfbkiatAti4=GHG0hcs|Hu05*3)D9>_)sM>9Y_% z2*8)&<$wC@ICcI=8D8qM)A5?B&nlSA0X~+A?g0OX=rgFZvMPmpqf_<^TzU1Mxjy@B zd4fKBx#}m-XKBFDf7$wM|KU5O&w|7Lr_cUBS)Yv?DgqDdvy1VTqR&P!k>akBX|A~Y zKh|gUr^fWzOuQ!Pv%lbj0Q^V1{7;`9r>37G!%KZ;<26;Eg_z6%zKn_P0RPMN8PQs-{5JL~ow8;;v9>O2!4u(A%do|T+q^1ZLK+9V%B9%#IuD;u zZ-lYTDvZD|ngzS!^`}>cPsa_txMgKUW%!ill=VC8L9j}H>9w3|+pB4y$)s z9p5|Ixi-%mz#SnlN1kL~yQlYLr#!FVB)fdig3tnOJo_#3g>nM+1u#FQ+9SVx!{|Hp zfgjkT^lMC@l0%^ly;;;WSi+16?fk!C~6G}F& zkHCJ?BFl!Iun|$*n}ffQK)Eoh4FxQW)<-Ki%#e(pjo6iz?}uQeHb+jQJrdcqJrb8r z(zNB2A^Y*jekHPxr4@7TuByWoPu3|y58i$Bam>NJF$=B5nDs!1I( z3qNG@2QCD-f8~7GQF;H0(D)j)67^xbia8sP2aqt_Umh@_){ z&I;3cB{$Q!k@IPkmeBdwOOlQ^4q*k@BmEegFBn_;Uw~Q9#~n*P)Qt}R0X@<2@}(QZ zdmnUKh)3Or;uz_}{=(kwaOixn6`Uv-cotS-Y_;IOCUqjKLhq)@vq7CIRmX<;xAJ+u z8f>y%j3?v2^8Q@|z@R8(j?duUSF>``+;B-Y{`Kup7Zt3mdF;;jE^QeUuDnc2Oh9QM)W(!}6ETkAiEu<7F+75}>8EV!b z!jpA}AZ(3GG$+g@4G`d$1QLodZt+#I(Heb&%X~BgDqg7iu?isUq7!3e@C_)#5J`P0 zQ`abeJoQc#Kq`p@NrpaVu&WsC?a;?u$mI^`qYuf^$vOsI>5x7qp*ZMc_5DQuKSv*j zuqt$Hj656E5mI%GJ}Tw&e08wN=EoEC;Zg^#xsJ)ZmIndNj>xc<9_#4&8Yp!fo|~vF4{?<&>O9j2bpz$P5^*yJSBp5cOxOD-8Sf6HU)TBs>38Tq zwkiGIM}3B{KQ7^5VEmyRjBMOA&=7Wly|O)dFh{se}&~jUi}r@#WKePDx`_qmdko?nCpG9FP_Uo6rRr>Na!;NWX~5I3Qq-bmOF^6ZOT_0-F8L6>AK#-_^G4Wr7v-I z`P$Rll&=#|pBd^KiUBf)ItTqWL+xPnWvJuwH8y|P!TDu%8LMb_etD};aC89rk}~x1 z`DGc3W8`Owxc=wn4_}&zQ4ywt9+iXzA)Lk;&%u0ho}C?G24OlQjOF_ z`aT<^m(t0E`NNq4N^Svqxij;JuZTd>w})KnWKE;4j?2Tr(t3mHDz(Qtny-OUTOmY$ zG=1MeVsWw#6SNqzVGkPabKf~&~HQEPapkH)AtO~t?knHeE38FM<=2$DMKHp?{iU{^W(cXa{nBC zcVkuPUzI!?R8OfoHtc=n^L*9CWGlq81Nv5XbIf*tz8{b&8R`2DkX}kB6X<(_sHxmh z=;hAPw->`B^j*dmC+jIu!ZG=Mk+j~R3Z?c~N6R%(>KAzaX!?GR#NuR~L{4ujzX$TO zo*y4Ojkww-eMdOBhQ62RdjBNj-2r`{o=D%_AKxZ@zl8b>ea}0>j6al}q3=)N<((qG z+glGUB{VxS-p^9|$o%d)kVwbl?TD7jwV>N}X1se6Ih1EdYAnsYlW2~O_tnxm>_1X_ zY`lkQpwwY_{^;>uc%+Q?uPJxhj`u&v5PG}=w-8s`9PedR>1Mp|)%9M*PaWy&i|1pA zU2D+3k8X3kUqyXpyx%I)<2?$(-;DQikU;8q$M4q@Pt|NCTEofRor2jO>E3pj8e8{l zkpJ1R)4+}yzpP9yP2){0L3+{CbT`d1*Y@P#!njMj*Zhzk`b>Wkk9En^+DLU_s=^-OqLBT-*v6cIg>`#C5-V2?sSVJ=1pZ`y=&_a|m_ zjA7VeGGQQA`G*ry*sO4vgxUt?^z-w*z(K)$HU^#uW@-@Dr~@Q#lUj@>V1H`eL-7jDv4{Nrx8VO`k?6UXgTve4{}Ey)8UK&=-EsWiFL|4k zg(lj=|5u`xbNf(m|2yfQ%_igj5Bx;>mnY~SPr3~k@r(ieDznuxc1E^a=Bs5=12#pT zhv}}G7u(3Skhmfvaeo2c{kSK%`kL0X&<5TK8a@g;5zWD0k_BL6Xn;jJ2d!cgO*}W% z60}gwJ0e59K+k9z_X#J|r`hF25y-g%MU0K)2?Xz=QXbL)+X&Buh)q3as_UVId5{+; zG4gktLT~q2wWU<5=c1N=OCrC)t_}smC8%3ni9eBR@dd_QZg|B}K&Mgz>MN`mj^#rj zTfBTZ0=E!{_Vdgv&0Ca_K4lP0^$Uv5OumnviLn&eKY4HQibWX!R7weerRrpqBkIl+VDr$ zsWDs=#pyt?y5kV!-$4O2N%A(SgV9Di^63pxS-H`h|GoTi9-B?(k8Ah|{4q?PYt&Wp z+&TRJNd2&clPM>6HbhYy{BI^^lI7FZf*nVHr$Xj!QV*kv_T@T*^!OmpJ+<-+#%i$1=!01f3sX$DAeS2Q)HjE@ zRd?eVwj8y~J(z%D|BZrB<~LbSqZP=jQz@^Q1=?Qu4G;YdlQ8vn{E5D*{q?sczq*l1 zAhyo5oH1UjZe#EW3nxJ+!}gMC?`?nuf=r7hvyCYUCnG_BoksbEQ+GJM13!Nw#6(=X z+nzJCqA#Jx?aH&akRtMI1n?kth);`eizd&virb%Wd1`Ovkm@;?Xc9eSGVP)k!BN{3 zxt5nG*RI6mNEk{6K$a3?Iin8q($Na;uRd#YyygPS6=|wkbUAMCUZehYpgT}K^)#$z zU7j_d@2ng2{o*n=D-cUSd&Ive{(*J%*pazrEzSM*T{j zJ10Lc?MQ!}nmW!nBNd-t+cIy-{YAJP`FZ*jj_^E;Fvgo3o#f2MUlP_Gn_Nx;)pYneyB@{QpS(rRQL|cS01l(O=7mnPmNS z)&V1KQ;qmiP&H!Eg z(3I+f{mpUdKZrov7Z4z-17!z1R2Jm9=atp6{PeVX)mx+`=8vjg|Bf!u@?Je{(hrAv zKsuO!((1W8wzlE|*uTbM7AS07pNMHaftJIb0NZbO&zI9*ayTe57S-sQ^O%MhjR8+>3%q-xkEYyzTeG%6cBweE&l9x}a4vxZQ_tugu70>}E{{I)%-ns_ah&3e za1g-ND!|)k#aRsd_1m$j@tPuE$KjKfuNUL(KS93MV=Bk~EL8u%TatWz z2p@E3{)o5#R{6^KP2Vxdh(56N?NC=w_txjzD;=I_r;T=iTNY}R_&o@UQY4{_e5J)(gZYt7EZAGhBPp1TC1-s) z-j3~xbWa_(_5%pI@JYWVy6(_}P$nimOZe=@K=_i@=x$oSca#1h{gr zasuHhFXn)7R~-Xg2t%Vi2H!(iaB?PC38gv)-?)o0JTLOBC`jCey~*>(`Us=;i2gUf z8M46De@XGF%1#S7d;0CoWg`O4#GJC>0p|)tYeI~l#(;Bm-tbDhacIC^7bsjF2%p^= zJ#3nsR}YRsFbcoj&u^d3`Rs{K;D92(?aw*UDL(*i^ksRKHn66=erF_RrA1u#aAvGR z^_+Db>6zI>N5jI^zxzikllqUaIGyQ|%;DVEy#1aiE1~%BEm`N`6dcWn-gezE@qf4}^;E!%&nHWEe*{-{5&W zzr9hyYqs`w@HA9*QB~jyo_E`7&+0o*4KQZ6ZEyXrx;EMgimY^*eVb{K1Vm8 z|LXG#jFnQ=C<{)8wZQBv+$--Sr&qU=>|UKta)x!wKFJ=|DLb?*V4n>@F96A02l5GV z=IO2UVSE2ePu(d%TIxJ$S|#i`7%&fpQ-?4+vb1gkH;Vkbh~}2y`nw7Mf@z=lm7}$JBp0 zP}|GXaU3Cth)m0Hxilhx49hR}gzv+R+p;iV_z7>c(w$Eu!do{6mMCHni~?#6a1dvj z%oZ3B%rA!L`l)_rPdw^@L%(wx@Kc2q%xO8W{(HiUF*XwDfOHAW!h9la7BG;=kZ`Z7 z0^wtqvEBmIa06@cJ08mcg3Hk; z>kB~s^YQ<}^h)1np4#J?GJ6-UJ{WyOU9n$!n#`BW^Lwe^;0Na3y@HFGj=&eH3SZ=q z&|oI>Yxf&M(2SUYRg$+bxM{k5UicAn< z*W-csc!gVacs$A$493>OuOAzaih;un{`wyn(MBP<;Z|$e4=yqqqFo3tqWB5C;NdSU zX9yIr2}tR(zW{*?{a=d~b5 zHvq=bE@Ky|Ad4f4Op&LCfx#f?131f5-+~=*L{f|Q0s*S{n;)ZjN%hNG4`K6)uDTxG z@H>@2*Lh%=3NXw&!Y~Vh6SOVm9lyh1MNOE;3enI|LW2X1Bmu|*EhNhGtF-w+j3)gy z>cu1%lAxqwjTxJvso4F_7#@qQUws1*Fgk&9-T6Re-KU;fUOuju)`(4WKnnaimX6pB zd~0!{3wg1A?#wkb+9*)7_Y#IJz>h=K)A#{~Jv7)rgMqBG|AbF^9ylFudL9_rRj9E% zEe-TxH~U|917?*C0~OOIIMfRNT4{o5IsE!DfJxI6>`V|(AJD9e!*PXcU6Qcu-D!fN zeDo$#0_;u0bL^p*V|>iTJr1T}?2gLsx6$u;a=F1)j9T8?9j4=&Er(CMJAqtc3|kEf zfW8F0kl%$ZMto0NE1r}kcVXd9**(g#r;8LJDC0f1c)Q?x9fIODb;h~3*=|QEZ%5HM zG9E$~bX=P+QW!IdK1dJ>gcKZQ)jTehrIY9YGWKg@Jc{uiMQJ7?=csvBc&Jh#^niq5 zYM5neU9B!>0!%AoNEqY!XC$XBXl%SCuzPMf003Gwv!p$2POs0xPe3`IP>!)2(<=il z_pn(3I!jT>iblFnk0jLm+5yxfQ=y*IQ$uZPn3b<;j~L{V4*hVV}WQz+UCTUPajXwFB6zQen?9u$vlYGG@Y2scioAH`HD_h zZYLmRAJ6C44mx3_cH%g~3bHXZ%*xlbuU1D(C(feusm-rOjij6+(*yZ!da#O<6ZC+s zq6d%gCwd@RKtH7fU*Ht*%kxJI?2uRlyvPL{C+9B9FYW;9qEx7-MRm-oS zbT2^#+>nC;FMk+dSCUr|Jd8dVkMZ4MBEa;D5Y;G#Y(tbiN?mP<)nYNw2ev#7F8wh$ zQz6WG=?uJA>3I^NhB2pAP}2?mWvvXS2M-R-n=3sUT!6Eh1q)b>TF$TbYCli!iBktu zOp6O>6Oc(j^GFnU*KSLU;JaQ7tA0%6U4^6J!xj>vF?(vKGj|~(^tB4G;o(qQ2&9N; zn~)-JAZ{Fiw9@OXWt$;D{QmG!4XPNRaEdP>R|PnJk@EH`*pcDw!Dz6XzvGlZ!R{P` zbmA0t8zY(HLVi35K+hMxm!M}6ILXQUgEKJA9T{sZ|yFi2G{EU(3eJBVrPSsXTucjN|yLo+`yc?MKc=Ok07CMwi9 z#nf3OEaujEi_~f8J%}w$C|Q@_BUfzEHRH>*oY?D{4>mPxCPU4KnVK!uT;_-u0Qfpn?MPNTN>_XR@iCnd^s|nUqBJ5$ZAO)tPoct5rb5Jj zR5y3mplSt$Ity9nqy;O`*@WqdR20QbHDxTP9t$$!*QC*ydY$>2gvqHmMk9HXurM_X zQxDdV*a^>6E<3ho|<8lm?!cT*Sxpd|e{B2hGv|P%s( zoD(@lR$J8o4C{YL5hgwS)@D!65-HI6eebQf@%}+lU-Q8dt&0(@$#D51w?KH$C@ajLPvQ` ztdhPYG5t!Du4zruA4yDqMkWLkvgukRVLGnvhT7p$^fI1i8Tdc@-FEDEPj*eP-`$TN z$@aTx_#*bZ$xQm6{qFzRe)nwp&)a_I>jVz`@%FoiS^PiPes>Ip=U;8V+X@kgsbK-; znTM+N_>p42Ta8cJe)kUEe%AK8UD9^mepj>BtdGn=g<-TAV9&&J%dVWKVewsx8BY%1 zfh8}Uj+qk+Fc^D94Zj$-=}89cB&2hJTAi*H;1uYz{`zsBvn|5t|I&xgO0`V8-&g}mUau;X4QK2>U& zNnfZM@Fp1XEhKE1wtH^I$=n17uu+(GOkQ51W8&_yUS#Tz}wA2(3&L00(O0WL)Ue`l3d)` z6FRfsWd-W}Et(?5LM18csvpPnnl z(HMM@`O!s8`rrKM|9F0MJJ!xW=l#vzo57YpetvWdi~k4DkGvS3fA#!mHH0A;R?m-? z;YZ5+Xf{6S`O)9;_OqTJt>1_($p7g5&8g@C6`eL8!{oMDYzeT^GvVjDzq#^T4RxFS z&9|8F^WNXw&%mzt7JzYWy;-gHFtAt42>iVFH%ES>2cXUV<|#}7*~9_|0POhwX486NG+}>pqkKr&6T4-n_BZb_b;kBL?>BWO?Wo=IBlb7TOwF3LJq}Q7Pr$>PMjkuc%?w|qN6L3z#>tMK$B4W975my zsr756slCiGys=1?W>A^#zbSUQo4`9tabN67vSU(?`P>N0_qBHQ3ec26AKT(%*lS6~w!=dbIn`Usj?Oxu(1OAkI{tHfRyb$EaCBS30K4A*j*D|&9~ z$L)+ZkZ@a-q|Dd=%PVVddH9C!?0Q{?rCx1Fz{Xf;d`6a~2VJ>~a8M!z; zw2xQ|+i^s0Mu>UiCIx3iujo%;CKIPw<1;GoW36#1r0BFYAsP;s*1L(h$`lV%{VA++FiI|!b+1oJ!a9pZOWu)INuv=rB7cgAs*xI_x|*7O>H zczXt^<*`#8N&JB`hSSAG74GBQzGdtzIYSII4HZ<0M+Yx1#jw-qgO2;)3>P=!^2Eg# zh?I%dmx5WkUb7sAl4v^!7Eg9&@{#1~n2`>s!+4IMzbXb5F67@LSgvuc#Tg*%%hs%| zvT9ledTt2=3%Wn9e=Uw()46sWCEdxDMf2Vs< z08;&L$9Qg8ORrY?-@e2bNb6BFNsj^J0;jdc({zP6G`Yr8LF< zi&Qs&owOi*Ug&SN%3uPf>Ek&@WB6yJaYKaPDuMOf@kGhUIT=LF0659(wqt-#|3U*CTZ>8qn5dk}1gu4?r31!ExXQo`Ct(e9Q>KQQ z5(xVuFYzZ}9#3D}YJ76Rp3C=`q^ixI!Qa|%*Q_Li+S?2i__(Cf>$799@Bf_j!8bt< zQrtuJ9wx+=(D6kaVMHo(6`0*`yxPUcS_Sh9d%N;T%` zS&Od^n~K1tLMnQ;58+Zon2Ta=wjBf9&j4&nn#E^d1Fe??T`JY zI(!FtlrlI21Oml|AXuDhn=pT*KP{#y!yEOu;s*~M!I>8K!fdtbzZw`w$Dt6sVVaWx z*{JURlvUDU4)YrHMXxgN;8#v`<`X7Br+7KEfe3RzT)Bh$n&;sqKuG-dTDZ{iTuaSD zZ*)&j@A8=Zt6S%{U(^1xxYFAkpYy{jrcsWn@i>Z|=sa8hQ5HOWcTwpA!75BNafE}N zkuTCK%BY0G~qfV9rZIm7$m3$lGvcr2mYK$T#Sx zKGkP`smeZam$3Y*8u2r=x=yGL{SQ4$d;xFb-AQN6EN1364d!ZfzkGmBp*)2DtRB%7 zu@Tiyqfi7G(#V6dcXSpqqY7xRShY`ltgF?e0~#M`9g;SzL$3oR)+ayxy2 zIN@gH;N@85rq4q4hwF;4q6onRN80g`3)*v}WzByuHEXepnvXU$j}+CT!ES%8IVSS!_I+tj zFm=Y(nxF8)w$_?S<2tp-_{Sy<%haIxnuO1(FPX1Nh?v@msv5+Q*oj16THNn)n%{o2 zY(%BKsBCy8-Dh3j*(sff>e~Fp8RW?a^XJO%$McuU6Y~iyC2@0lLkD4u?ZG$$IuSD{ ztV)Hb$@R_&;!O+TV!_WAf&kQm`=7wPkO-KFtGR19+e1-j9Ig}JlOHWVt1uI;DnF{= zS7_8hUh%VyW&=)m3jV@)vw{}2Z!A zVRKq*!j^z{PJ}$Q-BX&D%%*9r0@>H;W*!#DBb!!kcW31{CpSIUG`%?9^ip}%O|QVa zr}k+%d9^X<_F6KVrX{!OHFKw8x+UIp8VEE2 zRr0EPJreJp+TkfpOJ>uw(Z_Xbr?a5e=kyqXHc)WXRyQMTO znN8D@+ceGGsZCqbv>?1Hx#?=j4aS!Cr0Hq$s+;~j-aWN*vQQ;tlS|=}*)%P=P1DSs z+VseH)1#7`o*}t!&VN|i(|j$jy6NZf?x{ULrD@4*ntnp94ZfE4G+)cBZn_2U zp4!=&$q1Lsrs-y>K=+!tQ=6U=Z+cpC)8gO{2F?~CCr#(bt8SVu^PbvqDNRde)3oF^ zy=LyzrhhL@3z^MGZdyF^(R4w)>7s2v;l%^%KX4)P@Kb72cspP&n z-;(yE*H!YWdp#2Gp4!)0CV|2wvuRp#o2HpNwdv=jX(6+@$xV-v+~8|zPnsShue#~+ zc-H|i;!W4;%;t!I!w${tNa{rcdW{%~H24MwWD~AC%x%L<0$TBDBu<6P= zH|2o9WA9;NGHDB^mlF@wvvHZuPr!G~=%(PiYYsu!frRx+ApC$PA6XD^g<+wHse#7! zyYVwR3&x#V=o(ZeOMvk7e2s%e>TmDzIRjbT@_J^XsuI(mNJ^gpU{q0Jde@f3@^hJ)APN^uVy4>z5toy{V6r|U6+{U<&NtcW%5@h=Fi6R zpo8|S*}gY1^9W>)w?BjFX^H7iC#BCd?S1%80!q5dp$+M%yPkB%ztQCXTVnoU9p~3n zwn$xfk1 zW8)b)ECDA4bH#E*UcR|vETbHQlrML~hhEoHGWNVtm$j9)88Sq8fu z(04;0#w*1t#8Y=2DnPD_nG0ZyL{W4KN$PlkG3(94bPDQXAVGu?l!^cXvh@NiS;JWt z(C48lG^NXrQN=6|aez)scw_LZ^!**+v8JWfGkw0WvBb@N4t4yA3Ug3U5HHp3!?H=KAqf^`MPsX|GyrRnWkRU2m)2Aqa{PuNNM&9-FuYZ zTgtCdVB`Xiz`CfE5e9RPgLT^NR>(c7CoW*EF~~G z8$4IIHojBUg`SBh;($ya&Idid1QMRr%5g6aaq5?=zGC8p4&(kLE`h07aLLB#l!X2To3~r!!k#qhBKud_C`0Y%2{~Q0^&|+ zp1>C|EU)t_67XY`di!m>frfL5KE{mx+ut|r`tz0v1}6Ev^mY6czL7qbg{4|T~aglCY~9t{b!0D!KL zz+L4ozoGOpll#g^WMUuyhzAdlw^v9^gol`|3bfgYtr%5pcT|+~ZUfSYZSpqhzxO72tOfo<&YY zu|0^KxsNadGA2nVS0uf?n8TjIPQm-)d_?q;?q!TrH149m+0s?2N_&kzOyDxqMu-dp zG2{sZ(?2M!A@zTdC%!FIK~x-F72ls`bi9mfRO^Ae9GEHhiFK%7&k}*O)B5$*i#pV= zB1hZPuSZkBrs&t(MJgxi*RIS3{!h@aAHPYoWnFQwP8rjoe*KoC20fFaUstevJNh*U z37@K8{g@}T(XYRJBUQilVU-}&-vND)zr%M*AAE!Aj6NX!Z&x48q(Bz=n4k~#H<%;U zRhaiuHF!~~K8WCp(FcqAqMmK*gWH)UMISUBfNx3q-~#4?$e%%xZ(tg&2C!RB?oyB( z6St`khDbXJ`rs%QZciUfScnAC2lI_W&LZxq5AOYIJNn>ii2Cj7gB&2m)dxAO?kCU( zBLJwY54;)`A6dbN}KU^f(LqYvicKRKMZP`T z8{fb?@%2L?b0y2SP6A`rRPq^8I+ky_EZbJTwNQw(Bj2V&E2PS|iyv%9z71NED&K~% zO31gn0oqQ>w_Z|MEFA+#eA}DvzWYnv@uc}~nZX?8TVL~DsxGQem2W@bi;-`ilijv0 z-=1Zb6#3@)1->Q8w>lBHsq*biUJwFJ^6M3QbfK@N3V8Lz8#1nZRFd>_}E6i z>4~mu-w7WN|ANc%72LfT1-97_Hww&wmvRogf^*--05(iH_Z`ixM133M)y1CKC&Ia{ zdh_AeXH{?ZT@PM5iwj7cW#;tL;`FnM{u?9djW7z6&(Ycn*>7(2ouv78_>!$Pks|B7 zCEURUwdTl7Lmf*!YA-@q*q72d7m$>X=942mwg12uzi-_frud(K{Wbm1GdV0dyWeA_ zqqfEVO^u$J74Yl)GQ;w%3Rl4?ui}g9@48-nfM<4d%~xo1qaRKko+p>kYY>Lkj56LAY|!m2pZ4K%>2k+SPD+V?r*?;#o7cv<#}UQR@8nP%tGnVn_&HP zKfCWEa%}WOqM1Znaw=%RfqmyhPM;jE*3RakN}}1~GD-Lf4TPNN)kGvZU(-dlK;o zxNjU9L*Jhg>7~5*?6goBas=y2Ju@2uzUFaVaFqw&(d+JM(b>uC&qM<9sv`hmWFGub zNSfKvFWoUvdm%y7*qeNVtlW&L0T=#}%#)&!uiryA1q0NLM7ERljnTO?1os-K(dw0YCgz^A7qV|pA+KT$vQ#k! zsQE0c6|y$J=pMrY)fIi>k5TFr<^h%6P6SdT_qj)Fl74r_3_!LU7e3Vu2$HV{pm&4+*TjM8pZoSVZor0BX%LEmKsb^LHjPJBFTjEeT_<^EWKWIZv}PlL=@1v_nB0ADEjwi_GsJs_sDdNAN6lv zylhARmWlptt9u^@z;WFx@KgUjjL%TN=^No`zv*K^jc4}Rh(S{EQFzeOW4m6xH`H#K zy$0CX3YB{(vD30?0~GH5iTd^ejDVo$)l_}!bSk&M6C5qoIC?+SAiB0(bgjL??&Qk* zn7%zPhO(bf-_C;yi>z)(-#$X!CPQ%!dO=BOQ-AE3z9s&W)vXWe7B^8sY4-d(PTy10 z26HE2zq57X)w{;kE#xQYy(x*_ooS`{xQ183-H(syXQ`l`n02fCI7 zeSKG~d|mYSas2)>`Zb?u()&9@X5w{w`t|c(6lE#;^^_cnZmnPMFz==6>St2*YdYXJ z`gJ1}-?rDg^O+?@z4rF#mg4(6cNh&i16YgO^DdQ{NN!qBWZ#~8ognQbtas06;r7Mv9V?fUxd?W}kI3R%2edtNEfZ%{ZA2|ZLW9MqqM7Ee*h*_CfeAM_3jx&U|aqA&+hLGso*fT zr(cgiis;vQ=+#c@*TE>#X1)70KDJS>N&7pp-<${Bn~8k3dIMyDx!$ED#((4et>>}X zAn3D(i)gDZ(X=x7bzNj=u_SL#MLo@N7Zddi9 z(2!jp93;R}9NXdx@*>|sgqWbj35Rg8&s>l}6kK0`Ggi1OUWUqkL-wVx&cR+3uI9zF z2(-c3Ofa*#wKN+?*z$9*pt-(!LbtTgc-*p_Cnd1^hQnrH!_pV}0!#`XFaH!_Trj)L z-e5f@sr-SO=~8jP6UZ0t??*T=Nm3gq>#*@$q<>ZkV+Ubcz~0nu7~;hBbPeWMp4vOm zRP}_eX`VWVjivyDAQVvIF?fmus6=>l27yN4Qd9pXAgw-*An8nU`|=OKVuk-M zwG+0`lZ34r5a6NbyAY`G@y2;UMhNWz3=zE;9xV8C2yp0f;!mW3rxyDKfIVw5g@G@t zA09X{g>UK*5&pSN6z|vqUR0WgC%i43+(RkQak;BpmyKImg1cZ%-3u8&1^bFbX;Rl< z9uhs+=qp~lMEe3HA~4o1E!dZs27%ym?5XU}qy<6_w$ct{Df_ur_?$dVe|J8I%%s0A zY?09Lcy@!D4hAc9v(AF1D6KXnfP62y;lrB0c zx#+xDQHaYXUQ9#h1Jr>3z3LXsM|rta#Ea^%ek}b*fm#cQ0780lJ;$S-=uCGk$#+jZ zihLNxD%Jt@v61CS$xOT*iP4YP!AI~}Fy~Q^;x)38en^+hRiB*2Qnd;OfS(UyIhUX3BT@77N_5ch^D4Zi@bhPs ziQwls@?4`n!gGiC`6?FJDSkc!>f`6g&o>Z{;r@>t?egBfAMdFX<~g}r$c1r!E-_$llb;vpqI;QM8`XYB ztY~}u{EHcEE}5UN)%Dz+48p36RDLe~Gs=RW8|Ar1-Nu3Bs_?$n^_vsb&@emWyf9UnQSPInM8vZ8@ z{DxDT(=_Z{6BB5XapXi<2ba71#bl(ASzo_H@#Ey4l3dGev0B>W_rw0kGT`@|`1<;0 zUC%NKinz$>iF%Utchx;83x02w=Nfe<%enl1BtB|>_v5qS_Y?6NS(3EA9?nAG_rvA6 zMxBCZBELIXy8#YZ_r8~q>b#kFFwl`Tq%{NRr5zb27@SPW#ekg&4}{!K9C4V*#2T@? zN^eu&tq@$SZ_!{{T@a>SSNO_ST_L>rQD>;L+0PG;#p#rZUiBQ9Y|)^+bZO&H#A&>Z zd!e_CRg(4qMPC~j1>k^lzIfW?`Ry%wp!*>wi2^+ib`v=Tb64mP2~W3%mOc1Z?3+)Q z8*Sp-6TQ-eV&=KWiRQiUU5?Mz1s zF-J^{?mGC$V7wkhUI_z^~WI z93^qR@g87F4mzHo`AJCoL|V;f>RO^(+*epgOM>jVOrC4h)huL$DOqVZe2>Z&!@)=qKzCQ1iA9dqJjnT2^ksD<%OU@+@?4`1 z#}iyqOLV4j|Bpvap*IIwzNTPd%6L{!#15F#JD9l$frQjU6xhBfWJBn4Y@uc2EL{q} zL2_=!ZOk&?NSIx86)~0d5V4hT?sWv}i#1qHcu@X@cFHdy%Q#sV3br|E$vBfOm+mC| zpL3?QJ^0UUr~Qj``=4(jwIsF=p!&6w|7e|mCi5rs_rgR4C;ih?cJ*OJ=@yoK%L z@2B(6Wd4NlyAbV9OZr!ReQ6q8=4%FLr*FW?+i63saMq08(89dtYHd-?=5)9o(oet& z=YHM_=sgunE&Hf^tg<|{m^L8eQa#hse*s-O-1K;!8u@e_2d|Yr5AU)F&VC-62otnH zI9VIW|3xe`K;hSFSMqpx0*>86=c_E?cseVD$17_<$qVb=&WmIM$MO01 za4UR;WhMaUSm2FdKaKtvKO)YtQxclhIZZ8nW(z2%LA5-(r4{QkSc3Mkd>@8B5YJLG z9TxK_Z!z7nT*=u9X=N`C`s+du&g zfbV)0+~1G+Vx{l1(CfN6sumPXh{}XxKEVhg=@)knz1?q#OMkvd@Eyhn?}1qH_37ou zWbP7-x>el}eYSdHDaNZg)MbM{Pi5im1fJLe!S`(anDP|(7g_49KJK6(q*(xR=74D! z<(dUv`r@1L*lv4F$F-7Z4L$g7YC=Ae{)St@kQ)>9U3JODFLZ|48*w>z&)N?2DAh5kem2lHcank5QJco@Gc-T?B@OE)3(50We&tA7h!_ z76iv&7)=;XVZx2XXt<<5-={N^Q?kE?;Wh-9Lashc`8`r1?=oa6&Vz+Zy71c>%ngi< z(WNr*4R#dEwYmWa0egB<9Q|X#m4hmW&m`L-y%@Tc#cOa?Tn`nS=DVwlkt2hD``9r zm3p!c)Q^LhwS>T?jAs@Tj$vEjlE_TFTg>E?EdN->^MpMFmur|3KuXehzQC_NrF}D= zM+*$G@q8E=FrN46$NkLy0-K7%AmcfS2{Xe2!v%a_z)VibDH?`(xdOwPOj(SSgz-F@ z-)>@VU~GmibtJwej^_Y=ZZn>{A{WN9b3C(*XOD!;spGliIgC>f;g_n!ivOOJ<&=F?MhKgMkqVG?APGR&X}!;kZx+N%Em;ZQC&4@ zYb&G+^pU3ywWL*I)`HN#XXTH=ofN^t6ZEU)4A|5_O%v=t8%jM*J$BBP*6Q)4X`u?- zNdc{k`3Pdg7^5tlN|V~YaGIWvT!liMkMzdmwgsj{#rs@%R1#yrz{9lVwDyettzT>O zBVH*n$};CG7!x2H%_0gi!Zz_&4u4sN&3ZmE7gxo2YW?^!qS4G#T8*I?U?x`^Nu>{Fh-H+MQs`h6Z79-yyBiU#_{5JYu6BpQHL$H_b z@QHv`2rM5{1w%i-GVpsf{j5GSl8FwGel2Hr)CdYXQzjtjKx2}>Jx3Fo8Jlr#0Hs69 zfs612OI=q-tiiopFStJb01FHR@lJ}(l(0njOcvp4J$fEp$qINn(Z@QlW>NWk0i7I= zE^5v<{4ZN;;VZIVAmI`k?6v`#CRgqisNb!JtZ}k#_>9tE4OT>>kQ2un2aPt*G4j;Q za5ZGp_s9(rrEJ8!@qDcF7)1(DfVLN?XCY?^NCsGe@id>F0x6L&U)?@Dk!FGCYfclk z56?>*w++uP4LsvOO@wFvWO!gtcwNqnYYDj)>nL7mgQcN5SKz1s5Q9d7y5Ye-7q6qV z`#;HOOf#AmiwS!_lH>6}4SSEB6rtTF_3UK!K0%&sqrLTvwg@iju)Val?Hy^_yF)C% zO=?hTdu{3O(K17SKimLV^~d8gvE1>xa*JF^;tb7K=IRv<J)`R-*PTeasF z3~YSPJ%z>XtV#ND1GC?4nn;{;pUZ?hNp9hi3cf$cOioF^l_2DB?)}|G#}8o2!$^sw zqp4}gyBEKVHSHh6_V4IghpEfLSsC&-!cIwVY`4J zy%w&{gMzZ`(CC13UMYCOTUqxh*rLEwyDJ&XxvrqB=F`?d`UPTC@J2R){EfUb28TfU zD5iO8KR}XJLRX$9q!ao8Hir+~^(@E#F<|6tFcQcA*E0U!CEC@B2*N~=q%Qu|=!;^EtFHn3w5_ItwO!3cH ze1YcM=vUD>$n>XJrs*crTxR;So9V)7(cgnGDd8ObO)ZlSPZ&k%_mAsEE2}OD^BY|y z`!#xY_zrKeVBCo8>XJg#oQ9x}PF6AA0w4oF$iOdT@N3SR3>iQY3mN!91_-!Z><1a( zvNMnYLOy*4dI3%7*&|pRJ5!u)&L=-Dc?2jp0AOLlcefhSk~EgHkchE-PCsTc>+6%+ zj^!Opc%>Q%;ga9+eFZZ)B^NB0v3xgM#_|fLe1MdQKA~OCJQKW{HqR@j!7D#Pib~Lb zsq{Gz$(lZw4Qq!!{h;-l&szQIzZFtHFw$8_1T7`gyOlm#)BES3DqY{C_UZ$@<-xQ+ zN@ZOKupdNbO*hjYMpwRIhcUK4@adFH!#7Fodn4blTlj9kIau9_RA|!ZS7J{Z5eQ#B z3ZtxVnfrzVO-pu8Mcq129r@kwWWr+fMJpmcg1_Fx7et^2+m8d=zrkO6ym@|U56$*S zbwbmlI#@;4l`9V?1G(t?rw^&f+c72c>vUE0%Pln-sk_ zX?~#jg=nl|Uf zpPm*s*lK+KS>v<+sU6@`&wqsXj6P*2F)^3^Ut{_otxb@(h3J#I0iuHRa1aoq{`yUl zzRg1h@aS&((UaK=kv&1)%9?upUyyJR$QV4jobN|5lT%W^OnCH&EaA~tnNp0Dh+N4d z_NBk_+jlGpV$ac~9>6y%-1m=sAd^e%4J;Zik3mMg_@*9{i9zXer8zwyqj3UBBM`ij2B0s#Y zc|3*QjeZN(>+!jxs-y8q9^wO|j;Sc6zL@+NjRDbhmYF(}^rb(Htp-f>)j~`fB8MPz za(!*(z3)L+-dlM47s&gS4`4KpxYo$~Grvxf_pc!lw6st^7BTCGWW5yK{TC*zBDsc3 zY`!bu&yvuaLQ9`_5?Y$bl(k6tN#y-UC;hbY{?_*Di^=<37z+~Q{e$WM-_dR>pVF^F|0$o7 z#Z+7>u|kwY(Nm3xZWDgY7^I6H?xn4>#ft+LehF`BB;+@Zxtd{-GDN& z_10g%O2Tg*i$nhFM^9!iG)*L~x7Pm|2?wEK%74Be#Y~X@uWI?<+QR*XSD8|bl-PRf z5q{}p+L!g#!P0(gz4d!!K>N4q$8F612%AZf8CNplA(BwIWH{gd&P+~8nQs4?t#fH=<9chspJa^8dh1R6`uDH5(obwhz5!Q- zfJWT_yv5dAe_fj-v-1cp#$P{rGJ7G>oPz)L_afn-kl=qg-;WY@E~#Il$NvXC{!A%G zO3HdGYb-u(YrS8`hi#)|t*aanH-bBoJ* z>#$g+e3NM|*IS3XnG)7p`{-}#Tt1wYko)%AsjwG>AboWLZG2gD=f3x*dGP?Zp@X#Yu=BF!))FV*6QY7giFUkgZnr z1)GH@RH?pK;0wc)=>FY?C~rGpPreVwzM@SkapsPf4bz`?$7H_c}FgPc8Iro8JX0lp%y?Yo}yW2xRSbJl2)?yWYX?!|Z_U6=OPim6MGAC|6itndk0IgmZ_@}nE==gj6Hd0m zPD#A(;O^K;VvUeMFxY*qo|5uIvQG|Q+do^fM!4aGU8dk3?yeJh7qDR#|61K3xd&9@ z_Fy5e$ASLJbgX;&1nhBeVmU7-LZ9YofVXT`HUZb*MgsV1&A}i3!`|0s&*TEUv0wHA zY~x72PczvyH0`N93Wr{{W7Lsl9EollUu=XWI%gB-5PZ~Td~);Wh;=R4m006>G}rn+ur6I z)G1+@vjX2b^Bervy0ZdUtkMuSsQUq`Nk}tRWoH(D-+VJws!jOTV7}$*Dz9gi&+;3p z+%=)fT@O%yG+8rs*7+ z`=qJ{RgXM11JXTp`-2y-lb?p~k$v&r@2$v@^2vBmUVkYYzz#B+jf+Xo)C(jNy(m|s z`p5|Ugnla<_F@(qlJhU&{*B+7i@$2tqF*=<#m@IoyR%Ak9^1??4Wsi%3BcIgww%6a z;POAgfv?F^hs`qN9EYBQP9nDfH>!AK&VVGc1Q~%QegdwOH1h=M^ zekP@Ks0br{iZFHxuC*0e@w+2uacBhTXTQi}ft{<+~lXi=>463}|s{bg{N?%`oO#1abB0kh>}3i0 zKCyUV8vLfisD z^&rOpU$Qj^4ImbiRF=Z#2K5xq<(Wy0?L^s=CsL4+>; zEF$k1>c890{*i&(uZ% z4l&G=IP?5x7NK5Au8?W}Hy~doc{j;2L)++uhooicbswU}$OY%X%|>o#=Zdd*UeRlX zNk|5sufnG6!W7c46%NvW<&WWiz=Z%}5beD_4?2@r7%r^%xcFU~??wsVpk$JFc?j<|&D)Z?1}Vaa zgw@yPl3UKATqNc%$Tv>qSwM*X9-Tc6RRKBc5q7A^c@{)+ORJXid66T}mir~ zE|O(q*W<@l-&FM2c}&gD^l-L4i2azi;Ljyz>w`&6|6RDY5S1RE36mMjW3QzYXaBtE zdtx1rSBsMJ=KlazA&t7?Xxd9+lrD_qqGh>TaTT^ zAo-ZHt-rH%ptG$MgVVW5&i2v^Xr>Etre0`%&)GUdQdh9{nzK)qwEwe#JV|asGLqcB z57}g9=7nVDOJWt6GpZaFwM~a?47;bJotcgtiH+c?%1%l48!CqnBsKjz@|N7bf@)6s?oY@ze z|5yy0U7O;}#@8H{CpCSi^I)(Zn)7F+pLt3@>D14Ov!4yl|DCNToNa?yAoC&rLCBvU zrYTEaptR)2WhZWDI-8~q$_7y@{qHW6@+wK`d_)$c+c%`Hf&Qev`hTXMh{<=}%BN+h zMe=C7_0e8A$pG~p74rz6uCqR^l&5W|{upp_4w8oIE`~B&sy(`wYW(H45d9WO^3xAv zp;_9U9RG<5n2m=&r87f+KD|O|M%eXmXW zG&z?ux#ebQ5ZZf{tc4Tk)eczsyTv^Ym@RZxt}MGr#92i+5LEUCBGrW{{&Ny1dMnkV zw%vo4%9)C`{iiZw`Ua9HqXeW*b*!&2bOCOt8T+Z1q+|Vtbl&X~R-Qv*7yVdD@e*w~Sc-$uo+UrtTTH2a!rwYAWpIQcdF(3;pfSn+lLv!2l8Ez=!n~pW zZ4yq#Wah-x7l{47(AZao#J*{_#NN>p5+Zc$@{LTqP;*%;z4HlcgR;iJ73kle!6Q>M z(!bv>3B29k2k~|O7|-CyU4zQu{~>NjAO9=X?OxwNhT*%t@$uf45ol|#&&u!iUM=eB zb+)JNH#Vu;ms$|0^~S&R&rvi=`pvf1Ugzajd#`&`IKTV~JZ-@v7ZQKZ_oSf z*F{>G&cg5s0` ziYx+`$pGbGatppShhf4+8KAHo#D-jXB%f%1>>x^qym{co_hrB?1C%lupk!!1JwTD} z2m=@Ck0?LL+l#yh4+aJ(8~7>bNs0_moY|f62Ph76fHEk2fU<19n51;K7@#-;1C)b^OASz7 z4IiL*KCJ;t#{8$X&R9A;-UwrC{km|4Vd>I-akGL2rLox-f_8 zK!-zAz`r2nVvcCgxjy$EqFI4^rhg&%`4IoY*Lv9f3-A08qHkRzh8dX8cE`VP8UoDm zO*i}tGQXmK;S~@8|APE5dt5aAxg6i*`k#fqw144Nma*wy_$nUg@eS>kqler5HMkw- zUkGsq6i69pj{_9>Uw?oi)8$@-F#}vAHfMmmDj2lyz<6OQZkwr>@xo-ON|XI3V0E2K z@Jwv89Z^VkTPx#-w$Za+W_MeR*t_QsC@B-mVV8Lwghc3Wl|LX(cYEX%#GtFQbhpYM zaM2gHyWOaH!@67L4@kJXofD7~(%mY5Kw{nPRr>>y=7>H1U-Abu&6U#3oADoJciZrL zbhoQ;w=)Y3p{j3J+26t+(B1y_Q}qYr+v@B=>4 zJ(b-b@SOEg&>tZE+gGiR+|u<~`?oKku1gy-P3k=QxBKwd+O;M>eMEPxxBGv2H*Dr7 zR%bwVsp9$)xZn)93(u52nf?G-*ET%?5HF){2U^C@{2s9+qhS_L+8}>l)DKGsbkj++ zo0mj%+l^oUH<+!ARB=*=v#kMdMlE+Fw^U;)UXuN{0j`Qnr{sY2F=LQ!FzWF=o zahKe~97ReOn*Z?$+}nhE%G)L`lZG^Z`>bFZCC>4PbNo=hkKyFV&$g*qMcGr+lUp7@ z*AFrCAzCf+!e&bBQOuVpvaPJnww389%h&!@nxKNzG@iQh^FAoL>}K%_{Y91HzkFZH z+LM}Az1~)S%0m)Zp@?37$;kUvl;3}2GRX3K2Si}}AU`bSH-Y6h!9NexO8ZCNMP7sc zkvs4}mmmEj6QRqAxBJs@Tl^!=?2p6BFN@`usg#9_P z{}#)wh_)Wl?zxspkdZtSaAT;1i6Ii^QNn+T1We8y_(}Eq8*Q_BEL~*6oA*Fv}aJV*1}Mm53_nfBUK^ zGT?uE7Z0rVrTuS*a9jD`!tKlSzik!PVEgb@(cyZzha^z%?GwK7Chj%ko+=}09~x8q zOYRD$QQ8OXQ7aQ(GzgmaHQ~({UV7QIiDn}fWg-6qDK--wz<7dFl!^Z?CVJOrC7Ag0 zxPS_q<{?Xyi@uDO$iFjG$gi9dJSgNZTSUmIz7p$%gGf@Sp?X3kw1-Ie9wjVQ5=0?; zKBw~Nuac1M6aEeNV5WNz!tl?MdkGBi-(bfXI_&=)=F5CP0dJ_w`rk2xGF2+${Y+7J zrvD7m-1#w{Y5Og1)8XZ-!`ATHpSVZD|4H0$vKDKbXk0II)DrM>y>TdhS@|bPe3Seu zg}+25!>zydk46qEDTyCnIQ0v#Db3{nIZ(Qx@Y z@09ta>^sCOoR9>|UpQGhY~|D|&i-q1%XiU3Ad%QKhT>g_cRN_lH6W6TANyHK3HGLe zy;n8Zo!RFhA+YXv^fQVR&NSSmSd)Eu2>Xp+*6b~*YmhK3J(`}q#ahVC=F+1@j`Ht? zi0bwJuT@F{&OLMW@mehk9jSVzQllQ*q!dFZ@b97B+J@9PTRXV`DNBzo&TPN0tf;-ok^B(pRtp0HV#7K*NVr9g<3b_&gs>)^5)HHg0E8_=*t_ca&eqv&GPN8dmw`|MXX z_z5GN)38deeQIa35)Kb-zy{3k8R;&8^&d~ikF*}ei*47+&54TNJYFxuV<2_>zU0w!590@m>f)`6U@ z`<)orMKQ_i3t-8}a!SC_{3VR3im^&noc)@ww77jWOcIl-{Zn!#u4;0Q_&`}CjtUct z{CjMRoU(ReN$bqOGI&Y$rKT5Qg!exUgItM52K20rra?9xfk8fsyPbddoAxxD_Sn!R zdu$BYn`n>c1NK-v0!}<>BIUdmF`ls2arG4F^N~-2`!S+5jCG$< z!}#lUu)_~f0bqx(eciOfKm7uBco}y)FMq)P|0>(VR;SvJA-S=)@X77981Ti*%zdcG zH#ytxLo0t@#8!TP(~gqtGs!LTW+E0j`WLsa1k2H4EVoX{DZQ|2m{S%&FP+8S?n^~& z=w9%t@a0&%Ux79I8}+dXy;v^tUASd(m*-Bhe~~OGL(89ep*8$KRqcB;0F>QjX$yY zj21}Qa_>BC%N#d$mZDow$E=$halV<)W?|P_G!Z`)8kX`l{@UYNj#FDyLP{i_TKueD z-}$dH?nlziqhFJs?iUC*Ou}7(6?A&TLVYV>D_4-b&J7Z(g!2Tw@u>BnN_|nT^gI|x zvIXya5oN-4FZFb!{pk$-bfJ3MmrpScQoQFe_~UDWMeWwQe)@K^u3rb$$g?$u3=8CZ zsl(zD&)v-T?ryRVg*zrE-l};Y1rDMm+or=UwF&N==-o*5WXkfZs zPCn;vYUNMy53>jO4eEl;PO&?OcG|0Yef0WmAK7-cUdHTf{d$Z+ufL7kF;egqn4ik; zzYh=m?sTJsZRZ={1txw9_`1#+cvQVU^!+KdJIj2_2urnhs@HZNmR-C!-=GL>G`2j* z+dFu5N1nD9VFuvGc7v&C#_=i-wgQj%3pOnFk=f*{f5%?opMUkUXTN0DZv@4J0slKO zh|DQ!%_?eJ2`22X>nK>;Pj=w(Wd!r|I-DQzjiR>Xq7jF1;2UJ^OMd+CQuwWZ{jp3K zi%0yj_|=aw_=86jyTdW0PV%pUy%x3MmkdXp?F|^494LPE{hlQ~-uK~ruWQtlN~Q=n zQ>yJ+jCFiiot%J_L;c@ZHQq^%KJF{O~_B#oL z^X^9cvgp0Q`bp8Rqg6oMz?NhH{W8Tl^6utVVJ21z%P}JjR zGGa%0UnqLx9hqHai_1MVFbw1xZWZsm zqo~JW+25AEKe^@KS?>F^Tnr5n3livTD@(n!Y60FKgAW4R%Y{enbvulA$a)rJ_5J*+ z$w;i~AFxwbk|9En6r``X4HXCN&upXt|J$cP3hed_q;SW2_L1h#6s}Dw!9)4_f|NRV zA@#ademNSs^^LRNv6gpxfzdJM*Q0Ze4@?;I#rM zcFH|C@7O$7p6B#9it;%0d}?1081v)Did%n^+=64uG3TsDdM}_W?VF0@|v4 zpWO&fFf99(+D(o3B;NJQiCH*87%vkc+opy#LyPoKy)X8UCi~S-dKS0WeFAGOZvB(4 z_-A_-L0QFZC2%<4eB$#Z*iwm?Z$vh<2#uou5;Gs<|LO!$_@A17RrJ_dm<6_(w*DTg z<87aDjzDF^G5(Tvc})@OzLwexGOO2R&ZdZ1|3ne=*vGeibq^Y};BlM^hG3_^#j+acyvq zyeB)l#U~3VQBj-ug|4>zG^7PD;#%r^`1^m8B;D5c|KMhY-A(x2s~877iKkY3koW(@ zyNTyNm*y;Vp?958{Tr%bF#e z`QmR*m&BAK5#_l>ctzf5X{a}-XtJO9d&oRbz~g@6WISMay`Q)OOci+lXS@`cWxY&Z1x~XF zuHvFumH$@=xCfpLXzg7XU6ZKyM{+Ny@k&6gVgW$@W85HH}vbi-Ty3Z$JFm4>UWX9UikY5^n3Fw(B=JdFR0&|y|{O$ z2*hjIsOOV2f=QH0Rf8yNhWdxuC7qU1`J7$SEh6dTOpzpCM10r(Kk0T+wGdT1)PDj& zEQ#7Fq7KTvV4{BgBiwsYi9%2CuK$G)QHvpJ@lgNM2*RrPSXPSuaDl4*zSMf^4Z-Rs z`)efFBL}4I34f_es@I64Qb9U%r0G|SE|$9o0y}M#J(RS$)j@li2%f*TIknm>Qqfnn z|1vb#`2e2j@kAi}^AIHAE3M%x{f8y|FS)q`Etk>^mQzKW-@_xeXG%Bi6ZY)E-G9Yh z=okwU2=8wntHVg_51F}sXsEw2z}#Of0KJ81bwS`R)!jZ}k%*kGL^_nn9IHr=Dbh34 ze`|pG1|{;}MCA2>yISM`5h|lwa8b0 zh`U>qNHn}6a)T*SsS~-cLvhy)^{+s%&i}#0c*>fuW*bdo@F&ag%|uVK>Dx$?wI^xA zjbKmG`F+e25o}3FuwDy-!LV4_`J@UqH#C@hcvwr5U{x~fY|C4>96o~oK$^tCJRL43 zv{W_g>0quvuGBui1|+?K@BJ+=*6;n{h+b^K zDxB=BSF2zcj^j;n?c;@Kc0=kKa2DZ6L6B=nsx9_7P7Lj19G+?EEnZo0Fm6XTKlXiN1kyRr6pCK$~O5BIddrI0wqBH(j9Q8t z6lMJ*O$Irb5CxXvjzLgyI~M1haCFQS$5vo5ZhY#hWzG@rb!|0nd};}1U6}ou?@3%} z`ksu_y|B$Qs1cxlveLB8_g{o$LhT`^zv3`J0X?n4KFz3RmG-vDEvVPE8 z?>CIGEb>z>Az)&JWs%*TzYO;Krhg+pE4V%>`%hV46Y_ssG-JsFRuqySmoEWyW+V0D zdliF}-oig?xVUATQaaabx9}G8$pk!+nkhB0bBunv9#82}1?vE7fS<`|1cKL?>=%bw z*zx5Ec*8Akr9LCIzb)@uUxA&xBs4~Buj8*AqGWoF5ykhdLVhisqcw`JTc0k$(-`X@ z=<&M04sz7G4sr_J65O`10hk)v)z*E*Z4I!2*%wxgcfwHu8|bgwU9&vntcUEQJshAt zywLeY2oK@6wclN`2aCU1*@G&qO{r@TGI_*SzS)yJVh2-`JYqLZIC;e0)O~nf)ZUVM3V(m{ zOMq-j8YDL%7o!wup3vesaJz51zCFnQ!$<#d<*`Guoe7oupAK(0aKE8RsVoYwKUAB#WUY@qy{4Lyuj2#FhV&_B98YTAI!iV(0Pa<_? zEmJxAemulPel0rEqJ9W~IWfzi(C~XyKJIQ3i83-+^j);RKHTLgHzH)35^{?Y@*ISG ztCwBKZA!?1fRLdgWUL6`;V}^M2`V9y`G?0PCCM$5Xi&Z8iE407`pE$ArB6Sogu+vDK09>#0aFn`COby^aBUN1*DrpRynm6A66 ztCjqRDIcd4-MB*JKOyqJ20_|R%|C(iyM2i&KP(fBz7-MUecbK4SOgg*c+J%TdxtIj z48w8i9&*13xtJKWAk+h$!zEVe;4;IF{yl6SrLhN!oFAgdca)@GqhC~|@%DEl|G0a$ z&05=hJtwYJ z<$+yw{!*2eI|6Abk+jU0v^=de6wuFSbb7`@KYxA<>1n$;3AbRPD~gqg-is&i%ahj8 zb8*XJqVF@YqhH2DDCK8R%71*uZWKRP+1c4B>|&w^wj&{L;O^Otl8tXE2~Q{q-++W0 zdIq!6rnuJxxStU2uj6iKJxt0hYxx_<&s`4%^*dHl-JZ91Clh}+>X$!#DE0drjI7P_ z&VW$pcOybQ&^b|}M8f*0g#GE!KzT3L`Za6cc_rzO=-*V!SuUTm2=jTP3dDIxhKB)cOGqG-=Pf@QX`VI&Yo-acF-Q zNY9UIRsQE9|KEHBLfi8)@ZuuW@N*c`!CtrG2maio{@j2+Jr4Hzto-t~I9OIAq-m0N z5$5yw3oNTY?~t;3@{6jh9+barqo+VR%y2Ul_(~7E0;e)W-lRaL@*u}Q19v;+Lng?N zncmSiNP5w#`%ocnzPLtGdh<`FLtNXO$P=^8{0`7=6`Vy}PxDhq18-G2UjE7g4r50Oc+*I9-=A-`sbyhH5j zBq2w(AtArR-GIHq4C-XtvGm8AZecl3k=9D}$D0uzRnmzNom;^cET5Ynf|FW0PHE3) zN&4FJhKr!q(f@>G`e!Ryf0ZUf+sxfcn1N6abk3Eep?;5K5=VblWkTBXC$IF9CxPCz zA4B9_8_2}UFCA@L&d67e$eBjP7S16B0Ouxp4t ziM@$Q#6HBn#D2sSVt?WQ;y~gc;$Y$s;w?l6aVRmBIGmV997!BS979YeW)jB}Cla%W zImBGzWMV#XDzSh#omfPiL39#l5@!=jiDksO#CgQ|#0A6$i3^F9L>IA|SVLS)^bqTa z4a7#GkGPb$oVb$MOk7P|LwuCjLVSX_miQ!b9q}pRdg3$04aAMaXNk`dHxV}zw-BEv zZY6FbzCheg+(Fz)+(mqmxSRMA@nzy3;$Gq_#C^p5!~?{G#6!fx#Mg;Oh)0RXh{uU< z65k@8Af64e?Q83-Jl!TH=$$b;PHL>xs`0HxM@xpCvv=+(g_=+(LYwxRtn# z_yTb|aR+fHaToDL;%?$g#FvSChx>ULcE3OAPyy_5{DDhh$D%kh+~N9#7yFN;zVK=F^8B-oJ`Co zP9+u)rxS~aGl)*&OyX=}DY1+=mpG3&pSXbdAaNnFlIS8<6KjZzi5_Adv4JS_qbtLF z#HGaL#FfNm;%ed=;-kbC;uFNR#3zaCh))sM6Q3b&AZ{c+OMH&FiMW}#h4?&iD{&j~ z1>$z%4&qMYF5-*C-NcuOFBA6=_Yz+r?j!Ce9v~hh9wHtlzD_(sJW4!9JWhO*_!jX5 z@g(sb;wj>L#17(VqMvw%c#e3Uc!Br<@k8Q8;w9o`;zz_!hz6$JuzzAtVsBy+u@A8? zu^%yo*q=CnIFLAqIG8wucni@%97;?j4kxA&M-oR7#}LzrnZ)tLiNq{o4l$QFnV3(U zN-Q8wCl(QB5S_%C#M#7BVi|ERaUO9#aRKo`;zD92(M7B#)({sHJ;XX<1F@0lBQ7N_ zC$1zm6IT=05FaJB5T78fB|b@9M|_I7p7;!L192nqS>kiVO~lQ_EyU-ETZ!9|}aUXF%@c{84@euJa@pa-6;!)x;;&I}e#J7kih$o5f z5Kj@`BX$r^6aB<9#B;>+#0$g^h#wL!5-$-i6F(w;LNr=v|HPie-ozwgA7Wo(KVk~8 zKXCwYAaM|JFmVX+7NUbVl$c5!PD~??B#t7EA*K^EiQ|bAiCM%PVlHtqF`qbv`;>%=3(qr_vx>!>d`iWm_Mh03*qfL{>_hBJ>_Q`hZ0kX!-;9ck;GBNF~oFYCUHD*A~B1YL(C;kCgu~T5(|jaiABU2 zL?>}3aW=7(SVo*noJX8bTtIw~xR6*$bP=nGHN?e453!EeKx`!Xh)apfi7ScC#MQ(# z#7BuO#3zVriBA&O5uYNiCq6^mK-@@tmiQcT6LB+f3-Nj4R^m3|3&icj9mJi)UBnlO zyNNFmUncG$?j^oL+(+C`JU~21JVZQ9e4TiNc$9dIc%1kq@h##B;z{B=#8brgh#kb! zL_hHi@f`6y@dEJ!;)leG#7o4>#E*!d5Dl!h!TyOoiM@$Q#6HBn#D2sSVt?WQ;y~gc z;$Y$sqO9Xx8Rj4kC8iRG6Vr$ziKB>Pi0Q;k;&|djViqxnm`j{Y%qLDI77(Wsi-M9HVjZ!8*husdmlBr~R}!0vtBGrf zj}lvmPY~Ay(94~Z9vmxz~%9}zzx8egOR6MGVS6O)L2h<%Cuh$+PW!~w*C#6iTt z#3966hz{aVVk&VsF^xEqIEpxim`=fnz)AeD6xh3 z1aU3#N#Z)npCfJ}ZYFLaK2O|A+(vwXxShCzxRbbx_#$yP@g?HR z#685l#8-&>i2I2LhzE&>h=+-<6ORy&5|0s&6W=7hMLa<~NqmQRiufL}gLs=p@c0&L)-; z%ZPJ{^N90_3y2RA7ZNLpE@CyYhPasMA=VKah>b)aaVc>*aV4>txSF_z_$aZ3_yln+ z@k!!3;#0)+#Ak>bh#QH|5}zY(B5o#bAwEysO58?#fw-NxgSeBpi})gOH}NIn%fvmz zy~J0D`-uCA2Z#rWhlq!XuM>|Dj}ng&j}zY{zC}DiJV|_qc#8NQv4eP;=qH{bo+F+o zULbxz{E&E&c!_wK_!03FqR~qGC-x-vCMFU45c?AQ5mSi$i35lOiGzrPi9?9D5FNy! z#8l#NVj6KIaTIY3F`bx698a7`%p&FxbBU9Q`NXNj0^)QcUL-`loqK~+gxSY6>*i2kaTtj@6*g|}QxR&@N zaUJm~;(FpU#0|ua#Ak`m5jPPx6SokbCvGKfBfdb~PTWD$B4&?ZxY`ko*^cJWccy&k)Z6o$WV2 zP=2j3WzLmhCHN~Jmcmww)7VN;gWW+!=SiXPwxH2@OemavXLKGCs!FI=gjy-oZlRtL zYP(S16>5u6`-Ivk)ES}H2{pV2s7HmW6l%Fp-xNx|$yRexD3?$-T?1;qP;-TvE!0M# zrVI79P`N_M2UpYPvy3iX~)UZLI+>T#juZS|VxggPM9PNDV)^)sP%33XDaZ9@G`s7*p;^a3Rx(Wsdw z)LNnD3bk4&IqRm=Cseagi-mexsD(m3FVtM2ejt=ns6#?c73z0FWeIg&s4+ra(;HN( zP=kaTEL4V2DMFPA)mx}0p+3Tn=$h{d^?^{Y3gs8-*FwD`)cZmm7wT_99Tw_(you7e zPpB^l^^#Ddh1wz19YQ@X)ZIcoD^!(GPYKl~REtpG7HXwXuL;#4)SrZ^7RpEhwLqxb zgen!PNT?#ARtPm&s4YT`7wQK>jTGt^LOFzbPpE-HT@tFVQ2nn5CExj|870&uZ0oL> zF4TFU77EoN)H0z?2=%m3M}_*1PzQzjiBNKEam@*#UKHx0P%jA87v}(WZWbz4s0~6* z66#5zW(c)LsB)o}3e_Z(N2oTTSdvZ z3-x=Uh6r^H-iq$*FI1{fNkY{N^$A|es(DeU4~6_(jRj4aMJttItGN|=JJtNc;LLC>XS*YRI1>4yuREL=7+gz72O zjd(w>^D;K7*JKEFL8ua;P7C#KLY)-qlu*Zn>W_EzIu8j|Ak-^DRS30PsF#J>F4WsX zZ4v4pLTwak!T?a~gsKzjQK4QCYPnEHgsKzjuR^(m8ge73`9f6+HCw3f3N>A*zX+8p zRN6pLnL^bHl_t~+Lfszpf>2JO_6aprs5gbm66%~#V}$xxs8pdoHyG4lp;CoP5o(-Jy@i@8 z)JNFII=3LhTW1piqZ}>MPXmgt|tkPN6R0UAUTm2z6elenUWYfRe&TA1mD?X>=O= zYsgDVa@l_wsFS>w)Gu|HSJl^feT_|3J|p%|pWEvzU*h)F)VmBTy|lv91Su6>pY67e zf`4XCsI0H|`X;*EzKU8;#w2e8Vr{DPxn1S8OBy`o4aGC(lxH{9)%wasa(0uiTnC+4 zRpIeeR#ZKdu0r|{a$Nburn)At+f_Jw`qHI^a#_e@hTsvLt*kztKVk zS+xBoY@r#U78(>4k%}dMyuAj%G=kDia|q+lnB=KgxuP6(uF+kwL>X%7T{GvTmuHNt ztnk)Wl~<`;7vEJyyA+LNRaUrIkHe}H^_x{u37(27UwOc+&47HK9e5rzWF0`BXJ!VT z+YD8Lkbhj@xmcnpn)(XQU#2yGwy=>D9L_(EEm(b}*WI|(-55`R<~L1vf~Ea}HtlJZ z_$5D<`cZ3^Q>3(+;Z5P8?Mtn_RzOy`H0sYd&g* zkQn(qr2UZ~a$o5;gu$LXL)%xzMECM4cZ09CzRv9b(yKi6b#Ak#LG{gcH#XKcmevvC9SYXdW81G8ZRGhGAoS&GK| z(!h+-z|7CUT+YBejq>Un+>I3|uaQP13V}kdxaA|GT=d-0>#r}Xw%%JV#W<-NL*%AL zw^)=}Y|-UMslO4$1ru%2|0J#T;yIQs!1_E;AL;|i2@2AbX>Z5_Yl&BegHl^8f--{r zySKLPp~9&3C`>x+Ma>_wgYxzCAVbAN#dRaHIXX{a@-xPnf}5(V-Iy_03_7uVNMTQ` zZ}K%X`GVybA#1!97Qb0}vTEyGwT)=xr4fQcE1RnSH_{Rwe}wXz5U9xB`liMzcNa=9 zTz&?yy4dy^wf-d# znWe!AOMk5LOF(pJ(S^xRw0yb|SEM=~HU5bnG==bj1Z#JM@kR7@H&R@3&)QsBvtWj| zJ`Xd&5dM(n&J5w1(huPar8S;bx4ubEc{*3Z%|l>nkNKY`oYA3qJFIPBT_blLc`Qd{*e096%oR( z>RDo3j4z|HqHdA9oc_3|mZ`ES;bZ7eS-6?M5S5LKtg^WJvkMJVSvY^V{-TPo=__ie zU=#`Ezc3`@!R4Qb_MxIxjRMOfTKXfj8xhhUA(TD+_WBb$(;`1oc!}g{Jm;SxFFle* z0|wb}o>V<#p-h+8{SO4ZUluYia5K+P4tj;Ftv?iP(VzC;1Xg(Um?AT?s(wjBt;gM1 z?x|l?UR~d~q{8P5Uym`zk8o(ZtD5K^x4AaW=b7FWUY~nOSe?|*brsAUr-ONG7uCU8 zZW9$ubO<%a8*;<)(;Pnq@|Q8by0K!3ds%(sLmcJAYac@Olaajy>*-Jnm#Mr>wLVNu zq6-O&KjsQLR+KWzGbU1Wt*p7r3L}&ry^XNz@9Ng?5&O8vvB!-+;`(do`l!W?87QGJ z{X||Ljl@bB3Gy$FmV?Cjr;N`mm*v<%vI9gIe*)z@NtuqXqA`8}Yx!mubyfQ_RQX1X z-IldAEn}vr44#@6mcKyz(BP?n*Q(LoP>*cHYafF4k&)HVSih*z?e&%~sfUSU#Vkhk z3Cyno^*0+X>O~&6ufC2`yolm#xsjX{=d1jLV_5z&&^vgWJU%b>!JzKRB3`TnhVh4{ zFQT|$0>k(t+W(Ys>51B36#ns7#jo}!WXY27vPNm~P=;8D@vSJH<3-~Xp8(F}}1O#Mcmfz`|HFb)!ynJSPMrKB6 z1hM*=Iw-0M|2_J@1AnDE^WlFZ{@3Eagjt0DkuIIQjC8gszWREPHzP~AnRE}u)rmmn z%(tY`>XQ;u!j z0son$eVY(ysyK3r)wn_9Vdj-N&dwjTWmUx$#vj`LgeAvbTTOe&tgEl9s&809$81K1 zVIIB?$EV&Q>OKA7=LzP_?D63b^Dqc!iJPq_Hg~`(G@mD z!rfczi7=#%&2Nc+d@c4#HgcRQJ3k^SN~eEZU3Ei7IzaCp$(&SCRV96(PxgvnP+sdQ zZ>W%gX-I-%<$pq5y{`tnp$L)cA1MLh?N_`33Rc2H+Ow7J#(H%0zNW^ya;YL{ZOdi1 zXL@;dU z1Y98@>CKL4bQZB8;i;dA6^)CUmbmLM?8BbJ*dF=_{FxcGE-=?tV?Pupj8+vz2yaVc z$nz{SDUobnvZ2GrHb1NOGc#OGn0YGgn>7;V9?|<9kZ+ZcF+tf+K()niq|3CQ)nbxQ?Z2^k-g#9WgIE~@Pt|nB7}^@KS6ehTG}(wT?kv? zr{<5m{$|r^c&cm*SpkW5B0~CNl(3ywerf&~_9G+Ua6a>n=8xULWpaebHZ|CYmcr>~ zQ^0uG`cm23hHbIf99t*>vg)}fvBD!do;ha%HWACD(oIzI}%IWw)UxWUo z0d2YIREVEH@%;scB$1kDOX`D-Y!%}h5cctZM3IQ8AG-zxRpsNk{m`zhA% zsBVl1_7k;!N9qY8@MnbekC7O)u|?pI)_+BmqWKfAU$LY|sALh+7v6r^x{wSwaOgAi zxR<&;u<2++BWgg)PuN1cUB6^H6Oy!URk)BwA|d@JoV#wBAZ|Y`-ob9BP{|(;192#kr+Si`WGdK5z-f}21iU~1pe^)W2>3jvRryM2bLef{t~PI;nKov+hTv# z`V*)ACn#9QmXLi|V~^H5$E;(~MmK@_^(n*K=P|9^P=j`T$?Yx^V=XtRxGH=VYSAr}pYIAt zBGd{s)_g3hS6%Bmto9WgL4?W(%aQ$tPM?)ujoz%M{McD+ze4mMdH<(bz8PK2J<7aG z`m+s-RWif!X9*)AKE?D~BnQnkUiw3qo*mcAsT0BL>e3fwQ$SF>ng0Y!DAYq6(4WPA z>|rcXMI^5-fA-pAk6D#LJpD&)xO8f-E`2c?F1!4w`j6VN*!dG{U&HEO)NV6SR`K)~ z(J2(*4%kOG(-*~Q6)rzU^KJ)krm2;R>88D48)TkT|c1%nP8u4RZ=|p z5%m))I);+EAU}$JLL;*)DV}_rej+s2@%YXBdyvNn>~YJ-B!cFkD_187kef13Bia9kiox{_%@E^_AEGTV1;xJHFi! zV-1>M7{7i$EMwC0C7#%?jz*5(e7`JR_`}~W8){TnmCN~khT3Fp;G8}OPdF}edpz~V z;vB~?d4Fc?J=h}Y9qaO7%DBYcIJTgES)Hf8!sQ)XT{TuT*Lk&d@H7KvTDkn#6p_IsS<)=!(UE%S%Md-t;jE9Y(IYQ2^z@A%2 zp}gnu#V_J_%zSwptHz3rn%0%E#8_^mXJn2WKVjmeES$z$geRo^`HeqRyB(Wu}3HO648n6)^CeVJlq@R2+v`y#$xG@E9Dj$?_#D+u9*Ya@3(2 zh8V3etRa4R(L`8alq&D@!(jCJ>&k$P)ewXeae0cj!$x}zXdaK0xeaR&Wg0FtGmZ5t zz9>OS<0N;OkNm`YJ5YLqs9esRa#Z2y9U~YWZcAl!)K@#a(41qK%UC)_4&xPGUbe6> z7QBsHg>Vfj0TA3^RCwhrdSs$u1yZNj4DYfEBnAi9I!K9hM53#j(%Hz#XhU5(ycC~G zq7FknO}3^?8ys>Vc8FsU-OHsFApt>-rLaVui8?Wl8h4}HQS4Y$@2FUWSBS-CSxKo5 zQ3Ce2`_OwiL`fo2#Vj%zxuE9o^2~-{IT?oZyI!JE+EiC3Vho40_YUY_Odli1VU)=) zzB-1Q?t?7a4ifG_n~&!nH1H03GaKq*c1EG>nP++^2BFX#cq)9dzKY-_6;+N|bBt;F zxCGp}bLKscX-%as(Pt--r=9S7{-)(eUbQ8clUo6-|q3e2&1;6UZiyuFz&u-{|0|3eDtK znqUx6bW`0!br@baq*)Vfh%Cg8ROC1ox$ES>TDQwlxx(>Kt;dr#!jT3U)p)tgvtq>U zj;2~y-Z0ngjt2e>@Ok0?78b}sG)?X_okCNtuf~leHq=74m>BACg+pFoYZS{CM*b+r z4-zJOK)x+qB213^fXm(#R)}93N+x!UoeZY+BU?+(xL={soJzB4tUG%u5O9~E=XVFtvi^^8sRrRBBmVmqpi%QXDEd|SM zPVt?^PNy_UIJd!tW)U4vnrRFci%D34A@xm$i;GaZTrdxpTPm2m6`QcMU^!?x7+y4D z5VI_C390~0yWjvwN|Ak3x04k}SBSjsCNG-2CX5O`&HUEZxtF7(KpmB{I=Y}lQ-AuU zYe#6ldAvAUmM)02*|WE)(p%M7+u(Cx7nZbI9G)gF%}gKcdHU?a5PL@bz>E2AX^=6k z_0`~Q@!BdGW~*Mnn{YHE3=H+~;;tUWJC@egV?ZNqe}&I%VFGPy4yH_wC3x*y%ni@^ zKA{;(Hw#^pXDS~FUs8)vDu&sn983P^6y7;EL;+n$wXVNi;K)JGf?f;b1+$ICk40RG z#y2;*rmwou_}l|J4|L)UH7oF`0(5Cws>*4XXa2k#=M<@MF&Y-EFX`7b4F6@WswTrE>0ge|!C+n$haA!3z&o zWTdAL>ti&J#?>`oywn4&mOl+Pj@9mEuoRsGxO!@2f@o@Ag$uV6^K`Ai@ocmgjDVGE zmyR3EG%>a@OH>9I;(5|-oB>}c4MzoqhP)Wzz$Ju6)>~aGrc;k^dvG|U^eeY8-eNDV zna04abic96;i`9g>uyu-0$4ikNNsn!;7VPERPauv+qcZ^u5%c}48v6`eo}W`mHS~7 zSqO8G7w+(SPm|B|Tw@$*q&bXHh!iC%R)AlQRrn`f;)fju{yFl-#!2aQqj(-@(+dZAW1 zA+%1~1UJ$n$uwpu!<9}JgP|Na&t_XgspP^PF9O`IFT#%>{H_x^A&jPdjYdhWmko}L zJ{#)sy(Sr{ia!sTMxMn{WjJ!>zYvq{tN)5tK= z4bd+hOR!s*9KW!l8W1>js&O1*{W7sAvj`;BQXB?k%5PI_u8T!Z~wn52nm5 zET284tPE%7Snkg$FPl|fdXM#1Iau$3>}j(K3N0aVd-kkSL|Hu37NfrHESy{Dj1YYK ztkRMxWwr-XW){pUvEG?=Puc8y%F4roI%nM(7N6V;i%f2YvlkSW6;3NFFDWdUReB$o zrrafFYK>Wkm_EC_aNe}S*=5DEX4yyg2ENz6E#$ixZ=Mo=zfL*2-j2+`6FV+ZG7FbZf#;*={GFA}8Iu4RM_Uv!hl z?Y+&5*{yi=(0;qcOh(Un(A8Kn9ynojOrKf$lr9fOr9s6rODm+S z!16D~dNM&`i?4;&HOYsFOf4u!PcYf`1~RP@tvyztRLLnFiGLs%UY?ms1FubKP+~Nt z1)B8`QCeNW@(j@vE3IisaHG|;`_pbORWFEN@cjOKcy`5~j(V>DMA&0eFq)@arX{L?Xglu--X30Z`3=v_a- zu?D;nMjq;|ISk?;(xFE_p~E@DuneYPgz!(BV=z&cWyq$+5g53RErY_G^@}DOxj|~G zH2%fX_RGcwuCyC@vhL0cHAa1!!2Ip?aSsrFI_OnE&@sl?$sA@+lX<&Hon+pAV!dZh zlysAg*+XE$9gu3dWlA*%+c*}Fo(tvrAEL{$$I98xQlrQ6l~&Lw{0)(kJ-lI7JCfsB4BPh8VeJ~{i@-aS8$KVarV#V;oRvgYrv@0-t! zFn;+Wt(|`>?mVga`^DwIK8(KucjjsS;c@vTKaXA8(}6!o2J??wlQn;4T>jCDQHK+L z7x>dPe^y-nabf&h!Jnr23*z$M5ysyE{!yA=zUM1fbp6YhhVA-K#RrA2)%@};VY#C7 zBeD>F7x)inEBl#1?pXZkVfr1PVghksXkeI#|hR!*98g?u{l#>=5nPBlrU;!ha68u0{`|Q29+gbf+9W z;P0vRI2`GbD|$WpBAy1a&wgkJ_)R@_#}3bd|4m&Es`rZ(zf7I%@sC2$^wH^GEQ!Yz zJ^gMx4f3brmk0dgHNW(7as~L+Pv&z2!VT`Go+O^*VnPYT^AW??sLLJZcxcvWNiWHKUepYXX5g|Z{rtztONgP%^yo2yAken9j>eONaFbr{4XXD&k%HW&qfOuW*<;; zhUro=G+;GeJgyH)?eKT7j=tNg*= zU-QeXO0MYnAA_eM`A;^C-kN_VxnuDchw(1}{{YQj8kb+|uSkh0z@JUvAFlc39Ui%o z&P8iKq|@iPaSn(;Mx-1%ASX}Dxf{RbimnGIo(9;}{2x=onVMf_hjK;dN23$M?*h{; znm>o!vG`?%Xpes@_y=7De+T$YJIII||ERF|Q(?S4b^P6_$1d={GfB0hFiBp~^@q+m zH2>h=q4_0saz*FA4NvX*>j3|=nqTZnuIT*X{)1FFZ8mBCu8udv{#@XHRP*P`bO%@T z_;o$VL_lOi__u<8wbuXLp^cop$)1^-md-yQqw z0RNDy;7=W37#DTXG-Zq>xnuF)6~@08{FRztN?Wez@naAW68}fwpLjL-AB28Y^GmNGSM>O$ z=7;3p!tW(_EdIJM{=MLzuH#=Em)~vUm-_n=_!~5TSbfm)q+C-`+01h8YX2wkxWJ#A zKs@UZZs=9$^K}dV<2wD(%VP~f*vq3Y8h6uAeQn%+`jaqzC-}{EhQGv(|D26q^t2BA zzmMi`(DI}_b|c(=9j-g&@gewMNFbgea49^c!&U0|qwDhlgs|�r+=m{$Ir9KN!Zp z3H-UYt8wGk?JLS;= z{tXGlvjgE)>Tun$?{nbar}=M;tB(|$K60UtQ8&YnI9cgqoa(h>w0C0=!fp>9@IRTa z_y@=3ztP4o<*@_&uBq|M<2b_2(BZmM9s{t*k)A+2xd=BPE+~G ziK~wZVfxq${>_E)_0fTFEjnCx^pT38+~Ne{aU$F-9qubAFS(+(7alyd+s8WauhIP7 zndiI?{%16Qcg6#K9q`v)1-}#gIhr3sO@oBw8n*Ml4*uzy z|Bkr)Ibr;LzZm52&UnNL{*^lZ?u&|#!2l!{|{B&nLa1Q*>7b$&oXFMDl+MAsM#*S#Haxj8{*Bf3oHW$t${^&{$gZRDfSY(y;!Z z`G@w<{1c?*?*Rt~*z6YGEt_yZj<|KQ)J`7!n6m8AcM^UKJ|KCamc{^vA5hIqW9 z^GghN{toc3)ckpI`Ln|KQ&DKkHGg_s{x65|yTD(g`QeJ^6+QjZgWA)-75q7x|DL$~ z;z_gfcYxn)FQ&xhmlCt{ry@(GI{v9~`9;Haei!)5G{0z9uITw6ho^S_t>8D?k?!z! zfWJV;-_`a~w2_KMr;(c9CyB?E^vyrSw*SQlgly3M!T+Ghft&U%;ORnhgOHXT$-vxf3=I_qDcq{m4Xnr(hyrRb+ z-hXz0f4t`J7nlEfgs`VS6^;HiSHbTB|Iyj1|L;!uZ3X{v&EK8!>j3|*>s0*rs#;?t zE%|+v`Xib}|2+ebb^DcyMrWmtAFd=`(e*Di#I8RV_~&VUEXBs*mlCq`Zw3D-&7T~X zzmJVS6~8*b{|`Mb|7<9~{w?*gZ>C|K(&4(APl?9~{#O!+$A@rRbvPuAS9E>q_DEMN ziDx(X|2ctpP9ogOZsteqbO^fQd7A$lDw#%7>d7c}BlSkF8$S(F7onur1v%eMAie7l z?in3!ycwVV8$M1%r8Xl0CGort{wETM=R<_^=y0eSyrSzLgNKlK#v^eH;>08RTYzv= zbvWr&1c=-XDnPGl|D@68uI2@${T%82-?B zUVS^^{1kxyjOLG(9}mJE3yo)4;_>VN|M3LkIgW69b+{X}LZjP(y}gz48Gs?k({bV{ zK)76lTdu<`HRs1adn=0Gt^)`6=PeG-j#a&Fft+m#*xe3@sxpok?yZz*+VnJ&Ay6$Z7=w5)%>ygwGM>q zsl#=rUrWt~Un~K=IT7xV4%eN2Z5{Z3m_R(c5pJ^%*VX)p-F^uEX3Zby*M9Y86uXVy zujOJ1<&6Z=>q5AfbT~B8yrS2~@P2J8__xQ2NAmSL!mZcg7MSr2O(0)05!lk-47fcw zK8a>mtp5o2q>eApza7QfvvP&`g)Dl!&mLb3X<)Q`h4*h|;D1oZ6SMv!-2Y+jecXHPP$~{k*@zV)R*X<_#EKERZiI>v3uLjfQ4k|m zjcnH)vAEIgYQXR3bIx<`{JFXJo;kzr?{{9Wb~1B6@8>z^Ie+iDckVdzwd-eO)F*yk zKSSV`8Tc88u2FQZpIglRB;b0HfuC0B=9c{k@8@9Dp;1>ZvxzT7yGZv+3b z@Z61H@*nT(aWuaUSLJU(yA!_LagO{b_=knZl%SHoe=d@X{nufWc%TBl4gCGWbKS+{ z@BdI7E%x6B{+0^-kAm;1z<(VE$qwOh$yg=-{7d^iSQkUpKlqgJJZ)$4=jY>SN%_Gi zg)g`MIWLcbKT!C{G!a!Y_+F*(Hutsg z7v+W|9KR&`&yzO!2JLp3BT_k30+)t3s^QJ|9U$NNAu-my>)`0 zZs4a6y4`ZU+~&TPQSeWQADjDH>XxB@oUP+wb6*P{KN!iJ8y?Rd=&lx>O+1IduQc#8 z4&5oDv$?M&@j;9$D|LBn?rTYdfBO9Jcx0fX+8sxL?!x-m9cVwua!?gp^ z(N7!rnFfA(pv%d)a!jb7BRqbFz`rc~+e&$P&$x|4w_SAQp3kv7iRD;x82D+0?q1Q^ zw4)68H3ohLp}SCY*xFUezyIT6S3&<}c_zT0BYe<#eEbZ|8x{Cz2Y-TrpI+$ZRp4hB z{DB63a?rgg^Po-Kk}I&UAbe2V+Ms(ybT<1_ec-=k;AaTBdn@oW3H}PxHk?-6B6P%6pCn6VSy(S5vCHR3^CoXyH^uWN@4isak4J~*&pW@T!JKf8=I4g;EJ40}DZCrNzgpo}I{d;X z!}kxcu5e7zP7eR-OYOYzMA>$lu!qqob~v3e#s1B}&e;%3(U_ke*l8`b^R@Equ>B0f z&ML9v?r-9Al|1bSH(@xLz+dE}h(L!W&vK-|uN3~Xc+V93`}e}*x(>pEcw|64P-^F= z<=f#7e@^UtLFESd`MQCf&lKk;zEA!<#kKRP^6W6aeBR_n>EGqHfAW0ZHME`u=v1$c{*dSM zCLgJQ=kq4}D&Pme-zdCI{KmnzRlp}^;`&Ji`A>tdtHA#N_}66r<8agmQ#tiF4t}%( zJ~1m2`ECV#8vJJAdDg(>pZ^4o7Pr3v@V5(J?s`YHfABX~;6H)PuBw1fgFjRFwJbbR z?A&cW^8*?y&l9i13&Ozs4}kw{DZkX5A7`+o{e1v`GVvpoJoDpHd|Vv=1eRR0gfI8} zGX-mD@UKh$d$rd9|EMf|U(%Ywj4%#a*g0DA(GY6qU4^)s=X2l>5Z-2;nVgNWRLX%{ z7gUP<=VLzgctVkX#-S7ZF5xf3nuRI$V?W-F!}*Z96~Z_S!p@sgj&jdu$WMU(iSRc2 zT}@Sy$XA44!a^YVwy?v+f7%EiquYdOMlKKa~Quu~Y{#_oP>+Kfd>q7bc zJbW5_o$%OVRmng9oDqxjKLEa7_*5v*E8xXE*V_rzl6e~5?Ydiw?8ZO+HJ-hM{-qeA_2gf5Oh*V}`_GdfKE z>zj5%B*W0%ruD8d8w^{FVy}eU-tM(5*D?G<@Cja=cg%`(<>+LPV+l-%F zZ(l7uM|UQF|LANyU*JH6Y%srEZ?6^p7`$il=h?!F^FILo$_n^#@a@9e^uGjxcAD@u z>xVS>MHS?K0DOG~{5bfUO3IHV&ED&D|FJ4R_;KN_>L2_I75E}8aj~^fO@B`qN3;#!~<(d5JPvZYO2qpgG;NOtv*xcao z*KYBtKU&84)tToLHMm|P&#_sHwG>nA%OU(V5W+u)!8G{mPCD;oTRemo{Cz2EQ| z{NXl4)~3zqeBRKVR1#zHb`BuYgeMAqW1&^ELlN?LMF# zx%KeRkh+0nJv8AYuZa4KMe8zSqP;bn%<7@dtIab+nkSfgWo2+ z&3beY{N2LiPnG=JAqKyE^{IX^0VpkeGL&Cf#Irv)VUucw@RvCJAN<-O`+#+xRI>pZQj-4O)*^zd11%y%$L*NI5=XApq`D3nJ+cli*(w{z^rI|F$1rP>v35 zg9yu!!lvJhZrvUd{1C~%K8o+>XFPks|GqRIA1pr~Bd}8|`6#ztF(1`9x$xxUSAPA% zKOSwc7mYYt9EX1J%Z2Bz29rO(1V@YcG4LN2-e$gvABg+hgm>eZe$Z!} z_ts-O_?8O%_k(xp(cRzQ&(Hq}-tvRrSNxAMcu287eAOraGQKJ{y8y=|9?bDe{cQ8=it5t;n}*F{M#Q}cyaq{ z2mfkm`Cl6dj(=hK!C!l=9#?JJ?-=-$@HY96<5t#FD)8S9zFK%U{s;S&-y8pa@QuQs zsG=Vf|3#kokAXizcx-{G?!-V@~QB63`2LP=xpM_=eu_s_(?){p6ISZyJqqq|2lEBWc&kvyYM#iA)oKwD?DdQ zCV&6l^GQD6{RZJ})^mKm`^6RTo#0!AFL&RG<46|#V&Q+QN{{lN_=V}}PtW}G3O+85 ze-8YZ@b7hadG)SmSVP5p^6)%wvmWRKUweyg&o=9UEchkD2aOM-(AA61ra#mHnrYyt z8M>Ur^VZOKuJy#T2mB)OW3wI@0{<7`ZPo*m;2&BSKE5Qd1)32Z5S9G<9R}Bec7rAt zNrS)Iz)uFcm7=p*4~&2x7v5$)P~Cw3b*qkt&3d2}eAoK$cy>c~j_7RSIS9Vlz|RMF(L)jOYI@-N{h!T&<|BL$4T%g;XrxGwxoydoQ%kDD=x zKYfpm^ZDY}-~ZVj|2^P$2_FyTv6)$t{~_>0!aw8icYf9pMMM*CHYSQI#u}d6dlC3dH7!N?ZUHPGWq-G%Dp&#!{9rF zFL%6W|BW7pebNg2r@)_Hf&X6cSIPZ7%UF0M|MH)Tqb21Bzo%cf-~ALF#B+qo^X#ut zTsnAC_@MbN3EhC`YC`?&>+#bG{%Qk1ebB8G9k%RL@{b2Da+H*36#NMWekP%dTb76I zrup5tUM}O#$8|OX>P_aKOLcY`_a5*E8{~5Ux;Mp7x#Khaj2GlHsD7)PaJ@qOU`SEP zKkis$mBhUj{FA~5`RRskKyW97fVX~#IecJ zVc;hP-D#p*s=UBY-=}@%pOZa)dciLfzSiO8)p=oi%R<*!>gRNGKRNJ=4E)rgQs$QW ziJ1Fo10Of=(*s?!)X!rZjN>*0ex`w+ap+#VSC5bHD2=aY--shy@%Wg)#n#jec&%N@G}Hm%CbBhPbR_dFTBnC z#pk=f&mfd}UpC0hX82A~0?m*Gm%wOZ+ z|3mgUg6gOG6nxJ_bT)ok!GBfwp#IYh-R+{YnZE|X-)!J#47zj$e&RUQTq%4|+)~iB zh|cQ#AN+jb4_BQoXq{RQMZTY-sYiyv$Ass5CjapWlYa>xZ9z8|zTA0{{!-vyDBXwa z{iIKSlk=b_bvDTNg1?{w|HI&q5Z-40E&9Glr znBw^feG;Fv=>6?qRAis=A+t^Rjo1Zdik)$@PkcWEMLvJz2dJ0v!zMoC;GJ=yTz-o9 zeCPNn;*lfQqiP>cODKJOI% zP{K(5{9GI@<`bx~$pKw{=8nmqpNXTzd>Z_Zgl|-I5HJ02fi|Ps2l#EmcRT!kJwEMA z_||R$H7ksU+(z} zRe<{2h2S4;ry8S-o@K@Z3 zs33Xz-z2~0rz9V^q^XjBKSvD>o#1a49!uX4o-6k}&vInJ zKPKh4PUDf-&KrEn!TnA7Uel_)DcYHUo$*pT50+<#@n}X@+rLl86-zjk{NsU>+k*0t z?*ad?^h=v|H3Ys}c$@l|1b?CM<<^HPKZd&Vh38cVCjauwfTm@tJ@kM-P5AI}vG}?M z>v0JD&bxK|-S#kfecA0HiYEVNshtORzJJjF z2>99x_-Z)&i^QSab-yY<_}^E+XTZNAyjA(Z4-5Yh1`i1z>Es#bmgDo{_*G-bc&P%u z6@0FO{Aa+wAiPa~9sxg80bh+l=t1GJ6|Itg{MciQv* z#ogT%@U7tQs({ac&s4yVfd6y_e04Q`=cod{75usi_zd{974ReAZ>oT=#-_-P74WU# zuNVGVr~hoZ%4a^pxF@Z-YIM|qh1 z$B%d7Xz}=w0snLb{0R6h!rP2L)i^o$Y6W~N_y>f?R<}z2{S6-(P7n9Dl2^sXi(EZyo;95dPFdlJiw%sp$o5OGO(*|4E)U@g>NAce_H*GewW{Q{M|sb3rl5O5bT;+b3x2@B zPZqk{Mfa-sk3F_JxIV`qL^okRbKsr(Q*7!Zc_5w>EBAA_^>Jm0|APAH1V1ReTOXH& z@CEge1%Ix={aB;WHH*%sKI#s_^&SI1&Cta}=hnybA2qIz9`KI{KhLR8dG+qg9jq%- zj;s9-@EPGRarpIq{&8~X?1!D5H$^+qIaoK9+G#J(4%=5N>z#0x68PqY<$weU9mD+B&jiJuKW0)D&j_o?V3{=d9DxIKP0 zAOC7Nb?#Gk`JbBet>D*G5Wfug3x$8w$^Ts;{ziF)!QFA z6Bn;PTETA?{(?~c91ouXKP3FU4*%k1!Sz?re@4I`c)#8cz0cvF3gHXuKaTr+kQE8rNS2 z{4K(xDXZkJH$3~7n9NJs-w612;obUwIK+Qp{bLf^R?0tM&bNZE+iV~I4EVo_f4BZG z3h`f9|KK|-@L!FK!)FO!ZvAr}Z3Ta&@K5OK3pjtlX1%`7#-h3d3Hw1G?2L<@_lDY8 zQi!YTDx($hb@h4wHtnzt{1cM@a(TwF5Bw(KJMf;#zaO}9}$ zc5t$g$5kBTxWsb1CC_rSgHH=zNqZQ8otMQ93&|9_>tdgA#d{t$4*oUa%dHQ#$HaU* zzor5{4gLY)ZR%kFe2*p1dKd?Pj_{S#1D`K3B6iMXB_PEP|HtX-56}4AijUpqsIPy6 ze?@qkdf@XVwpGCM`4V>vZ&MF^zJxQr+VFh7#A&7R+o!`getf>fxx$~Kf*v$3oaBi= zpD%H?@P~);^&XzjmsnB(&*w`VD*SDZ|AiO%lwZz|ZqnIcKjiZzE)zcK@bce~?Kg=yYM#kmj#~{-lqO?;O`Y4O+h99`m4wB zlKMwTJ}LZd8jr+gg_OUb{dR(XT6nHrnf(1@Grz=t7JR?(Zv3BYH;#V}eEpa8`qU== zNpy*7;cepI3I4B@lpp-g((?cQ0`u~NZxlgntA=3`45?;1dt%{`&=oU*X5kf`a!kY9aX?_?v~FscS6~dygM4^Y7#|*MAa| zMoR8ibL)RW2wzzL;2#v;s{X+{_xsuOza01vi+{KNKYw0u`z@@040@Y{cjNbX2wxDt zPVg5#sO!&--vc3hLHx4dw+n9*za02Gg?ID+;Sm1?`A;5;@pFsL|61LwBC+>|@Yg{o z?Y9$rpYU8AG5L=_*vu{&f3x7P7XCy<2l0zMd=C6-;W@f7`TKtxj+V^-xG3B#yv_Mb zC-?&^DL?rCdPv6~Q<+Ns`Nv|vB>y?^W5Qn^%3ti^lgHs&iR8arp1J7+f0XdEOa04x zj#GWm)rhX#d76Gk!B0pzgZxZF_p=J(*^DN(UHFZqsbT5g{CT`X5#=e#CLHTKd?kfiQX@_pT=;lj#-12$i<2_&M2fs@A z{X%)xbUwapM`Pem6dqH*O8)*Cv0^^ng!47w=Y{f|k&5|t@Dbr}aQKh6`OG)n9=;#^ z63gUeuD6`^LiDl1j4+Og<8i-+Wj@HK!M6!-6UPDYi-g}H`S-6! zS+{Vb3)MmY}clyCcLi4{|XIym5{{Z-V#XtU3$-n#<)JobR zpD(ddc$;~b&zHDT`29oud*{tG_?8O%4}gEC@HXSfI2Q}T+l(WL#W?Sjb(2l|O@n_# z_;UTT9}j@PS@=r&F`qB7*D@b$hkU-ojtb(?3I0LhZTfK*{4r9G@z8d75ERAZaSpsQ z9Z z_%`9o_0N8g1)mVUl727&JNH}WgK=oWe^*uzhi>q#!rSzNLGYu($B`c<|90%{2NU48 z3UAX7noh<#QTT=0eSm+q)Z%{B4c=*o<*rka^~fOjjQF?dM-$*L6aM_r{GaW~f72=W zo`&$xIQ(}`pRWG&tZQXG@}xGy{PXz|`^q>{MSU31@32)5bqtwhQPm4K|M}_&kA2|KVm&LFU2|h zTTqX^u+vvT9EZVQQ9(UMPsQ_Hg|~@A3cRzfs-!(o@HX>FEBF^=Jmjp)(7MDu?JU0JJ z_(||l;ceDo%{WDN>YKfp$=`nijuz*?2fTAV3qzMm{yY|KCHxS0=X`iUD9;hO*#9K> zho#Y>x%&FyE2vi{|Ni!K9L@I^_K)O;(Uv40R}n^v{Zf9> zz;oU^3rE#+lrF^|t|7LkZrFL7L4Nz8bH??50LK*D6y{Is=w}SPGd{jef1EF`yl4N2 zF3;C9=OHHlxEzb4ZgJFkR0{lViHps;uNVBY74XC0o%0xM@v7vXe_RwR$$#_=>@kb~ z?oj^Y9zF&BCE-sA<-P0HUhqE?zAco8xFr9>_{iB;ZFl&)mIU|Hv$Pqu>*xwRr(4>i zJnc20{`UnT&(*pXE~F{29ks&F(y!_MHG=m{u@gh`@f1X`K|TZidEvi4jWqcAA^evi z6n+H!lCNw3Hv3}LXX5@e;jh&01L80P3Ov6fjTiCX3Vx~ZHrJ^#;1>&jp5yfINr#u2GJ{6)SRZ6YDOP5fHHzxl9^zfC{NfL|p3ZTis&_(tJv z`cXA5PNsx!m$=3L&flX!@{I3N|M1B$vLCgA?-0I{e$)p${og3*M-PSMqo5y+f^T?4 z^KL)7JA^OjM|B8Z-#6|1Q5*Oxg?Hn~7&3*#k?pV#{O!Wq^rKPmYlV0F(UW-UYmonf zepH7o?|X%}=|^qgJB7FDM}6Q=6TVwzI%q!rI26VGcoh7N!rSztx^wV7Uf~f+mHg*Z z37qIye{JA1!n^hVaXeL)DWv|{kNUuG5x$asGzL54-zw=x2ZiLLpdZE0#Xj|;CH-i6 z2w%{T+QE-~+rA(5gMUnTH;yWZ;c;X=jDdea_!ETlugBw{C~imbmAKw5yxWhCZ3?c( zf_~Hv{x`zg^rL?8gTmYNqcQMz3SSdiey(du%8x>~3;&G6UnIXY>DP{*)Mgm}cJRLw zezwEQ>(u?A*ndCxt->E3%GX1Y=h=_Oz~3YM9lF*cv1b?g)E{%G&R6*0YS$3UkvJc= zzN6bQLaLH~JHq6X$JM$b4SquSqe6L}0lMxLKLCE0@HXve9Q>og?;q-)XG+EX6BpqA zFX0!3@<)64H2CW(DL?p&g`Xel|D7KHY)?-GU09NAq)N(;oW*zactT3FabN=|7>3mO&4OM z5Zt7W|%Vy4~8;TMqmy!rRna@*lC!C49MYSLFx)wD4SQG5Obf5=V>c zJq!ME;ceod1Ao8pHt|nhj5-wFCjOn^&llb%{#o#8;ceod1HV*woA@U$iA3HlyiNQ& z!Os=mCjMFQyDjGrw!a+s=Y{8LkIBFNvELWBza;j$HVGeBbP#`#hwlX6T>+m3zoG&@ z2R>N=pS%?16@FW2`M>QgKlrs3_|JlG7k+D~|F3)e=fIB$f4jq9ws5-o)9-v{tv18< zle`Sy-;(ybP(eZUKVO5QQ{x}_H^e`WGWoZ^cj9Pq`^$p=mGC&VQOTd5f#cYpJp(T= zquM|Cy~5k{zvSf@zlA?syAQ~Jy>=`*RetbU;p3saxBq0pJL}({hw`Hy|2go7N&Vg8 z@V$oz*Z&%AhWSsfibO6E-lqOK!M|Vl;~oF<>OCKB)Q;si{b#{15#Fl)!GA<}tNQ@ge!MF%erz}6;Ns$UuFJ_Ep12=?1I6P`;$!$-4C%M54yM@S^8@`xuY^d( zoizAk#Q#D?2aS8I*<$|#;GJ>TCT`>4$0h%6+|CWoKjRkf#PceI+b=ZVvpxB42mg%l zHtWTH@Q;xxntz_j=Ht%x7QX`fcfz}I`)06z#;pz9--NS?TOasm zg|~^@DEP;PciZd2;CvUh*E+P_KMG%N+*J9&zbZUi1yfAF_>6P;xRdV#KkGz&p2yzE zdQXr7NNb>q27v9tEX$*<&I|bbw(JfG)2KhM*ihMcgrx*O2 z5~m902N90kAHZ@f@mw4X`nR*3F7`P{!ePeYL}5A(_2vl|ospF-n# zCltjzf6uOQmu{bHLiuZo_yqj(_v}{vTJu5eW*oZZqO*x-VkW-BXyB(6y1Ak|AhbNS zMde{UGvN0KFINo%+Sf7Y-No@70YCm*9gn#<%H&_42Ndy)XZ0+6Pw{u*@oa)_Ky(X~ zmmoifDa%ei=%*X}?FN4Oq3aUe&7twU!4uCh@Za64%X4XHK0Au?$@+*R)4POkb@(67 z(UJ9xpJ-&;A`c62A5xN&d2w~eL=!s z?D)SbgkPEW-wyutQoh}s?+4#0yv=#o82HnKx7q)VV=DdriQ2bUzfu{`
  • gxejG(hxOSBJ2Qv$c=S~0 zc=kQdc$Njf;d}Oc4*cvVHP3P}`NxARRyPc4U6RBkTO<6viU$99ovv9=dy?^Rqc)?; z4}O*KdmR3oA^fX(J_~-%cAbCj_A&YA|0o)kp_>8uEcm(Kub}+kXA6J7#3BF-i=l>Qdw}1PU@)z#sf?qAXRr?2jzVPn|^^e9<(tnaT`9DVZQ$u;l z|4G`6s(kpG%N&Ir)pAa5h zA%w?bp@8RkTN0bAcL~p_dLVuWc!#c6Prtx%CXQd~_w0VIbvFBX{5`wb!e67T7R1l9e!3D0 zH=D{of6wj|;a7+9mlp9XXAb--;n_Nvrm8>wp51cMl{?SUPaF6q13&ydySbvfRpq82 zKc0B3g`zkfL*P4vx7p8|1fO_W*XQe@{&PkCS7w$mee?J1_Wy;Bhs}N-f6wkR*`Kx9&*Sge-7ovALGc`fu2*z6@tgp^ z+Q3g7i^LV8v)RvU2fsk}M{V}=`oYh2&R3lAP3qOV-uCY2je(z#{luVnMi0U71&Pik zo+ zPfI=pYn|XX3BQugkz(JQNE4ysrs|8iiGbYT3&d`y79 zr8FNODK8(i(~MiL?iM?ot(am*7})86u%JA>u(M6<@T`N$zdVdfzFwG*Vesoq^YNrS zvE9=y3gX(4H^sPCW67Dd%m;b?p52WV@cccyWfkxv;13l3Oyq~jKaQ<9nvbI@|Dln{ z!U}l)p50>M4_DrU{MUQ@XTZ-BzT9@r{EvX&E8~j|UyUriApDK6#}xZq)Te*Wz)|e? zci{zLRP|qvKPCU~#m7wk@n3?Y#qrP7=Xsm;;RyH^@o%#}tUe6$qVPfUMH6%@L}xQ! zbb~*^z)wGPanaeV568e?EWFM7Fg_pi_iydjhwb2B6h0`Pz0eJb&L*D2;2$vXlY?%9 z=xo-9{5`w6ar^aQC-_xzJd(R&*IF#^lKz|kgM=LsrZ}9N#;CBmuvBTf=hOSx9 zx@-m%m`}MdMln)&=?6bs^8c{Iukzyy)^+{b1`)<#9CkXz&b#>`l7AeI!O`M4CQ!5v z;ceCxY4A&gw~6Bb_y*yRQ@Ibyf6|lxaqx31@SivW{)9&tQz<5|-gZ=vBgOGcgMUrh zfld4d!0)Jl9|!+{@b0?qLw^fyhXw1p#F6Mr!rQFt(gnQDx^4h`t;Bz|#N9vsmlnmJ z){!4f~ zC!x!V&L*DC$727-z)u>wHKMaw*A0N5xmTCRW?eT9KJwS_cvRz}`m6t=bvE&61wSJE z+e-VPyyy7U4c)gyXS1#w1pgc1v9wXie?BN)*Ku7n0sdLxf93Gk@UD0y&$?`1d??TF z`w9M(sh#C$#$x1Ri7V$BCjWe3bH;)37x^CWr&YiYfj?4sn|YbPXXo%X^D=+W?n3cz zGcWV^>^2A=)L!^|c2|ndrd^JMZ!_@2-?LjHI-7a975rM^ZRX_+_|)HY|9c(ngUP== z<#05=&Sd)=0sm*=gW@>>-OHl0iDy$2u6G#t;qTc!C_0;YnZIYZXi~?+W?ts+*{y#= z^EUHx9G5_zcvJI1@k~KCAUd0P_JY6Nz)u#sF45V{%Q^6;{au&GW?oL7fc`PlU3&eRP9A-@s2lbS#L$@kzqFQ(&RGaq$=&+MytoB4>p zXE!`s^Fi?(h3;X|*~GIBoq3~ypJwQ;6P?X`)C0b?N|(oGJ{khw@;1%e%tw>p=k6CC z&&0_XYD8xf&ouZ~Yr_3xpc@gL&3rTh{`^|)$7VjNJ_YmH{^9xL@7XO8olQLWdv^5( ze)^%CAv&A+Xbk)b!rRP8aX=1lGat2sUoHM^=A(Y_eFkwFhVDku+0;k01^fF3ev;6g zCOVt>s1tlfc$@hs3x35rbo;cKk8(clmo-#nTBqw=xpLS0RA2WKO@lfh|Xp{sy-Fhvk%hc zv6+ur!Jl@p=56L9{+?a^A>r{Hgl?wjY~ncqJ~ubqPaKQc#lTMzx+>9?J0Bs7kxuZlYF>#zEqwaEWskZu=9Jd zbDWbOdG+qc;$n{z4E#lY82p&lxNQ==6k_A{m&+T!{8^x zf76w@zLTqmi;k>Yx72k*qghVKWz zL&||IYnA-{ALH>q27X9*8~^bSVSOaLO}}Ude@kgSNIAUYnzvu{gWo2+O}`iezg~E^ zUwrdrpZ4VK7yLcDhlO|h#T|ZpL3=Fe7irk(m3DNbl;6J|5BJpL0Qf5_XoutAPZi!K zj)@QBKC%k(p9ViEaV)nTvOf=ie?jE{O7=*FT73sk}I%=6}~3aKigq(`{@L~MEG+10o!jD{C*Yq z&w+nM`q5u>?+KXCUWX!|{{;Le5wyPg@bi&2=x!9y+k;AaTB(?n-e zo=NbNhlQ6XaTe~k5S>kV(%^R(_~Gx_Jt8`edrbc06E?jH>WA%vzi0QTWj@LC_v|(a zzaQQ+`TL)Zqs8rmzh`&3K{>mjYZcu*^tuVZY44PYSwMr5%=A9@cX&_+jC{i1$pf4f2GTp!4FpAe1U#en(*EV1xWlK=-Ej zYoaqG|9U1?cPg@2o(3wU|Yaxb&lLN#fxq)0EQlk2&+hdQf9x;K(EUtwN6;CPe;iqo;yCtzf6~Cu0CWSQ!xo=P zu^;dBi6bt8l=vA3|Df=-4ll3Hi|YU9;`(o?pIgoSw1VGg;HMk9HKl&uWA0}VyfeQ9 zm50A)cX6qo*MDprH~yYo+Mqls=vqbhj?(yg`Y%@w#qFRM{GkSZve3muXEQ$Mz`rQ# z2fu#Hc2I}@Fl4#TU@LC}f4hO79_YG6SMIn;KSSV`8~7QA&RKWbtlRi|cGJbrmGH~t z-_KU{rvh_p;?vs_OLirXl3FN?0+@t)&#T?f90YT&0Cx;sTT4;+*K zczrOA7LV6G9oSDW@G}72S(fE#hSzcM^}>G~@0tAbDf8E*5Xt)ewr{ge8=GaiFWAj6`jre)erto13$yibywggdKucQ@Ii6o@7b*o zoz48!3I0%n^7KI$6`jreH46R(xeq639G!%2o9JxjuV!qr++*M;4PB4u$}JD)uL1C< z3x9<(Zpo|nI^ql*!9E`PwljZ?gTLM&pVh0dXC=CFuhS*qt`)p<|5H%hyP->pADj7W z5PaOAJY&#J7oAQ2i+>dJhYV2Q>`uW`x#(vtsXAJ!GK-XRB=RR{kL*TD7@WbD;yRg*HndW}@dv+ZLep;bh zCOVsWB?JBt13!b%MJw<#0scj~&oQW<^7rh9L}$}~_}=A zq%bd}!QU_Z7xA7c_Q&t~j3@izsC?i0F8nE{6r5kOu=8IA`5lGsCDGZm+d7;iju`l9 zhVD_(+00`-;2#L_!}twAw?TB6%2kTJ{LkU>!@h4}{Bp4KP>4USH|n}Dev9r1?JnSa znKe^<-q!~HS_3~l(48+jcRs84E0_0tYzTb2@U^A+l=tfVAG%bjpPy~>iJ#X`;wr3b z4E(f0cTB0DjJcl-_(lUigV4<>^|RF6&jk3n27cmKWBnvLoB6CA{7>ck1%CCz_T3BJ z6Qa9L*GeR|@o}H}nFT^U$9y#eZo^|M9D$vjl$HD8P8`U&sOYxjP~r``I`YrU{@kU?Cs&`pZJrqH+?s{<&TA<@f8Kem`bM1R8u)2~?ljT4^V(m( zdMJwHKLq|9;maK_=zkJ?i||WA{U7h~-@FdrXAz#`I+K6 z&wsF~ze(_8!rRneb8jTFQ+S*D>jD3m@HX`~1b(ydN2}-u#lOK5|4Hz73U5{aw_;zm z0{=bWudBfS5cn?PPYW&o3@C72m<=DzP__R8|K;*2m}y>*J}myPbo?)rUxxMU({TKh zef zHhhUk^=+63E8ttf4-3Cgc@OeGUpp2Z^Pd5q6~5g5z&MV8zeo6pj$S18Z(j|MF@HTAH{8JV@g&#P3v zhQV(W{thQ!II5B^Bj<^kc%RQ#V|1m8g-<=CA&z5a*(3KI{;Om6_g|Ls>Uu!)(Dl21 zA2kCZi&3ZGY+JKy>U9oWKZy7^Q7VoHVj$>LxFC3K$WGsNs8#V&E|x^Yn8 z9K=EW!8oW!w<7vZ=zZhB=v74*hfBC~>1&0VKyJ}S@oyA1w{3kxJ&*Vpeu$KBPn02i zwS0+1>Ua=o+Kp=To92vr92fa-t$eQxp)E>0#-yYE|!rx4;JvCln_^8H*7}uvq z>-k5FToMh|v2V(y!KK;ICI9c01`zw^{rnW`Q+`lWi}68q2XDVF0CJ%699OA(13_9ZC~YaD%A&5Mm{UX0@tj>H`2Rp-NN zJO1^+&X$C>^E)Rl^NQ@uin3xbLGc9>7RMw^U^I>ijf;nxjngp4t%Y;CpcUnU`5eQ$ z#S684&cRHvPRBk!P~)WgT40LJec8Ly4P?e^#mw|5C(b}({E(LlJx~-zyQ)(~YpP<4#j(LU+ zLd~~oMq8l>j%$-ptUN~h%cxHa%Bd%%UD9kKs{f;^w~78!tac=~9D1UtjYdGATGX_G z|L7+T?e?$fdFD1n6>_Ti75V9de(PeLuVWqkK~6t*+wD9YVhi90Rn7Qs1l*Q)YwkIg z9x3K>%y8kj)`0geuI4c63)c7VJg#6KNZ=U%&3RDU4_ddk(vaw!`OJ+Ik0H@kH~#JY zsB96!$6mVZmWTgkD=ORpySxG)DW+eLp73xnk5Q%}o0FF+Lac>&uhmh0@AJYP|7-E}t49;%`TD{b*1e1y3Z z|2h$jt>TY!BU7nAtmApgixrhl<*s|<8K&~+H-2B2GMpc{d1g@JAYx@88sIEKy^16>Nb#Rj@g=o$@loCg|0bR74G zpsN?1cU|hX3unII3ZP22=9p@alYu;2pjsy#&OZv` zu2%9}uc&aY4Y~nvd%vQ`os@?|C)Vp|lt$0{>JOe@vh(COQk2lir|SQ(yGQKy`rAco zDY1JhKH&%e9|-{OiP&@09;{tR5sMKhF8Ul>0U+=iIkZ zYX+d83{q8;Q(bxcJlrIneQtg1JWN!Om z{dMC|gK+Eco+)KU=rze!wLy zlN)dSR-F%w;@~FHdH2iIt{XPWFtarP;!=vEN3zJQ#kHt+ofB)v>@0rgPe|I?hubHUM zXv6v$Izx@?^hGITbc@QUyWdJnXb&o*bM%Wl%2eYR{Bv9!!t2J9bUyg2-b}IePCnQ| zeD)Xq5r+zPT$LX=pXkP+I{1jaN88=WMu`+V&#|jA=Uo>yMp@O~brG{s75%u1Z|Ryz z%0l~n_?N-^j#ISXPt@~M_}$O(t8&SGZ8a_w?Q5$;93NHQipED3g`Lx*i&0PI4Ro|s zrTSe0d(q1-)cL}nDwXy-#;p|x8%6gO_9-M+C)F6-Ze>8YUPUXo-E!_h{nPI-{H|K1 z^Y?%0w;6qB^VQn#ga1e6&7i!4@VhCi{r-T}gj5>m!g-Wkw1(F|yzN8)kZ&rclm7%)i1`t zb$qjgn{ScdyOizV{>V}zzkPUV!%BOx%$rA8wNKSzi>}Y9$aV0E3uO*t1^LP$UppmV zeV%rzItRyBwWiCs54thF8ujQop@8bA3tr&wNk3l&co?d{NdfLj#UY zXb9X+X%|m$9!H9OoL8lhq&*g1e^ZutUZDQiJT1BqW%k`*XUVFfld53u+JUz7D}J;u z=7ov%-ikAx+DCPJ^Zt&DH@*SmlJZk9E`1p0%Zo3|h`gooGLC$$`i#yO_k@_(EL6(J zN%{1yPgg{5hR`=mG7q&u(^`l5@7vnXZcqDSX)y+KIK+5M|M~5GwK?5!=RRnC1318X z=0uD9)9wK5Zpdi62RQ4I>+jMf(R03cJ<<}rN?CH()2eu~%F%WwVRyw{+U_5nxSZ~> ztC!{2LX{H|-a=6@YJ2Ur9f17y>3v`Mc0)nDmEN1*`Y66-hiE!nB02SZ`FFH6@S0keKhc3Fmg1M-1&(pU~iyiH0mDVF|>)H@^SbDxkpRCGQ?TD4>K$J%Mpzr%`6dt|wCV7EP`%XN)Z zWb6tjUupwQm#Y!t*-!rft%NGo{#a+c4zYJw^IIJLLk`d4srx=vR(YS1`lBU!KCR`q z1C`FXX{%Kgr*y7xz3TI<0laVgk@h>=nTOuIorchlT)*lM*KecjvXt6ZYlmp4-xN&q zKBFDaXuo$TXQ;;~9KUQ4YM+fWCi^PmR24m2-Z3}$g#9)RJ1rY^zr7vrney$)C;#=) za{KKs(QZBW2gaV&`IqX-`_F941{xZ=x8~=% zy#HVC7bTFNCaeKBNcng=#8etDjt}k7b%|~}MM$nr&uX51k3ML4{cxqUrz_BBnerSO zx8J-EPTwD_{&-9GAKG9#i6v>HjGrg4?vV2NqECbK!(TwgSxzr+)w;hIf5#+FD?H`p z2Woz#N8IB4j56R}x94HZkL`FFft^}uPdokX$d(6duHd>9_aCaFM*}PPkg-e~QOifqxW6EIZdW?Kk6i@n?BG&n8j0{3B!Tihm{Zbl5inV@9=Ro#T zro8?`MGde2s4C|59~CQHo>+>Zc6N=?1t79j(R*Rb5Ktv!|Ks(;dTD=t?Evv&!&djf zt6X-eJKMbNPxiiOm)8&1tk>(xVZ3LWqFt-fyY0GO?&+Sg9`wD{v{SI(aqH|U)|D-P z*7fhV4s3#rR{Yx`~T+x$+f4?!`=HmxtLe?d%hQcaJ*wnL7!&4|>&lj0I)C+!orfGd=t0^JJ<|@$U!`uym$QcJ_*$OP%~&@7SSiiu2j}=z1FRoX_g$^@8#qQyxJf(J#*j z_xw)he@3+W;>u?JR=RJT+8iSP6CTuby!yl0KMsDgl&f5xaY>-DY!}}Bz5z4GsZ9OdJS<4jHXmxFGO z=x_;8rF=c8YUTZ~G~wRQMEeOk3$dSqq!l`+e_et1OnLhS^Fsp;6i1IaZtx=%JUSox03S|^+`+gG6c}@tV6Am^!l$K`B*$(m-9)6Rv89}6kf(*XRFwG$|=vcitNma)o2Zy5c--ryZX%x%D99sdFD|z1*T(IpmvZn<dLs-;hTy-|%)+own0hng#|UF$e8Uu_sG)+Tkn4q>s8Vn1@? zif7b7;HUJ+x@X)_j0Gd6xhX`hO~P}6b9?G!SyrYW4V|_+1O^8 z7{`9tZ8%xmo#n*wza6`79O)n|j*l38 zUl+-OIQD^?*yAv7yZO>q3dd9R$<+0$#?$T7qMtxm+3w8qMYsC<`Xk8KhU@kD!ADhQ zy#1}BUW2cUXR8zh`3r|fe{w))oRI^9N zb!#{NHHyw>-CFNFcY<~Y@ULF<3^9{Cp6ItKk0bbd@!2|`LAnX(>J4;pgnrwPwY{M8 zq7-zS4RoE*Z4h11c}E{~8{2~YwxJ9|(5)1Ezm_<-aglMhusv`D!(Q5bc=2ry?3dh6 zs2BggbNc(So_?v!aXq0rD97D^_OHYnqtO$j{Uhtli+TxukVX_ry&lTKzEfV$_Yt6C zVqAEg%9($@u0BP3Inv3$a#?gAhQ#FpNPXkNww*-Yx5&J9sS}qy&iKk2<+p0pWSv&F zgp?siyH|W@CkFq>aU9OejvVMJgU@~kcN%=PHk_IWAEZZdsydi8k6V7+#>ckf$HbR z!dx3riI~h{!^Cz%IJ;+l@D&$TKIt_p*3HD}#k+BUB_vp-;+w&ru|Bi-_JSHJ(EphY5-B!) zt!{C$PATs^M&G^Es8=TqdUW>rzD*R);IkVqDHLw)mvp{o9K>88AFnw1P|M({pXc!v z2-zdm;@ABq4@NO``(L9NJjQqVJByv>pxOh^59U0k{a)qtvm@3?`5AGw&&(FdKx@0x zlwJ3JY1SjJ?5ucP+xZ>Z22<={$Bt@OGgThf&p=J8j@zhil3WTQEi?8K|0ev&^MgI# z)As0`iMdfp=4G7!s0qXQob56L?j_;e{<5|xAI@%(^wYaRxkXdvxu3@GxosZS{yooq z$@^!+Lx)uZZ>_HKn3_N95aqSP|A!OTe|PdRml)?y6<~K?rAy9C^>vgVpvp)-jp(Rp zf#Y^3>@L1SuU{|4dnTv+zWZ$DuV1hI;}q-HjnC+K$aInStFxijk8BHT40LSs9R|97 z=$0AihM{XT(B+_;W1!>ycEmu}4BhS>;c-brx6?q!{q1d{V`pP>>sP;3apwN^X3+($ ztH+?*VBnW6tV?v#eW&!x`y*Ex*lUBX#UOt@&^3sTqXg4bo*1+BfbbEiK>w|*> z(^U2*pxYCoV}FaI5_XI38fC4(p3DzeF>vHk&xJv_F(6G`!y$JRkMe{Vxnh3W3wY0dy4d3=*9%>X__??=-+DYWQRnHw% zdEx%6`oq01zAJh%J}7UyK+Q#JY%XtmOP!lU^-0EJoe!haGv*jRQ+Uas6Kr`-*UOJ3 zKKXi4^QgOiR;M8yXnjo(GWwXa96O_sHjZdJ&-vM5g<#!Vjh7nQ*?>Q2hi;IcKD@*+ z7;FITq@yp5s^ zyGC_IRoR;XLuxhwJFYS2*L^~SGj-Tm#ESH93)PCH!swynH zuA)A{J@;_K@E}Tt+aOd{$xUeGR0r4A(jSrt@v>KRc|OJdjubn?*}w3%6ZMJ7zRu?9 z(QiOpUVZD1+KoI6BVXHP-Rs`}x6sL#s??(W8Wlsd%~!yBPw3StLiDgHk4fd?SOWi= zA)RxHUXOBB&*avxeyi5QY3OQ2_YL{n)#;(qo4@+#haoM<9#=Z~@rlz6Q^CIL_r~F- zbl_|r`ABnSnvJ4wl|;7k=%0Vw<<1Nw?@Psn;lcBE{V^E@o%@-^V|of zhp$@aEQj%)z`vJ7AGE%SqndVx=+dy2f^LWCzQd|Tiak_(-4indkEr!clz(u2BcsB@ zc<=lDO^VTP+VGNvh3)^S+sSY7p2>}efBl~XSwa1)Y`FU}Q`P@(rl|kjYyM_*U(Qa^ zIr(y4Rc7%YR*KHazw-(cDzO|qZ)p)-wR~Qx zYsTkk=o&<~u2iRYt-1bNfJ5%eA$kVh$@*^q{2Jle9GFV|Fh3*Ebr|R-pj&33i(@Qp zG|;7>n`5Bsgf3#B>w|9h^}4+Um3IibouUgGm&T#nW}vIaAhX#(*96@L16@0GT?V>d z=vEr&ve2~{=(y%-FwjjxS8Je4pc3|8XVCwl+hw5ZhHi&}t{=Ls2D)MBHW}!0(5*Gl z)nQ4n%0Sl)-3kL;8oI>>I-a-G8|Vh1iy7#~pxbk8c)jtKiI)s?+;`t@plgF}i-C^! z$+2D%hAXc;2$c zz+MKrwFdSEp<88OZw$IF1AE+HTxno030;SQy*B8U8QANAZiRup0q7PR*yDXUEe7@` zpldL&7ssNu(ZF5`x;X~+I-#pKu-6A&%)s6dbhQTd#-ZDLweG(`{iB+D6bAO1pxbR= zuN}HQq6_M8z0kd6U@r^ZE(3d`(Csj=HwoQN1A7VV(QGrY*9zTs1AE=jZ85Od58YM+ zd&AIeGO(9}ZnJ^CI-E>wFtFDQ-9`g@Y3SA%*vmk-*1+B%bgK;PjX~FCV2_txR~p#k z^W{1W?6pC+%)nj`bSn((4M4Zpz}^USEe7@`pldMD#jzPzD>@7zzVl@Yy1iG0uMaw* z+aUv>iGpeu3j3bWZ$&_T#e9 zIpqz~jY8+dFGx2Dol_q{x&#isBykSX@%eH)4Rqbm?J&^wL$}>PHw@i216>Zftp>Wf zI*iW-x@PD$8|c!|Z8FehpxbDm8-#9yfo=@CwFWxgE4Ic!mxQj%K*#6HtuoN{K-XcQ z8-Q-5fo=r46$ZKq=$0Ai;EifOh!ejc zT?)Fe`e;S@It%Rm+9~g>3vo3DN$yuFeEv8O;8t|~Ox7AcHy<0=xJ*wu_j86|&l&%4 zDyLHExRJuAfJcAzEj{93wNo9)Ai%I zkEk(v4(;gMbmcBxSf#x_*jwq_eq4Ll%>sJRkE)2j6ZT83dRXFv^(~jfOmp( z&QBI=a|QmXRB_`}TNJkeaL)P9`5q3NdYBW{^MH=UpCuV)+{VGLk^GK2{5SYyX(atz z5Y3;9_vG1u_z#KsPP_}}53=83T3*Jx9h|eDGJrpsV&^)3ad9HTZ|Uhc@ux$b8pF1o z<6ik6fE{PQ&(wcAY>a_(_Se3H_e@TGNPE*i;F|w>5C=m%Nr*Y9X~eyaPL_yOMOi4R z8IC8-iTwWTTh%{lw-0u=Nxb=IYfq zoa-~U$>*`lJ@!9_L+&U*`{Ur8>wA9dWa_H1^mVSE1?8g&I_LV?l}Z^Ofk9I{CQGlMmL4 z8}Ag}w1IQ%uXZ?j)#DDPH|)W4k+qL{;6HJGP^G@Z%OQq#`eA3Q_`gDU9MVaT+xmG< zD38j48n=soCyniL9Clt3JD3Vo%G+UB)x1;BKb+6$KYj%I-w*VCs@LK@lXJXyzUJ?d z^9+OK;Ivm2#nM|DcKPq&GH&>O2ET{PrI*{_SU+qrbL4(1`F3GJ zJs(1n=RN!mjPtB}et^&Qd3Xx^D!GsDo4Qu>yi)1!fpkK*NA7?8o}=5($uI2{KkuI< zDE?inC_gFsevbNNMf6yhEAO^2nD7_+^YEtP&Ma3sXY2Ie3%)`4uR8n(&d?DmY+p;n0y9TzNPYM>41SaFe^8$y zKZiTK8&?(1qUTPjLsNh6MB;iM%#{~c<{EiR;idg()VJizw*S%20PM{9gsz|G@t!GP zKdPOFuGm?6CToTs!)$+OMcP2JsBhH9_AD-A2)!CA@1dzhCe{9CF81a^2vz z30LpW740*S%Yt+AUk*18Zi7WW<2aw#D%^Sg`E13ZqVlzYd#Oy0^_&40>CyFENqZTE zorbr-PP`H44{w2;H0-Q-3+!ZJXY*TNX99M1yajfeaq_?CEwIxIJ9BQTyxvD(r=>zW z94G1)VZHn>dfmf8pULgl`mGu#nxSh6(W&(hbWZs;2p`+}K^foo#V5}Ga|@OM@56g{ zIjP3c0r0D&Tpx3Id5x&AO{n>a3oz#~zUqU0^ao1G@goO28^z8y)u#pJ(%XM6(KHUw zJqwI+98*gq0n4$Qb^Rd3D!K8HJ^3hw7zNt!(gyt;(XZ3;NbEnCNqPBF{Crb2v9`#D zkI(Z>dqHJkcZJw}e^eWeJ>l5Z^Bm6E^*mSjJYZ_obIq0S{BzCsiOxZc48M@b3Aakk zw@nDM?be@1o_&vPUq_= zm8-(~W&ZJ)34T!<^~CC$EK{Gv#ej0`x0k8Ul&K#oQ=cnCpFn)#C*;dpjrUA$yVq~k zIFN#Fhs6CI@_DI_@$Q6fyXerARdRJvdc>}E4PW&4-ut27DSDnyF}ZsER@LKhf&VbO zt>7l0e@X1huNUX-s_v8j1w*)(Cfl@&IQGgL|Cxkz{%5}QFyBTk}9_lD`Cm7BWjbsX5unDTK@eV*r0&Z)6F{{Ptf z9yl$h^!;a=w|Z4Fk|g1kQ6UTlA(;|FGN>fUD^UouHngdXgb)THwCzX;Vc6K#w#*XS z+Ll>DUmFH3ZQBw;OUv)N?)y5=yzfj+Gqv{T`}^(re4h7uu5-?PpZolM&U2pgJnsnn zPKMkH+3~UYLT<;9A0OB1dw=o)$ZYWaNg9Am&j74KIwi92hLDahJb%Ub$pNMHM!u)c zYUcOUS)3SD%*NUua%5ObUk>l;w@d4fh-iMDnR+nRhh!g4&DE5j^^bx?TX>^?ECwt< zq>!KAdF^MEw^da`zbjys6OY3siKg(#7>4bVQvc`itZ^mS95duhZT)hLf|BY6n9BRR zU;4ZQP19Vh{O9@7w2$8l5I?UG@mC>!s)6xYz8w$6_^0~#-(J4V&no8UTJN9#+w;S( zN-V(SvU-Z=XKbQ&dx_^m-Z?QJvR0hJr?VJ0`+r`{r%2zNjlVZy&3FBs)>fU#So3wG9z9Y1H+cE)Zocas z@7KF-#L;X#KGcKET#`Qbw)_=PF!i-8dT76ETL zyWZsWd7b%Y)~Dwe^8zZgc|kmmSjMxy^HRb%^>%CNXS*Jcbc>YkuG9sWyog^Ffb(`8 zzOy$q_nHJ|UC$zbt&vf@A5O#BLg?vwv)jLI&~sVPHoC&&(_K^NQM)aLtzh&M{{_LP4duV%jA2|*ls%yE7^8ggmLVJX5~2#;#y zc0)icHvnXIMtbqO;PZ!gO>4ge20qJsydNr+=nK)h&rei8eGs@VGrytTz~7woV!nPk zI2#@H`yPOdCdl=jK2X-T%-i47CY(`j_9soPi>_*_Pem3>8#9h3JR2|>@{1&|S$|Er z*VMoFVbs5!@H$SLv#;YH;h@f=f0OCzrM7`*~EvTkI`+-e^{1nN@_d{QI_ZkZ00u|zhjH3VshE{;q z#kfx^#Yv4ezfLcQzOJ{r-767JmyGpUA@X{afOp1zI*aDd|Bk}-K=Qorqf34e?1|-V zsAc;zMOb5{n~Y-wGwv2@lTofQwbz47;IA#2XHazCV%HPf*Zro+b8x;XJSKts|Q+7}V$csh%i zK3wvigZ!+%bZiZ%JU8(U1U8b;7(`i!bVfbo=^PQ-*RYU|mmB(sowP@vu?ptCYHvMw zNNhPog4@8hjK4{vrKoq;5QYy5wX}ZG;~3P}Bc3j=%yh}_AzjuEI>T0g)@A&+x?wnr zyC(bjc*s{u{zGuOTH{2#PujY><{(80Uw%m1H-K3w-p?09UwUpWdtN^MAnSRz)l^j?aSy~d zWuc)D(pUq#Rw$q6xmi)NYp~1GeVdxUC9rF(^7kN2q)T2F>|%Cmp66HOCPvaD`GV!Mbw#dkY+yNc zL?aFDA#UG8f}ZShf*vlh)hQ?H838?mAN6(_+jCgZ({Ov{LQkdiJO#aU$yCr|{Vnb< ztq|6_0HatMC+v02f#@n$|IpL@F}LSMc+(~GHll|!`&xQ>91nY>C(c(C^fWwQlcA^U z(e$=+-grKM4_Kb&~;wNjB^L{~3 z!^?Rg^emE|xZXPjJq@>~73SszS|5$er)kjB@bVb|J#(Zdwr545+H=G0nE^d{^SpfG z_VdS}X9MN4p7ygGdZtTHY|n3ko`&1g?L_p)r`(>nd}anc4KJTD&@)zgVtcL(dKzxe z0_drhp16EQ1U(HeA5JGm>HiC2djitc-yRh7)G432h_c@6#Wd&{ ztp7oX?dcHoG~AwL&{HWraryj9D_S<~z?_!X?XU@-*NgSEpZt??e>=a{`16mTr{VUD zhMo%PiQ7+A&{L;;Hh4Xq2R&VXUCW+d20ab8XC3sENl#opcLY5RYd`rYzCKu_n4|la zb3(lf1Ms>#8u3;u-UYSeW$x$gia=g#IT@<8AC-FMK~H0##e+@>hOpX(@7A(xUI zhZ?%%rNJJnkMOn#ZYM$^(ckY!7DK+Mw)~k5mv1!)_Yac4%u+}C{Wc_Dgcz(OPoMej z2l?_w=9~2}8FEu3_b@nJ^80-^Ru2;pt?q3(rBn~gptrh__OKq>o`UPC!HBR2<5>141oNK+WEOU$Xj!&`+Ojks5d|CXLF&qXu7wnZNTY5`*G&&ZwcacSG<%0 z;&?Udj8qY?Gcw<;2BZB+?y?}awm|hzJKsf!QB(i4uOH;o4X|$v;tk#e`{qI}vL`j6X}Dcj;Y? zAAed6!Szyd@%VFRu%~wY*ByWQLB6`S{G^7-vpl9kKDyiOj>mxug8ZiSn?k5u4!wh= zw=v^!$J5Z>Bo~hZ$zV_I^2iA61^~~{SG4w|FYWRrrVilADgMi z#y{v;D?M?)*)HUV#j>9L;i<$%`^{qLT|Kk${U$LS^99Mp{pPtnXh_(HQ15+5AIPt* zE&p)CaNNZg+e=xIM^kuskL}bc6GMUJsT*Z;ABQcl}J9h4l}`OF@oqWBtj- zKgbo=wmZ3bcC(*NgWfsP+n9c~7;6P0_ri2KQRU6r2=wu_DSlQq!0R(cy#zTM8o^X5)GnFt*%|i5`F=adZ(6?D&(=Y2mF#LvJ1889`#;HD#X^8fUKZ@B-42dKD6jLh zv!y+M8Uy*{EN=&!)6W(_Pr+vDVfiLTp?;(%?q~0HR{d~Wp>Sq}N7we#~~kl(cYCiCKRYGZT|3`LLOi>lErWbo@|)Ao^3TWmm}-#|_rQM*G=9=$&(at~A*uT=3;EKInD^s~f;nEy&H?q>%DyKA?D?0&|2>;w7vlGoGX zD7jCje9Z@@Xb-k<60qfOD*(RT)hxl{V&`oEY>C764bFhx@&~;hpYdLjk)I}r)jDh6 zp!sCI-$C0=e}X5)iQ54U+!wqhqQa8Jfc%Rve$H__Ufh5k*k9I+Y1Fg7tT-{wl8^VC zT8pT?y^LB~CT>>D=G2)=tT!ez*D`USVp9os<;=&=^EzeA%3|BU59uTir0>f2d<{Sc>Ah< z-@Fw_*8i$ng%v06f~rl~zGd%MPx}exKaaWn)th9O6;#%~IkU7hC-GgQ4f8HJ6>{A! z=6)Wx>r5sA*SPZ9fL$etz6inJ(0aJ)-y78Ww`SXZ>;g7ugjfBGaeel=h!!wLAh>WW z+VgX+M^AgOUnA&Yg|z1T12&j*{$MBZdkO`*oNr+Ikdf~hNT*8a#P+@y(qXTtZw?aNQ zUY>tL{EfUOVc(@$g>=fFuT>7e3h8WGIne$-nAdiH!S%-WKN$4>`|O{Kbn+I~vj5tU z&ZgPV{>3-k=16Z`kCz3#8|YuP>XCZ-K~MTcw=Zt5BQy0hti4Wyp5#ll@_9wjv+4O< z1-<3c8|U+)pts@qEF6#V_xH8(c}Aw5hUIfS^hAqllUG!*}#mVKv$d~UjZW1x41^v3ob9rQM=9x&C37C=w=%Whu9fpeMGESB9GR z`cjGG!0SFYV>fM?*k!|E2!UfeFPw<`N2MF@^KBl|wQ;%bzS=t>m~lO#{o|o0{l{AN zzqdUNN2mPZ>|cX)rz_pq{>MYQ4Y$9?6}a9nu4VtVLC+6k|4QXiqo#erE0F!~CMX=d7k3Sbn$%R6=$T%7oOnFw`C;s5zgmWLtCX%r=O}qaopjBB_`U7o z#D`V`wZB7X*9SbqKw#ly^^Dlk-eJ!0H0Aa-Ylf$d zBqI=gHqsk4)%$TrMukg$x~=Mg9(KQx;7Qhcr41BV^tu5doFID)jVNKgl9BwmY^$p= zo@=~#559ECD3sSOVD_Af10}}Q9RR^vesjxeJkM z*`I$c_9wkk>pFi>(DTFDKLhC&E8TefX&%zufc>?`AJ*e?=vgW~SA=?GVbHB_9Oj>q zJclrrgE#BQ)_xcUkhMQ^`G6I zP0bheB(6jKzP@>SSU&xrr+CSaqkK5OUIu$oZ@N9x>eRc}SLSy&%qQ#lSpr(@`PtKzU}ifA-J~ ze9yoNHvZmXI>F0LA%QCq%Vi<#8nx8Rdj(4dt|p&e&zav@h|Al8verYbP-46A zsP8fOY>Hu=Ck#cWsC?V)y3MSrYZulRt(dZ&o0=6F&;Q0lxTf`4Xst@Oa#)P?Rx3R= zSi1F;gXKEwdkkj5`pdz_r}CV{|3Fvc%7JaTrOlT{+=%h_FJ2C_XcSy+yHF0cbemNU z)=F3ojEy@UK0j_iIV?eX?U#9a?=u5%wbRRN5B0QDE9-cDysSy$Na$-^IZ%avFJtsg z*gyE8+qDH7AzX4`Yp+AI&W;3P4V#YiM|MGoLyTYb^q=TSGZSP z=kuiPnHF5~FI#5Wg)5?^S$BTPkC8xNgY!#Ihy8Rk(kWfx`TsHX(?l8C=SsKhKhaOe zAid<@J-r`OKW%jj#t+%`pXjIKkzTuHt>609G-o=m;pOVKKb$WmqK)s zMXUdF{be@NTdVYbO#P(?2DR$Xyd3@${berFOMUL?{aCJR>@R(=t*oooFBgY?+%LJw z{iU=?qNw5h#pfCMuwyaoSiRQEhfmAt;_<|(-N&s#yyQPU-e2S&$J2Ef*E{z7?Ddr1 z@X2^`z@8d5w(}jD^@OqihlStx33sO47(|$S2i6B}yp7u`T3edh zv9^Ju5Up*69JvX>mAj(34W2eZhol1zfU?9dJEcke%@wcaLI$}=%s)?&o#S> z5)Xk>t|Eh+S`5pIFst(k`FfVvzq$0^y24v=)}H=9bYEQu%taI@cH0e=qtpgPIj|0%9mw@M$P)b zUpM;yTeVL10UZyylb+ri)Tj|esWv(fFKUpdzM+SO_YZ*Ev`L)*b@=uNh-)ehdO zqqouRU>)?9N$-E69gMyg^YhngwS%MUSj%ns+>uJZKy&Z-abuX9{^XqWi z`!GMSs0OQ>VRMYbn>h4%@Aq|Np^kypN`QFde#@daixFV?DP{vb~Ll zT*!YDnhuw|H`r5edpitK+1^-%aeG?;eI+Tcr$tl-S7V1&Pdu+lC3+z=qv)*VCJM4W zeX_%`74uD67|$D-&u;f)KZVkZuXC+}{hnUt^)s}$jm`TeLvQ;|wc1)bNvEtlSnx3|ro_w{=K*Xuvm8s9Fnh8Eu^pnU4Iw~bxrW<&2-<)fkF+Zfc>GRTGe zSAf$c53gen8{WTde_U3cS-0UZ-x1P z6UNJ1?|pcJL3~bRcY9UM5?diMzhiF!@kV>s;Im;(?5#g1=3xG~o43El*xLhgd7WJ@ zw)eRo-rjjgxBc#ow|5of3M3cX``{06?}&%6p3|-I_RfG@vE*WVZ~o!!ZTm3R%MPQyZ!cv+iyR}l}hgF(0(ub;q6_Bbf@p<_8tjq=#qDabdzAVZ>uv-;+v;FAnPDk zA-Pk*>5>!b$n6Sm$}!_D^=|;-a~`(etIs2N9w0qfS~8bBCFp4ZZvV&0$&CFUr;oHr zQ)L%31X%xvp49%HkE25Q#d;dk|DVLQVq^WE=J@?-_HrvT?6u2e*1isnf(Ov> zTC*A-{~oQ;w_hE7ar@bg@}XQf&i8;^mF(Da!*ZQ6<@$k)$w=?tVgJGmeGRpP_OF9n zrR;BLzG;8qV>RXV@34PzhQ5Z{LHid#Zd1yCO-6eE4*UB&UQ-^8DgW`1+m!O3myzDT z!~O&&N1;D8#{M3VYpneo=f-5DcQrU&=vQGMA?7(YfMo55$w5S$=U9&}N(=Ze)9>T>cYS-`a$JJ`{2xy?;kN&CSr)n0i_cxuuQFcRupn@ky+=R`@u} ziyvKFPfnwb!klr%`22s)*u3WVOeo;8e5>Y3-g8n9kF`VU*TXm*TS{c-mN=)YogU+{ z4b7K6-m%fGFCOoC${P@GA>vI@yltoqZhiVz!M}7P@tB9U$oE*qJBZ5QVtqCD-3fTt ztRJKjtkOEyr#|o;0ez#S?*eeT8hx$7TBok!KTLJSDQ7C2a@6{6em8i{g`P6$*%zFy zMvq;lQsMvCneH;gU#;uA?wX?H&g)FB_H&;i{Z(ZAG=LR|en&m|=*jaB^7@bUG-;e3 z_QTQ8Q>ylHlv|NuKU*l~DQy6)IZxSxC${b|8*R#v*@Mv$GREH)Plb_NAKf@qWKzy<^o~4_v(v8uWkO`ADN<0^^_T z+6kO4w##WW6xavxmMR{Hbh_l0-}s5jALYqbjc2^$RBsC|9y2|b&98qR)FC?fO;|(=M~lpzLqf4?T8jtaH!WyobLTU zY`Q&=?lh!3rH7~6BINhtkglya;B9<+Z=@4*vG^svzrynL`++5pAAFe0v%%3NPY?3e zdbqBZ2k*F@vYEDOhWpjpa!1rJmk+rN|oN78(X^;okYv}=|XUK4T!4)JG=7}hfJQ~YLZL$6POH$=XkoR5XT zu7`X6>aJheDk000&-qxMCYabxjH^>EWoY=533%~3GajO;fv$IRuQO~ni=nT&r|V<; zrAwZ$)=#qT1Nj_tFZjpRZ{vI`R9Z^;yxOIr@9G~KYryW>b9Bp4`y)P?}`;Cu7b$MmPvTkK|Yx7 zDx6pL_VVT2h%UKi!|B=}la;PYY%l~jcHhE52ZjHV9pT9$%Y6i{ zs_l>R{BwsHT}}J(aeuw*;-;AE;wtweAh@w|r-{n%GNfCnbmRIS$z4fs>uG0}yUna` z=63+*&RzR@e&cfP(3o^Lt(+Gl-Qr_B-MC-9y~eV;zWiG8X64t?ZB)M+0PTHnO;~ZS zr^^mcS5v>1O4hjJ<(%M@GGhj2@#1m1qiKnvjQi5R?y{cy(yB?GE(aL8I9;c9@5(W3 zzT$EANmn~wH~6vcDvMno$1%D%p3hhFd^bmueO%qnI>cOXW*`_8@}$$OU-Cwe~lES)ZS@)v%h zezD&7Wvm+(C$J3(6&F92q6Q>j{Wz|_5%64ykjj%honu2f?dqh1s}{yROf8rP+zBVV zyB8%EfNw0FK8Vu|Nzc*siF?rKl3Rv!+`MrAQIt3mp&8GS8I18_GGGk!RF%5DUj=*N zZ?0yXwv1-YPc4b8`KiX~u@G(CIL-X5LkfM>uFkDv2j>xXznkC*uj5>=$jA}xYsvid z!L_yID$mbe^o6TwCzg$@@2{HXtoKJPW89~!n&;O>8<(GHNRxZ&r>GqqPfc*i>7V(D z%C-J|f0kA5i?t@g`&(YtTUX~K_ ze7GMmw#!a3?Rsl7>{aMC=uT{S%&Jn zak6y^-j}9Exm|~CE4#L>V^=-pVHS!oUW$du$R>OZUW!8-xJ=@PuUST*52y&)OTH) zig?wE$HAH|PRFTz2WKA6yUL!1T$h$3etX5Q?|Rb;)seT6c>SP@|J<5XymMq%Y^Sa_ zxUaB+=6Ga9U642$QR}RSay*y}eIY*&seqC#R=eh!@t{%d$Ofp=CW-NhO>0L3kUGCj zQhArx+f8mwO?}kl(;9KSk0+Jb7g00jG0YI|c-Tx>B5)L#U%sVbrErn3N@x-BQ{A+s z#j6r76;`8osi$0gwQz+nubGEW5uYCXo4bEnSRpJ(y8mkNJn<^=V(}7Tsq|NhM~YW2 z|7Z)>S1Dd4dn<*Dgvk(JxLW=f{xiq&x8iHZFXbJ9fqeoAEkd z;PJYSc06#T`*%Obu^b;zHN7W0w&?BHs+Z%CyIgMQbjJZ$4q*I2xa}h@z-ytzXR**o zoQqydoQHvrSbC)6qCSpq;~tFu!-dm7ce#{sW)n}hv+w~d2s8fP!pdzuysvQ7p3YbA z;dtJ89{+RPNKkIv2={LyTz;bS(Zc?RJAbpM)2j=j5xpDLi<0u)bZIdj!)j`@~wqw;ex5|pSa2Ks}jdoE_9r6i{sid$797G z5dTCxJvEhJ5I!B-c0{3O%3zPgcIF=)C9*$`Ip`7 z;jQIAW4yv|aR17mJB}!J|1l>xjvwSWb)e&gCp%6&$+7R9j^pnTzg>KqxctYFG4{2`xtIzT9%EuGN%M?F7&w2HU3Ky0O_j}OGZ>8{@2b{k>#j(G}j}r0E zZ}jp#N8`g3@e#l9_)CSIg`=js|1#ko!k4dcJw4Tbr;7Jizbq5B6Ber9jTL@%v+M1k zel=9M>^AqWddT&+QU94H-s%7^-(q1ECX;Lr`D*v0gewZ%|G@iQU%tv^^0m(QR(Z_8 zq?z(ZsT>ZO>EX+TJ@0hBLRfya$3Is29e#s{zbh(qa{DnHfYZIz!Q;o2KKy(fPzJB4=$pT5KWKM>w6Y_ELw5w4r; zdRi%;U4^T4U0SJexS8_(iujUSUH@v~eBo4;!yI9WaN+)5Z`Hy%!e#ro|5{L&xLcOkJk;@lg35We=wRpWk2rMhs{mMnHOfD*MtQJpw<@5cLlRaK^ zs)tveCmiPfMQ1stgr$mKb+-GLmpY~=I+h4i*C~9sW2vx2SagN^R}GPU8_Q6w@XFV` zJj(ZVJ=I4D|LXZl?W}Yo$D-f6fB9@rujmEG>i3o3*7EP~Sh~0T4|MtH7~$VtPf@<} z@}`dI#qMAEkjtePIYu8lR&OK!lO4rEXhe8?q7bh_+yH{*s&6Cm)m^cVCSXV zJElh}-Z1gA9HY?w&T(FPy8MR=Yt?I@sRFkv-CMX^cJ1gq`rhR$UsOKs6aSrKy4ta5 zOZoS6jP{a$XX*W1dJk}3eYEgz(z~nkQoILk`TnEg&yk+rJ68YIv9gW)PjW2X&oTPM z%|JbvYF&Qr}DtN-NwMUP0&9~?_pIHtFi{{Y9-0m3sK zOO^jhrC0g3>}u=!(_bq70{1VyOMJd#<(rP>x$-~4F}4vKU`n>6~}Vr zC;FSmuYBD7Q#Xn$f9aQ<7k%yFl?OVHwsTAmax4$1{Fa`kaK$eQ_I%-bqO|9?QsY>; z#;>%-r}UK`9)<8p;=dAg`e+O{Zq%v%Z2AUmdeg*VY$Zdw9<{P@pwg7EB>{@$&Qr@PpceK zDyK;0lnUh}edW?qE%}u6RSQ${PfKq~a+Q*cghh%UO_6<)E0tVjs3+A&rR*qDzROiU zrI)#UwaPnvf%2vLN{v#u%CYET=c#eR631w)WBL-uYUxRx=e$yK<&rBpNAX4|TFT^+`2%|nVb&xnSqe1|)xhd5Rbb4;BkF8|7b@;}2dEiBdeRIYeMgFHMErlg;n z1ZaOM#FM^KVUhF{DPFniqg3@#t@=o-KFU=eMe4sP_1{Q(N~Nb-c2rAWrSzpV9+XR8 zwe*!rUpnXu7ubIj=4qX}MC-u?!nFL0#EXN!Fj9D>utL~g>(WKSUc%nOTeW_Dk8ry1 zUg7P+nZnZ~H%xfC@Kj-$;@u^@L--5fEa7d!8NyqHcMIpCSZ^PEr~99z=NDmJecqAo|E8V?g!T2-VVzy; zwy;vd*AAM9=^r#dBt0Cob$(o=@XnUSG<$7KJc;bzx#-Ho$K+&PjdYA zm5$?7K4BgI8S$Q4rw{A(6U8sS-Q~hM{FCB$%Z~Qa|AE#atBXDUn-d&&QohQ>KPh$p zMWY-OviHLA&f7@7-8AP5CExBg=TA!RD5c*`xGKbxeG8;#sp>1Nzkf2!^^DPTrLf+8 z{l)G-=jV=Lo%q?A&W~65eWh|9qVjK}^rOBWue1D1g)LM*OH@A3s2mmv$E*Is`ta|y z{yS064Z=F`S(5K?nWq!hd+*fxZGWwAhjrWzvgezVJ$~8Yjzff>2-gaiUghCE#K)YZV|5NtPQMv~R&r$j>u5x`liqBH|WwQ4cJy+_h=V{^j(m(Zl zsbX7CCp>2wsPbQ;{Hze4{H~`{z1p!#yi$BrzUyfw|Ha@OkCGr}!-Ky_N5L;ct}xwhA94yjobI^sn#d`5h+Q8=GL6 z|0ew%_ZGf%yz?=Yjx)pu3A+jNM|k+0+Z>ml<=95g6CbT`-hQy-yi*)|T5=X~Wq@PPa~#K==$M+~IQb`z%O7_P&re^v*7>>;$MD>=P|r_W3VZ6gYQN_sFC47= zt~}fQmz?J~@m$A2r#bF4%5lX7j$?(NpXq#r@-c6;^Xcb1&K>4BS?TprJ@nUe;AN9N ze6LB4lU{V(aiQa{#J~QX^ONMCmj4^_|MmqBPdw{5_cxBo-#Siy-ti#S+c(PJqsrIk zviI3zJ>ErsaQyBi#{(BR{#xlr%Fi(Aef~HPe@*&^sa{r%bN`>Hes)&*HoeIGzgGPF zFLAz|%5S{dPk7FKz1mCl86Gb@@1CW0Gf(Y0Jolca_OnRk-1a(``}}6d=_4GMT<-Yp zsgBQ2b{v;>?51+uPvtsHdV-RayE5`#>pRbAc6;6}B<+9@_<>M>GAFT3!?LyZxRptG#?5q|JQTbf2 zav7p>X(xPH?ckQ*yPk_wf1}k-exvY73LmHT_OR;VB-xi=>hf=DTlHvC8LNmGd(`+7g?Fnx%v8O+DZ4Mc)#F{K`fjFjyFlgn zuKL|hD(C#)dHh0^^Uu`(|0w-Sq~}$oGhY7Z%fD3q`>Vd2see3wgX^8E{<~1+yh`n6 zuJG$A9`6yAV_W6>0rl_KG(OH$fBsvDuYCMma-)^cW|A+~crr-s@nMZq$Ey84uXZ_c zgr|SK$}dm$&Q`ihRj(E52UR0I{xd4);qqUoac`pf!*@z|u?~fc{0!*l>E|haxyH|1k9Yq9@y;hYA3W4?da+~JzjMba&R-txSTRW9 z(;O#je4KT%{BL*cEd5JWo^92xSE{~O|I*_%Q9G`X|0gQ%(ZW3Si?u5M-dDI>mExC3 zZyWXJ67~DG>hCL658c#nJE;8?svZ-gT;F%9pYIg!V%5h)r9WBi=QX7_RpG@7FIImo z)3|ZXwXS!p(ix`fNxu5S1;=>!slsD~Q-vLccM2a<|63$}h4Q&j<+%Df*LREXJK-;c zQ@-@@u;oR0 z>wL|&j$!}rxOUEG?CBWx0e9-={IL;^VgGO8+0NUaJLea>^mFIKw<`<#i1*mT{lk9e@#6i@a{sW;`6luC+IJcD zJFgY*r2Woe-}7+s(k`y2>H){ zM>&T5%@-c+e6jjZJC)CJ^_RY?-%8bMrON*$wU@REzfidFA=lSc@;y|pqf|bF)$Z3Q zUVp_Kr*Y#W)pwcd>nxS`w(@Tw?EAf!W7y~1e=AQn>~sEgXXhoI9K-(RGga^HySsnb z=loNRH+%fV{los|cZNHkHq0^Xb3R)A>$~IJKkRqTQ~9jXxD#o7N-F>5YBzhRy&fX} zC83|FJRVj%yjb~vO?EGn{|xzmr}kb{?RJz5*M8zbj@9A?;^hO~KRU%ReSzYi=a@R% zvFu#O(u*96&vGo7?O1-lV|tcj#s0p}FjeSSP~cc5zPdvD5QV8fE1vczRxNT~`mAI6 zCCB3V@?YRssqhl{SIqQ%i|JX8Rl=hCoR{41SRtO8?YvC5`d;Ue;#K1#HN1{j_H-;N za!em3|6Y#e$2q2sb*z5Qu^2Bu+I{Yy982zX{{rpLta?)Z6^<429K(M00>!VAf3@sN z-6pwD9HUPi(`y{7S}6VRofm)XnAg<(D{ggOBrKip{;Mk-OCEJBo#j|I$1%OYF?ve= zzi~{>bIhCTSoI6Xf(PaQxMOOz{2!M8(T*j(9iwL*%b%A2AKcE$>m8#u?!WqF=c}bR zy5Ift9&s$_EBPZFtEIQ}SI$dSAC-DPAa9BLSHA9;e%1At-=TCDIOg5uSTVz~@^10p zIhNk(n5Xv*3Vx}0hq>O0q+>Py2$St1??A`ZYdu~hT;1LMOTTmff`2(y6e#{m=cWIU z|Gw^Dy~=q?Sh=VBmn?Vx^1llAa{sCiotJ&&SaqoMH*rkigB-N8dVk0C7n1*6@%L8z z=8i>QyMM_##{$`zr*sOWxB4@MzpnVNIOdhh|2oIiFXVra(mB|%0x$2na9;kt^Xfws9yzYw&#`2+hgZyXEPu-}J;yQil4IEt zh2QR2tbSTK&3UADw_5MD6hH0$MWZ~O(%T&Kl%KTnQTC1W$?gK#TP!;x*;lUqy;|cy zN^;fe|CQCQr&{AenZ}LEr`*5f0mm|pM^z6xPm32zes$n4NZ(|~imMz`uQ^t#AC)Pe z1<$yDdcNZS(Xq6H=eu|p$BJznQ(Ya)Ui5g?f06&Yj_G$C%ij}L3zs=oD_*Jgucxkd z|AIWnvP#EjvHTY~mS{XkFLj{z|CV?}4jyzS+$@QO<1SNTYf^YGHs9Sf9? z^iSnK-m&})$4GYO%~N~O`w1n&qNcw8sG^x;O1xC>UzPT7|J8>%uKAhccf#a2=WT=? zg`I^3!b608g#Cqsg~NrTg_jCTh1UzG31fpC@ZD`7Oj z^U*@sR=AU}t8hPI58+Y5V&M?s2;qgovBF8hslq#i<-&)B^Mua|7YSbzE)#wvTrK=Y zn3(AKX)SCo>?G_aJWyC9JXSbBI7~Q7c(HK2@ET#6@NVI3;bX%2!smsHg>MS0g)4S^83kM5_3r7nt6_yIG7fut-6wVPoDO@0YNmwO(Tew{K ziEyp3NvY?fm9U*KCEP<;DC{ZhD?CX!RCtcCL^w`3S$LChx^R|ouJCDLrSN6p65+eT z6~fPj>x9j&^!(%rI|%cIdkeb@dkgys2MN={^MqrB6NOWRw+d$n9}rdupAjw;z9L*I z{6M%$_?2+Gp1u#_80`aUevGeMRGjGfs}`1@?7U!rW2LZcp!3uq$1-8+6z5gK%E98o zqEnrh2r+g3f6|5h!y$8F|8U^N4cspr;{O-_TLS+rf&Y6Y@cs9>h5I1+roja4OEq#c zJ~dYUn}&*Ci(K&mO_V#e3!rp zw)LB)T}dtySxGWQWKWViabSmi^d`w}n8;EQmPlcb$T=i#p%#EPmtycuHdzvcWRDd&%y?T89tz2N1oC^}GtpE-_B5c!y7 zm9O@gNuX7wLP zLgRjlBs6XdIY^D$v>h*U5Y1utWr?n!%q1Wkd@STag|ur0pGuMM8ST}~kat07sL700 zzuAd0SYb2OCzAXR2*;;GNU%0(A)QHjiC73$ku1ctO$MPkyV6jst6K=Z%K!^RP9?!g zSxv}4KxmH1;2zvU#xfc{fM5hKNF%!-G-nz~ucU{Rk`#+r$Yc@I_OM6=qx~8rw(ai< z*@}kp`|K>yzcAX4A`3~nWriFILPJfaQXzN=A79Z!6Q+U|)V2!<2luZSa=t?F?tBzo zCSoD?ikP7lB36jciCERYB4Vxg9TDqHc%9Y~g<`)5wFlA)b9>;Iq=@Wb9PEhZc%2KO z<`J$kyujGk)MF**!y_iV&h3-waiPdHzz8p^Wkv09vOMtCTNIt%sL;Yw5q(=6tI5Iu(Da2yu0wR$!Kco~kfMZ4pR=P4w|<6urKBpA*B2u26wcG(3d3?G0aCyY!u zkD{}1pxC2cB(x_uUS#UcWNglj6zPj&R~$bhxflnNvyd_ofMsK4P7j<|di23-F%}ow zIid*foEQN_(aR!RHo?jJIJU!qr~b^7N3)Q8_{6n%kO&_BMiF*anGAOL;J+_2LvG2G znJsc8qhZ&l$#7;6{ZD4dN|3GKX)X`JaiZNaN#9JuM#cJ!qlS{PVq)>cAuMke3_Xs( z5wT*kLidtKAwv)PkA+?`5J|PgaU2RDx=iUFLUNPH?j#S1v?p1a8S<5g$uvPQvt`<{ znm8|bSsA_x(O3=l;D~18$PDe$4;~CPHyghs3&@_skrlNORj{vQyHgR9$W-*>te_4% z%gnB{dCyFnan2?JL2*u_!x?(XSNYxyjZa8j?DP(XYdiWplluT{r;7(K#FBh;3FAgtbjN&Ju{&W~HXS>YK)jg987TE)s zbp@avm|7T`7rCXp3-BzGp*UhQ#%2=8jS53lnu?1Rxh2Z5sP-72>d;xoq>!x zi5|3mcO1N$Mk8^=Ayk~=8ch+wsbzK)tNA1xFVN`U<6zWDB$E;KC?K|N zMbXES;~hrCJD5D+wItY$XfhU(0@)g#Ci9X)z%8v0?T>V+|LPX_8GwW2@+5xPI^&Q# zMQ&%v)zV@zGez!Z2=>X^48}s1D`Xx+zQ~lpXC_Vc#|$}LEtN`}L@dU=QXh)@4 zPC^5o!oiU-!d}&EYiJ{r*aJgy)KcRzc5p}0UijG(XpY&+nqKm1o|&!x_d?^vi`guJ zdP~0p8_`ZE$!l;#*QrP;2FIf72V`k+5Qs*J@Z3W8lm}Nm;#+;5|A3*U-c#suD3I21 z<-qoOCrSB&|8!|=jRNH@+&50U3+&0QkpByWrG{C|_3^-n^tBRL939QEc*vZ->Yfau8F!a>q?B`{}rrsC^F%7D@RnIRmr zG8`=U@n#Zs{x_diS&gaB`iGYeMNr7rcr+D~?oK zd??PrH)}OyljYDpX(^S?qEcRbNvB z5_2cwmt-(m$QsWhjvNd*21m{nA{H&H2h*6g3I+J`0p)n5jBdvfr$rCc-w$uk&Y7u( zk&u~d%*>k^p{s z`uE%3h!U}4QM=d;gyojTkrSpcIIp>cak64dvW#Z#BK(rD8|I7=v1qm1X?)XQYl1&f zRDf4Y!*72&>?_%!l&zyErBDW1BcXW|$-WS?j8gE7bHett;izF+XfuJ)nQ~8N5^DWn zqHd>T(!gjhkz$gwM0jq4cxQQVl(PH89e85y`)IG+4(tK>IC|m83D#P0R-Ms@`C-aa zEEqoz;9w~|LXS!uaruQt*D)yJGV}I`F@qkzz)u{N?JdI&Ydgnf>Iy30=PoOLFZlh} z?jN?iQSS}!kzF{-ZxbqQgsS@DCh#2#!iSdTXz~veH3j`~^QyNeci@$gQ7^+0UuJo3 zeJ9+nb6l%?dtPs7_5-X?dK^dXDju6h54#StbI_Ly1v%mV0q4FagCRvESv_6591qh+jsyKrLy^@UuAr{9TQ=pAY>{$4ahfmRagb?n^+y%s* zT((EBwGoCQv+-=v#?QX+%q)tHgtFl<`ms3TH9Vf1=6XZpb)54VJ@oriNRG!rtrl{j z2*6umR=2CaFNOYVvO&=`WOw7p%;zRsvnv$Ev%b*Ne#0bQt(8RmMHx>5C~8mhY2JEm zZA8@ix5jmug(R5Fw>awG)YsuSMctGoYIbTSGXzIGPVtx!w!;k96FvcYc%obbzz8tm+7}yuYwIK5bkmXF!|* z^YWCvqm|dFA53%hX3&F?Hgj}8jTnx@*33y@M6ca}MI>~*#bDHv+5TqXUPQ^spri}0?s3$kKp2&~Fl^ENd7wE)P2nt#8s;kV8I_3-&eWQ9<8lB(sr5V@ zb=D}>Z@^x`fY&HP2Ln#)54_PBet3sKt@krq+&n%GXpXl)40(nj?|`t~n+y9W=QE@L zKfKkbaY$oE4)0@G@ek012XRo9xj*2S1YecI`v4;NlweKU>O``Yl24NCBVw;7oFIbF z*5SQIk?lzE!B|tx*9W3|Ma+U+_{0|cZ!oaeS;zv{vCXZ)FU{|YJVi~FF$>v6vWMfSXR%7{E1|l$crRgLZSj|1!1S^lMKPvjqPC)_m@WB zDca9T@O?v*v5@mc;P1C})KlCQ(O_+_tb3rN5wZu4F3cDk<=!~V{T;u&Vp_;S zO4vgF*JZg&C)je0EP?;vPwoGyMkCFBuYFG#!(zCQMokpqIWI$vhy)1=?0SfHb_hAq+6|q zynPB}El3Oc((M9iD)<)Nq50Q1>jYw|3tQt&1Qfox6EGAo+CO*1&nY0cCOsf(4#8$f z%iM0TiP6j*1kwvAxl`|pNZZzNn z7yh3;^f#9BDe%7l2b+lP?_-DGkCt+760%;#)SdKSl zM*W>~&r*oq!cS(@UT47b$RJxGxxX;#dpP=pkT82(%@AIFW`q!?*9n9Z8*>A3Les9q zP+|-FE78u)A?j)S`~Ciwq~ZN@NJhG?9}??iV?hqzcC^IJRb)7s|lxOh)8D zk`F=l4$%f9?wcUykpB*8oY4w??I8Lb2d~xUSdfJ{i>)senaZeb5bchPsD&TE^8p;@ zc#WrAE=^;9Bw0l{UcuP|&C!4YoH5jPj4O;`T_NrJNbHe<#Fcn2@whbZne5>D`#n0*l=Usd}6Lv96O$QY8pD&%>R zacJsW1I^6@VYJx{`3!{lm_@=D4;gYR$-N*9xrPK^KDLm_B={_;g-jxO41_Y5lH_Pm zK8Iu&2t!7YJfV<_NjhPuWyl*OmuT$%J;~M>yBT619N`;nw4gIXUQ@`IB)e%;|0_vJ z<`91q2o(%x$omShZ zFG7%BSlU%84)YDk42U<3&(VJ8O!PIBFk8!d++WcmY;DVX6VBr zX4@Y`Om(%0X*&po*A$9O!LcIX=rbagg{dM|I`@fK7Je;a3SJg5)vH9zoK|QIOvhvn z0O<%~+RjmkMY{}ya}-PTIfamY;^Q4Zd`a3&KQ-KkmzQS_t|Xt<~Tz*<%o8|4~aPrH(67L6XDIV=V1mvgCjHQsB!Y( z6xcpW!O%*Q_Z9LRl2eqPMY~<(5r(V+q45^Nt6!`h|5steLSR;$Rtw54z`>}tW);#h zjYmtpMY~$$9?EdK%Cszm+Zf`sxHL&(AxP_?oL*pY@arN8`m7eYhU9MPzmnwFBEw16 zitItsRQm5G;VL#a+n9phf^Z`S<;3oxqk7Njb zh!zc>ysxnqo^;M6<^IBv8=EQBSn3p`Ec7-(TWxl$6Hiyxx74dwGv zgfh}IP!lZ_Sw)|Jh**6dqpbB~Nch~)$0TEvHNLrTi-bh0wa*Yz1Y$Cylut|NNfE1? zsYsdmv=G)B6_{HlVj(L)m`~FdTB}71l{=M!>&s_u?vmURgfaXb-he+XGP4y<-V=GG zHBNXR%PH6-688F8z`rsYZ&FGD7P3$oFl}s|R6UR~w}SKy(MH3YAtelHqRCcAlJ+9s zZwZqpfneg{s&~{J_8WvmzY=+t6{ngOEd5v zBd9He69@9==OC!gXer6J3K@dRijILdJ^Sz{JXblKWDY`NnWI$Y@W-}F5mWGn$ge5G zb&EZK7IHBNJIaZ40bw-z%x4$n1%J+jUMw<;qymJ|nox$z z_QY=)a;V5slAnv<)Ng2x0gweL8An%Q-ax0Rw2p6#9{GUq_^3RWWL}}%}4@sr+ zKZ|4=<#GlI2WqOmn1s(I;_SABH!bMRkYONNl_+?9b%tM(2NXDyF z+K}+WGK|)WLe0_PQi4<1& z?Aq6(7m2{%pW{;XG)CKBIkbuGXc2z+Df*`fPXC|E$K)m@$Pf$QBi7vuIGEk{Nxl`q z|Ic9>i7H^oERydtD<@xVaUh5I%TzhXkUTE3Gf5wmI@94|dUU6%;5d>{AGRcqKU=hD zM=|7DmAbX7`66F3BiADQ0Z42{o zPK~3MnqW^ONrO<^tt7ux$PFZ6Qa*~L2vcuHJBQ>p&BM2wBzxh97MMdBKil+H zoTA9wg=_2mSoDmqt-l~SLyhec5*Ur@*~ zB;ShcOj3*+A4W@1+kGHZ(1heKB2O_|0d9pDtsO(I0%5eaB)<{4oxyo|9_@05oCU&Y zmy+Bg(vM`dqFqgyBeXjIGm^_iP9UiQA-+hNU6Dg-dyeEZk=sfBAc9jH_X`Vvl;b10 z_#x|P65iBM$zdeB;D?K`=Fs$4=G=!<3ciW<6Mcn)asNybmdhR_`4a@=9#RcL85?xD z9z&TKj25o>7n39)z-Z@?oC3mVBS>x**_NbQ(eOWlHJ3U*TZ#Bb43v45Kb0al#YG&1 zs)sY$(FkUYG|3erhmqhf11$unR!l2%ZpI1HbN6=uwb&G=Co)AXHpRJ2r4y3j)AZ*U8X4DB# z6sI*_gqKYFP+S~R0S{V!14D9^_2neor^#qfk?>Z(MkbRW5bKzWbFfly3r^oAr^`e6 z>;Qa;IeJ=!#eirZmBLjRoO0SJ<0D8onPMvc1DTxP;V0fh5xyX~7M{6Z;3tk&sPPVe z?SxTUgvmtsGeV1YFfbSYOlHK=xmDy&U=A{qy_?XQ%cu{bfr;FP;Un5j_K(CM5$z$9 zdy}k|Ef&%d`YwTo$-Jj=2a%%aZy_)IJ2F|?~Ck+j6_+>{8`Tz5|K9aWtT|#@GT=I zRw^tJevdD^=8j@9?2m)@Q90+}geD|Fa;J${S-!+5JQyw94}l|_@WJKCzbMPy1svVE z&nUVIKXHa~xCn4Ld}EifZ>PgZ_@ZIiI;3q?;IL>8V_kXYACFkgo_!d<`v&9JUwRu2Eo3shq?+SKK{nlY$=Dz`^q5k;p@%!> zj=h%6;ud<9^^lkoFqq5NKwd#(5Sy zlDRwZOC`MBjsLE}LjIx=4nDUN73j>B=hNb)ESMl<(1 zeq$x(W9^Lt550Ni%UK}uF);c-gd3ourud1a!@d*7vXRwJtnNqSG>$hNg#G1nhUaB! zU=~B+*v7L_h!M*%I-J>e5Kb6yKYflD`4h=mBJ+VczZ3!ZSIH^!4oOYnBGE3p!{hp3u=gK7V1?IhG!jY0ncngch4$2MuZv_`lp793o2JV*U)*&0)P4CM5xD_-Dyrs zGlaFr(w`>b+(Lx%P5&$+2UR`Vx6_DF>tjNBP3`(P9fwcZHAIKrTA)Ive@>ylZ>C?> zz4|t)=dSA3cTwR&#Zf<>q+cca4MmK}fG`yXvpQRiM6a5;AY4M77xn5u{iwm`iK%h= zKUAP%rhh&}e-&3r>G$7ydTA=~>%Bcp1;JdaHuyi$xJDQ`0P3=wKF zQ1gKIxi@uO<`lF24(bU;eD;MDBQ*o68((^tA0~XSBK}Ojia1IUhtr>eS?sM;s0!2q zr@y4m;~o!=V(9QsKvbQSc;EKatq9q&sAFwaZM;;SpH>A@#kGoX>DTi{tsBBUMsd~7 z*yE~gw?`<^30N)RtEyAK_cn~W)K;M84EjS0BJa=60f)f98`bUH#yV&M@d*%h>7Wv! z^!H@|(SW{E%qQGG>V3;$GN5v3yYAO5(*t6)L<&qi{h>Fs zfVome(<6$=n^2V67tTJ2 z(5oU2LRrv;)d~BsA_^{c>i7K?T(?n|^pq8K)zG^-e?J}9e2@Nk_8%rfIrBUE4UN#R z$0_hk#eEI9e^sJ4fY@J&{eXV=r(YF+?~?-RI8;w;&mz%V+)tHfTcRIihdZQNwV8fZ zKRl_3KhUq&M1P!KQrx@2RX5Fam#H|tP7(476FTH413V){S1_Nve%nU;Da`MnaaG?d zu_g2SKb<$P`S$&X$EE7uJ!oL5LG~&7)wjX_hYs{llK!e$&{fp8=+_&IYNYypXngNG zm*|t|_eNFzBl`7(F>be~der&fZvHl?1xK9-K25(hFZenBP^fwCZGPqlL8w_Rw26Mz zd4&G?IsH`;IzVv>)&mLV$;7ycehY6>ssf$|x3_riPL6vy(Mv>(eqW*ATJ;=-$D!ko zQ=$H$P^>?Mjy$HiTBO>oKLmdp9e9`Hb3~{P(oc#OjSzoK)pQuMRv^VOymHweRC#<)S zEGR>IG5azdD986!RSba8oIOxEmFXY7o>nlAP9dv$XZ2$`P%hx7()ARdXH=(kQjP1W zX7w?e(9~%@FNnKX4adXjcW5g8d9{|gSw(E5KT2gU^~VLFzO*>>eGppbw?wF`s``g4 zo|2`bK8ots$yn&4bXV_SLPrtm6OU&RYR+cVMKo;%LA+0ymxmS9tIoWy`ql=N`7{;2 zh0K3mS^Os*DDzK}W&Qb=CPK}b?l&)A_WVPovlg6hDng#=(*{(uK1+p{?n1Y%cBO;) z^hdQ`{}6ZX8|la^P<1I{AvvKRj_^2dpc0R>90UpRI8o`KxO!XvGdehee)SJkvG`qd zv+eW-8+EAT(zO zva75eq&Q14M&6_d^&Q!YQ>Tdg>DI6EU){fhXV zpYuEs%7c$9&M~iJ1Ko;f0da;RJ`N(Lh|M65Q^ZgFoIeqvtVI>)AWAdk&f$u9KZwH= zaR!JPicrsBE1mrn@oXLI?5T)dXx>!@c2UGTK!g;r7{p(XBx0kV^LZkawXEViLg!k_ zz{868KM=oA#G78voFPRVMugJ2TM-xR#hjZI@f8sNtBAWnY*xhMAU>;z*U?>mRgdPp zjR5{ak?VDPXzrBwJ2h5TCtVRQboKQ#1ciE0^(Rj^bnzR z-m8e)-pD#L74cgT`zd1DzCO;IiBLLwD9(mAF=v`0z69c#1|shFa~>l?={%`8bLcEo z`Sx2yoB-ldMSKjzCPjRa2&MB0Mf~y2tg}`TFM-%ZlU(h=w2xNSKB0&ch@P1I79N0nFK~h+l(PuZSJVuBzv)%GwMN&nwPq zKj(5H-c4eMDzU}``MsdM?;+y%RLQY4_vq>A!|&o(C1|k=L1@#rgV65$8H8@aK8Lc7 zZrrgTbh9@Qp-v}ssICK{gZKyt9r$VFm=e>SH3x+5#&!_8>n{VLlj435I$d4>p;PRj z2wT(1w+w_%*b6}DRK5*_9vDx8&_ibLnQTB0vtvN$p}7Hs9?sW+&;$Ju5PEW$Hj53! z)Nq~yLQg{NAik_Pmx0ie-Tffait_>pJ#`**7+cem>M{^|ioO7Zp1f}Zp{MmHLFfs8 zZ%R59UcG!A141t>8$jqK=Q<)zATgZ>XHnLwtkOSsfp~ zu>i#7idYRoi~SG;l~b-!28IcBJ(PDJ4`tf;Ic-{pXDg0Z@p>X^>Gv`E_1@I56Y1#Z zv^}v(?N+v>{fOG>c@10(;tbXFqWcj?an$Ba>1eT!fgoCM#VWF&t8|34bCcS)RXk2_ zznq+Uj(+!7nRh)!QQ<4J1q;>Fk=G~I{i}WtV?T*2(WR1xC5|dXoXb$Q6 ze_pNnrNR+IBws7>I)U2b<=1MJ1lQ2-Tj)2c2+1$ak^BlPj><1}YN|Q!p%O2@PV*Cz zQtOqDqq>`5T(;iZKzr4(!Nm>$0=el2z9Ki&W)o$ed1j|Xs#Sk%a&fu6``B0u8JyRgW|}A zVmhpxk+;Xln5sf8+WK=mig;WRzoTD8=pU8$d(x3Ac%v#QSh~jNDseR~uBoZLxQ0%p zLaK}O&*AhpO1~}ClQo~C1CMhp5f=(4i!iJsv0C-U7EerlW>l>-nzM!o&tdhc1x0An zmlL79SMLWLy-I)m`vS#M zKey1YVyn-G=KNl0~9}?ByD|@9BsO_}U(_?eo5x5nq z*!IJG0)=XSiCrIJx0A&DY~fItPdN}=U8csq3bT6kTjAF!Zv;nOiVj@|f`Fe5S33H_ ze!;bM)!{|WpRV)@CUFv-dlD6TPM=GJvZ~))c0C>FTXBS;T`8v?q2K?bYt5lucBIei zt5WqtMsBM)jSddbB>nje{VFS~rqiFhKoIa36f4f5it{4;awKk74@igT&rs84h) zRHf=iEq#j9t~hG%tqA>d+En@wEEPPcI7ibTkMlJm_M<}08S!&o0--t9_CKatsoJk^ z{t<@mA}`dN()7D028r!&|KJq0H(5k%{c|pye5H=a6bQ}v9*EP_wEC={Bd_E8wwjzj zL=987JoV4ps4~^C>t9cQP6DAhr-QgaalYi|To2+Silg4Q@w8T;KVh_gAH|V3L+-H` z5y!rc-fcpyyjT&tk%L||Ye`lSTBiX7(e&0jBIXim18*fob>gGNK1PJn(bld3p~b#W z#6iMQJ)npa$VdI7-m9SW^t&_vNcR}j#P=|{7J8okcrH!fjUFJQ2x&3a%>Q-&v5VR! zg<|LPmggGa1HdM_*QWR*phc5H6X>VXa<)p-XvYZ6CCcB(#~5FR-}RqjdI9iUpbPxK z1&oJGVprfPl0B=%jq3ODz5dn1jB{& z$}1&rqS&#adn4j9YvBn&ZJn+u9-JrSxq4pyd*;VZ>=y+Kj9Gw*3Sh zr#Ag^$LZF}oA7g-|98;ohH8KGqm|7YTYpHLZ2X|*;{Po8-3}D{CI;=tpz$~D3mrpT zXRPIT9<**^aSa*=o1FOZM$~^iQ2aE}jE~8mDD5I1&(ayY%Cpny3_+o7ezLVk%1uAg zFK`~On9p{912pBzr6msprJe`H{sOMAT)Q@TX`c;EJqPU`f*(#}W&JVhlQ;-U{oSbd zx-DG4EiO`S`Wr=jZaIeIa{aMeHa=$k<L8`YSDGt54S3>i#6y zd5pwsTiu@w-o^86DIB?*W>PxeLC{TWB7x<9jJN@2O|Gi+EWP4}j%`!l`Z zNxaPX$o{6fKQkl4^knC`>iWU!hIu_TazC%{Hq3!9IAe(AO-!M@;YZ9DOo9$Qz~u=8 z>we7T#e1DURB7V{DX*??g;A=mZ-w!&Q8G{4(A3*r*SE>etFQI()sOkf#JUH0-WoQr z;U`?~0?j-rMOVjXsR)hFFE@Vm4{?79n%0Akk4np#ehBTH#P5wgzKz%OOI9ATJ+oZmcmd*f2T<&rcqHO<7Vrt+Nr=4(rk$EnDhSnfCtnh!zcOn-z9(+9NGJe)j*^X1L-^q-pylF!9sFJZ z6#FIy?Z?T+HHNreLl0Z4cy3-kvA70}gH2BSxD@pd0nNAwZN^8+CyOrPap;L0hwFg0 zJhQb&%1wXLxDHsoKh5zq<5MYG#)Y7qpH}ZrS0=&|S3$XcyWQWPuI^6?uG7mrX2WfL zf3p0yyl*Il{g1MoiHXO!+=flRXTIPFXcOaEmK!y2`5(AE4QzTG_JA2+{Eu92V&n-f zw~cBUpEkaf2bB|f6J>u>-JkKgCg;PGjjQa7s{1p}xa$7Q9C^iQ+k7qMrk3oFs?QJd zb6IA5WPek=KW#>a>B-J>)%And4fA?x2J5>G6My3MUvTJ2rcG@6GnWq=*f7H7E->;J zrUg@=i}!j3?oU^*KNN(vy1o^J!%E0HW|M9*Hozz*72Q=novv_5Tg{bimJfl(Iir{`s<(NxClynbI6-j z^LT!`3Ml-N_#)el<2@LTU=zO=qm+KSmEZdsyP4UTvy&GM3WwS&d=qtI9FQumo9pK6B+ zL#311jM(U1A~%0F8^80sO>cMN?mA5sDP*U-1+ht!vbywF*nzTZdT$1X&C z{7gCydVW=DIl~Q)%)Ei0Z`|)%&XZMNXN(UpUIZKf{u1~&@YHXx+$F#aaL;dY`O&}& zfDZxp{uc8;0z4PE8TbUycD^07TpDVVFU7a%ndK74Wr*JN|E+XnFO0Zs#dG4P{6v)*Bh*W|yjA1Q%DFSDG9V#kKzmsrol%)hzZhKX00 zFF4~>rcF$tydlK-E0_cws^Rj4fpt^3JY~UnE%VK|2|Zm7N?@hstkvz!{yyt+UhMld z#;rYm&GBHPt?dA#l%9fi}N_j#Ha{x#M(e+u`?>K(TLP(0&XWf78Cu4&r)hlH+;u6%&hV&^XxS#E%c6eg`OinrOzy z8!HoGiK}1~=hxf& z^Nk^l|LXpP&r4+ znOIP=2 z1@W*Ew)tAhO+DEkRiAGxemz$9H`V7G&CFqXvh!SZ{owNc|On@%l>%s32*z~LGTVZ6X>sw(wY?Q2HHZ=9N*Y$0(^XhAT zd`*8n&sQcUP`-RG<_ivj4&y$enJ1;_>i8@bq4D|U#xIF}5|sPZ3Ata5^8s6}BAC&1s)jT@>#%d14n=d(${dQc&q_l1{?t%HH-Nd0UrZS zIgHB>0ImYs){~&+(q5ZYz9|^?@5gc`iX9tf>siml#Qt1v!=^VgUvLDpiShqoxlsd` zhq*irYf2Qxos zVEmn2UUx`w%%I#hie-G-_);EJPUKCL{Y`a$#`^_1AD(PnWnWa?pK-=j_h;tFD^AP) z(}t#&?2oGV@2mIk{kaiz{t7DRx9vZ!t{=Q^nAcO|@8WgehLJ;=FSzF2Oq-ZPd0&M2 zg2SMrGr2rtVACuv_xF|mc(VOoUEloCr0WdT>kowiu~4>kP0CHR?R9;tjxSt?GdmRY z5auTnn-1f7tA2JN_JPggg)U+NJII)7AJPU<%?g?8>;%j5bZJ1`F5KJk6PEO6J^%-F4l0nY(ufCtQBelPHT;8Vbzk6`}sKv_Q~iqc-2eks09&n%ZXHX(lJ1I50H zpGLgy1-=TLhd9N7|3+MnMm!u~8vH%MUj@7k_-mk9@A4xs|Gp;}E_^S`nJ9K_=r*vP ziB0e0avRni&3wTD&?ZLS&vJtX)3;zu+gUfCS6L;#t&L9@tTG>9R)P~5IX2M6?qfO9j8I_A*h_` zkI>Ov0?@NGU-^8H(IN7+y5Z7fda6Fg3II*|} zje|{2{5Tf%p9M7IBD5JFDW5F5h)4K2jzbb?%QIVhq}=o;UA=#=_s>ov$JdNcrDz!! zf^z=eje4)!!u3o4+t6%h6nRnoe3uy+rllW?bMvJ^hRbc3I+po@3l}nNVg}{Q7cpOO5Onwhuw!84I4;jvFmXKd3$r*+ z1sxATUnw!f|J#Z2Jx=H}zzHRK0&+y?^h| zjiB>aP&vPC|8aHw;B~{io*MZeukSX@fiF1Y1eP~3h4O|b<_ji4hd#vR2?OhvaJj#) z{Ku2+_v-rQk7g)TUEd1hVWVUnv!SWCy{>Q7@x}9^*`Gr9V}3HRu9@epVFMeMa=8l> zJ3+BJK7&T8xLmpMt3Q$ZOR%`rP$-M*wtqX6^Cg1MZzpj7@h0FfaEzT(xSnOuyAqiE z17D}y49o%F{5Y2%58MFU49oyu0nYd%%P$3<3;Z_lY2ZUou-sLDV(bR(0>}7`f-wA# z;JJkK`TQJ!_uPU_5#>?nn__W1KM*~e?U{U`opbp6KZG_h2K$#i%I$gxXv%Htw7kzD zC+|bR^L94BMLzuL!uK~sp%?W14>3dE5&a~eugLml`+g9|(3j_Eg1-MD34PU0^?63y z_dl3%koKp2`cp_Kiu=IoSp7);)#5=FE)99#UlHDv|9%LiBl#}+l7Ca`MUzqLkK_AA zCHRqx^7-M{Z}1azoIaiXTk~;V zC+f~A++Uo1In)0H=J0%%=Q7>xoPKIy97AU? zebw2lzZ>+WdE%$Y)q+3UkP~?mqp&~lMYjJp;41iQ%A0fy`g>l&`pbYx=-&Z+)UelY z7;<3eZ0Ik%lEzPpxM9pP(Zy)0==-0pI&6Ei@c>1H<&QXkaK`EDcPEg9_`Bp(G&%%zNluMiwasUh?&Szsj zS$G-uPaJjxMeZo@JAsC|&|oXKXZZ@oL0}f>2n{(?-}EmE|IS&$eswk%_fOr*uKx)4$46QiZ^L*Oy@S8X z5rJFv<_PzEExy^flk+@_T@ztC-&R2F51fH-UEn zmwbZx^BhL0*M?EF?~;>QK7w|>R@xUs`%XTI+jlk47LQ7mKZ5?Kl)YFt=b`MI1f@KO zeT<-#%f3la%In~m^V$6QwZ7(p{kB|xDRuoOYwE+U=zG_1q(bn8jC_vkcP!Tzn!vYR ze{jH;^D>FI*w2Em%9T$E>_g2jAQgX2{piJr59Vi+p9Wv@%;ZNCtRJ=LyWlH547fl1&XFafy%pjp_cvU_zKoMf+0Vkhv?r7-j8_zNzU75SvMx8hpZ8bS01Kt;l&t%k zk7oTxfTo7{m%#l1p;MOo1Ezi{8r@S$%-l9u<%8O@8OUD5^Xjy7r|5CJ^ZAU~3m9Jp z&bW~2cHsHIL;JZr4*U&p@u#``eBdL%8JoELEZ~E{C;!gMSpAMO=t<{&C@$_zVz-?*}Sp!hqTki4_Yq%x5Mu%fnwjpp#2y${-%AQ zqloLNQ#qa|?=Z2r291MFPW<>F>UV(Rr-^2KO#Vb^2k|&)3diAUplyD#wMWWLKho9D zKkI#3_4Ch#nGyXj{rq!b6iQP;=etVF**tS`{&6(+%kyx)@r7%6{`fZVH^BO9xqJ@r z!0VW92hRFB(@z1z159@V?*s1r4K7~;O#O)W)eiv|KftuiLlZ@5w@tqk-==4lOB`n- zerteY-^5=ae#;TJdx2LVZm&n2zK3|sLp<&Ut^ofQ;55W>Iq+k^5r_BNK{0YJ_U8sB z&*$<|IP@u&Gcj`km)kILA@c=i^fPT@3gr!-X1-t&bZ8Uo7+CiiE>Br7j&Wf2Q>DjY zPS?=qxaPIqU&*z(kVE zO>DY?%gwk6UFmTd)SlFDVi?H?iDt8Z;k*%9;KM9Yfwc(829*I-|0AW9tv8-^LGGF8LYwiC^2uTr@tCrT<8T(xHb2?gBju() z)$^O``HkAKn|blydVUjh{;IT`8GoU})%}S+p_KWn6iU3d)%{8RmDq2Wz=dC8ITM?{ z%;h$$yPEle1E5Wee1+u(4Xk&$+yT~o750D$U}Q6wo0vnnB-J>)%AnVH_i1U z@ikueZP;`T^9B2_W!l8L>$p5=;3(+W*O{L)Fh0QLg}t4pCfo1T^(`MubyQv73gcm; z{#(|!>iFV$(Uu1zn4e6He}m_(hHn;P5_ITW<;JfM{Um7C5_Ei2 zTF&%C=(^+i{`86%=j}IFFg}F)n@<6!UCiaPfKlLGz!!kC6D-#Uybd@D{J`g#e--d) z;GSQAePA!J)Vx`WFYUC+mEzm<%yNn2Rft~(DE3Xf0r46E9)$Ru4om{yhB&kX2Y@5s zABFf`1bhrw139za<=68(QlAQj3vXmO6UB}V-T!4h6Ps@0avRp&%zVKC&?ZK1VYxvA z>u=?92UvF->;V(N$n9KiVh-hI+=Q<5xD0Af>Nhcp@!N1JkDu5_7`OKLHOGUEHvKp0 zQhGLi&~k~_62$2Opy`LuLC2}cn^^8R4Vn)@(jtnf(oMb-To;!@q86()#!HM zJXc*m_4#tABv|OVG3#bbM4=&h$g*2-^4H2RU!|YGNG3{mowjbHM$+$ozwW*8m>{?t2OI zPX+b^e*-+^Qs$on%mAMQ?sXaSmjP|_WzceIr%k>T-==4lOB|;men$btzKNG3UJn6x zMSKV%`6pz+W5SmBZEi>muGj!SiaR+t|)O7@>N zH1)RE>-T0mg3`9QNV#dJdVkuCNFhDhd9J#C;C$1#o|?h>Zo|YMc>Na~dYow!oBqh< z!v;1y!R0P6@+YPRQ=kibJ5Nov->d6eK9=gJy1o_0!$!$GZ9`LUdtKkEWcqQ(G-UfUe7`~kOM*~NI2Pe6F4e(Lmo>y@BD&TFv=~r_3$-r}fQ?BCjJAk(N zGHAK9(v1HFEhOq{Of?D zzz-mf>wspx$-nSCvi$GCu>Wb6Gg0i=F#8ninV9%LF1KM*j`@NkpiPWF!*ZhrE`OHG z)4-;Gz#cFIj6cWaCPtp;ax-p1S9)9qwI}tP=wSTbbvWn66Gt#^?eS}l2ODkrZ_=go zZ2X|*60b)Pr=1%(UZx*H2OXy(Z(_OQG-y5ql{5VjI*q&;jBxvpo>kervGs@4Z{r6o z7yl#hdlgXZn;5hoCmYw$34A~Hpm%XR4?J{YaSa*=o1FNu59<%L`N_nl9eCcVpH_%{ zptC@+6BMiCGiaoW%at3y1O6CTgE-|7j{(Hvlh<%un!w)-d=7XF;@AN+>us3M`8m2v zFr4u^mNQZ8*wERD^-PTH#^pB5fiKvW`b~5(e)kG^&~YmA zCYC!+gXTj}Iny7Zv&fseHz8m4t8Cub`a|ls@q?C&|NZd$E}+;qF=#(dHm>0&o>$J< zhvRv6{lwxLG!8a7@uLg%Zw8ui5!#H8lus68h{wV=a2(P=+x%o}kCdDKRPRq$?@w3n zPv=KP(D|#B}=c&o|dv$%w$5I_t*SErW*eIE&ZD{Ik zuj^ZNeDS{#b`nNId0L4yFtd7s1kt!}%cKpy!qb2$)f$O## zF5rB*191DRmLyiKI*rDzX8@?%k7;5Jn%ZE z+kvyb&h%5j@Bq`@!25uEe}l`{0B!TCS#E2Gl$-KGm*R_DDU^6kL!6ERihUD*fjBKk zeC`Eaf%v>0@i6s-UIG3sz-frra^S~+B47V@o^MLw!Wk@QV$;D~Zo|5FGGA~2w26^J zSZ>h3`gd`;1FSm~_J9dsJe2m@_(99X z{}}wf1Ss}R44TJ5<8Rs*I*Pb1dyeC|^!bU!HE0}ca^lCasQ)aW_-UdUACo^(+CeImYmbzhepK%dR__m1?+@ljMbP;xs9fH%aa3JD^gh|#2PGoBuG+9^Ci4aR zXEAMJ-Cq>Qf-DGC z`uG~b{A6N$4$oT+M-*Zbbf{tcdCklpp{wIlA~7*6H-3HSCqc8;pzBYiPGcYQ z?5=!0XW!i!vllSF44iQx)9t|Xfrs{Uc^vo~;Nnkn`T4*{fHO96`B}gRfwp_3X-Oia9&%Wc^7KIRLKfHpCHG|P<|xcvQGo(48WVGo!A#^-XmiII6+F6}jOYmJ-G z687Wi9XX$ScVev6xUuD@wAaQDS}y*#!|yABV&BA|c^owUrhTEKi0i3SIi4r)FtNA> zje|{2{P-a1cYxxjiDrCE{zPd9@i=G-$Kh(AEzfN2k#f_I>h+`Q^`q+bqx`4{I)4R~ z%Ud>%s_Tcoeq`>0GFabjn3&J&uHeuDrcG>W}7Z^E~X~7g|qqjVAvi&aW zN_BnXkXF|>FSW)!koDV!rt*L7^`qDL{&B`ap07+yp}cPq^96@NM?b*jW}cLytK+j& zgvRHW8^1yHlb~t64h2qfN4%zaIL^uNwNziN8a|wA2dE`$jke4&A13H@d^h0=GLD2ZP zhJIA^1LjW_`a$CpzKYxHq8^Edi4va})OU1|Ec6IEv->5%? zeOu7>XAS+R=m%_n=qrWslXW_1eng-@;r6>2PqE_bRT}L{e2=gDxxn1bOs9eFcbLxI z&KS9q(YYIVD`V=0sd}Br+{1JT{1og&U?+VG_~C`WfiEi&;O`ROpBJW5X2m zQ_y!l1UoAV?TA02%^W|eSL_Nu3%-pqP5z^@qmawSesl=`!T9 zy@umq=9l=B20!$f;^WVi`ai+>oCT)3nRbBLUZ&$x{xPO)?UMRK*P_2jQ0+m|t?Y+7 zRzKP0g*2Du|AxU&IjHY*jIm9Ob)X}kVmfspV_3?8QDE+7o_`aIS*{7?`5O61{Ezzl zSNr=q%RFe)cYXRr+kaAt_Jd!SV1MKA*OB&ok;~mH(C#lVCN5=+BpEZ%m-feQ;W&i9 z%6yyuS)c#qv|sFHPT}@tzrpp?T@Sxdf0N6!0~9^M6!fF;GYUD^A}@M^3FyZl9|5KV z>c^oU+RT22p_dJ)-voUZ{@00~5qHVA@O35Tw-S7}1V8lk@$E;!x2^XQR}W=gxexsd z^!SrJa8Kp@N&PS4|82$)&;^EXKsoA@c&07w5q@kSKR@|hjroajj$OVC@~YrCq6Ms2 z0c9t|uAp7AkTZH3$89-q6mblLc7WlJuw0>bC=@da($H^0|7Pyzc#B_xB9{g~2Q;(PC!r2FQr^C3_peT;&Wl~_y|Adi{E(bzsS2jc~zIJ zBXzRh07igOU>s=r7y1_aC-$S)7t(3)MNiO^x9~+Sw35en_73j9)SZk?;^(a>xA^D4 zzO+;9O8p`DE9HX1&*J)nl$)4^f2rTYuPkF7(3BrTuj2Nlp&x->M(i!dx@p)G{~Y*l zp3ewB^uOF6w(;wNpKC8%XGA|M`tVcy7k>ELuy621E{yWT*LTp@H?m#8^BGg;F^YWT z)1WsoX1>qZ1dQHWC?5-GKa*m;+*cS=E@LVCQP|Ik--3q!ksH}w9qcAd`}Z;5^gq*v z{{IZ~;}5D8MxumfD5y(rNL{BgV{WR)Lqh6`6$*52C1k=z@ z^l-gt#3{OwX<2{cphZvYJK~?QUl6&_8no|8wigF_`ZsbsqLB0Sa3JOJCs;rHCq~iF z`r4<~cSr2R*+2rcTrUv&q8~>6LT6K$FAx`zw_#lew=a7g`<0NmeF`+jOB3dijEujp zGGFXU{VwWHz^?FZC~`sTkD&gDrT#GL51jX>bNf@s9|!pp!~7`u<5==1jrg1MzqD8S zFaAf4R}}p(dH`_~}!x&x9DDjVj7Co`&qCQ*v)39In zXSNpsihlMM_BXVa<0SSyM0p1N*MxB_`eD&01vN&aVkgcPr2lQ>*YW9lb@~om*oz}S zLmx++`U>Nd11+kaf45>ju+4AlxZM%Sf3bh2VIQ<<-x(a=epKu~4SPWGFA9AJa$;Xl z%5zV#zWY~3(Ra{3C0}g*OvA1%{vq+-GGB^*0`;d+zxWsJ&+%|sxIIy4Cnd6!Qia+jMte=LQ_$4Uisp+gA+lf*1v*>>%Uo3w@ac-Y2 zf6{lte@p&|eiQ028@+b09_P+`JpFOLv z-^HE{>!2S-|As%w`iWF=f1=;vcu2isSNzT1!F(xqU_S!;&L`M@8uO9N|2diepeXi2 zuxFe9v#?(W{WRvcs4>6AE%RF#`DL>o?&kPrrgA)TK+nH4w>JhkX}6%1=ccf}Tg&L_ z-<^+FvHWyl*Os5L@3Ow^)1_WP(NCcMH0l?AxQE-9x{v*8Iv)PX{1yTYebE#D!>Heu zpBdPXB0ocA&TlE`*CBsG$WQ0H?3d|J6!DaLO}=|iKHiEK?&bDJVLyia4E1uJN`6K_ zoA$D(&z3(9?1zz`F7nec@-t=0PgnZavc9KbKl^Wt`&SsHf3n|4d)IS2#eWY`?m#c{ zYN37<`K{!O z{JanOO$x>GGYh-c{QM!}V_Dxt-+htmO{0GCFV@HLYkH9TJN|w~7x|fap7p}e7d>fz z`hKq8mY;PS*?t)L87(tEbMP+*{WS8^z1EVSh^N$R`WuD6QXYeUG2~|$`RN$>nX={Q z4-kJ#{-j~Q3Hce7^&R;r^K%@u_$Bdmq<<~;LuVnr|KNU#0!2UkWA-l!Ik7J&FY6(9c5OMSg|{i|1$PN9>Q(E6o&tWAInXLuYgQwJF6y(b?=jeq^>F;cvc4PnnX=?(4EbfV@4~+OH}n%w+8ch5wzxrBZz+ZCmi3f$kDLj9B)UQPgjXfA|v^KWJarXrBvxTl=!$n|=%J!hTN1 zC$2A~H*lUx|K>o8p2R2gQ}mBze$T?b1OG#Y|1s#B{!2Ykhufc(^$q?xhJPuGe{Ko? z9N165zbxh_uYDPApXs0Qqu`6bWAKyge+K?X;eXWdKW_2gfqh$kL}5SO&;1nziho&) z|Kg`B`tUCX|3Zd;5sQD}pOxr;*mn`%v=Lti`euB^zv#IfzZCp)BtMPoUpdS5uXG9j z9I+4oT*JTc&x`lJ_?Lyg3;$fnPs6{I#lINr+xjpS_@P zeTn^IeE%Kj*WtQV6zBJnKcN!(S?If1Ut(AvT-cNOBV$|_6Z>h{H`_1#&@adLKaKe0 z5SQ@p3imBB@Kc|~__(kzK5hy7uIQtEaU(u4i@x}uweY3?oKJE8<=}V9@IMTG9s1WX z`qzDU{P@J6A4U9K!~dv7U;Ga}GQR!j1<1e0IPNY`+LuNBVfdXvJH&pvg#EDChyNMF z|CmKz?1z6fzW<>M+5gDz+5Z?&{C81*-XJ!9&Zejj87JczQG(5il zY4{({VtxRM|1t1GKjL~LK(X(ZuM)#E?n8{JC}RQ`oy&9vbQoy1S7?ckgXhbo zyo%KbR3lK0z-v7MdmIotac=B_+6B!EVtXGGJ92*PuQeZt&07$AeCNn;O?*22>;Gg; z+^IcraeQcpC6V-$c=DL$h*J~K>=92bjA!6{iJpZ(LvA5AdY!6MH zIRC`Oryk!t|HOqSEo`2@WYMx?nm^DS>1+OAbELnfS&2kaKH0gk{mF6(g?=p%+xs}v z8bihJ7p=DG3u zCG(cd(;ZN6{GDOY)8k5lD9k>2mrtCq#5>jqJoZj5T&T+}js$%5t781>6M z{ny`gzqHmjZ76HwX%*uKvGJdjQFZ6*mkgGYd>rj1!eQk2vrQEbp(lE*dVCr8qRx)f zXtziiygPN)@&zB#r(}CXTUt(Dd|Y$y%)`3ZclLIyYinui?(XWIede0h-o_1~4|Qk1 zx%2G_k!tAZ>S| zdW@Nhk$3@b3#c&#x>(cwyI)}VU$xNhTA=k)=X!Ng1$lPQ?3N{M@mZ0U=9ac~@!pLs z-EHxfp5CtR*41r|At(FT^KcdBdbBwZW+V!Ev#IeND_gqSdwRRuTGuUFNs*hma!qS@ zOK*2;M{m!fm5q&s8i%t6%dc49UQ}gv&&JM`DkRxErg?q@(mcFl-HP>XjZ3Ht=dA5o z*}Ark0*JNN!NA92W6t4#ZTAb6<)=O<}Y+AWCzOP!CNkbkJ9|-QM=#HJgM|}UbMIj*J32$!aq9Y& zG;!yNuJyf4EM2s?x!1EM^R}7>@8YRu=_1Pckdyn)zt{<$G?p%ErXEY)I`tNs&u?*a zJ1`FHQyJ?qzVI}P0Z|W?Ocs@Ddg1UZO>ZOwXU_JQ*`TnoV9J8t9#c7$4ESFbrwa4 z=J6J7oSI*x;=`2hZG9`-;=LVRogv3pLE&mi6XvE@&@wmmT#Y+&>-3xR-prN}B>p%L zjEzH}8JYt07t!q10wX}AxUcaubvp3{~^ES#$R|?cO zrn`Ol4sK8}TG`q|Mn``st#VV><-Mc|sOq(}IE9>{UypI`NMC>xUMIMT-%W8xZrQ;d zJQ%K0`t<*_VBuc6s6$eGtsL~p!A2Y`Rns4j=<(KUa*apuQl)^HbOf6Md^MFBOm5n; z#WN!3VScc7!2-TpV+Nb<#;p?z0NPe&1dl0OrFNPX(9ATzQQ@Xbk_s-ji)&$Ti827*(tRW8@w8_5P z@4Verf0V}Z+wZ*j&f5$BE9Zx%-0IDlgewBqV@LOq4lTZ9jC@H3U<^sW%s0F`*0$O9w?(Aw3u~iKI@qiTugRCZJgwapZ+PMM zRWhOBu3A2^;ZCvjCQZ+C@qxB)#m*`6-umWCR^AY4>6|sYWwD%Y4PCCzw0!4VOMMdK zo_FO1$36e@i;Z(0mKQ5GP<-+iGn!Ynm0~-qRjp05*&F;3&OCW5vuZ6B>e@P6*Wuty zKA>s2wIxm`x-AJ02Gcb3egJmtG6$GAUgY>5kLM)~rNy)yB1} zsAT<$mK7c9VhOK}$1Xd0@vQchM|QWhuWegNmsRNsL(3dKS88l*=;)*?Pn|2<8aFh~ zR>yP=IieTW;(8lA6Nl4T>iV`h>)O_>XzOmIpRuOOurmn*UR%m=VMTCnR|OYs4=&mf zT(mE^=*ICx4`0#M)zf=eXM22Rg#NUwYU`ydeTQ{+tkoS)2{5OJ&R{78ynbVqBXF-_ z=FGNE+E;aTs;d%o2cnnGd^f<%%t#Miw_mN!!8ej6FBc|ai`+P)ZDUUmGqaBD=RQ)Drn~6I z+oWyMO4dWGVo%G;uC=_PRl;b#<&*G~u2J)>I&)6z`rfXVUb<4=7jIE_R2D6sd6>TA z*CMm&5v|?bts7fN3=`I>!qD(?Y|Vuu%c`t_r@O6F+pHr{+nF8es(#PPz||f%cBeAV zj$<}m08ks3nLYUw4`4y)Vt zv~sOz$CEFKl@hf#HtLp^l;ZY{e%)(d^4V$b;Q6(s+lRaSPWENlU%R6pcKfdkuC7~@ z`(?=%d1=C(*Dp8s`O;OfPV_Xmc_Tmdnm6!ux_VA07WUrD>+;pJLAhV!_D9_Q7wHB; zKy}@`#9u_++7)xg8I9cHtUX=FQy!DM!&lI~%kjM*#}~c>o4#NAOXYFqd($Ulkq6_| za?>n$h}3j5eu9q)j8Yks?E{aN?Z39esd1h-t};J){=`h_7&woLsUR`%QWQaOa=(%U zFH;>Uk`Z-x_%9_BJf9*yKad)#IihfqbqfN5@?YNJG2rjQms5Vd&lN;7}+GhHd*{}ZFy+tnjVRtm= z6P`s6-sxuy)IPajSBfnx?Jl1b?Ys+xYAa-~Oi#1SunDd5glrP+B_%pM2`BMK$t0V( zK2O*tv9XB6VXgF>U3cqBjtXyB63>mTt5A-+VdzGFNJj7B3<2GXsfT13xr5`#>byvM zvU&FpTSpHbwXRr8PXUg1KH%?!k}B-FZ_7M*5uXwazs?=Tv#TntN*m(oB`MjWXYgD2 z#Gq_jIs}QF*eV@@F&ikGzp`!eP51-<;9Y(|FXdDr^AGP-ffj(om&!Gw+c@&$AZ_%v zCY+FNk=0>rdp#v&XMU*|R1e+I<3Xi*IB$XHw;R0l9eB4pI;!_WWf;*7c7HEM#_QBE z`(58%1dhRwZ>A~I_WZWaIAxap_htOZmHI@YbW6rF$^-mv=}ndW!}scq#N_PqWN@kM zHOdN_+T0uG6#+t}PYLu>u)Z-e_`3>ej*LGdOzm;#PD8DQAYBoD8pX~FnHudB|YeQ-@n`){9yp^<#Z*R zDCxbNu?#;_WRq05Uy+lR{-24cJMdC~l}Juqa*xSY*&R959e5y^DksrrWn5XiLC#?k zzH=C(C+MVv=fxj*4M>jaQ-kqSSx#o0tfaE*9OXLq1XI-wNM0#zw>DtRS&iYncVd(G zerPa&3vzms`HHyU_8;XAyb>V%a*~t#wW#L3Z}4{7-g5`MvZsq|w~GjKSGf6Ha-Pw% z<>))q-e&X-?%)h{kUS*+cevdht#^mts0CPT?B4_3!2`$jl257z&-GTb%%N`b-mO%( zP6qczsXOoJkzP3YHiJ4tFxLKJA{@nJK8l&AWz9+Mr{YAJP0to5=@!9TKn}jyJQ!V` zk1NT0isK#Zqqm=X)8FyifK%8Py}kDEp>FoO+nA5KS4OWL(<`%PdA+i-i=LaHhfaIc zJx)$^-%Mi@y93fzE1 zKEH- zvgw?Nxo5mY%pU4y?%rM-qdR`Y9h0$#wV$~vf1|PS_|s?3X{7Dd%*GR%XSLA9p!^om zDoGz*B~dS)RyjPPt*(~XWEM5k!#Ry7ETx)L-Uri4T2{~JD4o)RbU!_q;Ko3LoFbXA zqoa8HTALBo;Zjj0$v{zExnYTl7~K<2jyKuQ1gD(Td#B_|9 z#nCZxMY`XVS+s;c$!LlE7+Eh>O1P*ysf3L5Olh$|t<^CeYpd9Kpcid_cxZz(f2JCh z#k-JBvFQ;4U%Gqp=CzM;#q4Gz)?AO1dPKIr`8IKt9fl{fSL$+=yb+&+C?3B>$Ei_2 z_ztfMpVF9SDOtOqY8YD^>$uOVua!1?<6V}LI*NKcMv;7iSH=AHiRZlv&evRHy0iI9S@`H3Kv;OL+Q3W^}A!ni~znr_&?LGY>1=@yyiEP#%FN+VGJu zHTTahB8^?cU-R3ZqEdRxGjfTy<#9}f!}W)OY4xIcr1>z)r%_Kh9|l!F3$ENiW6TS< zZv^VvStcH*`7*Dpc1MfyPw(U}Q=UMkX3ptuQv&qdYkOOF8$Cn4XlYC1Y_&C~ng4L| zr~l1XQxx`gzwxGfl^!G@><(-W@|j3-IRhGX#b(7;q2Hg@@y?V&Un+x zDi20{dEhA(PkaA}()tAnUP4)q8Ld??fmyZuqe9dir$|?@1u$a#l6hESKDM!* zC^sjSzh^Y;-HEmMlULRKlD=N9W4q~hyUt6#%MZo+Hm|LllYCUPi}*Os8qY0E@|!yf zlE=4E9kVkSlZ*XdlKZT-#*X6ypIayHkPcCKnc(L&aUrKjZjbAp4oUwda&sg=NYsp= zV-ZkxO!f|YcTs~zKvl_2Prv9joicg&Jh=l@mL=Wh^v?pd*-IX|TRJ#iis!q|r^f*p z%IACkUrS|daXUKs6HiI{y7c_Pkau&mbOih^=@4YD7;{&Y=N`Einlh7J?tmupbJ4JO z2eg<6a_cjFgWN;YQ|XW8)~7{ByEpi0xlv?fnt7*_otFEXzIk%QyT4hi9=WlZdR8*Q zrJNe+ms^7t9qn7{L1~ZSn|U9TeUrPFPCjm<-rdV$^~h~Y_g2rh+(~Zk2jlrB_bUf3 zw)iG@Df?|HEcYgJ`CJ|H?oAeRQ*KITew#o2e7BqOZc18obO=W_Ng^8|lzWgvzO!t- zPRpG~_kLMr+(GZoW3j5_mSgr&$s{*(q?_?>Ia+kIdqbB=lMMIFJB-}Ja$hl-_ien2vUrJuwrc{+(L7(ZnMpYw{&=qJ($+J>LdJaJu0=!q*&tkcNjiS<|El2k^3^#=?l5?sB~ zO)x&Z4o*9Rtmr-X7F&vQW# zE!hP6#6Q^P%ZEXFH{RW#0%8Q8LS10{?R&jPK$b~BG|fJ zU?uoyD^yc!b=g@!;~?O8Gb;;_+65}X#!sP2paE2%5_kleS`&#v@r5-1nKXK<%Nd8S zT-(*tMiYTEviq31zz}U;OJ}jg<_tsb%23C_ySg`0QWfd2Lc1#Q z^y_Elc+XRgeULzQMs#9>_n2AEIp`$B_pUR&iEW%2QJ;jwtIC>=+n`^eKKxyof!x%; zrqOGO-O>BaJc z*td>J{pvMuz%J6;z~Y0^7o5>Q=)pL6F21CJo+2t4{Xi8_rY3xMKDSIYJp2Z>d_B|} zUoArwYfX^>m)-)c;gOac`yt?o^)+tBUE>Y0d(g`bJ9|9*;l1MCfnIOtVZ*<&73dO2g4?vLp-d8eS?nsin*y$u_x+G3*OkKYg!O@Qrf5Mdj5>>7BS(HYslI zS6jYLoS1IqN~xU#`6`FEOgoE=<8;2#EfZXvzuqlF`QrKvh+yd#QL7cz^JcrC%dV8 z=o#M98`C10#Mem&Qh^({sxZ~*F}C8V?rUrEr$JLafN_;HNiQ9p%9-X=Pi`68J9?5kNH=Q&q36%kJL#I2Lb22S;4{&NJWF9bSyDbn{ms}DTtb@%W|ZaUbOzL+(g>dD&zH?E^F z)#-Dc#Z%qa)`33-y*MAhI3-Q)liropMCD9#s`sC}MQoGTKFgy|OeP>jQr)eP*PQC9 zZ%YhH&gw-vj8i@H3-3IA_^*L3suwe*XLaX1amRHJaoz7u*qToDLGMMdB^%dQnCkSn zeeqQHwKexg`eN!pi&y~Tlr#h9$wx-q;mVojR8Mai+vK&+a(Yr;7fJQu3VF?`-v1qm z??keJQ$6*7m+J0Q^iIOkyXzu-&$IgA`Qnb7KHMFmubiKtHJ$2-JH%Sa#%(N2b@~8F z@l^M3dG~)P3TP>mKgro(nXq7qg~QedHyvHl}fhdyn0X`Rvf}*v}4`(nX%$ zQ{MtfUu@@l4G`|W+Fps$(7INAHyS-$sAly2O%Dw<`kFMKyj9q{AnTWQa^7VlQ}GD6 zy{NgPk-puMK0npdwT`~3ejOEv<_@~9`#D>r{nDH+!_SNf zaDk9s-d)e2J5)p-&q^+8?xGnkE!sCnTM?VpZ<0u&8N$Ws# zg`CW1t%2~l!GY+1c5ER0LOKvR&!9UxULbmBHmqpv=~zi$hD%?UxSF$Z(aPrDnKSuI z5xZMEdV3bFY;10&KWZW`3|s#*vR>JnS$-V>qg}q?;C)lBZQYaV9ZJJvKQt^O!0V-Q zjdRC4e;KFa%QmUgWYlxk&5ew)-q6wBqPv?0%<(HCjg5Fxn!ZbuE{A>Dma;yzGQBFS zL`BmzwiT>>Rq1Z6XoN{`k&1nPtO0@HmjUowgUJ# z_E~wW$s(UIF=grf6?lKCy=pB(aq+*obWFsx(0BpS0^>yjFY_4B58d_>Zg8V5Lf)z- zt#OQlzTfd-|KZC7bcd9@OBg^|sj3-mO@|ZwcU_j_1;d0h6x<&8Os> ze8d7#3PHL+KFRQVdqpOPMl9x)txu2=62tz6Z;=KcI?=(L+0#YKgN_IE|hhr zfXLsy7OyVVY8-YN1tbhT|OA3|De{@ zRAur;58E6Jd1OFO9&2wVxJ3V9EqSc3+2}z|9(w4{Ysp)c$vgNp8+p*&%p^V5;Y{eh zwzsXdcGlW#pBHyx+qJz{YI&*4)G;$vb=x8>1r+`kI-@W1Y?V53|_NKRyh%Oh0APR)ayrPnEM*4n)1<6p{BQKTPU}$ZLHPc z7HrTn@-kJ1W*Fk0rYW!+?ee;k2LlgIB+@&67t>05NK`D_Q#J^UgXv16T$snlXhB5f zHvGF=YkS=#?DQP)bTbPatQ92mWB~$=u95*M7OETNhKFoPT!9i6H=1>LYqkcaQEb=N zTkWpbsBP8|#UyY{w>G-#8(j}J(reIkYa&P%8?9?OGZCuaRc|JdCpG{RAS~K&wj^O< z&SLkiF3kOcS0Mcps~(%R=n!o7P};nFAM13ZpVDj^rNS4rjmaXE?Id?x#Ab4biuRK` zP_(7off5&z!D2}2Ce8TRSrOX!BDf;@6hdL90;?ak@|z-ONH7gvSNAGl5vz&;vcWbT)>*)%VUGaOe?%>Es_s{8aJC^A!HflG4#0E+A zELCxC+~>ioEs!+r`5)5COCEAl93l}Tf461+uGwlr?6XDQFE12?ztOYxeI@l2c(|hQ zp(hO!+S>)+&Qz|~Di1*DP^~o}aFG3}U~5q$60MC}Q`GoX1jsD;s&`b7gfiQ`-frFS zYBwvj^=`e@L{bWKm}?Ui0T#O{Je?D8p&8rdG2;Acx!%}l*Z9!ho|2UgphS>?89_R| zyNLaSy?S%C1*uXnNadi(IGS{0;yHHHXLR>_$WH8xpJBM&JA6G0%Khy(1TnR71SwJQ z`MI4WZQvE6XK1Ol7Ig4IakI6Mgp_ka0M=^MD_f;|>Ts|Z^ey?ZgwPh~sc{g{sqo@~ zEkeXk>K{6VY5E`D%El@@5wwKO_1Qgip;v3ka4?Ng#B99@5gphA;fT&9-)Iw2IZcq5 z=nU0r%8dfKBa}@db2P}6M3R?MQd5zuEYu1cn=~}`k(V&ilcA9Y_mwOnz>$1kh1~>H}N8X$@j=;2Ns08=JLbtuYbrfc5j6?zZzsJPr z`?+D%uDyXI$rEmW%aG=zI~zj&_*rJv*|FTaJm)Ra`PVI9V`X|1LQ2hL5I#%Z`{N*C zJ1K<3TE-t>315Hk6aF51F4>3^@-wTX$6S!SoAQcN!t8_R4!h-g6O(td5dE)1D>~T1 zKzRLJNBeMxKVPm^@l8RV&d-5nXe|ou%xOQ!T_qrjxFL5^smH-c^WcNpZN^+S;IWQ9 ziG!rX^0FGER1?9J+nDA8Gng=;f8GCBoPSM1GTlM${VuaxfB%>Kqh78UXl?zs7={?n zX&_$b!a{o+8Dijwy(NK8lo`K%CICrwISid&|G&jKza-GM{=!yjga0121%W4-yz*KXD-8@Q$S)>@FdZ?)-c83xbIP-2V4%0?R= zeC>uz(##8<)(D)Ej1}yJkF=4a?SKaNjkt$C2o8n=yp|&!m>IIOw1E$p3eJ<|fVMaj zNHW4B4LrFbSsyL&(yg zXqMoPItXg6+S*uYz%g9ARsmtQnouW#ou84|QuPX}-KEn>6kcMeaLPlWUa2OAT0>fk zv$dPuTCByk^>y|94!Mpa?Fwvp6P567YWO`Fp)?KahT9y7Mq@(}h&=vDYYo^ms$^eO1SOCBoHJ2*rx-VY>*E!=| zAxALB+Px9OGuyxdU5r+|)kdofM_!R@N>#X|w1ThzY{6UR&m7BBaJI8fyQG6l!Ib%Y z6;83*tt|{BhQD>eA3f`wKYruw{s^wtf0qwEb4JiP<)S}6@AuC?G(11J_z?V6{{Q&g zL-0#~aL(_agFlBC;9ujQ{wxN$u;J|gL*P1`M$#PjwpBMOt2E3Wze1|U;R06VLUpN6 z=NZS4EzS0Obp<wb#Px)F6mBHS&lO;GWkcp9z zM_$*qg>i6kt$?c=Jr8Ts5QrZDfzrPg)TCxdG+(WE*4cX!+HjUhAq^W;eRhqcf=l*C zY2dQ8D`^pjT_K~#>s+v&v$Pas)l^!%>2;VIacN};Jc|&EN7>>+GNjV`s zM-fk4(HfK!*0fx!WLNS?yNG3(!!q`h(W{Je(kfN3<*!W=J1lWZ>(59GDdPGDwG1(*V35cG6&0q4kRf>_klm$*HaYQpQiIeKPDU646 z4bTYK{3VWw0K3G;-_&I8FN?sXSK$8;;4TC7-pyM0>o$8cBy*ZjQ=^ZPK$OAGc-Wz$G(e zj~EfUDZd$$_qF@B{%5jHp_D}Bsne7s7$6e<6hHhK%&#k+jEJjAC-Mn91JM8?Kbo*9!kJd<^T z`Q%ZAtI9EJ*bgUHgaACR^+*7jUA!W&)ZWOs%3(TEZq4o(%woCZI0^FT~!rU_6 za4dR}wmA1fB{(!+2ZL&qg9`KFY_+yphRzG#X1TF}g?7+22r7Kx&v?JnpK*^X?Dlqs zSe~p^pCLvkHFwSui)Vd?M$%w;PthcK%oCcTIq-ao%+VY;J@b<^4<66>ES0j9xlhm( z`Q?+Ds2SP5HRfnWCeQlx%*x&wo|%~I&U-TUmA7fKr)}~GhSG6*_UB(ZzRvQLOUcn0 zo@H>3koP1T1*y>_C#sWQ@lr8*_UBkCw$AbtOUKX|o?&nnl=lo91aE+zjpZv9gJ*wc zrDE$W&#ZI|o#B}UHH~@Cth1F)NyXsVpINEcI?FRF9Yg767KEVoqv^i3JCEhe5Flo< z85o~ZIXKcm3Jc*S|BWX0ovBqd_x$gV-1G1Cf0Mlpq&vrO1G^Rhn;zCy1Xj=9-e5uM zjzBxhs4WtpQ$qMp(NlZzFvTxKZpc@cE?3}8sR+-y($>)BcDuaAF2vKfU9DH-_g?cT ztt`@Da<{-#jJOzRI>7PvTbvRbTSLPd+V9F%(N0eHf`(NU=tBYBeU>hP@stYl5-eG=@Ik}Z`9Z7U1;e7eMNLnSd-U<;o+g{Z7*0?;N41S76ZB&>wH@}_|Olk z?eUchp1vd)bgZW#e|m~^z9FspI?yVm3H1W_G7vfGhf;ykm1;%mg2n7C4Kl0-t6&qr zyr^$Hp#2h7uyi_5M`*4emidU~a8D8bW5Rf(Ff)Mlm+j@K7CR!6KS1J^0&CPnd z)x`JJNc|D~oprb@l1j&B?FJMek@o9hs#mFB0%cD(SJw-(${S}(5T(vxA4lk27`%ux z*KE<(!k~*HzS+?&VQ_>cQcx8&4T$QbA8NJSEklZ627X50bE^ok6zwi1O^?hBDfV#+ z9ObDW!Pag)PL?}1n!zN}+mq;%42G3a4J)@W?HCdp=kXbrI|kXe4(+m|gU}2jC}=02 z*!E;NbgO*yJSqNl@{9@`vNPWK0^61PqZA-#f`tP*JXTumDme3)$p?*)ImX0-m|d;I zRs)s~cXY8hrlHATOdPXG?geN(iCprF&7R|xtHGzNO7ODQWDyGM#w2jTeiAu|F@)5z zg9FG3LWjV7g3uu>&k;I2R*Ktjd_@PGORU5VwkbfNuI1pPQfJN3wTNF5=dt}J?mYTe z{h?u;=BZGzPF}PVbq5h7u803#JB>2|w&Vpl#|aQb=5Ro|FSV-5339%)OYVS4T-)y{ z1^Ei_%#@>Zp)VNW8&Zq>q2*w0?e#y&OftF25ZH7M_`ZI5wORxnpP5B)L4g)}+S*h% zEf6S~X#t1DEJC{52GhBgCH8Y{r z4c+{@mQR&NZP{$HX)Hm_jaFD@Ra!GBU4oX8M&pvJ z(i=STC6^?-$kqWvemp47Nns+n6BLLyg3gV4!S^VHr+0H916t@=XkYFil^E>@p;R)H z7KUe`Vg-l*2g7Jc=BD`IEELp%f^bJLOy`6+kSvrmfRe=f0p_y#;4~DhF!_HWQOpm+ z(qO9x*c|6Ge4YkNBfxT)EXIIgF4z{>QEZqZA`J?xFRt9y+x?6!_%1H;?gSn*KiI(I zMAo(dUv-ArTJYlYP;%xEr?@sV6^Csl1u~e*T3pzTs-QGf%o_-*AtAL!L!&>{qkkGAjF1l28z$tN^8zsEw*cG@YHV=8&)Jj zM9fZ?Q=vkr!g;h;uX^jPM!m8H33c*d9sUqci-RA7ZNQHg=pk?P7jsZg)Rul6%#p$0 zYcrCQ#q2Q6CQAT$m1+OQx)NE*B4+8?IZuUIPcsaPDZ#^3rb7p_ZRLVFNJKnhR&hRP zh(7x}Oq}qR?4&Ug1@3Z;#>o@IpAs6Lqy`;PQx)!hE44sf@emyz^tcZDlSfIEc*s$v zRH6_bpP>F6uu|0>e>JV@Tu>0LZ9kK1?Qo*lh{F0Do4dlWB1OAuQRgV0Q)$kE6L?88 zBC3tiKPAwH1sIXL{~|8;{hZ(u3GZ>Zi6yKH045}3Eh;Ky|JmAvFl54fF;uPIoPDq)fxkd zqw;eVR3=(XRKh!-N-SYLG$P}pK9_MXFTg~~V-DC|%223wA~tNq6L{l)Ng!b}Eb5G( z%jLVD4_NApIaqh;LMfeLFP66}wqOc8@zWD{VjDE-h`$~>;=BM;Kg- zas>6d2Dxiq49D^@@^zS0)s;nC;tVXc1{~!!?6~2E31AW(ky2YjMZay^ z1SNwZTE4@OT&XOv& zDBK-ZK5R?m5svpAB6yWb$R$#<-m^uzx>2dQK$L{u1BZB6#mw^BN1sSwhHhDH8pdi6 z5@P!=Np4OoE#CWL0%F~g<9cFYEFre%u)3*?vh4cEwgPAdrM3e=NQm8yUnJ&u?tHae z>9*Qifh+!qS+3C`u7pN%s=)-&zFjK$>F7vjoFo}6-UJiuLuM<|4Wb z4?!qa`{6pVDD7Z^eXz^1?|m>KcH)lqIRK-)7KI692p!d!L>tqZ-l<`6Ej+D|C~X!` zml!mh9!Z7}KTaHCXr4qaCb$m4{=sLBCX^1UqYrQct{NGgK8MmffTAx<2{lieMFR}T zwN`B7YJ>qXpB`>XJdHqi2!JZ=+MbhL3Wrwp^lADL5x}4Z zbMWcp27`l%Y3yP)eIH1l+aOp<6A(0a^Zr0Z32IE>;4w=>1M=vtZk$p7~_J zxP-Ee(wHat{o{`(H?DeOqu7?(o;$_i4oLDh20(gp#!wH8;W+jb!>CZUZ{0DM4A{mJ z4{^lN`@Ixk8i|b|MbPblB!6Q7q$g(#jldZE*fh3Lp)6s4_%vhDgl#O1BshBizzinX z@XuVYHP%a4mRoQ=gpV_AMT0T3Bv%k~!+?ED_SghL3{+Tb3pCH7UOO>gPzhlL5yOX#PF?tv#s`1ERw94s zG>RM^4EQJ=d;9@#N=;9Hd>MX42w?%GKK&<!#R&3KK5ERm3d>D zcs4Ynls>07<|HJyqcrGqF{CtzQ(96QRMeD?zmdX}QlTTZwEZ-0ONU0xvyE1z+^9cA zTIPCvKGa|X3+t^;ot(>cTV88*wNvYY&zf0&o)anADU9DG||}Dm4+qAi~Kk z9q6q=j6&%j5l-DulIZQ|<5Pik2s_16N#nr8-5s4-uHG;M(umfQ__z#sHTp?~nfMn$ z%xVY%l8(9{QPK$<24^=FQbp1yhBqSV6qpMuWw^t%(OoH59*8ylLZwlIyu@mwe653B zlF%c;duibhBYtTn&My^eH*1v*2m!%U5+7MCuGQ97;K3deR0sfx`O!yt zOWCUK86&|V%rNjlF6BNCQ<~sIHyT}xou0V-cyAN-$XLe(Z^jgY-;lq;uMBG+GnYvb zzq|lWo$#BHe)IBu0xam)EBtA;bK?Q3 z?g@l^rV@W(%WSRb-R;F%t3?e#PcE%1J%9dP*;p}D^ z$`bI{NxvKAYjHLVK_dE%>|o39z5Wh=Ak~sZcQb{II7td|FyyBihd=3W_a={)p5c9y zp-m}Q#krZ3*UF?kXCzdA+oArBUy(tO?r4b$_y2~;(m(o1|M+var?(t;%tVX(&u97P zlv<2950f6VO~M3ds3v=%CJ+BCgC>(8Cb}H$b6p<)q(Ayf23;n>O|*IVOgC*7=?%`{ zD7->WxJz@e{et{{sUG7fwS(cDChfR5$E?Li4s`7%J6&yUU|m3K<^EcQrT`0CSP+zZ zg_$~kueJ`OU^mPU{K;ma*uBy6I`9-_4YGz9Ls(9x*pf0~3Qj}@>?HdXgVj>hFmepof&-sKB(3Bs6q+TKa)ahW(&WZ68=R#i;;?b~Qobe&z7Wcxl$W@p;ja4} zpaAFMG92yztF_n-fEAb$R+Uc4QAEhNb$o?N`q^+75voqZV?>C^-)TfpoR;5E3CY8C zs4%lm_DI})TGL%a$gMNsqr{($DX*dHG$y@6Mi_zV##If>3(jS!Of>Ukp^oULAm0Ll+N5AX z7qk>{ot8Sy7 zl&nxkl;Jj3VT#r&;Y`)|2Fl7ZUWS$x|#X7zM z*W3FBTZ!!}X3o=R8cu9t!?fIS!fm~{lc=0=@_VGS=6j@UDaso)^GwIzy8WbGQV=?W zeeF7y5ai4}tz5>8HM?*D{hCi+4)d7GfooZ%o3Y09!lArr2Q8Lo~+cR;<< z^XUt%&02f4(YgVL(Y?{BiA>nPkz-TcR%#xKjBh(dQ7!V-4?X?y>3I6Zb*y|}E!P{U zFf3gaW2!qH$Zg-XqzAmNaBda9fv# zoQZDj(i1eH?OhszCcDK;MbSjJc_}CgwtCx+b)a#+E(Ha-Z1+;(&0))z0&kw%zBK6B z)~^p`##zIy6!^pKUvI~)T6F?8r`rM^|MRKH)CNM+gt>ND3_^O24!=uw%M04CCrm-4no49j2%A#Av?bBOS=yq}U5kmth z*Hmr_`O_`q0cYLsp9T^13JND8TcRRz#A(?$vc`;Y`^H_kjFUCuNk!KLH;$?3ndr_j z14R?sI;Ns%vU|sLBu#Yln1-Za_vm`>EG|w+Lqaaw$8?Bu*gvL0oaY8I6@IpZ9Dez9 z{Asv_96c+aEo2%o==PBPQX$YRwHZm10r?HPrL#Vuw^iOe~$~(!? zDb3J?Tgl;R3M{|l##ELgZ6*h&q%XRgJUm4;(Cy^GS2AuV)2M*%CwI5m;_44ig$lBv z9B?Y^8_LC?V*5tBybk?2!`_8#cNp!%E7s~7vvQI1O1$?#%3z_1nYJVFe{`+%PC;@+ zn`e@4O(k&-veveP%}>}GqVtmWged0+=26pDl1OLDN;ugXiRVN2gybC-{?E{Bm_ntz zXx}A6tsL|;j;}IWo{qalW^@~_^d++feQycu&kPPQo}ZW-QK^_wtmG`pTOsk57kR`L zo<*TYh`hzbP7@naXLQl8B;yAAKI0UPR_LY-q(b+ip)-@cpDd{vtz?qKM(?eq*FW9} zL;YuW!134Vl3C_NDa)u`SK8#()^xYAS(*=iOfF02)=aw|*IlYO1rJhP#YWq z?a~{Y`j%&KMY7)R#9nzx0eG%cgO?SmahGXQKqgyqtM5tylssK$2WsfCP98hG64UiA z9~;0<3CnXyJ$Vrh3L?+#X;IpbGWnA0F3;#-`En8B2U zaZxXo@TnKjF60tC&`G^Ro_VUTl56LS(3Y^%t$Ov=5`0oBZ3f-)?M^+4F(SN^K&lZ} z{%GemnlbXd0^31o=r=<@T!#k?@Pz?l49Q5=&nq$rkrZ7B*rUvrAW&)1?f9&ti8WxT@J1GUuQlCkPK$v)rtv0raoHdItbh1LQ~iVniQ+*_ zb`aJd_J5U?NEnPaJ(5f+c4XuU1#nu^(CePRNZz6ZLx}@skE0n0!NPwgwS_xU7u=@^ z4aR?Y0)ufyLLcpTAGewPpY?}-pTK4!YlX>bGz#qvUYy*1oDoK~TR#cyI@3q>>xcT? zc`$)~-O&&YA3e-9eDJgW?q>}eW@lVv_2?bEP^+E|Y^m0*b-INq{L|}fzEkUG&?O}O$rHq+OX$ug zzCNvUGJ(b(gSRrLY#?453TuPXoHe9b{;=ryA(dV4eu@7fN!GJY6jLP9%(2t>1)X z_!`tpq9f5c7xX&#^TkH%n%Agp)*9rmg=y}Z8julO0wfSIPW z%fW(4@;Q@D{mK4s$GE_0H?$D-L%|f43T^`twsPd9dQWbb@hKU5s zDVp05ERrmzt(8u#4UOE`>e?;0yQQ_;di@Vv^hd9dLj>d40s*xO-A_B$af$Qa%h!Kr z7)1i3ywYlSYnTN|1!R^0A#}om3!LDY2h1q`V{8MLg1EVI2gKB^x0;Zo!56h*t?doc z0IJ=r)Zm~P09DExxGo}vUSW~eGT_ho7inqb%zA-FB0>QDj^C49Me`wKrl$yK=$@ED zECS@t19d1Vuj(|nlN|EGdb{3g*SlM2QG&w8Z@=9ipYunaY0?r_+2o)BYJWE-=9`uV z(Ku_{7-uP8yM?JUl?Irix880+*?o6wX$2qb1X~=xFD9;f$D6;gnb-N_K$pv`X9J9T;X;vxtH9R(|gF_2g2qFQ*I z8(Qjfdq+&q{?Y$y+F{IGYqVC%4VYp#yBqCbLo#~6gh%<>QQ2$d2Wn*R1I_}t4<;LS zi^o=uQ?zIS8a!8PU1;kF=jIz7m^n0xC`997bSQB)JjJnU1}ia4 zxV^73NgCv$4x`#Sa7IHFw)akk#vi=OL?OPo368r14tyQgnD*RitG!n4Qk2I51fy9Q zhr6kgPB#+Bt=1cW-E{&Ezuh3ZD8y_tFaj^b9E`vMb1+4`5Nf>a%far_l~t;<@kdO) zDS|(k*c_36WE?v$Zro`B*OkW?3LZq~6z$FgX zpp43%I7CY-BX+Z?p_%IZU%S&nmEQjtTde$p-!)BYgL9@34)*+i7B4cj&bvdi)_PHX*C+~0u`Dm70%wb8Kk2fLa_NC<>J}@eUo?=yR8RmO%E~` z?J}Z+vpZTSRGg>Bc=Qy{lRsOkkQ5=`Mi-~psZr&6x$WW84e)@{5@b_Lr3xh5O&b}= zI723{Sb%NijdC06-rHr!t9BqqK%Os~hG(IcE-x=Yni{V?EtfFu{+c+I@g+N)>VcE^ z1N;0g78UV(*J};P8M*E|2QM>7*#y|^IGHOp?X67^t=`i($jLa1)1hE7%|TNExbRNn zU%A(Tn?Nm^bt#ZjnacHA<$?899g6j;n%PnI*>+V5_#{H zjFf~#PzA&VPDUQwRdoJ=4XUz|d`G$$0A0Y&W_4)^Ut z6Jal+d#N|TD@$e=u)bqg9HYYoBpD^^jdC52H!wS2lpE@55w{J`MvdzwO?M@XcXk+rHP|I`qiJP0?@73a1 z?lt0pQ0pK3U-~&GjAz>$|8sV2^C870GTrCfuvMt9)u!P{U=EfjIG`$B0XHDteVFnJ zunrK7(gWq-gqbgPJZDVF^$ja?O5D@5IyA5*kf*%T%E)5`m56KM2>oP`;;#E7m|Hm+ zH1(4~1J%9x3T+YQ0UUF|LXJ}*V*L|FrkML=u?Z$VIYi5y$-yQCc8dm2l-wDJs;^Iu z>P8CC{OGk%fR2(I>t3zhZndpvBFFy{vl!@M(zxOH4Tj}<(J+cE)BZn%TddzQ1pfkn z83=-F?Ivt*;1yaAI#NEDNVYVTOk(tcyUw;|pdEAgE;bf5(u{cBO>I4SOGFO4L&_;jM~DbQ!2~t+rrgWqtVf~d6lEivi1m0@<|OTf z5^#zVfL#MS1&cYnpNu^a{HMr2Y-a-g{qH(S#S^@z$T#e-PQ^hIyh-_H=)07C)+npn{?Lb%n?h0|v^ z!)%vIf?T)XZK$phd`(oYM#xkSac5;IVJG#)Cc1<23#=E{iR37arBR9KAm=6$E%4Mb zp&JNg+U2p+yBFqHVH!o-C1z3B;5d1ECf-G{8F^-y zNU!9x!@}vCQe-!p)s~LpchuZTXm$8LO{FIS^TLGtMuMH+%n)hI}6kVJ$){@+X$Vei6eOc7BvmR6%uvs1dA*!T_bX`CgjMR=+iTFtom@np_LfM+rGYDegHZ_sqV_F7D0oRv zPeh{wDNU%}(p~wZHP_k;Y>YIl`x0;QmZ0h$EbOoCRsl$%bxNTiSQZrhV?pW__;El= z(9jFYQ;~Tn`8Nou0Q^C>E5n(+9u>;VjB0_QiincnG6=Fudzl%iL?x(Q(zz`)p|Pg3 z1{Xc=T64pz+`L(sZq{yikS>Ko54eN@BE+{Zg1^^Fmn&#|AD2~O8@<4Xu3f&w>Slxi z^B$fEkuF!HFdv>`L7lB!hT7fU=pSW7m!J`DVTz{G$h!n^#zfDM=GJO!E12Pha+22i z7CnV(Z&aWI)+XZZZNGM zR_MuPW_vfJbNsxE{(z|d@X>La=WrFaci+kmQ2bQj6t)F$he@d0BzLmF(W*1REQn!9 zx!=3nT@V&jifnrC<0g?821Q%~hV3joz|p$VSM)fW1b3*<`I$j0 zk`X{3q@$W!yje5{A^kfC7t)AEK%&TI=NbGqeRkN2a0J-ncRSL(Vl!Nd<~z=`APsp;Y$Fr?@Gz4k*`rm z($O;AO;L z)5zEMmpMuOzrEdUe%)00+Wrb}k(U67!j}M~=Ss>9y8ojl9EV49W2eDI|w(nYZ=!-@=21 z!$(-acW~Z6dL4;K;lB>=_Kz?4qo9qY8@3rl2JtyT(f`9qpjfCvCu<(9AHC=sbZc=g z*j1!u0ax9qq@X8lZ#QJ)-~)oBcE6TFQl%0X5yC!tDi={6uw~ioj`)&JcU&Nwghcar z!6clqz`(CECkS}9AB7RVs}*rHl5obayZzh|bJeU~d$%cQDLPnuwB%5%G+-dGL`po(am2 zPb$4@L&mnB%^B;xiv{Lc%u&E8NpSybq21?=C|42Uwj*k6*nNK#vT(4?!t-RZS_#bx zA&yx$z;k|jh`Dl)n-e|v+iwW>6>mw$eO2cE=;=8?%$0lG!sxjlhqN9)EuEuTmAN0i zmCwBN5Od`oH#&Omk3w39A5FK$*JbXv|2d4JQ$x&^d)yA`x$lRx?tO%98_ zWeZh!D#5;Ii`zZ-FR<^!k7n-gw3_hT1fC`EW`0xjx=N@1lp1zdIeK$Y^^Thp$ki-IYslDD5W&U%jpO(~jU*gLBkaAzg=?Qc39mrMt3uKZF=b!FO)!1wAQasqdx$ zf76}%t;FCJoBdBt>Vo`7&m^Q-k}auhu8=IrZ!s^Uz@=Z2$u9iHlstjcSDI{SwIQnk zbK{)>_H+LB=Y(9q_IZEw5K9NZUk>iX+zI^0{zZTPygxV}k87TwYHblbhrh=+Zn@(@ z-{Q4aQAz@u1y9KTOS(*J5InUzYCum;~`*+& z(rH9F4!P^SL(H>eGEo7eB+J2=PxJ|46ND)sJ9;<+Ymj(RC-yp8&(Z^|Htsw{`2UT$CoIS5b(S%`&Xj4FrTQ#rw- zUIvG>D$C*UO`+?_2v(4T0CkuJDx_spIgCSs{SRk|6zZ}Z`v1g2WczPx)SV0Z~)Z8Bor@2lvJ+4sDuKgqY_Ip7?w_i z^_yU_@e*XgpCI<${`**VBH?&v6-Zd!bs!IOR)RDvffnR(Q8g^Al&knEU^gtPVT~7Y zn!rm6tMt(Y%n~zTrI{vl$HlD4Zn)t*+zz^SSjO=*?Iuam7K`N-$SIW}%PS>|A#dCN z3J=_m5&))f3v(Q9@Rkff+zBC$ED$Z*Ue2{2g4+IC@Q{gyYYQlMK^#AWhh#h1a9Lz? z6e8&*K!ST^E|hTyw{Qu7AAH>I70&*I8SFx48pGuzNKekH31X5 z;l6kj3(mrXAHvx;z=30N#>8Iub^k;9MWvpAiNinSONk!~&cehfgtKFS1E<@JiKFoA z-bgs>6z0Uu1Wb(oh{f&xb}Tpx6UQN(@dx!}!67wcqPNSj?)FVzyF0CePjPU2vEVFB z?1ylC4rg|y1-B{-vn}#0Iy6cQ_D0kE2f;f|-Xg!7sJ?1Zn1MThc&E5tZoqznydOW} z$O6Zf3X$5*M}sK?c(KDvX2@_`GcydV9gB!E8G~4alMzHC9>g5Rzm3|>Iy5ws3gL4hf{X+|WH<)X zLS6)rPZ;eyG=IC^Zrwn{N3Y=XGDpPSg?g()9#5Oc4yN$Bxy-JB_3(FCX?-xc(o0#7 zRphq+ah}vt@vsiqExc4@#UPtOmzb+s9yEfTa9{U3-pbh zAIT5Vn+89ITj%g&*6uX&3usLX?FhslLyBvoQ-+%lXiel@o?>u?{6@RH?$Il!@Mo>O zhEL1E#_10Krer!NLuCOtF9xqZp-CNolkLAxha7mdZoSp4cAyO_$Xs;!nq~l}PA=9; zt%BKfJ!~IK`XUtI3BY=_22V4sf^X{9TTNy{pkrS5aT>y1fYQww`5H=|C0|THt`| z)I582coLe<Eo8*eL%N?u{lX*@4xX19shlIKa>$&NI(`L3?d73haHv_=}cSMSY3rS zBNcd!5SH#B@!T6JO-(LQALa;UhP)@r&nl9Qm9x=_#;Pf4)8JW{GPN$e(TH#B!lFjv zB=M<1@V&FJ8dhrSU9Vg%uS1{WrF(^grl|_NF4<{qv@0Z>gtv6D?^BGxGh?0R31xVe z=>d#mPYCgBh&Un7@D@O|-X;~)#QMP6jDn2zDbPonIK7qHuEZ4Jp); zpMOY!JVzgq0(+i*A`*#MJcTJ}=pX0cC{hs;^%T8d%gIxuqDSK@c27+>I$v@8yi*iU zPR=5YX7ckEX|U($F4CY+;4g}WN}~qJ>eWX18i~Jx{aoE;Lsl%(HkrW-Z1QffFxP-R z7DV}U*NpoXO+!`v2242F6FaxU9`VX@3nKLA${Bp&Bruv5W+jI`=yyO9E6R2!L>3*q z06}SOZN0k{3DAU5kjnu!*UIbbka2^Zu)b9-`FXKjTW`UWK8@ODtpOPb{FJrkg&%f0 zOVH34WP;hDOQhw{_JSOfro*e8TRI@l0jqGFIeCO2tmWcz|8iCXk>1zj z*z!OT^N6F0OXyV{X^jne^_#R&0tjO8g8_Bm)>hYBoh5J}-Wn9zmb*20gtW4GGhCDO zpRCnOH(5qwxjRSR9j!HMxUxX6o`cUSZVWyNN?ifmdbth>+lYIKu8^>Z6`{epw62vP z?FgO3A;VDg{xkIEuT>s^#jROdyG)j}qaWv-rN^kOXm*s@@d<0$BvC;(egb~ZBs|K= zat9>49JWAQf{qy_Xr_LjhwlMgB3WPP#`JDk!!DziyTz&1R{KV|UG*R@Mb41CZuuHO zQ``tZn-gj9${ROzbin?y=)vQ+4S0Y6Q>=kSE_a?#pq~TLMNV|UU$-#j-BX9YBed9y z+F@ZT$Q!SBu@Gm<6Kf)b<7;SR5B3L=EG?kP_d0E6nJ+4ri<6PQC?pnH&_fTwG;-N)W{^Qou2)IqvGflCC> zxMoBezJx+B!&?;lpN!*vzS-(}h#tA=?FFkekXZEoBeqs)Z4pm+&&pJ(1bPp8prDf3 zVi#RjIH4Xm7SnX4j`Us!U1_3>f9RjHFyALsfrJX!-F+-vTf~ce>B2U zbj0G5H|lVpdvEz(9#v={-z-f-Rf+A3E%>4wMkWAbmY$M>WMFq}$O3=~!}>*EYxaMH zsT3fsyT%~lVgOd%+^oZ0KP(y`@8`nbS&`@TX1QG_&4tMUJ4`&jW5j6`#67t4hDTyR z+5t&_s!H$-kcJ!Fj;Vr)r_Q{BQCO_H2(BkRAU&xaj%rvT;-X*&Es`8(}So!Dcm)vEk?p2U_1&uWEf^E zuqBTG&$g|=JB78HX7Xw*k(n(9B;tlQNsI%V1=#N{*YN�havbpTYfu9QVMFpfW7< zqNU51U=$}7b}ZEz*@`b;!kzlh;2eu=FZkzYkhi&zH`v)fc?0(%$OfB_XPNeSm3Gu$ z5%N6Ll7c(;ELlVJd&@9K-_^V#I)F2*3QQ6}N~{C#fxz?#HGtED$X#Pkns{rP#9OTu z2v|1ZjX?-Pmb;7I61gRUX@6Lt>E(shHe5Nn(P}?HZlx7w*4y5f16zoaRq@8g5nqpPatOy z_rlL+*$NuGBMp!GmI|}gI$rLm!H2Xy9Gx}#>*5@E+iGjgD_1H|w!xFR^sMBFp3ehR z$P1HH$@LoMvU1G>!)`$nn3dy^A$neyPy(4*n{F$iAN3-;(I z!Jp&Q&xb+5xF)JKhdF=iFl3qRCMFDP=kk+0_y;YGDPj&zgGoLb@B4S4;PY0UK_|`B z$xNFQ=4$fO<^&nab=pMehU0UbE?%S6$~jynbJ{W3G|hjt;LjO{umiCuRFP!nl->o8(l6h;i`ypp?5@!<@K`Wzg^t;kw_6H8vDu;O?Lt_EKM*8$gJ$N>g>FqVa#Shp;H z6T}_U>#ZA0wYpR^h=(@q)>;cLS{30K2&OR>-@uv|{1op*{6eP<;U?T{APER;CAQ{8Xwqj7{`iTVGz020LV745E-*+L4OXN zyYR>1mUp%eH)&Vl#aiW#*>V?t(}Z&~HXcL-b?Q|N|D$^h-IYkZZV9NMa%>I?kw7tV zCvhVdJ1=B9@Pms1Z&tP%U=B#TSBHLFG2zgqD0A_Zn)+lv-nN_eR_b#rh`YPAfi8?m9^Ev(h8Uu_Vb(;?<|*~p5zJMEY@Wg;o=lPfTns&_tfD%A$ole`s%V%PV7eu z*H4$0{}VY}pz^-rEnmTD5GU>4{}Ifp#kKMSwbMN^%)vwUb{}&R{G9k|Hc9QA=-M?Y zMkcjVEt2Hssh*_gFfG`em?SeNKPM*0&B@M*2{AIMIZ=Bu-2D<)P>8;2O>##ImR1sG z!SV`G7TzPou!cuiD?Dg|N~0AFu^`5C)M%^cXtQtG{s7@Y8o)-M?*T zXXokx4W|=;Br#|J=<32w0*Y{x29GfC#;GCw(1YbWuO0wF$><>fg}2HiUIFHaSMmd) zSN(WaAvV&B4KD}W*6aNncd0Q@fw%|&7jeP3oaDqHo-kiyeh!aq2wvw2;3Y5 z4EKw*E){+bR{ED0Vg<+mP)Xr1iy6YNvk8O&$bs{!fphpdq|5$8EaPlEWgJIY7>8eH zW1IoVf$>!X_Y3&H&`V_?Cfj_&EgDL+7=a!Jz`c z(G~%~ud@k&0Z1tTW%s2CvB+$oyg(KgWpVuciwZ~aPzaM|8r8jz2_TD@0($7C$Nx8u zTn}VYs)Dx1CXTLNM7WQiH2G+98+3SR#=$fcGJQkEPBAGJk?2l+yTj z7{4m;3fhS3_|rVm`p&b2s0b4(EzJAgt*K~OMI9VGb^LPO|SQpcAW7M zN(|0uToH>iJ~)WM8C}YI!!QuA$~b;qj=>#WO?!vGY?pETk{E+Cx`6fkaQU11TKKuhq z`F@yxq!+^7U_uwp2or@OKJY{nx#epBo92<-02ZOwh$@xBEa@Iwe@X~bP<9;K(?t!$ z>D31G5DVc2x8U7q1P>h{ajIHF&EXAPNtzl$XSjW{_kNXxIK*DU3*UH*0RN*?K}@8R zUqC?mmGf7RF+sj_b?>~+{<7dx;uVTg7x^ z_Pk$|^`DLxicaf4q-hpCL&$+mi*vG^FvKE;LJi3zG5pt>B;6Mr{76cRwBb=rk)TRt ziWV&5_9meX>Y?Uud^S82u{sOF+|7*z!pZDyC){o&^@I)x^Dw-4G^s4l3N}yEb3l}{ z?Zsov-}ua%UBw>h-FMBBjK6@&!_Qw#>;NsNPZs2=Z4&$monk7?fw@wA(oVp#m?XuN zs|6=i?nIXHR05d1ox@tL*cfJrv;4@`K+DR_ug5XES!enbnSCa7@UMov=>M zl3mc}YsyeVFK(?M7pwET@MAb``HKt5!U{8N#U2rSlBmH5m>L}c=j1wdfO4}eGw?hO z$cQChJE_Wc0{L^DoxqQwaPvPTGZQmt#Y_--5;HLZre;FGIhlzLP;O>o2A-#x7_sDQ zCabcUz>$Z}OyI}K&BP2^F%yKI#7vBUshJRPPG+J5l$)8Df#+!^MlAW7NnJJ*IGxg& z3H%sVoe?i}NfafSQ7GnuSdy5F5im6u0?x@?bbxX*7c=lY&Bcf%Uvs%Bn+qH)>dXax z4E;`jIoaZ42CbM0LQi5QM!?ie2skG*(E-ZMOw7RZG!rA1e9dG_HWN4l)|m;CV@xXJi#8@N~F-~0J%%vG|Y4RAw3&2&Yq&IjpX>ezdfjLq@ zHvgsyHl)gEhj15`PRq=8NRZ`jfCAJBSY8M{XOjz8PK(XOCAEzP5`~`K=pryvSX~6h zM9ogbmZRN8!RBgs5%8HU4^p_%@XVft7A%X8R!oQ_hV5R94W*Vs2AI4P`_yC*D>Qmb zwi*J^OnT?zGb)(D$*f7pvPLy&%@YfXU8)$Z8rz0?QbEnH0&#XH+DE zlUb3Fp^PfhDc33}lmk%|O46Tpg|eYkp=5wbq3lzWLhET13P3X{l#kD-PzEQnLLrwJ zRj4%^Dkzc^KBFQToXm=ZEMHWSPWehf zp&W>!P?AElE0hhT3MB(f3T2;~6uOm0p#U_KLizZN3T1FoC{(?f!Q=z4&$esjHS&<` z5;i4bznH4j@tKs3b_E_FS6Vm)J(re=8(gl#!?V8$*Kc;N4*9*C#OUPPKt_x$w8Z5W z9KU^zC(5%Sp5^zeT$w$-E0)*bw$hY0TW_v!bW7r8C7>U>q3(P?KnX5aXryI>fVYdF z_o?|pQ9^ilxd`Ez?-L~ih?522$(MhWN15SHNdzjj#iV9Pozs-ZELSpV$hcr;X8uHNPk&iRA4oX3BSABBHz{}go#78sC918Kj9 z6(EqYPrDF;*#995h%hMv4-!93K}oPP{65B_!VX!7Un_~-7dM3>Z&aEXH? zQ?U1b5!T+*FQ~AN9&3jcnkV$m+2+avDs~>L!rK1c7+Cg6IehRULe#+hg@kZ}*?IT| zZl-#;FO1QRaheYQhFggi^6q5|#bmw?-$2x=VfM|^+*1sOOkDqfPh2hb?PuFSkQwa% zYK&;!WfKjV%7>q@Tf_eC78#H^J-n>f_wILCMv}?xKbuc(y#$^lLeSqJ-hT_1B6qce z9}Atu;CuZ3w~=Z6gW(VRkM#$S3;#O$-^2gze?Lz9{*&-0gYU;b`@)wJWD$$$zkdWF zjQ>{x=dl`3V%Vtl54dIC^nu!&{^-&0NB;-$5B}Hjw-IM`2eP+)-rxN`>9?ah{n7VI zKN8}71J>1X2569mRe~ca{{aQhm?5{`)A(@as|Le{u|H1~d(rUs()0^;m0Ct{$ zj;zlPeO}PPfUFV15Xoi2knuyz7GCS`J@&Q!@uT72cf8i$`5yW2#~_*WK;SX)_aM3B z@0LHHu&NahEveT;F>>v>v@0l?SB7Ge{kMEq|boUm0TG|7Nvs^Fa-YK85hEV zKJA;Y3=~(O<7ac9)Bo;p;PAV2lnUNk4Qw$$*m=!GUjlNU6OdqS*?SXrpc0Vhi++Z57KO*yG=f$ye$vhk zuqAmZ*F1pU`%(V@JeDhHW}Gn3g}f-Ker`RM62& z+Th4PiIfL;1|5x>G}4KnfeEX?#}XH0Xa6B?^dXv8CTE99&4_6CVP-rbKSvKZ@T0q; z1RIZs1i9@0or~G%F0sI}_cqa1s6GcTbAhM3?ErhOU(pEk(=GzlmBWLAJ{q;R@xOME zo33mc_K;5s#XtJr9Kh(xX@Se9b1xN|O-%zXlBt1|2;W{tzn_PPb}-YuL=%ArFTF$a zO^ba)GG`06FS><=m2#(E@nA^3c`X=de4YSj#Q2!8CIAK~Rj*R+bm4=e&v8pWdc#HG zBf(w3Yzt=uxMto1(3e&#WrTfic>Ku4M5BXMdWSbXa~vHKj^a3e4&ULMNT4U=~wuUCbheY98%{iHVK*_C~W?U#m@58s)-VbpyaO%WE}nz165!wo3QZr-)x4 zzXY;-kg2>lywFb$cY#h9E#whPAj1~#hkQ5Si}hg6b_&yU4tgsatMG6Z*_5yaQw(Pe zhgtW+!C-J&Qwn+gJ7%J6GTH>_MvELTnNGTp9Mx!TQ2Z5YLFz3T99ZXceX$_;0C0j!U3Hopq2ZnSHGXWai2 zzO?pVa)%4bL|j3K@due0AB4?rEJFt9TKZunzvDswkRKrg7C&FRS*vUi#ggxH#~~Z@k?ffgOI= z@caO_*N}LCE#Ucw;BOZng1^fDAD?>&6FZoD!lXXDy~o>CGJ z!w{&-Vw@5hF$~aFu-8bZEfPY^WAq?QQ+OGZ$+Q3EEM{(k9*B4Fu}J_ALH9R(|Adc!j@%ZzXInMsM08DJ2l z=g&eg)dxS2#t0YKvOwI$h#&CN1>UaLa1~kH=(5Oe4t5%im2%~QDblf**z&YDx6$0_ zKy+~ViJP0~nb7rra7;y>$SXVItmDJF1^RYx9oIUf3W9wL8E(ez4FYad;Wy<|0&!DXagzP!v^| zM$#K)7G=#=Ypdmr2AuccbJ-ASL3Fj=CNUNj=Qw!3kj491tR^?kB7Q3sYokPt&TgD} zu_k%PbX=u!r<3OnopCCLqDi!~F~`97r{ZT2xW;6Q#pD$POHC?%`uw!;Z0H5zwp4s1 za0h71klp==J*-%W>i|{;dt?~eb%H?*uyam3vfgTrL;D!I))*Jk&cCjx` z2g$)s{aO=JbcHjE%v%`(78@g>2XVjfw z$!il88a7jIuvy$XP@)RA(Lu;K4iYu0n{fleHa`g{2t8CJ@_-%izv$eAQFQ-Ga$}g(Cx?yTAq%jl7ZPUl43hjmF$3&QxI~JISyZ|B%Or73|$bUEyG^qN~+7RHqSB|8A(bw`g*L^ScecG=Cbgs`_-#&-p`P}(14Gr%9-<&!hf z;YE|fC!TXI;&s92zL!CD9FI$b zbQ2C(;|5@n$s%2b;N%Qy%2?$MoSE}r`PCL*VmkP+EoC?@M*L=xythZ8yTQ~}5EG?a6+z8FNs&tS zW5P{iY2}PU9J$D2S6qxo+-7zz_`9TB&*;X(gF&do{}3P8`#=5Bxv<*hJSlqlbN}W; zfBtIepI7T`N1|u%Ar97u%Pjv+9s-p@LD3kHe(?OS&~Ks0@q&NwJ5ZAoEff<<+vF|- zhj$>+d$&KNUAtRT9pEK%;#sdWYYO%G)t3FDUHZ(6lS3lqlHYmTxim!_z zo@>ChA=qiq>Rl+_UD6cMqZuCa=-ofOI0SbTC&`6+vs!OMfv5mGp%Ss;lvf1<3A}E} zKQ!7WQ)C=^H+>=n;$+Bz6Fbm zvbzyz4(^X6G*6rsJE4a$5~G3cW_^g@fV+Psfo3P))wT$VyNsac%gwFe`S8&X4R7an zasopMt6QgNHO@x8TSE=K<$}LcR|FD%Tx^t|vgHL=2jKHjcvBQ2h@&Bti9gQo-#xtW zIDd2}{I?m9R8<3k*N55pr*TM716%>6z$S0$5}fk}eY03qjgWX$!fMNhg#FeERR2H? z5K7?Ti~j!GZ^w%zgYWQ%SB&(`tYR_ZjaK^sQfdT44`0aUw|UUDMr#F*omcBOyIA)Q zlZs!ti>PL*}xVKVo(5mmf zJvP`lY+h6}eOUg=;|m3kNWIs8Bpra_Yye=at^%QnX)#Yv1p`fGAA;)j0A?6~fO7Rf zHx9r|F#s?!>}KNt%(3y0O(yh(V4Qgd>lnU7?tEyb47!c}i-V9r4F&94pfDHUHemHe z8{CDr-fpee+TAUF0@VMovdfMU$|bt53pOqZRdVTm_Jo(M``U zUuh(bbW`aE9g3pJNi!AmujwB61;Kta*gi&~kX9J|l)X+CH$axVv6&hu#y&*?$ z6K93+q1sV%^qQa`Nc`T^aB^Sz2FnA4?+tu7iZ%(4TU|tXiqRf(J1@6XvKtG-}X?BWK3iAy$-ce4g(Q6KZSti$Az^f z_)h6-IN}uwnos5ShQXnxIJ@Wh7iroXDh0I!u-M*kpj)*BUjZr#%@nwOtGI9}-h>tY%>meoI!DZ87W?ei>b2gkPH18Q~+%Vk7+4 zu;S3;1bf@U!LJ8-s%6&wt*A6C9DPDQU*#W0d$qy2!1IH3hpRmx0zQs5w-ZYrH8+J= zx5CkHsWiqz)75V?c!S`KNaQ3+Tv!<~iLQjB=Ohu78!d9okgO{qYum`qJ@b%F#QP=b zO2|DMGaz1H$}YIeO$oP^>k1(QrhysS5vn(pb3mr;d`j!Er3Z%GYwC z_X9dJP|f&{)Z_%k$%g1V{lzvA?7xR+E?nR-FPfoqpvtSBa7RRuL_S%Wd5MFp9=oXA zFiQD%GG&z2CnXYgei-h!GN}Us2qaGJ9GFq|EDFxYWP+1BwR2!H8f_Q7hy)_>Z4$Yf zpa(=PsrX@)3ulE7QrD2e&RAuG10QJ1 zuoe7>eoxJuf7Z@{3L&=6frFRpN#UERL|p^N_sKIYgd#T$+<$irR&qEd_qBIzpoRk8 z4VncqL2x<}z>O>w2$(g-$N*S!)Cg1UVU-Lv3sqSUt7M~tC{b+|m<$Np?+P3YmO z5!uFokdnN8xjg`BuW~Ca|0z|U<5)Zd*4+oLPs@MTgM(|tXbediC)cQ z>6+K!X&EnqFGNHrA}D3qVBU$a z#=NgU7N9T>MWAW86>LDht{?%I5q!SS$F_n0Zd}cQcdg6}TG{h!FgFwF=w~ zZoa94bU~s_7E8-GH5z5>fCCm`;@A)v_K9{x);@u1jkueH0+71XTVh*E+R9F!txKTV z$;*vA3eiNJdai7z4zftb9)_btW@T>?Xg40U&z&4J$O{JXAWH8Vz1-|j6~iZrRr1WT z=&axb3n!4AOj(5(Y~l>r1v@pwv+f(RzV@NSy>15`#oRjD@y_^=I(GfbS^7eOIbngZJCsMQP~<=w4$dG1^zG zN?=ganXj)DOom_cmV5(V`l=cN%YbL^!#6h6jfCXH;&M|F?Y|eVm{@eK+M#{-%t~R1 zocrvB_4Fon#C5h4@2D8-HYJ;44oeMfqUwpm?WQHQtDd{Q;_$nwO=+oT)gNy{7fczs zo82I2DH(OVp!(=gNV8lwc_?u}*zj%vIuh5e(f;7Oh766QD2_CQfyo`C-(a6XcpSNU z6tO`~FFOZ&!|h$4_tG%(uL166P-K5=S|+(S##;lm@|yHEy{o|x4vZoc+T`_vX3pFm z!bHB@Bd`AoC3PR>Obcp*y#7b^g*f66si6&s`-MS2C=DT+hF<1l83Bh9XWrK1m%jr$ z33;6+{W^q(c>8bF$It@!Xe+!vZ@#VAOo(VE(h6@sXoaU?+|mkfUtI=66uRbj<3EjM zN7qm-Y<{=PyLcK|(*oel@A_upYX|b?cgDpyVai{fUNrKjDll41)5DDeTQ}x?rdCkM__#rJug5PoM)SiegU{a9C*tjxJW>!E#jws#5 z@_45Vk>6|g~fEJxB*uwcUqyr7gjF+9d~27uZgSPq0}`(HVX(>A|y7zg_T(ZJ|_$zhzf z-Ic>QZL2F`oM7xgS*Qrn87kkXcEF|%`m_YYA}-K~CZx)UKyiEmD8=Uqzfs(s@EgU` z3BOUCobVgbzeP^Ts%EulMS!gBm%5UrdQ$2Vd;5n1iH9G*D=~>7 zzbLcgmjoy6D6{?}7aYK$JM9g2SYtC7cl^h9I*cQ|^A6u1Bp(sq_NQFNk+ypKePNvc zG8eYdQTO&fBJelMRe<{!NC?yLJai>@97g94E|pSdeJks-@yY6rhAnA-mMf(tw{m-^2V=92&F zJ6#5n$uxY2FewJdP6Nqo+I_w-@Ze9JSSQnI=RE?CyU)7ag;X-12IJ7eegBzvxC|r{ zYWP)_l7R^|daE9zcE8x${tE%;-s{-h|7p+r#rx(_a;aj0P(C3`xvv?*DbjkH7PBBVxnsJ$#=)#L++BW#CjG zB4hz)>-K*YEZP6s1>JZuI}e^A%+B$j-KqPK%*OHCgh{pYFWL{u>^pp}@Zs*BmUJ@P z_TMeg*n7_HI@Dx#9e+u%^zrr`x(~^08h=@sO?z)sAjT$5dc)TUh<5+tj;oLRi>p&R zIGL{=!vDvj%`<2z(<;5Aw+OWM_U^t4g_rohtNRzE*%*sQ%|x&U<->OiCNy|o8U)Oy zU``3!y=8`B`{e?Lz5c}%EC>dyuI~y`*3NwAQ^LeLdQK{~G?Pxj#%|`1z9_IbeCJ)+ zSY+}vC3||kR|!*M{NW2p(P>jbz5SO7bNt{%cP53ZO%(NxKP}AjqxU3+s!b#HMz0W{ z_I45rT$^NqhcN}Yjy|2(Qne|l-qDK$Q#?4jJ*ix^398=lZwO9k`;X(GDs9&X9|%Va z>uBIb!nW!ySS4(~Pu_N2fF|@>7k(daO4qCLUT z2cJjdNduJaMV}`a&CY|#p@l5sl6?Gj0o?u@TsWqC(bow~`Cq@ofhoEdeVVYq4E_S= zXPhwTUi2-(3_SR<%Q(6h-4@2}9^f2{!$Q3IBZ>u#L{7Q4upytDNLutX|< zgk?Y$pk6R;%t%!_d0`033v&?)IM%$#0^gSxC|b&whC$N#K+_x`gUn1I(~HgoF&o>a zJMI|JhnE`E9v~@IMlMww8XL<9^O|VR81tBOHe?x1$)u)i=467Jeo}@v(i56UXl%No zQ=#BCY=ImU+)f4&Y=q1`rIYv=N5&{VZG~>G3<~ADp(GQR@8;A@IzKt)##Y4fq-lYB z_V|+A+pW(Mtp-ls)AwvC2Aub;uL@WzZha<5QSk)L3GLOe(@NPCTDD}quSn9?*#tuB z>1_B&?b8a;n`?91h$J}i34li2bRJM8Cz%qUHqLY7P#1N%jnr)cY$L;%B-*CgUEuf- zvBTn*6C{{7IYEMXlnIhBBjg=(UQiXo$qB4rDd{1K-INo~l(3a@!hvBQ<%9#n=E;r& z!CGA%5}2dwr(kb}Pf4<8at)I8Toa@@bwy5(L9uajhuqXC1bfd1x~&Ov5-RPTkCQ;M zv^`D^M%Mw=Zn+U7g7k)|(Qy)btX+<6fYe^Ua<)-+)-kNvK`GXo1(sl@3Bg!mB09%a z9?b4d|GnAA>A#P0bee9(7G-K$6x+Uz_9eD_Z8!w5d1=j%7;$Pw#0W??18p?v8xNcL zHYI{nPZKwQNhXUEMAs=}0v0oIOvCK@HjT1RB4ZC>ixy2CZ_}&M4PqiaI)QXnqzPJ_ zCQajFRB0L(qf65;`?ME(_v*DC9=900ffF#;Ijg9|HY2Tox9-<|2_mCr?vg*#)^YNAcXGiz9X~&f9H1zKFie7AaYX#;u?NTz_q=T z0+*}&5!?PF0=C|7>am6O9CH8IgMSPMD^nvJqBN26CHNND1SdAF8qgeCRWTRN;)r6yhcB{!ov1Y5uMg<*K zlMM>mt0o#`>#3Ro&;s;xuHIMqLXKCb*h|q!FmA;CRvenX zsYdqnJy1=bn;V~+MhGoP<*ug=10pR?jbp;rZEE98vHPV(XhH>%3c;ow-LRaxU8)JD zgv94WMP!?HDr87oyA!7%W=>DW24GWp;*5f&pEyp~&br~`o%V#nzOb7l>!j)6A)GG|C;UwCjY-5KZpL+`;`({;EGE>J4I9IBO)GZc9~1+hm_PPk0=L#(`NHTmaDu2 zrQ+=F4IHO-c-aGK`A6!p*^&}wwCQsJ^V!F351zbt?zapAewxmE@Sj_xHthl7*TmyR zp!0G+1r+baYJNzNJSKXgX#C?KF(eHbgVPg3?mG1Vdyu@0_rz5GZjcxzcw*?(Ueoc7 zDJ)d>T#u^vyYZzJ@ z)V3|>B!MB)HDwJ`%`Ej$e&3klb;N5!`c9kZN?Y{3zLO>ep490|+HzKHXnkWJ@5<8i z+rE=da3!s&Hxlm9KHExUwlmY21?4^p)?N%vaq(zHaS2&=4o`!rKBukAs1+Hb?V}Y1 zK*^(h1xA9}R{*$;Tb@4>x|SCJ4dXWHO(Q-ahTU7MHHv?R*?&cqtVXuq8T14k;(61}&tf6BZS$5^AfRWh~a3kmmURU(&QJxFs z*+!tGVD<67Q_h=4+amoEre>0Uis7G>+BE{BRkcPxaaSLP39wXsENwif^F?;vCG9@T z3!Z_Jg~suq$48yK>E*9hr!zDY?mt;o#(~o9e%N0r8(eN@P^?m3GX+x~gX`_Q@izTc zuwpW}-)=C_VtYv6acGy!8*TnBbtW7v*9JG;d84mN3Kp%wRd?QKyI1;bl96G9t-*$q z3d^lEP+@`6^6Y4QEv9>^m`Gnb%s(x)f4Nt?yo1w#SRYC(09w9hN*?45lo*%QNQ?D@ zZa`X$3HG7Jf}*R6IS@4_OX^#X`629AkI8}=C^A2Y{VFm>Y@o^f;PtD?`ia-CDwBfn zt;_uI?N^sEegkFZ2d`gc#(4YCW>K&(4f1?!MT%V0jM+Bs6nMKedeE-+R;1| zih=T!)cR0p0T3IALX-53G+I9h2c*#?#XeM8P=r-U2cpuHvijC(ekl9ZX-d%yl$syR zewCWUY@pTrAoi=(`it1FT2o}x*Kf>zRh%l0K6G5)y!+L03I!u2*EeRr zN>0Jthn9L2|O3r{vUpme|F}2$n>No>xeWx_`>?V3;oL~K84xf~ZGI3NsWt<|zBL;;MnSRp@mZ4YRBgLWB|ZDh zZXQYj=4Y>|stV1t9~2s!;-gkSU&~)JB_wb*kY9Rjb!j%z0P|}dQVO7Cg=Wbv`hNnU z@5;{%A2cQ?G}=mn=@`frAT7VoXG#^8vq|dkmd};6D4y8aa9&l_xPL6nPSpxc6O$$n z5}Dc+>t||MNFN7}g?Z_|rZteDuxOoG(e1^0y$~=jE-bR1TJ*IWI2M&|0`Sml(hVJR~nhp4gOV0&0o3Pan(V{ zh%$Gyst4+=A1vs*eBa#w)lfLW<*Z*$$ zxw|~wG3c@R{QU(IFG$oVKfHwOvlOxgYFFgAIMmbn|4S*e;D^ot%41-dR%&4trpkf0DI+`sV9UU&E!oP!q$hB$jL-~# zD+7~wf4DM2GXSm(?CDAsHfp*v2$>n78vu6(#(2qHTS_oBX@q6~Tp3vMC08Zu`lEb| z&;`Jq`zaj{eJ}aJmZjIo)OR+f>vz26qryO| zI2fWqmsq(0N$!q=1P-ixT9qp` zO1VKvKUJzeTk@b#H5RWdYMZVleVW94mM}`an#%9~zBPhu_i#~7g+d>fKsTA-=|quJ z^R{wJRgt+Qeb31e#v-i77^w{r1X&>2yWLP;BUs8?ML9$C^|M)V>C-~&^oh80h1PurQpw|e63G4O zfJ8FEC*sDLK{d~48jHzi)vq#RMWbr4wk7JNcxWqqsW89zasL)6NkZHoz10VPtxvfT z2vS+~h2PWM6Qx}50p+2Q3`Ro*LyI(&Mx-BVDKJ`^2t9}esf&CO!}Vus-3Oz9e4)b) zX?k=4Y8_wLaEaO=V#7UadTc@J7hgQ$DmFdV0F{a_Y`CpWk1a?|G8E^A0=Thrn0_{d z)6kkCF}Sg_ZNMnJyeFbQ?&&l{Fu@Z+ z0M~R5Q*M&;b5_L~k&u=?!EFV@N9}UT)$!k;+xCr{X1K;k1L?oMaBFSU7xDl)vQON7 zbYx%T`s&dE)1e;ii$DNfI{-SG*nATTppP38qJ@TWJ?Hk(*$q+A%EA~`AHCiX6D=hM z2NSIwj4=hE2Ml?m#ey-$J`{o>CR!aBW9nNo{41HWJ+?<-x!`+y@mgSJR$OWV?1(nJ z<&>F)=k$)ND^j-Y8RhPy=XfIw7z_1_er4A+_W<+92TCY0(1b~WCUgdxaD1Q%C-_b% z&6DA&N$J*50K43<3r}?>b7iB_qcZJW?Mf}l3=tVwSx&2!ppwNJMjwgxv1!SPj*M9N zfkkKFgtjxq!B2yGKi(}{)8G;CdhdIX2^hV_J#Z33)6%n?X{m9^Br)BKab7Qn4Y)dd zQSy4A=Tj?`+nYLrNrfNx8bkrn?SO-bj-JOFFgo9DV=z&BHikjOt*`xop+$8M5J6T% zvNJP_x}2|G;o1N2{>{-sm22xy$m@x*qp#N@bOC3OUb}C z@Zk#fU79lXdu|7#>45Sl_nlvzm|Crl)NE%)T55_THOm^Fk!8oXI-L#8v}ZWRV3f$1 zfO2T72Kn~mzbf1MfndV?`F+QPO#ev2hB;I54s|*l8SHTxW5y9zcKHetzZQmtwVlsb zxE`hshvS7a!JZ%&Yq7)eL>fIU=^E6iomod1GySR2`6_StRu;eth7|jB7r4R>y-B7v@!N9cSFU{tg#M*RkTZ@p6G_+G4e4Pj?7GZN?NKj zD-FyH5F^YxnUHfPY`V$Gj)Xx$=_+%-xpY1H9Thh&E6tvjfJTsRCttGI5!UeJw1l{1 zyJASNM#p7j#7(dxnW7dG-Gw4sUrFaL-E0*)DGw?&Zuj=|tPGKpuU)}DD3n!GgTI2- z3{FA)lGBy6eo#vq7A;3E`v=afvD7pD*6rXFIS9IamEGV;o<0np$}3?utES!p$dB<` zeM>9Qj5=edC&|RPk@N!FC~l>R$@tKIjfN*s(N@)mgoE*78#Zd+lD|Jlk!e#uNMRhV zqyqmkI)C%Uf3(~Gb;R(|nbxo*XKJE7IW9BHo|c3w8WU2GS7da%l7z)&**L7n6&8^g zmlX%^O{C2E4-HvFrt>%C!ivybS7>B{)c6#f?+T7ecBGEU8Y`0*xx%9p(o)jn;F?Mo zaU)BKE6O=uGE%MuWm&`QA-a7mmmTe$h0+W(~Lh3~DdYk&1}{9=nqb z|3B4+pB2SJpTqHM+o<8_o7DbYk(l(Pq>oEY$O5m{@I*&~GX=wBdK%_85>dXdv{_@* z#%0E(CT7|*9qBS{k#X9gV=~glrPCe|vsU6t<>w{ja0hxl=P3_3PeS&{Y?-G@$;0*V zCOPAx=r#I4KAecadNnXHCQK%4R70HMcy-A(iaUFgdm!U$(ZX=ILtLV5WCEs*BBM6-zX;2s(+^Gc*rPP^ec*s)8(XB7{phODFcMD3Qpdz;*Ck2(b1-(Z>163<-Q{$D;7QmSiz1?dzTx0 zr%{p=U4m{cLD16Ia%$55ts?!j3szCJ|CULPVwuMd%u*M~^K>qDg6^&wL1`Vc8~ zeTWpg8iEnl{=;PG2m4s)j|_B@kqJ-|q`0VZn)K;@W>0p+y>G{ICQb2UZ+$${=0h3Uy@AP$Z`><*wi)*o+iKTcw3Y#ie7809}Il4)-Ll7_h_D zU$2W%p0QT)G5gl!8n70E(C{K4sX-KsduG}%aQ`&xK1q&E$1D{ zQnx+~CD2K($0JHF)tnrYT3x`U@|x=vDkYfj7S4*e$Q7ij^%7T5+-Q}*a<@R0P?ak* z{cVkWjaw+|rg|;Ndv>SNZPcYvYyvd@^QFThct%Kl0;WTIY+9!M9aMixS|SWJ=!3x_ zqw`YgoTnwYtm+Wi7F;&9)Sdcl$~xQb$jC?|wW7+o+jpWcEm4opM4F17sJ50YYlNJQ zr6u{EiP^w`FZt%`Pz5##hY}eBB?f16@;65n<@X0gxzRAuvK8aFWY9mS3F812P>}_m8%k0%uu_!gA{3h8{0?r zR167ZPjFBx9GjN*KGq4Ltbxh{$wlM$xKz%^OjPMI#m6Pu6JTahi&mqHQ;+3F#A0=+ zmZ07sfqHHiX;gjR*hez8$W48vQM!4HK^j#Bv>C*y<>++9seK_W(`d0y`wjF^yz#;d z+hwGsx&y|h%mRTej7M~g>NIg8Bs~EmQ45$eS!=0&3ZWJ|SC_*vKEc7BVQOT)5((y_ z?CREwx^ALLh*j=cWW+hMAS+rWVPc|;vdSR)uKnFmyKQuoedKTqg1ihXazo1}sL@zu zv*Pwv;z|&0x4RO=(E@~1l)F+4wU3I&PL9KYK7d&`?O=jbmem!m^#&4ZRo^*%XRI;G z=u8cOWW6irFts??uz|6UCq0;N5Mzy6s<2Qk726iwk~JA5OT!*RT9Q2@E_IAU!PeqR z<`P5(taHiaS8Gqg?hY?Bs2RHwXp$Nw%|C4}EW;|1y8XtX&KAOZCAB)4}5XifVek;+CX802+ zxihfcQ;KvHi=@2&`MFS4`uqlk(rY4>0ZkK)QfA{devo)c#sd>1<0Y6jiPN4iKF-eS z3c4J-i;7~U`smc9h=;dFDu&an1TIy#E(&{)$ryyOF^P>+2b+R=bkXQTu6#LDxqULx zB+`U#1aozkZ%U}~wzIRl@ug5tvc=##uip+4pVv)&_CAvuE77Qv}xh|OX zHU(BqHT^L*YW^wp1KOh*g+1XE#!(}~?U)F`5NFTGN~P5GN+?S(%Q4=`oHi<q34%lR87V)*;ecNKp-Gvl(d*wR+R z-!Q3zH;S*9-;R`olyv%T)V|X>eUti4$0#X53kRg9eIQMp{Dl#LTTUl`Wje>iC6MPg zCGXaPutA@NO&bdAQ3G*_%b52h;hYai3djqGaY~b`eq(j3B*~XSDzzf{nU$fiUZQ?$ zl~=BYK-7e@O8rh%vea+@dGb?qJ%45EYNAnwWTv_*r-_3;NXV2Zut8|Hi$6rs(A0k+ zEOznDlsIRqxSsdgh+qCNV~nVH`iA0)CH6dhLxiMYGkClsVI2DFSXkWAd`A7N_}_MN ziom9%LmYhih8ajhM7>RjH^M?`7KjcCkOiBgJ#!o^&CZb{6U0i>2vK2@dzQ@>+VR9- zde-u;*!Y#vS>n)2)4z@oFHXJo<6q$KlS{9Kh!;Tkx`*F^cwrhXCWXk852DqA!!qKN zKN&72{+V)_aI|Xa#Lj5t$0kfH#-xse1{iM@&nryAY!#K}un4)F^WN&VTAAq-++UMM zM%o^;Fh?qhRSy8qG!M)X?!FM730|5*MEQ>)q3)jp)chN2AWO^&$rNQPP2#m-no`1S zRqV1@Me}mgP|>)-6d{_r%<6R~Y8 z1=r4YU-CVKrwfg0?D(1$ksjyFh#gL&+)#447U$;;5$0@h%!1L+E~;uxA(o2&6d{&I z0_Xlyh|ee$A=VGEiqg*v6N~;JTzs_I6p<2_HCAk|HHC?($4&4xiXS(|D)x4UsCm?KafvVlJDsBFwJ6c}MrbnB8acAiV$GhI#(!hQ(Y+{0C)j^IQp|ll zjO^MDj3o51p(uMJIx}7VMi}}3+0$di%wI$$GmgxR1jQsyo~bzXHP(^vK9Xl+A~}XO zPd{lyeeOGB3KvBeP1r;yje%VN%=XZkT5g31vkpD2PQ``SC2Dd%OiE6RquHG2^emAi zFbazZNWn_ABP!3BgoT$p6W@pt)84R#eL(vS%IE|}mc0=znjVIPSZ4nhIxH;=i{GI2 z^udQAq4=})Iil+S3-#E8c=MZ9vFQ!2gUe4X!i)sF-yk=AadLEsW&3ZD0&F`{x$!9S zf-yb?>k?B&ZpX6y(RE7mLo2CU$*arFmQxO&AUrllrNAccvsH)}#v7{@L60~T%j5(~P`Zz1#i z-=R)4y(t?0Kr5E$-e`gefk|eH{r61b4XY^m!(n3epC^me-;9!siHn!fPZs1`XvcE2 z6TYXgY+T)9ar`<~%$qzU)xmz#@uP;bk6Z-XSv00%F$tx`s5m@pi1=){DEM5Mxcqrf zM>=uw3lXB`kE6wluMZVvk3xot_7@>hVse4Sik`q;b#{;=*H>It?d{LUL~v2Y{nYaI!V)9ye2&}vnJ-wy z^)d^*^_*$g-GryGs9lAcpk_Y#^VH1iS6Qf;Z>xaFH7f!aMOmQX; zTgQipNDL!8YO+h+h+85Ezv>|Ay>O-w0 zd(;aNxJIyHE?>Y1n%~o|U??lvSaI=-VT$GCgN(Rzay3HT%f3KkfK6Qex;B99ea6(o z>`~)Vu@HtwBH~|ukzDe*v)#!-JpbD8$8TCunlM~o=T6WLRU2U+`BpYIzwvJ*cE67f zvsf;WR9;Vsd*31ZKQ(tOsadKT0w9EtwX(RFFzO4`NyNv0;?WJ`ZD>>RqAM~f19Phn z(lXv>F^Jk%A++-f^)TL^2@C01?DIb;v1sZ7ox+)F8~N5qCZ+3KHkx|boG6oMFSDqd zO1S?c$vH;c-)I?=oCezmysO4%;l4nzW#VfV%QGtMA6mt#{}v%;eOdQ@h`93QC^6^j z;o{Igz)~*_Q{wQqEevRD-pEtZZ*Pi86ERX;dUyWB+jiQ0y;YP5|KJMNg! zQaMmjb2d?N*CbvK7sX#PdLu@x`l`X3I->DwVOU78uP{wbW5t3$#X$0{C|JMf4mi@$ zNlr&HrUO*J;`~jMm2E?^Q;Qcf(5K_X#xGH7RtoGNByN94nB&pput<=8$mhP42%kC+ zY^QEwb{QkCe~GoixnZ)eKK~N+)rnsw#q;5pEtZNY)Kfbc7Egtoha`yVFH1UY!!kd> z1W#Okml%j0CCdKgy-ci1cC5wJ20QZ@kdJ;D%HAdxVUC`WVG|{opqt553{`*e%dz7A z-&rgTgw^a;1TpO^eB+Bf+nGrY%%W#K^E&@4%) zPot(!x0{RBuZ&F<4>p)bi#vI*{bGcel=J$#BgBy@ufK_z{j}H7S=YRdB>?W`6BqwG zU-Bp>{htU?8t>~8J+W)7uZwU**L#K+ZHT)mhUe`?bDC95%s@%7BG~l*Dhq`9Ip%@i zaw+zlGK(R)e&8nD7%}~;R&n~P5wa3*d|R3SS|dGx<*m*&M_yokM6U7@hzWuR|rMT0-@*70>?^$B(EhBUjZ1 z6RuiPJ~nSK;ie?zWBUdZuANdpriS3wDCMJJY6#9hDIbkfF;cb>EnYS5{xhYGl>Q}_ zpLaIvmx|%3jt^8bRayqdnV~6hP`uLpb=6_BcwN(f5g&|&18ugL{`DwPJTgM;`;}Fk zNYYpIlxZeKLvHLfhbMiINW-XjIS1Ty5jP<&KV`B0>vA3{Dy(v(6V)H1t7?J~2fnW0 z+6`qD!eiN`uVcs;bFA>t5Zf1+P(}G9Z=MG{{yHZ)zXT)uA_|5c@tBX|{2S^pUex># z{iH>XzN19zTRe9W`&I$N9>VYjQJeASkz(3kM$kbK8(9r&zo9$(As$8!<0B-=jwC3n z>rqzmA`09=Pa)}?(c$EplPwmEM$yI6KSyw;Sn=m0F&c{(e_^rQ1Qm;=U@mCA=J#ZW zIQ$p1UpOWeUcs>mG^l2i@e%7nj|CG*^NJRKcrxU?Z!)Eb>Th63AtNW` zQ2dvw!_(AXK;6zqxh=!QwZF8A&GjZlnS_Na(@$mfsI3h!wxz>p2{g0rx>nLHHJIpV zlLL|aSK9JHU7U9n!m?o%^Zsg>nDV#cwQy1QKf}cRhau5MjbP!k5Hx77BP-xU4;L-Nq*@37Ht=<(!Gr5`#8zvBIL8uduVI&-qd(RtjeC zl|k?SbYB_x%-=J6h_I+`?3Ldb3TJY5x`X&8kB(F;3$8-QUETA2ZOnwnDN)jLjwlMMgVQv(w(^t30f($!(MjRWYE2j{=rsg{GnEYK)d*E{A(0z*a?y zxD6>_*|zt8X_IZSB^p+)xGXxqNEhYCrSgG%tE?DaFk_<3b`6M3TA+!8QBBRx>icFxILC@(s>-1# z?R*z4#ICI1!mjx{KZTVF9%QfiDzuj3_TL#5UW=Y?#X!3drG1S?ob`W?g%E86if0Qj zV9KAD_G46)Kkx0wm@0o(9WvpxDyN-!43p0&(f;?!xHIjW>JX-odHX$Ul#Q2KoW6WE z*|T_+hV>H%<$O~&!qtXbES1EQS&d%tP1mKJoPJF^hQ>}#lNl?{elts26co#a#~DGk zDMZ`F3ANLCDs~zZ6qRqJ+#nBPlT}8TUisO`q_+1T3^viktI0zwmeL~Xq3Uq{>K}N5 z9xK`xn6NTnXF01q1x~v7{~K}arYQl+UX;;<-Cb~E;kTkhC8Rcldw>165-@^cJ26}A z`xa*Ww;D`|H2qnhA3_8CL6S`~NJB*s19F%@`>hyp>01`d3l5^0)}3$BOzQ!{%0HsS zw*g_djY}Tqu#3Xb%&{0W>^w1|z1#z|c4140eimkfI-y0G!mrpJDyN1$-?LceEh2pS z9@ZAhJ?zSlp(TrnWXTfGB$KV2s0r)3hn*$FZV10u#8&`03s-Ft||>FGh^Q zFIW!4`14W&s%;S_tf;&ag4>r7)7W{5z}CjHSD13difNIUrsC&oqeN{aRn@h3pgjoN zgWaTy=+~>=q>AX*+5M!6=-12rkPLC*QYPB87}B65osrB9{hYHGth9kVX04?JTLDE# zXnX=r-NL#B&lqyfkqrh_CTgOLHFu0?Uv7yI_j_r~RL-=Gqe}0uU&>fm_85~$}{5(=a{jW`;oslYhXgndlR946`Gw;n;T96aCe!GW9!iHc!PLTeRk zzzG@BF=-Kv!(v3)FO?Y&I>xF3)NdUagSm>~!E&x;Kwe6Uyl*>gV%kEqD6#zzT9Y_= z(v)Nqmp=|kw2Af0u`U!jD^XIc+PbKgNVuOdb&SF4OH{tijCjyQ=C4~dl+F|!%G#E3;DU?xV~AZ}tr zjbvxdcNBJ(P1CUxBldkq$IskYbSn^S{tl6C1KFZAM7E6KVTR`br7ViR3t64}Sm@9JnD25oL1$G!^#z<1H(v9GGE|G!I2-Tf{x zbq%9L2`pDIDX&u*S@}JZMNtvU;wZ5aBd$tWJe0E7P29wYdF5O+TfV2Tv+_eXS)BNu zj-QWyDrM33JtBJ>WEa4^g=WjJk>P1TDT@`~hb(G|1JTX0`0y0TqHr0>;wsCcS`x4R zzCyfBPh1@RzK(V?XtONNe;NTyRvQpm&(za(UD$E<+NGNSH>=#h4vO@l1zqTnNw!IP2VAd2Fi z8minT+EFz3;3Nv}Mp4~^X(}mpqUi3ybbE@Jy^5Q~(H|N*mM~JM^Z37-Gb6Lpj8V z504rNB1SAdZ6pb(+EOD?#E2J$vWO9fq%h9EsR*NWx~p9n2?K`87@aig-F|1{{A5fTwiyLqKP^^3kneeJYO#CtN^SmeIJ^Y!AaI?o6hL4;7%VXs8n0BaaeMK{*a?VUKc5NS>RmHqNqqIOs6)iSsC<$*)FF!z6|oAodGmpdGSzaX zeaLj7nKIpEn19M6tGK4-JVrU0j|Z_a;wdsNrNqp~te+Cf`9CE-8h?t>=`^7%Z}C7D zBdUL@@KI8r@X^4Tjv~`X=O|Md!^41XMG#$T&Wn_j`FQ@*7%_1;toxLh`B*TV_*gug z_-H~**#$ybd&vV?jMzS0;iGba!pA|*bQ+m9T&7I*46gy|`S8#I5v&lWzpWs<1!U5A zx#;Z}QSvr6PsYL4ML3wf>bF_)Zxefyeuf5hl_=F=vE`3OjObE{TrX5Oe!+Nhfv4pT z;km{zuge{qO_cvkVejBVIroFp$HgXMRR3<{_-}o(H-Z(WBy9 zQlxM)Z3HEshvcP?iIXaZrx{)W6d~{d{{Y^gv0~QD7mEJ?^{^RjFQV4{(gcb4fN*5cOu{|p9HTB zEcOVL^yz3SzlBdiqZq8W~VHQpql= zE0F6l=Tct@l~L+C!!8;|N*2UvEUL5)E7!!WBNggxkTMoa&qpfu(~a-S#qEJYQ>18L zMCFisD06C;w( zE6Z$J5!Vtv&4~^vU8)9q;;zJ%qf`_$aZu}EI;|ob8AYtvIm#w>=b#x8Cuc^vt$eRG zplq@hVNFt2$4^G7YgLgq54@ZPBKT^&Ab6AEjF z-#?m~?h&lWIuK*A6z7-$n*oK{(3!&9w_yYdtuFZ7oE%oZt9nte3HyFAEL_hRf7e8! zQap*MXu=!H{~};YiW@uB%#TQwBRS7-n9f4U+f@{t5mSYTyo7 zQq0Q6gv-=(=%1_xJC~T$akdD%*v;A0^_m(1Q{Wx7=S*7%hPF;7{%1@fSj6y!{5_3I zM9eJu1qNBM^|CLY6itlc)-U`xqdZ=0QROI3p2CprS~c(bXWgnfT&sm(SIxagfOQ09 z=~<1UIr%w<_aUpf?4uQX!l=5Cpt6J<+0}4UsVDV%%}4k1j}zvaZH!abH~r^ATP^!{MU$MQj=P6ifnqEd+y6aEti$FT?Hc&Ug;Fj0 zm1|eQe+GKJi)fx;n$+?ue?=|78oi;7+vJMr)G`k;>;!}}Df&#TX!#ZU=$ziJtd*zO zv0R$Em=;Qh+Gx?#)qy4muNQn(5;M$P_Kw?bcBCc*oP0X&HFIO%%t=QI_ue$`&us&ruDy`2$fe6R}0Wyu(RG z@mD$Zf21440G_-R3s1u%g1YLCIHxU|hImQ5fyAKu&TWT4bl+>PLNvPX2P7ojci}FG zOZUBXFAMHSoYG8oY;YIcefVn1mojvjc6*3W7gZRqAbNBFbw6_k)o>9YsqGP>HePv6 zOOe!M2iA5j!Ocz>xZrM9D}pOX#9JmF6?v4T=NVW)BJ>R0LUQyBd_}_a3@jyydIs*5 zVqKA_NaMbTSdS*EV)e{<%tN-G@lRBgl?Nf<%`D(OBw%hW_Z(;~y5@O~n~N@>gxiZQ zU^h1yUBJv8)M9i2mE2@>0mo(GCMGF`Tffo0&8(zbFX(11H#Fxx3Z^GusqKCxU3(eA;!c&TP8JA_5mP!^7S30G_y>*I;lZDX}}=%5=r-?LaI&7|&80;trU z)92HjD~qY+G6LyOpgz2dt-U+kfQ{qwuTeWTj%y)d_=tPXt=c%>(tWHmCcdW#uCCg> z{x`g*3eE^QO)BQPt6-yK5Yc6oz_i0?6+7~Hv;dUCy70dHk?Q$Y+)HBL9ry0bs08<*Yg91zpvpQ_gnQ6& zDzbafL#6zwN>LVUcCUz=RILm2L{jcE$H8%Izf+fh8sNwh*v`L)j%v8FHK zE@}88)iElz52@alUD7aLEeXO$zKbLgA8|SRxl0!OS}9ADhiLZxS{02C1T)}Cr=J!1 zNcKo2P<|A`T0fhFRR@UUMe6h6Zd$rDGXmil;g!j-HNta~Wbe30yw%%RigV+m#I65` z#>;+vrMfc-r{HiLG+cQBP`9-r4&^B`$>J=h&Amx4ph|QPI!|@y9@I-!<{q?1_eQ9dqA z{+4I#;5(Bou1`W0XN!&F@VjxmFi#LW$C0PX)&GEzlIxJ>n_E6G*paciVb7i*Iv_Tr z)(M$*q`Z=?zGAeW<(2HnbyK`MHrkr8=M*FO+Uw02M>&P6SXhlIN5EA> z=w1a|Hr;u+yj>lhnWrn#gZG+f|(AYfSC^E#1Tzdhz9Kt&*i6Z zW7JveTBoUnfP;iPe>U+{%eJ~1Wmk_P&HE4>(OEp(NbximdrWP_6Iq=+o*@wXJ~Sy- zDBbi$G~mD&_x>fhD1nM~KNUp%nAL&us2^2SEcK&@N~eA--h)D_A9b>0I0jgQL!51H)(KT%hk|G{qkg`mKuy?qm22(9;%#b9FwJ{!`|e z+*hIb0|mmk6|;z4u($vUE@W=eAJ&ZUK}Mv zxh0fsF<@Uxb#8%wrMiS1smmGN1%@{nE?q_hDgoUFyY2$5)dsc=cW(}U}BW*##$d{E?=dQjv%9TX`mC0@@l%vnwx(?KWfF+W^j!W>&nBj2{w zh(O&lT)F~@LR?%?+TDdF-v^rzUphNP?Luu}sR1aknZ~f>6Z*XeP?&iix=Zz{%UKA@ zw>i47j1m==Gh9tc*)MFtLQ{-bOv&z3AbWdkSZJah$eM*F+JbDR$PH^KUs(m^qqw6o z?i|JCucf%94EF#knC}wiN0i_M1v2KmBE~$gh%r|dA+n{Ca$l%YF_+7@YKl9uf#S|F z%-N`6K2QYA$0)&U3S`XJB<9;PckV}sJcrFKH2Ezm=1Cth)!7txt(M{*GF-Hckgzmx zRw+hQeq^$W#Y>Q?oMXrVW-r3<=a58kolw;6AQbm^sp#8f+#QO`+edMW7}f(S&ZKh} z0sX>7I6mY$7`jAQhBA;a7zrU~de z+WT~oN%fq3MR_YY%{fjJEk0iCrG6V1yQ$ypi}mWac`;CQGm2LX^Nuq~hUEGphW7wn>UY;tm-;Zo)`^1DtH&YxLIK|C(t>N(O!i^@^lML8x^6`R(ywR1L z3A4w@IiEdl-1ykH<3sTXC*7pZ^T1f#Xso(5dS6B8?-BsMf*}eXmT>)oN8k_PDYU^7 zDlccpxqkT5OrASLm~|)gaQTL4EHl~dxH~Sx&KKmc)9EnR_Xyo3kGK~bk44c7TojM% z05gbTd5fVpy9R#vqle+12(5(R5V8Rzjz_;HOEGeR7r71NHFQFpEsNqhr?H=^OiB76( zx*LE_20%_>bk{Jy+p~8iP+nhyL^(H*=nrw-T7oEEjW%s`r=F}=-1){=Vt{YDr8GDl+A8Bzf22QCMe^;%ACZqOP1d)pHKk=Bllyxsm~CC$ zf{PB@YD|&NOfjz(+^#x{n=A`=num$gm6mkF8?GgvdM5c+bnuPI;JMjDaLYO!u_R8t zE79oG1fBVY+@k0|&XkAZI*_m^x`!3_6UHSZ&||Ky!p4mem-2^%iG$T>dY<=&Bv6wD zIu9W-f8yk76Rbt6Q5*ZIHq82#Xtk@CBRZ2}f0+qcp_$_L1ZvwPS+rC>j%~wc9qu)U zGZ|?mTqq6s_HlQ~=r?g{V-5VssX+h@)y1Orlu#y;qG=^cFfNStKM@X6GTm=X&A0;RhA!Ye3DMuqOKAxb5A7((}h(g?DOK` zIrhZWE+xalA)K7@#lb3Q+N!%?K=d-a^8jqT9!772&k89?#oQ_rUsH=#M#qxW-~!6~5^n9nEFXnqF(?NgIIUd~ z*`6vBQx#>~k>$ipI2nr*d6coQ0!&(Oax>$JvK`3XhI|(B2*-si;uwy4Sa6zw6tynJG2*+Tm@>Ib?Dl$^yO27*Pf2o13Hud5VaA!f4JKY_lkFTg=@^lLXv(Pz#cEjBdOwJcVxr+OiQQOI-Gg z7r4cajkv2r?B0k}H<|P^N=r8{KqJa)E;}}whT(Q{Y^jfk8-Xl0De;G}wPOhbh>?U& zfK{9Lj-u0amn+Cut5d!MNW6iQX_pFNtj|Ib#KvkvTsmlX-C~TsfO9P38eK9Iic1<&apA?}6bG3al?9>j2$g4HQ!r9Yf zc*KpkDQOTz7{)OS(NvQdB9+is^k5z}=?P#A8F)_BF$SXrf?Y$WHgeLr78*GzMTd!TIJ09tCcgX8(W>dZz0F77nB z2VB_+Ohvmv>T?OAwazqFbkv!$#LYU>d!oC}G(kMBGsTG)b*4-)33)~CPSbcXd#5Q; z6znu5iA6h2@uFlWSr}D$h%!Q13Y6%E441;yA4iiJVgmucOX0|ie!{SqVL3bnVR&IU z3C<)iyE5zogh52!EzgTsr#QaTWR=6Cyp7N)&JfA_*tmmlF7_Nyg$#?~>MMpogkn*> zi5GTN^<)Qt?m~q=--X+664TP@xh4#hGxwOH#pFg*QnpxKPXhzeEI3JJIZP;P0HGX3 zd%Y<^0c(T}FoRpvB~{5I%JG4}@e zdvUGN{0wE>3@BbBAz7pK!yTVmrKX-K zcHu~FU-3t9M7OW_tNW>gyH2}_>9>X?yM-9uH|B#Ma;d&Qg#C52+Zlt*fBrs3`g>gb zy=O@XCmEKWr{7f!3og*_qYRg{((ej}*BCwo#5Kpb!I+je*>G?$xn2lpn@vaYE>WJj zZIlkSAF-_w<2-J8Ad?3T3JG)}&qoLNB4_dO0o>gjE7!=%BALbvtW3q`1E%m$e!hTL zmRS0xrQ$Lovg6Qbo&hal8H-)=sH;06Sv2{S{e zRm?6AA28uqB8}hm?G)F>u;wzcjA7MN)qwlC2TfVpz2(u$3?1Pm>(IjA6iW`GeI9;7 znn=-+n+~GXpa%U|O@zv>_(Tpg_l?mb<{%SbRATZWPGG}-+y@9&Y36l^@Ej-6+@?UDjddR4*;v;hUdhZjjL3@X zl&_?d^3nFml*1gCPjNGDP+SqiIzR>UCx?M~4J9~CfsDD~Fk^0%xjQKG#7)Y5`nHO> zRmR<o;exZz8PI1#FSrAvi zuojTD7mi&Y1^OdL-FA(p9z*&@O2dM^D6u>xEQQn5&<8T~6@@m1I>4I8Gs(&0jlzK{Ff zQ@LM~6-geVMQcZkeAQ&wQwEM3ZT{c}jFR`Lv>|xzj_+7c7?**wyt?%yEls=&VfD4f zD?MQf^THutb)lO9Tnjar1Yu>$79ZUW>ElHKv6Y@MFw`MHz_WJ!yaTc$C4muc&Pijj z`Obu+>PM>~k43Yn4eSAg_Q@QZ0ZSGwDIAHh@KcYc&FLd2O}MfV=5HB{)5siLO1h() z^KnPGd=f3SlN4z)u8WbK_ti=6VpE&B4=ig&WI;aB%biQ~NG&XuaVshAK0+;)oOuMx z0EJXI+na&8ff7_xAghJ5&5Zey%>A4qYv)tGx&1~WDa5VAvnXik3@-yJmn> zQKF)scbd@`oo4jarx96FN+_C9^-?62GOm{5x>i%%3x=g@7(Gd?^)%3ToOV+S#Z)0x zl!gWSP-4la(B4WlbjBH`TS%cb8wvM5hPN3$Wq7li!nbW9c!lBYM*7{!aLNJV!u3Ru z)?Pdf$Jjf$++u>^kRNAB!a6in-sq8l`KS7P61^dWe((B^)iDOWWvwRNvqbXMBUs=Q z(5J%izA4@~!opN8PL!(zqGed?9Yq0#S&RB)vJlD$8}=5Ci2NueG}Pn73j*5*<#tka1X;14BHs?0(vx& zDc5{8kr~(Ann>X_pwH_h^otlyzd^qX88!fVHjy^MY}iC@U-M`pJ%qc7F}-4l-38!o zVA#a48_=_fR9rV`B2zoLiEO=2P2}WtZX)}ya}&8k3!Pp@SAUDpO%Uxe<|)NAAq;+1 zw+WUq>|pqi;pRIOzK`KqKvxr4-RWu~n>&H%CMSByiF`Mar=9+r$W&U+&gde_bqo(P z%(+YA#BYG~gLQ&KWrsjYk;zG0GgBJwxww2BjiEFW3X$r-jVEa>I}GrV<= z3Kpd4ihW)1@;tbKISP~d-8W5X?ty9I)OK(7%gv6mcwe6OESw<%F=^m7SV;r&_syb(`BK}y)ESm5ih(AH!3P5E;_x9 z939UoN9hZKjev3*UVEF_sK3p_!ahpa#YswEQo_@KGT{}O@PX8L_yrUY@g%gt7Qq6_Fx0wp}n zCK5ctaK?xrozO z#G<>J^h@q)by9X0Ij$kCMHEjbSO+LRKVD4gMsahyQQXEEv@wMxGlNwB-$UtN%VY*Xkhq?;r2Nc@|2*Z7%#&@25^9o?pxBM#VLBo3#u1XEeALS62SbY zdb}ivRrlbSrw?+{EN~ z9ZJ#k)PzTS;d}A`wC_E@LH?%cX4kv5Y$1rmB!!+fx5p*MrNh$cPUh$Wa|AtR=pI^G zZpM{v-r@Q1b2j5a7P$R9z|#`YlbA5NXYF}}B;-1Q{(S3!DbwM2AHQ&$CDzS&7DId{ zR1`b{w>KV}qQr-}=5S>{QSKz6SlEgTlbauK5QMiEe9749iETa+tk%ycg^zh~`Jw(T~Ub6r|^w ziZzmV$DO~CkMY4OYK!C~?sV3|zsMXX@*hj_xUz?llGEj7o#&qSAiQSG5U$jdxXm3% zlIhV`hrHZAsETbX!N^dzfZAz&A>?i$J2c*mRqnc6-J`TR_7ZXD<7}^VY{hfGabq%L zp%QsjVP$Vu8Hg9I$fFUvZ)CB<_yk*BUMcq4=&@U+RnSUAJFvoy#g&PxIV#ziN(*;a zl_hu^4PfZ9iFu_cOv6GHLBsWai zpm?{^y~ORC%vd&1ztTGGrrTz>D&uar?Y7yo8F2Wn+u(0c5%@Dl!UYV^BEs5n=c!3~ z4wt^B;KEI5BA)e(9z~K1Vr*e#i>uveeaD^vMKhzoODpBi6i2X;3CUv5GmOQw6vk#l z-7`~cGOZ}Z^0~;+iVT>_d_bjFHBl=C#8!WM2Pb+JVj z>-{LKY~k=hm98OJ=ku#L(;k8Lyv3ZCcgEeQYMbOwoaG7=o*iU`A!_BIF1Nvwsa-6}O~v%T%49jRTt zUaz+Vk^7S=X7_hq`pT;|CzbS+X;2vKNp-SU`jRy+fGE026oHh6c2(P710S&SCYAjxV$igTGod-yvCoEgDt&mv2qf4p0R{#_u*2iT~{SWi33QgfBDPc z-#eIJoN}0hr!l_qvMwHF#{0MAy&i#~B3s$t5g$(>#q5wqVA5_8_T*%-YOXm( zY$P9vB9xWR(@~4yHoj$wnU(FGMTmVS!^L4GaNS&`ZC#nd61*{mB{+2|(iSWyOuZ`z z6EXfu#?7R-_A-j=Vpy<}q>EJmUtR01McKKc??V2_qmaE*jSAU44~2Yw668yXq%2f z)p-_ARoDF}-i;4om{b;TcRw^L>ahY8weAF1sRDTzHr5fWW>{3k%mKpnFp#N$xSA`y za+R@Kn_a0Y*?g!7cR5-lBBMJM2 zmo6%@uba-Y-!q+MkLy=aoDEcja}1YmB>9Fa4^1kbQDf7R6KT%vds>TECuf=mWu8P6 z02m6q%e1+|>|^rgv{5Ffm{v)B*=v@hoBrzNN4R0i|CDM~9rOhE+uS@U`rhs4NH*Q0 z3-;FGAg%*5d0Hl%+yzPQA?c~JCn>J158y8E`1LrtU74qWC-cne5a=Vt3-lBDs`^z> zrOsYQyS%N0JP;+%-so}$hi7bO2dqNf@@<+Mpf;skYJu>E&3v=?EDp1Rs@S!dmwTR-i#k@OXazB)D{5za;n)612dv zey$vtv_a)Mq)Ba|pv*``<>Rn33vA(B7T6M+Sf7TFpoVJ*Rx)g1SiKd(LoGd;i&{ER zENkgT6>4eXdZm_5Y(*`#Zlzi}T#H)T)u7bUfwQQk2AoLbTFRTpMCZ+8qDAvS^k^-S zySa_vv>hOX!ZgqGD9k+&rNR`hHY!Xmj%7364vF_B;jI8Jbb>m9Q+5(;15`T7?D-O3 z@iwGz0 z%wb|)C2Gm9&7^ms!h~+MPkJ{fJH#2Z8zXa$sM^&Jg;M&Fw>*6=)o`##Rpk|nJ>}g; zE|*H)j5{)Lnzj8SGtFbEIYQ*P2?Pt}R2XL1$hCR1c^G}FR-2A3xLS!O582}2KIo%R zew>;fYNcMQMIa1pClrRU4if4D>5s$Q#bR1eyEtD84$==_Cs>Jg9 zAXTV}w|$X8OFw=dsVk5UO63s2y2HpLTUgm*t%Vh@*0->`RkDTEZj~+U+EE~B;f#0z zcClU(yNlf0JM_B(0xgTsi|{P|poJi7;Tc$$smvw_wy&4Lee zUo0JomJWi+BIkshr+ASP^Ton1RzfR;!O0_QnNxaLba*NM`B@a#i|vNr> z)}ViRzU^C{Z`0W@#lvZKS>VF>sc)1&RZxn&O0f+mol6ug}aq_S%bLM zCn=QtThOy{QV$Ov(Hx|u%|9OwBxOQyVha3!;79m?}@GbuIq zZpnUCQFa593{LNn;VCQ8?o5ltnpkIdnz7obqxK8cqzcbjh2rZKEKjQ|P{OiPRAbEy zi_XXvP_bHR0r@mL--A#LdK~wAuG1H52DeV1SD`!$Tc|us&l0R=*mF*ndqss(?%Ugu zZpC>@ae`qd!-|WPj%Ua^1s=3QD_x5_F#6aX&8_jFqj=#k%r0^&y)~5@SFp~gp+OI+ z2_BIQPM{>@;zn?4E0xNp3QHi5lu7Fb$5_P3dPutYmxy*b!-H+~yM^IBK!M{Z73;77 zYT5t|%g0f$)3;|G)^^ZLIGHzP2Qa*7=ad|VYXy+Jxf;pgvvLD6z+F3(Xv&o#@Og-G zJ6CcQrZuzCQ5a>PX;+mG?{~QkHTf2tHn(>Wah{ulrARU&U#T)@PDo9FwCXN^^69Ho zs0%j;_TD6zcZ=XBfF3!QtXFeZokPy5+mvo|H^G*BUa1dhsY_ds`WjN8Djy-8;lRcs zuh`(-VmM;Y1|Q9ZW9zqq!0pFGV8#=I4GfzZb}^jULxgF6S@BW3F*v=l1T zcHqLFMk>_gXH=-!467N|0m^h8GTpIFNY}}szECgU9RGu+H@H=yT`mCXC6Rao(9_s%Lijx^~Vj(y#IupGJKU>1kQkTIn+ z1{`J7-Gtg4Hy(R0lnG8Mg$grUo`7OAv#F>R-Ut73( zRIfMhIsL+mFaRyNXtu&==p-Kt*}0BT@1=9xSkA^lIIUaE*!ot#CefVb1n9uUq2!qJi`)_r6bdut2?ByQGviALt&zPyD+Ashbn{WXsKhE%ZUHzF;clYXlB%f( zuAWSp+ZgsT%%4IbYZ*2%Y-899s7biA){lgzp9j-(&U;FDCoV42OSryPFX4__a5Q@= z(QlfjNw~FEN_bl%V%rc7rAM)fkVqY4Z7KFQg5tzBDW=J{kak}#rM=9sYC8RHV0eLH zFT>e0D7*qtD_ie2KV^H~LX^&WmTf(*Y15ajc)PxA^)xbVXKKAOwX)T2mu1^A% zya4LTb`6^hqV6Clu4$EJn|%XmAI_q*`LhYOGMqMtb2Hq>up}Rt+}ojTlsLJ=pd}*w z>MpOgh|v1oC=@&4TO*_cRXQv^v>0SU;sJ9TtodPc5T9^<{sOl3l;mS1fnNi|UP^As6u0Wl z<8UEG1`hRpKnmr8Ih}l)=rpa(DGpxX+s)W`hS&wT7S9Z=rTX!%-i50`-j`p=C{vg{ zHZ9XW8ewoF^HzX|+QCFq0aZh!dPm<8GyvR)0pyopsT0#l(N--aJ{uS|F}w*FV2jw) z5J-zS*$q0=iil1DAW7m;gPSBapL3JM_H%BM*omtI^^&OG9h4*|+POn%DZfQy#D zCy=5&I}Y4SfYoAIL%312raf*&!zGmZO0H~iE7}cQ-Ka0xoV`I6?FrddYnl9_rBpO` z%ZuC#&9+4=!MvyI(?CW`5o^G1lzy;&G)Q-1H zGj))8v%UHuu{h@n1TkqD6}y_@3BUmsyW*g)V&A>g|6)JCG>FCCN*btx3tU*rg$Ep9 zv6mnARqT5g`(Nyr7YDJ}S4iFL;{x|EoUt6m4$<~?S`TX;0XETdRP(#WX4<|EXafUV zvzT?n$Q`>3R~BL-`#f*ZQ8Fm4S~T&Xa&J8 zhP9tSghrC_Say6$T;bAaZ#SL6A?-)>53WHT)5>)HM)%s32M2v^K}5Q0^Wkw!o)%wG zdy5XAc+sWy1AXYxyWn99c))6&;WOfgmzaeoc!^m|&Qj$oIR&7M+aTj=C~jUk#hnI} zaYtp`UGgV;L7|?;2k22FUsfz{&z|&djJ{LPZFcJ*z7rn6eb-#18z;F)kBGI})x>rq z!!AIXVkU563bnGCnAbv=$BM(|BDiwQDavz+=&Nc(kU}8w&rX3@HLnA{$KQgm^|Y+-^|m#2xv);--9LV&N|}w z8K5s-b>uJmM5;^Fa2xmFov9+U9e~39aNF`TvfZka;#FsqtvlMY<7-64I`Wk$T2BaS z8D3ymuz`4l_q}aAT7jR*b0H>eX_;`7HFDBNb`J-0cZcOE1( z1xE>10vbqT>v?Z!9HPAcm$*0oiZbicM9(sUsH%Ir`}TNyx_$d!5H;2Ou{x#K^?r4$ za%I-&NzpNBH(bJXP@_t zcq51q$jr)ixgOp)!`}Psv(G%`U1Th;V1s{6?YiRC%Ee_zdHo4 z2|g5TzDM^q!8?L49@C}k33)9_TFyzdZFl4-GQM_jL>Yh|`nv-R!3`%<>_eyG{0Mu^ zx9>s~$$y$+?C3>y;_)&$wm*dQ#gH3iPH<4L_$gi51<$r`>K#{%wK;qHc)kH;ta7m{*^tK}C`DWT$?Ls@qFx)G=> zvXeM9vYee`I>$HPxley>!ei6^^eoIkek+lyshVCW1x>tQ?kK+x2s+2azCtT9`h3{b zcn3#^6O2%Xe@y}>%VZ0aTZLrd(i6e=g4rMG(kl2-u;LS4x&;S;<7_5sao>((gOS>b z8t_ISEH|Tu*~9s7=V!`MC+HFE5gZWA{z6~3V4w4^@I3?^C#x!YIbJUHJX{8K5clcp zsme)DaYb(=jq)*ZTdB^y!p@4AL?$M{Rrq}FcdN}pvZqD4+&gVP4oSX$g)=s|Hc36) zfT2dq>L@DG)t5T+dc2|xuZF>}EHhk(hQR%5bc!;KKdz5|9w%NSZGuyGx~4*`E~UA`Ln^}0Mdg5=zhB>3}~kgWB@gMzMnepdl8y)ZNE z^b5}UkMBT?n=N9)uLj>)CLp84Qdu7$!wYhWY<{)%tFHIavX~aHT1TRk1Ka=sia8r% zQXF5N&JM?7F+OZtG@j#wU84}6DMYLZ<@dw7zlDC|Ee5XJNPX`EMzv|t=Kc>62^QBb zM$amU5izD+Teb~1MJ8%8kbXxE=&10j}a6?OY95dXZQA9O=9L%=iDi{ff)ft|;4INeuzG9p; zHf_SUSRajny#11UR;p$K&WXiLYhCjL);qTM;uMLBmsm4A}!;5?BaHegps?D-- z%d5JPW#d^DwPv*~9`^$#sza-7GnX#UKzj1CZF-ydN>xZ3{8REOxE6fj6FvCY@&z(? zRZxmMf**lQt7(d`odrpTeR0D!|S$qZE-@zL3rW9o=RfJR;Grd#kXH% zLU@FcTdL@Hc{}}(QsYg85~qz!4wAmCP8n=cR#WBCL@@2-JWc`b!$8~e1y>+!`rTgB~a`- z%DKiiVSSO$`Xc)l$(0J$2p+jd^;zF#J+Ou+1y`!dji@Znco3@xVK7*_Pdp~rBiIkL zRCMa;8XIb#-FTl$AEo@T1{6Mnul)r>%5Ke)92<#m$+2-I}1tR99GDYmQ?DXQ0s6utDk z{Fo%K4TKTHY5uh$#c`6O6c==qenvU{j8S?8M}bx;-Z7qf5R@W27gFTqB3ABmQ;OxVK*9{Y1~!)nrwd&3NQAto>H!!_T#bepP~9K!b95J}6f)z-2m$iudOW<-_?x z`8qxOav1wou1Wcl_Pb5L^Lg~^7j&)V5`&vf@_8GD zbt(PwtLRrD=oP#m*i%jSoEpY4D)PVkP(@?k-ODDlZ~S<053+f|9kt7L zCK~5jjWBP`Fi#n#mA=z{K%=SOj(J{SL&rsb4;LUnUM-1y5X{-Zz~)7OT4Ir`(Pg}C zj%38oMk>YipbPPb5C?t#I-*OkO7JyM*;lE@F39HF4Ebj!s#ku>kBX z|K;&U8x~xbC1e^LGauHsrkB%zpw6{k35mYQ|Zraj28A#o5qYZB!F5w}FFHIoRFTry!Q%E!T z){0=5^<>pfU({^g3e;>@cj=nBSZX%Z%zN1^4=~8z;Ms~TmYT=6%}Bz7&__q1T(wmw*KQTLy!5QS!`N;2 zOv>%r?-cz!59xPQ@FCDBp?*?+3{tA~B0>#{57qQZlV4pWSD1%y1ccD4%SFII(>qqW-*zMNr1v3E674QHaM4&-?I1(m$C(@6vt;=;!@RzYBsxK!b9(8u(GtWmgMV7yUl1re9t*(E~In@2CdlMg}-aN0GU+T4X+> zV?U&4UJm0`tura#(SFb9SDH`1TETNb!$z`eKsm1lHd1&Rq58y!Hc|~Y{Hd=I;ZD@R z^VLR@s3|hZAJKki>DN(4zjJ~Cpi$SpB>A^BVK&mZ9pOJSjM&KP?b-_I+Ox%U-K<@A z&^5E{+a1vF$HBIQvA z=%u4j-n2s~m+cVBdw0Oo-N@McT1?8#+V2qkn)cAIUC<9Svh&IgP`&|D>UAeVy%Ha) zB%sN^*CYz-;F-OTB-+|c^7(bbx}1KOJLu;Z%sC?DX$>89Am3RRmYt&vU(7I)otHJ0 zS9HDaHC+d^>kwTlPm=a7L7(7lprM+AdT=PIN3aX0$dqWi`^xSxwG_uZ^ z^v`I&Ui!U&D@wnh`)rW%Q&N7-04;PB$~g@}IlnoF~mL4${)2~F8w;M(a$IN9%y7|%}!8m z*oo}yIf_u(*G=-r;0Dc{+$n zSazP>h48x=MzXVdmvA^j*AI_O*Mr*i1YKL7k+xUxvEW<5htKKW@q%$={AP?@Mt0dS zm@|HSA%$xQgMr5@;;z>WZ}vjAhk7a%tk`eC7u8&VSR%Mxa1T&s#Csc|7jT<}TRqTk zK!@c`BRVW2P3W+|t?538V)*F34{BbC8<4o6u?ugI4!x_{(!{Rb4>I(^0O%jMqb9%( z(c?E{897ek80lt{IY#2I_Y6FQz^GgYiK9cr+;_y!f)*S5n9o`-6%ynSS&|dL@tXw0+D#5H#e%F2^ zUJ!gBI4D^8iSDhyP%jo*kpsW#Y>RY;^^fDbLB8-ySisPoAgk0U16v(VGeQp{*zL!i z|62roSzpH;G`n|e7V;Zs5zjNyMFfYwGKnpMw**VG=#sTMk{GAdzkXs6wW%^nH7iGe?^CAqv@ zq6er;VZ9DNB$`vxtHa<+zKQJ3&SDlVU| zXvIoR_@hNHT8&;7ZumjE4z^;}22(%js}jCnsT%i!uHT?IC-k(@V+(DI^Tt~U{u;rN zOe0bxyB&K&QbqbzFnYyCMsEO8rE@I8+_FTqy4Nw<4I_dYwuDkmSVs$gP^opFE!u-h zD1L4GZ1U0)(#^S?HTyyJu?Ul0poNJM@yk9-lA=7;gxcsWMXYu)Wi3Fa%*yM){t$(r zJEE0i;m&^Fh@dW6LaD0TNZGfzQ3QFlVj-@N#p>DtBrWQ5J?9SCW+yG8LarRmwkMDzohh#34f9SqTk5oCzOju(>H1t5uqi`ZkK5$=<7 z2T_M5Quu>YqX%ul%Wczf>Kxhw_%Y+eQd*zRjQ;-7Qfye0-@|8;T|y; zB9rp*VdPihW%RaSx+22M?Ebj$S1IW!VX#W&9TKK@+TnI>vP}N~t}hQwfh!}tCfo92 zDMvu)HbUBHspA4JJk0f7O_8pC=7`#V8yA(7~I0Y{V zuHH-+m*8$-*_CuD1BMoG2akmoa6gk!g9JJ(fnqP<9`{bXfP3Bxa%Y6xN5Q%hV`v?oQYH(4>J+hajS_m90$1zLgKdIGrhi;0YpP3}%II0vNhyw*Nz&%mc&d@6U*ze(_w;AcT^Bi((14}c*PX*&}#kuDM% zl0a*l7$~-htUWuii4>g$xndAPT_Si*Ft3@UIp9)lXM;@@f3{plg6F8qXUEx2!?`fq zd41MuJI~L7PeqWbrHfv3&Pw0n@%%cX>_imIV+12c_Rt@N#g6nHCW&4laX(1H+EaIT zhcUM_nXCH{wWuYihGStN)w;gOe*9>6R6EC&L(ZO%o#W@F9#D3JGAipJ{b)UTgzfIJ z$`>sVZg%of)SJ6WZ~&C@PG!oRMe%O}TjkwhtY9k7+BHrgQ0`>6wDGIWsYi`|r5zB+MJ za_AZeWwjakFo`|Vd#_pLF*iEK7UI}VFlahN?Y9GUDK?``xZ$zkdNghmM(ZZiHHXP= zjyiLFT&wqn?O|vh>d|#;tM`fRPbng!KPT8K=o7pnSkM8|;XS6VzNjq;s_S!op_T+c zuSx9<0#JzH^&|X#C|G`!gu^Rc_l;PUchilC%DatqUL9y)Zb0y%VD~Y)^a*Bqsg>{= z@x_fOHR4GcDyGD5utqH6k5y`Izf?@kw7!iXgr1L(TcxVC&msEw#i!;t{aXcx1hYHo za!T-;;8S3zG(77Mm4^2uG%A4tCmATVg&n#%v6-KwL3{=w4CYP~4+v(SCFwcp`OR@A zQj9r2i;3jkvYLpS6LE!zjOjSR7Qr6De!=zUKsww+p4^IRBAB6jc`IZh_*uwVt#S~6 zoPt-nDd#_MSAG6%PUYicl!5&4KySN;*awWXom;nK+0Lum5w_#x9L!^()Onute1feP z_`Ufeu}<)rV3Cg^h1=1-J5lUt!(FkX<9BFBH}8lYUA!Z9^o}guAcW~jA-76B)jpY= zI2jb5eV6FpC75%W-=%_mf&+qMg85hITOrs0)O8K-^_yTqAEk1m-&)a3A`X@p2K*56 zfUxTlcCrnz+1%`Mh~7h5nqEqF0Vp!@aMUd;Lpp4`hu|M1VCz)|zb5z)$gIa)@>+8h zr-(s|uQAXW!B>Li*XeRf(AmfD79b;Ix~EGbB+4ca>^q9TYYgK!dqgh{ZDMO)$u2`S){mNMM^5Jj9;=i zUBp^HV4JfX3onT)cu(%KKc(POzC|Hs-v<2>)K;Wznh3RIdB!T-i~ZOZ^bILO3u%pa z_zBB%QtFCi;rRG5&T1H1Gg2gi;RzT}mBcWaGiHiJ!a-DNW-MPRhGHZ%ZyjBhpte&o zgVv1Hq<>nKXg>I-wm!k}7$_}@mQ~pRjyZUqz?PI(FrdGm(#83l7~Z-zW0n0^gwlS+hHaICj_S{~blb4dlM1+-Ekq z#&=Qjf)zjgl$;?Wi=dLCrI081@kmQ*D);uq&o?wQd(i^Ja91qVh9Kc^t+9Sz6whL> zSOz1&G{Dhkwr^0Hk{139KZEN6)%DEwErRkXYK-mDk!#rh_orpJR`}dA+uQ{>U-Ku^ zL!NO+NL9XP$RWAQG(>2nYJG+_Qj<-TXh?tCGh~XF30FQrzo0XlE-pbgP~q10`_E9~ zDxZTgj;sZqVL@Bv@YhOYo-Jj;g6|iqrk9}RT*L5qPRw*IdjVIMxXLz==d$Oa^*LPK za0P$Ek3*Io`tsv4{r%$a&H+U*AA63?hFf3Q;%6^QOj@`+Wo2^W&q+%bp+ZT(vDLrU zIlBIZ-iJe`enbS5^+bOG#fnc@kU~lKGnD?UqtNa`vWTCFM=+p$uAwERF2h6f;-@&X6ylJC@`SE6Jo zNz;=vGSV~fMERoRi7il@T#!beFYskcZeQ=Gy&vM8e6^0*E+-G$J*Bj z=dF_j)=TI{V&DMK?)4%j9=}=_u;H3Ay@&Pj8{14ZG-#WF_3Dh|pKzZ5T8Cggmw<;j z@bE_Hw{j2JX7P^kgzx{S_!&?6E?bd;$4gSa$2Gwzd||V72o1xm6qWzRHa8Yo)%M0V zN4<)2W*Q3T)EaL6qK#$|+hItGOWsF-OwnG2JaB`2uP`XQ|EScz9fXT4aD0D?0;0e z)0v=!U#1E-Aanqsu|aApsM?lhr2hoZWr=C&un?5+=~}K`*MSA^rByq<9!ydzLZ7LuM-$Yo_eK{*x(y-soMGhOJQa9vo1L;`W%{3}gC|adp>tRm zJ|Jn2ke;V1hAkmCjUqN1++8~4ZHDwpNZla{=LR_*A^Ldn;Nkgz`BRYpV4H)Np>f$8 zB^ep9#mDnF>mps zapQMOp?#*>S7>lF98YZ3vKT+lZq-5>KQC^Dp?S&1_D7RU^_VTi{H`C<-9oiz69T&3 zQn&>Dg3fA@Q_w5u7j)K$yP#LlFX-IP6wOlwA9)l+SI6V~_3EN&p4&c3p6vSqUAc|8 z-CvJ;)r@;n$8BL;FXP&S{Q*naz4_TTt}aeoK2Mc@L6yOm)$r^?I!f3=UDVI7w=YK# z!c*n2)g-z>d|Zvjp7jJ z!dR-oqj#t`XT)Rt_UEJwyeFXR9W+bJlYUA_n2C}!|9dVy-I*M7=|7)Fi3Hb2oE3P_U@-ew+j+I0;gEu%SRiW2aMhyxK&Vg;S`^1X}b zZX|k|h~8$RvxVsIA_fHgCnMX+nq(tf|e> zQa3|%XcQ{ma}_QWmT$r-aXm-*3t={M6aPQ-y4ZSuFE`HoumGl;oSe7>eQSBrO`XiP z$E(e2V4S{FtYN+$1G%M!8RG+ExX&>Lt$V{7J8iv)u7UGnH$M8!2LF^L?ACDjk5|aq zNMUYkaE*OVq!&{$V`ic$qU-<+Ru&?xj(ac%Ok7uDl1B%$%b!M%71`hpWY!rA1QIzu$(F4S_#lhK<@MzIQXvwuNN=H4r1dqaFT8i^B zI#O80!~{tnZC@@p`kxBNVe(?;oy(QX^TE&V`$EO|fyyymb*!_`R*%=&EfYBEW}aQ! zquI}1skW}S$BWQL&9qYOTyOs-lnf);k@Dk82bib?(;?E7f1RCI38NuMPD&Grx1&R+ zJemIrl}(6XSPf_?WNGSZo;^x8`tW-Dl)BN!g=rp`P76+0jg!7?z1>uSwdNLGtNlWu z;9ntA{l&yU1<>xSB)SCMf*wJypbv;FQ8(7Z9?MaF9T95n&L5}yOZj$V)Fe}0X{u)f z^6c`4usl1xaWdJlu7Ku9NtAOd75<%ipKo9KcPz7*-S=*=2gk6dHX!FXvyrpGP7}&U zUthTp3F8Pxoi=+Zvw`EkeF$Mbs47GHm8xArS246#(6vpz1zm2ko?3QojF#zJ3ha}y zm};ilS52W~=k@A>ujF+BDY$Eygg`yf)kyR=6FnZHdoSrv*ZtWe1@>9`>q-ICNd28J zkRn)E$g0iDuylQ(UGwSc4!VwL*BrWfg02NFq2Q#eS6pY9m5ahfjMOH7glNu_q&(;ea^HgCe zvT?fFSYnS)OZro?*}h0WJ3LyN%4b-TRt+U~j!li4922JW(Il|}p~P;f;&bSQsjc`# zgC`~cO6u z*y=K&ysga6I&e(|YY>u_QoC7u?kIz+cLUfepI`u}Z04AAp*mk?|JktUpVgHz`}eqc zi*cMAB~Ah9nV~uBI8tW+vk{&@zere@gatB-PL|uhfuI;4r7XdVX>zrC*lcdJDSTSi zm(9olS@6-3bg7S@jfJE|DSRXuna&ZNbSf;f!|~y3A%72A(O6)53=cU?Uyl2&f;LA7 z%~4+2PWvZybF*Fd*^HMH)VJ@Ou6%|q+ifK#BcWq(LYM` zIR7>DG6NQFl{reqvS5LFgPfjJz+vWgV9mcKuT4T(kTkPziPJ*X;CXsiNrE9-1J`O^tryDELwti&_X!BOPWy0vH zIgfInUXY8*68@V;ed*0^u0*3) zRvOotE4SOfQLAgm_1&6wpxDLkLw?w1kKH5rw4G*1h1jBWcwf4w*5MuAKB>Oa$yzXV zK0{t87Z7%%)>Naf+Qx)fR!xIzu|`D_UQMXS$R1hoob1}Oy08O`-NM*AO!l6ve*^Ym zV~4^T89S)*8ie(&p}(b(IbCBn8j+|C%Xvm}mi`-%4pb36^(4Ts>Sc{xr$aStM>?&R zP`ce7t-@1o%Ij+)A>VGIYcI($)#@bTL@4BTE$GTs5$YyvMV}#7m#A&m0Y+pq^9J$o zr(0Z)lc-nFcab4NUENrttz)(J&@!_Qv{GFswLrg!_?YN?NAw7K5C2@eEt@$)aLjymx4kc3ar-_LL7O`tt+heVm4GdrZxXs)xPGP-NBinYM8zAiSyO(fw0 z3Dg}zh~(?*g#2FmdBx8s=w}GMM0vFiw|gPzzzAv$eaYwQIM$3J=sgPUxsT9}@PXEi z`p9bMZvD6-{-}O3Bd_Q6sK(yZhmF}DH$YI~43*nQiZ%En=(nyXlpwX;t6#LrG;f0s3 z5Tv&ef*fy(J%-xZN{iDKQIwMNm=n*Foblb+G|3s?-K~(&C(`=`1A?xnR6Qr}E;UL0 za-Avhz!mt6=zh)+vy1^k(!zyY!dsq>c|BC~DT~m_;mj=?SzPYfY+sU+iskBMyrQY5 z8KeTQ#cTs0VjDkktMkY*Mv0%f47aSNnnRY*yzfY}{YQ1Y)t-h)*EGy;)?pP;mtS9t z9ajtMG1C54RLG&3#iSK~N%;G36BB=0vLbQeU;Yw5ClOPhm?%pPO)P$oE+zV{2_%3{ zW^SaDYF-l_wxA*=rAiW zZE?!1g=vf9=Py7w*2OcedjuHmyTot!Ho*+6sDMIJ#!vJAE+yU|7?0ca7Gqg|$-?AB z<5|@CKmI?$41o()A{iZAt-&gZ+79(|2>5ey($Wc)f;nkf z8W^veDE%Z=-50lv+volnNMF2(+B|?PMSc2C?0T5!91;9P>rR|MUdl6pC`>i(hQMA327&Yc9niOl=&k``=fuC0EhQ)R*|`)Zo1_+F2Zq^~;x>*A z2kqDqgFRS$`5vzf9klBmBtLMwh}zd?xAb8!9oJ@8e?3#V_uKWBLfHq0X!rKxZnr1< zF;QK103Fz~2kf(ry+W%n8s;7y@)|pU8n5V}J?e(7mFg6TV?EHaH4<@d?zf|V{bw%i z%Z>mzoj72}p0LCutm~m~vXEl0J%|p3?=%zb2dZgH(v5Mb-W!DB`T@JVIw!rEMC>|4 ztW3rVtpE22zYIGIf@3gTx_H1IHp{V6dD{@yo&WE_!3RVPN@dx=xKh14VAuQ2xco>q9?lJn=MnS^x;E0q3pDy;s3o~g1lLU*v}dS;jO8j~m_RYZXssBTbmO317d$+` z#Cg*m%H}H-*(w;?l4ok{Ae5ddA*$#XJ`bZB+UzqUW=>idIM5*E_6YV8J(vFjMZQY( z^%4Cyf#{$82at`AhZUtP)R{f&&p+cL&XsBu#22O}sj3dtl+L>d7x!(j4Vb5VhqU+O zL-x6-g;sExZJx^NfWX^M+Gl)=4W-E$m{`Drfrf9Q3>RePVZK^3hPICltN)NRtU1rX z#YHY4u)ZC}SajGP;-_AX*fH0P{UaG_^=HhO&sIm;?cb{5x3JwcAMJBh*%#RExw5!9 zOVCPLS}WA8>S!f86+tl;V}l*`8e+w@-7ag(jFGrBJvC(^95cVz7jZ?&;;4=~vFt}- zHyjpWofOthVKFi~a2UNo?8aCWN~pnMzVfU=#1vTsUCap<}S_=<0J38_Pe)Kmy+v`#{;lqGASq~T4aO?-sC_QFzjU#r zFW_6;_&>piRb&5v3>JjRcpOZ4eIL_p97L>j`@y{tJ zZfx!1v2Y(%U3j8+1C^qVLVB5W;T`QdO2|sMe+{C|LRPOd7yi*-S)eZ9ZBp1()iI3z zdtTeW(bG1|l4;Mdg_!Z4yW(aTQ#{6A>!=LWuuJkeafUf-x>DUghFS=Fc$O?;FAA!e zU~Wo{a4_O$PTIJRGKH9Ly(o%P(dFe0anp6OXaO-&uRgiho>HJVY{`nBg(=7IEq^bM z+ZRN0e|sE*H%oHW$Z>mWw1Al>>?zUQ*PeiBJMYo7T|nl0O{cXnix%l!CkNNz)nT-7 zuRHDG)o8RpW1TGFB7sNHE9evS16AAtbgAa4juUn$hhLXZAd&nSI3Z(K^_i)o!`m*S zuIo7=CHECeZh%CjQn{~P2k7d&Z@PZauJ`Hc(ypq!D@+NbeVeo+Q%#T4U6IM8>$;PM zDA&70lv^b44l;eIU9ZvA6LejDQo{P^>J7SX)~@I1>Z7ZEFe6kAq9QwqLf1EB$1;#! zbqKXGG&*d}*A*1|s$4=qnbuP|+~$L~R^n6~LaEYIu(Nq;`)Mc`_j#U%TCub3G{yuH4tky= zwf>+EwrbZ?bPWVu_i9%!U7Zii3_Yt|+v(~Gy57~U`{?Qpy1vt{Ep+wJmDZ-G-O+bO zt88p!nemOeNy=zj%|;isUV^%RR%~<1@iv{KB~Lk;_nfx-*XL;WQ;zOF4^?9){8_uX z3lqKOAO9Aww6Jnz9;`nnd2pFp@rthIsa@wHgTMJ?WLdio-pAlRBlwMR!OspF)Sv3$ zcNpBSb3z^L4l|vpC+ba46jPfzna-X_)0{eui(0=od%_gS7kr=`s!BR1EWB%zbppVK$Gy$B(OAg>avxT zYXVZGCaG(hR1Haa4N{w~SV>h*K&r+hReeRIsw63&LF!f*sfGziwV0${Xi}vlQt|T2mbKH6c})*2b8m(QmMFg)(U`}vKc)6xla7{hUe{eO)qOppzggPHf|sD` zZ-}`)yJi)(ZvtWOn8J=;lXQQU!Jd)s{nxFe9!@~&nMvy8bs_bEq&x;GXP=c+U;2M*e%0~Pu8+X;PgeaU)h?29KGAm47e*?70#b!0sR2!@ zmZV$;sqOc_E=TVRtJM9Nhh35>a!+QPEsC_g0%<+ z1f2tP@d$ba1A@+{;x6bF32jY;ahC2aXX#u_FRH{7Ppn3B z^y$~Fwd<*2R9BveeHMy+l9aRrcw%KhIyUogK|(}hv3J0zL_QB1G|C2qM%D`&rdB^j z$j#cdn67>!Q_c@WG$h#SNl79{1qt)i$AKtK39k1y1n=f?h$tpmRjr1-*iPLFcHr z3wj0pg3d8<7xW7H1)U$oUC=A&7j%9ScR{b9U(oqk+y%XYenICKaToLo`URcN|C4$U z^a}a~otfe;=oRz}Ii?&42h!V{$3 zZ(y@N3Fpm`n1Y_QLOqx02kLE5QTI8OytFUGsd)4F5oYJ+aYE(*Z$81!H`ASGr4m%% zOPL3J6KvQi zFkf{B?6}*c?JWjS3$TdIp%K=(-ms2QWpC^$aMKgjmj~^s_+dR6jaOkP{OU4s#`UKYO& zvm$g4ia1`1jqpNd+>Dr@R+v(~Ly585WEs~&(X4ntf^_0*ppzAzU z^Hv)L?b*8OBs)s3zcUon`c@?B86t0&j(Ia?%w_5lBU0$+Z$;=gZxPXph`>#Z9%U5| z7X%GOTRxnxyvMNC$-?O!5;0B<$>#O3&mih4BvEHE(Jkl)Vu3nzQc`^w;`TvvF<4!H z&ju&r_@pX(XP1Mts_`tA8N*Lgs)qO2b-<%tR=~R zo?4`%EpapCjK2|czS?vW%EaS`?~US%tv*$z<#xXpja+(9{g#Ll%5?VR3^Vw|LUx*@ zN{5A1rPvIJpp7dhx;7Ji6-3V#aj7H*1bth@y$VbviymkyZ6lIJpPr%oy0%fGZ}rtE zyj%%uZhw@s)mV+iWnv4GxLf%zSWHgkWfjX=l>Hy<)1|K0YwJ?mPK5$#)Qm8nVKxB} z!=Ixgv|cxbp=-{FxOUOi6?CoCuIK3Lt~SHAYF8g!J#dAx1wA$LE$G|MZ@*wb&|53I z*+F#Ikrsp+#Tg`Q9$B;k8=B1Z`&i4BUq;!Dgsg`~Mb=}ZqScX6h~Wc42-85a!QBdI zs_u;Hxu(}#;Fo&;?WkSfmoi^n>qLI|5C;j^DPlD;KG#Bdn0W$&=K5A>EsB+>`Z9(g z;nd@zzE)RQx4WCkKYVdpz5A%^f!}`B9`#1U?qr|k7WzvMfb(q0jtqjh>E0^1-=b!9Y z08GP`WsjIv?|y3Bc}Vh2(AACzal-HQXZtrQXHDEJ9(9xBqr29`O{xHw6vpB5BbKD; z%dj7T8%369$UX;4eGYw}Dy9sFh5Hf7`=b<>=C$dIm{*$yMi_=VQ|)%;T${qTr>JOp(OrbK1A|~7}9fvAnB@hO`Pn>GAf2178<{g z0()*iU}UhmwI;#{uH_(G)swXpM`h?b0TCv=iC(ty$+MPN}!- z%ZZz5wi+wA%~&@XmJ-Dx)13FANB2uraWi*f&U?DSIUuTtEGH^&U1SMSAJ&U{oF9kT)^s<{ohN8Jr8(gL7TA=6vZ_a2{Mg zG3Q6*?DXq2=jVg-lSa+?+^;aj7x@!&eoBMzfHO)n`A>_s*YEFArlTfjbJM;dZnkAT zM79nlguMHtG81a9d!*?T3~P)Q;|l{`&_{Yp5GEx43BzB1C{2-Y5 zAMx$cxSHSIY@#nmaIIkOe?;~eIiikkLIqA$qe17fdGpr8_l0rB$qlRPTV_K^`Fi^Ed1Txeozi%`#R zZ3Y$JM#R^h|3G1!+^38Anzj~r1zcp{+(ZljbqBDpNV;Ic)q zYKr$X#h27v0JLBt=ZIcGcQ>eGG=)BKrOudccSMfdu9qA+)QE&JE1D`r(pC|%N3ufD zb)GgyQr8SpTiue!duoiBk9Eu!jOn_-m>%F)hJX!QqYnX}xQ!uT!uPmY{{2=ddxEC zcXf~(B;|)Ef;?pOd8)W(ayq$g>ZGwoD4wqordLSO{m2yMxOP1)u8)O}pkLz?5qyB? z2g0~i>GsHOT&(u)LIaE=N?$Bi__y05hErc_N^Uk%c~7-WO|@2;zTO7)Mv?04F*fXo zkn8Kg?@==UGgHIccZlA1?trWBIW_5irKLW-BTVXf>U}iPP$!S$KToZ0GAw>wo#bvo zop3qR04`q82bb5H%ZWNGmzXWa=AF?pD@OBDQ6Hg^m}Ki9CydrxuZ?zQ)T?pS1JhQo z*GpHmZcD*yR@tKYp5Ru+X%n$IBGP_}?NL{p3r2eoI!~^gI@exL!r;hFXYVun#WEDc! zG@;L$P`31zMokG`XxBlK_m7dh^CQtM=={WQ&u3vP=>H<$&i}+>i?lcG67gE4bC~&` z5ZaXuKVf`vm!#mT4$@2u_P`TC)-XD{KNww4reDy-q>x*6qj0Nllp21olvdD!xNC`C zL3gex+*uv`BE$LCF+@Pnl_zo56J7ac=wTiD6GJ;U(9c(3CZ(cDlHzU>{;!)5BmhqY zap|P=G<`KQd}azBXbMl8Bn9tC$g_!r{Dnkkk$eNSde=7#!%b|IT_yDM2>O7^Ha&D4 zA2;Y@ni4aLmTO4m8sH!QfLTUdrK;*$;-X%i2Ct@;xT)S5is79m+saX!zm%f6H;eF< zBBq<@tYt#v6v1Fi90!;jXYxAM_!%6*@*xzgtu0AN`yK;*)gaSuJYKD@1Cr1@#~n5F zj@=kfwj81c>xIoX3(_$`J3-&O))U8l6~WsNrhK$K>`sFYZpV=Hjd{Y;H`S{WW+%!G z$xteW$}KS!F;%iS&+{!52(oy?==vULtfZZ`)Ig1ym*Vq!fZzDif%mO(%QMpD-htHg z^vPdoptj#et@`)0hTgq#JjDNF=r)JBa+?D$l4fH$3)Mazx%VfcSJWv|xtg1U9~*+LyVU|^ioR&45Xap5ufMr^F1MTc1ZL0EO| zgR(Cirg=88u+C1zMZG_*zy;ZmSl`^sv&sJqy6-<27jI>T@hxtI2D9Hdk9S^-`^L&A z6?fxd|A9{1Z_DeqGXz?}rz@t7wYB~BHn#frv$2Llu(91oSfE>3pd*HKwC9-BXF+@9 zl;+o~Th}qLaqj;bn_pEqojDv^o?k_{l!E)C3LdIje&fQw^T_zb{IfBul$>dgmNWls zJoAqIjtQ)h96ZJzg|Ab37boQVw0xf@x_!iepzkWbz1OLb7_)b=*4ZaJgV*d0pG;9t zy{zbOh$uISzS|m@(R&U2Ke9-au-06GQaa-|Et<1}x0Zt02~^r4lP zXb-xPXzwQ`MXt~=XYbYdF361WZRC9z>KIo~0-r?%&i_0v-kOs!;_a1qng5xpTa9>J z3`m^0WbxAYZz3nE@tOy^Cez_(zPT_P*ZRohHtxgV<2B0@zm%m3>HsP2idiTf`&!TrBZpd*8vF#li2|K1?&DqAcA#yMdwhVPMMb*CD; zr6m2Lxb>0wG4`4T@fXoL0agCOs82)-IpfRK?d}-m>b0z9=CWM**Nu-?!gNI|$6NF& zsKm=Bx;7F$uJJT(#G>(lH2j+w&s{t|-lp?0cy}|NuSDXNjgNOWR=j$NSI!tRu<~5^ zZ9Bcj*y_mB-(_rt2@O_7+b^Q)n|&D?aaROWw#oOklwp89l~JP%8j-di{s4aeh-Vsx zIc%83;1OfUSbR(gVvZld^bhm3cOi3rK=QG-PJfoNL(hb9sRZg zWA*L^jB@-HixJx*`7*IObj_Ih3T2@6e#}(N&qW~=KE<*SeGGGg1vJg+6_gOx0`ZCe zhzmnH^`sc4aH_9=tvsequ|Q%PhkQ`}HJ`JStZ-6)O~Ejj{+-EmOCRc;LO-m=wLe(z zeChjII%8D^U!SVFILXw-qCR0&!&xz1m%hG%G_AeQl5jYfrfdDbZJLZ$;_B~{EF)!S zZz5#_4_K9T1XI?0>$goAo1>e*PqN5r>usdz;v=T%n51b^^WL62UoZT>wB-LdpM{dm zUrPIWyCpJ7|@1LoJR^X9s7^K0TY{A}Fpnz+A{qw~iom8X*!0CEcN(sL^V zJ%^|Zm# z$3}O&zF2-9L{-f1F2=jp;}rY5%aF;LB=;GeF-HT|jFGvi=o9QwX4RfX(dpDE9D5U? zj;Tdo%al0Ju>`rhrHuE;_XVOy&~-_^dx@@V@_k*t`-p*l`Mx9Hcjfz@d;`@q%<@Tb z-6OMh@_AKsH^4B?XGHf)`F<_m0r`GIbPW^zAH?OOe1DSfFY*oK)IWER^D%k8zoYVo zI624#O&`LE-3Klt9Nd+Q02vm;iuTYYwqhH2dDb!pV9Y^%@PQRoe4M24g5*&6iu$X8Ts z4ftv}wsx)IHjJXU_z&vjTP?5WgPD5f9`^lR3?|xe*dI!(;c`8gM8jc3r|i{-@hOwN zBlFaoSP3%xn@6Ij!|*O510GX8G9o+GPK+Qqo;Jy4LH8jfO}6aa9g#g{j~F5VSCrFs zu>hc^kvS?f)>0*&!$L#Q-C@$$J}NYJGDHBbpm9WK05zABIz+e7I4XXE?qepGCz{Jk z3E>qkg6`ucjdf$frC^L);0i9C@QeLe(fzTw_{qIZbS>L~&7Ro~yvjh5(^%7}v9UN# z%zmf3v+x4WcPjrQ27t~_ar4ykOziXGR>kR28&Pqe6?!O49$r*Kh(5(AqaWk&mINfS zE9Xg3)S~32$-K}$eF+{K$Dp+3Q{0@CB@6M&E8g@-{>#$D#Yrit34c`WpAge^nlb%? zo->GVpN*>o(pM(qjQ{;lao?%TEXT~GMT-(}^*z!*vIgmQo|QP=$wQB&>%WschK+wOA zl;kAf%QcRvZe~qGjl#{LX{sa#tlW7d?*-~Qd|i%+Q9wWEdiuHZMSu+mfiv^%ISyG4 zlShIQa6LhqdbJj2SAm&8hko%0w~Z{rLnFAkU|_9d7Pt0V-T+3bYZ}O|JTVXtLfbt< z@WX9{M8BZ(9lxC;#K0Ki%uxM#u#fJ1RI)SF`SlLt`TAwXBQ912?#*{h*KZ>SeS@h~ zhw>dWLn<^M!7{XuyhimA^cL$o2A0znrQ><4C5uz=Or5+7q~pQ)@4#vK&I1ru z&+4lU8yqthFH}P=6sg&GlnkxC%G~JqR*h_S#H%}QhinG2?E0B8=W7oMs*fFxIe0m1 zc}iNc%01$k5igtYu_ZYvBO_@Qb`GWT!9jTq#NQ7w;#J*7$BdcFRxMkeoF;QVxCSfu zBwB*%fULGT%a%g3d`?oojh(o3zS>ye_{QRlnTO;ARq1xjwK(!U>cpjs=6{d9OL&JU zrYKmveB29R5K3(;fQsPIc@m66BgD}8uXwzrrW+D9SOC%WoJZ6LPe}K0NFR;I!DG5i z8Szo5vo6OB^9OH~F%MpIv~TK=2kGM@cYB3T2jE2$5j{lU`~SIeC595<{>tUR_909v zs3!+m0k8SL@fa$ue_EWXFCbF~HwAOOy$~7hDRInF`^z13c`F(EM#~e_iz>&A8A%J+ z-@(I9>T{Jt{S_7UY?A{+W>w>Mtim6!+wm9tY2NO@NLM}ZI2Peg<{rml{Moh#0?t-r zn;hRrZKLk&gM;ygB1x4OqK4sHF_ih{W`+*_hReP}GvbjwOhpb-0mC^}=$NCrw>wlE zp13qpr0+{p)kTikA(4k`9n%-4a4-CdjD^VwYDcro^?56fK8!2rs zrWO+|dXrPHssTw4cZVh*?NSk*pEs6t~qy>1uRHv@B%n_7d z54d)1GX#B9CW7wMf?n2w9@B!p(}EUhLHB4u-v{~SN0@$5xkb>I;{@GZZVGyef;w|4 zsFts<-0{a{=}R!;NXMhCiN^E0396;mkaGQIk+NM&*{7vEsihp#Qf}5#9@J7+ZZ?_i zjF9rsW{Z?>$4PlL81ady6H=o65p=KPw_nhi$8Qf%*+Nrq+bbNF`u=&XBgMD|Ynj@= z0}c7N>R1J8rpm33+4?CkmAT(BLtSV`!4Fja3@lk;G8cskRucXCru{NR)0BYpHExc~}pge=|ot z-U>x~wxN{wZ$rCq<^cKy?+-ZUs=Pz!RTms~d=t#ZMD{<~S{ybX+g^bOXffcWW>b^? zX;q?;tGb5%0oOh03{cq}2=ND1T;=#%b)XH6uFkyXDv@Vbo8ym=&I6BWQI;3r^|;D` z*T|9<{W${+LpQIn5r=PQJBv*|4X;zsFX-Grt%jBO1Xa7u5mA=j)FQSUVWAU=VNFSb z>fPor-$6@WnT&hSD*KsZ3~7`8Vfq4`fm?}t7FDU+5&n>!y4&X%zg(go^^xO7DKvtv z0^u&`bn)9Q*d`d*Brb&#UeH;@?{c7uo2`ykJHF-nrz@mGYAI)5SccXdFfwa-dV1=z z__>CJB03u2mtC1+R4^_}K;{sE)x&|Wf z%~_n>3cvhR4b~tWJ88PW#tOE#hMIygJtEzxSEe$nU(`63&qd`SYm0L@Z?yt5F#M;s z?toUk)Jcr!s(yR)$Z9*Ix{ImQfS|iXlr88i6=eg}H1qPlAJwz%4o(k2ee-{07ilM| zv1vFxtFv48Yz%)~z#Wf%DUP+FdzG?$89K(8_Lpt+s-f1Aj@Y|Jc46cyBcq7xV%6PR z2j=P)XW;4QwB)n}=v|{hSAk~8?Lh<>q@b&u-yUF4R=lCL!xS|^m4T6RZAK{NA=;f= zB(|WZlHWccCjHcn9jK9a>~wr1S79coXU&c|NlR8G;;Cueui-%%w`=7z$Cj_2av3u|vOZ3hVU64!D+za&DzsIQofKb@h&w zDGQUuCe`QN5HVh-Mht6ySdxkx9CL94RSGUe=JUtQ^93vL?6@`AosEv!IJ@{K3|>MZ zqGUYsdfVg`@*{0y8?qqSNilk|F;Xg)_-;~4k)Ru>7C+TupQ#>zPii`v#FT&1JtXFH zPqSkNE-79Xa_MV!;9+YjPg}wrBxjnbyA_M^ka@UfN_IIGr>?-YtQdLFYYOQY>6Q$3A-5KyldyYodW#Pk zh7t3{?kQx|_~?VwkGqlDa5o7y3${=jrui;RP+L4^Wr`mMP=ijhDB0t2B&gdS7D$O_ z@#?16b$YpXldxaV>EX9m(78t#3i<_|t#m0D^a%O|-FqdLV4q+>(7liDenIDci3@}+ z@Sp12=e7x2;2vE!beoKIR5dkU~ zz07PyXsf>_UUcJB|ey;=5pw>wObF_VG zALTe~B?0C+`y5PW4?Ue75uV$%=Vf|&BR##^vyYwuc!Ky5kzUYwl;0j;NMi7Lrz4Fa zlJYZ%avfuk8Opui5kKcIX{pkKU!2a#OU%$EsORjt&rrwrJEqguoCFO8c*6h-)6Z_BH-GUE+YFcodC&P;b6*%DdDK&io<`QwfU^)AN>d{@sJi*XunAn2Ix}VE&3P&yt z2ho{dwjvd4cMH=~^#mE+i#dYuN<6*x%Nx!yH-;b?%)xsHjdcZ?zO{IK;84ohMTXHL zB5GAz^r-Oq%*cL32A-7Eo|12%a?F~MC?_rk+b}e9w>#qF_3tz7j=B1)_poEO{^~#M znDLGN^iy~4(?Unkdj{XidzK>NdgY&x{$+`2=|~@X>qvV0Aw5Q0kjyQ6!M^`pXi_=P zA(m}!lxUECV>@RV$14+F7473kjd1=z*}R|$)94lnfgJZrLJzb%X6dgE=7zgRLI}Fg z^V@lWp|K|>j3*A#q%Nf`uRH9R89r3C82X^F76N8`ZS2Vzvvn{GBM)m$$a3-GlvF7p zfey&xyhxe-K1$)bMDz+eFUz-}^NNHKbobKTFX+BXsnKgp4o%-QbU1{Gp6`b2=f!TX zQQPs$l9#VoYR;QI>u}6U;q%Z-IAzWeR)Tup;rM1r`tqNdU(3_Q!m*rngt`R**9=slGT^IgephUgme@wVR-O&N0j)~8AxpYQ>=v^#UcEZz7xN3?zUp?VG zPs$=>UCLs-FCudQW~OXDZcT>u$;+aXVCB3+CLTc_5FK5bNdIxi`1f6(_gQQNWx3`y zTaH*SYPven-cWg#TTrQUK{cHRM|OgQwJk$>Y2n;P1=?_CDs!u2LnXsQ&6zc zDvzHNYd_Pg3H3`z(-;1a#2+6QbO?O;Met{!5T#_me_MCdQURY{#&kZX1b#v1OELFX zg0DrgfP4!&-;hVV`rNJetmtJ1sVbsY2VGZKM~2NF#}0hG#}RSJA$Hgy7EQk)P2G8` zG{2;%oEtCaFCnw{LSzbl36)W%%{!pNW1!_ZNOUo&O!^6?A9v+n*&a*@A0`?i_K~xK`YA#eJQ)=ZQDgf-7GE@{~awgx>Ks;s_fFp?sxpC8v1pm z+Aj@zFZbkxcD<;*R~?q;0v_ufJKa~qvkh<4BUVHWh0J+>)e&C9!L3wQ$S8@;*nxET z8h0RBHdiR`BgY@YognmV%YKm!Pq;1|9MGxl*T-#Bnzi2o?{f?@xs_CkNzk8NJ%$!G!ZCk50 z)c*(wSO4L>|NS@Mr@l{9JfqbKD5wre-%w{g&%!yZF?w6oQuv7ryf^HxZ@g9te?qI^ zCwEUjq5dQUhxNwAo8a#8_y6|pyZF}wjDqvV_H9)gJl6cpw_bw_7Vx*Dciw{^O~J~B zfB&n|37gm&gk5fvH3xIY>rJ*DhX8a)6b1qRsgy?SGj2jQn;C!v9@;bZg<|=${v`#1KC3_jLsZ9<{oT8t^9dvNo~Pc z)uP&xxlpk*W`%0%;d}J-RSCN3YX+?)Yt4k_ zlwIFU$Gz)2xxbQKU!Oy81x6bZmmOcbzEj#>ZP5iBRYu!=aJ46X3g%P4qG_ydba*3q z=f|_n8o)21;bP~j@}thx`!arKGwn1D#J2mZHvB$c=lT0PE#AgG9bSY|KmK|Le$$q@ zvvl?YD(BLbl-;o({>V(fBCVw0;r+O`=~xfCVI|o(So(=sW5YZMzf;W2qr(aK6=UY& zZYN;SW-ji10)E$+x%m7E_|;?P;>#ysYsp+(b`q+teW^`6nEZ`ZX5mx#rK0^PGPA_? zgYx68Q73TY#VY6EpJ(yn_S5QzmvABUP*r$oCw!M^%eo(e@<*wmjuEBBX@nPQ;CrRP zUyV73B*0A!kf1j8s@UekcuA$PvE#63n+`nT*#nk$QaghA zG5n`8~X1lbOqF_->iEwVAPHdxs3Qh(pf^t$f^{vj`|>r}WSxS7Ps%{H_9dOHZ3o$@QIU@khbJ34O{}p5a^xo)Khx+%$lyo ztt&=uY_f5(4%q})__nV2*m&aUs_-7q+c*kN+{6ax3L(7zrts+*k3Tqh zmp_7AjRjF)+re0L+ot+6Vd}49X+52ab^VOzpAWN?zJ~R&Z#Blg#I3}*jJ0v7HfA@h zQP= zJ4~5*UO#dzyN=&x#<+9d7vJ38Tb+mE8GoJ0NaEr-{Vy8oZ%-M8uARe%rzTiLb}=>t zoL{(ujys<`+qhH?%yufhgGx6rcAZZ(Qw= zH`zU8_kxAv{|4Frhy+gsuG;Vk`V(R4hi|q>zHeQQ$nb}kuixJ5%bzwDUVp z{B$$yKVaY_w<_bpmsMdD{rSy*{55Uyv`aW7D^I-q;{RRZXDdv6;w8_-XJg`Kcif6% zWNonc%ebAF;3#@TdDVu^er2pEuiEI7H$VKqI8hF5^UBjN8YeDQ{owsKjlDR4;!Jcc z2V#aI)(LS|h#}=f974iDBIgxja(UHe#wJ{n;3bQ2$#z^~Mrq3?YmtqSwaLcGI%E@M z%^u*BE&`ptoIE9UkGts28g9>wwuY5SNE#pH=#+iOG#a>=(~rB*WizH z>3`@Od{xdd=?6h>f1Myjb++fZ+Qu|1Sicc6tzh**%(j8C_G;QzPG`LM!h?*R#b7M& z+TOF59(^ri%go!9h)@Ko5d_QNyN$y#>mb$2pZi%!Q>dSEK9D=Iy1 zU|(glN?+=ujKynJ-()P`qZ)no4ZV&YZpUQS&ZAVDo9=pf6qIpT<%j-q9H`zX9 z`;zTPwm;bcWCxNRM0POQA!LV={gkXlb{N^=WJi#-$vR}sp4h2;6||2TgiD@A`_@7D zeYLs|vw<<&48n!S&w}t*{#8NwdNr2K3whrXIjm(c^Onf1D}pt^zWI{1cm8owZj zw?y_`8pK;7m#quJuEv;mEr_>7c5D@boA`_^?IFR&Mz=OWz9rJW6imAsFuqMt&S2s9 zou9%=?bPOJV?`1i(G_Z8V=Z!U06DON-cx04SQ9j==$F;Uwv~!CFlKeZLDf4*zf*bE z*gRCPkn6UXg;Kp;ZK--wRP_d{>a9`LTdbUC@-1Gy+P%@Qsv!8 z<-K3!{aJenf5nye;`UnJ2Qu>BlLQZSrGbrqZ8_IIh)<}5cTRMGlx5>?luTXS5e0YY z($k)d2^}E!sU5g$=*8#8sSZIHsz`{eb~7Ju%zSi!{B|x(l%>XA-)ZFN*8f| zqdRQrRyj6pMsptPlD#=6CAa}wb@Oh(X;~U@XqE-TUjM;tM9bg+xR@%|Eu&&H`ejt?)F97_714L`yeze&wb{pASE>8aepL5fs_r*b z-6yKLk5qL(tLnZ$)%|imslpgn-TU^}>b@?c?o;~Ir8AK_JR4H^kAhryU3(Am}i8ZiU0v(p?P{6{jB`nQhm+g`C7G zoeg9+p*6Q8Q{%0lLRz0yw)Kzt43e^ehNQNVr|skwtp50x{htMskAZ+k7HtkD@9;HF zZ-a|jPZ&4w0@j2vL3w=3sqvwPM$752m8JeTP1AH#FL;QAomn9;yEF*b;gZP_;^gcrn)z=|wSZy7l*Si#dEa%zm+3L};;TU{Sd*LjyshKqA@nQ`L;xXin>47QRfn}fIb zyuH)2Qx{XO%!X!eU|gC2mteC#P;dCeELV^BPV~5X{Mmxry?T5>t{x{Qs;kG>d|W+V zGO5z5$HTO%$2*olg;TqNfs^%JLF(e~t!|FTHh^3GiF~OC>Mfj%I|F>6-sBhzP3s8s zbJ_#-I>h8Eq|tc_^k~cJur;=urC&XsHDABjYOI>ihfQ;1w8fXJW0qc<=>WOiRyu6D zFp7>@dXA=})7WT8u(7c=CdVuTuE7Y?t~?!!X~!%k4!^Xk$8DzwxPCP5Ua%JUO*{oI z*NubHnGe)EHzlY)cfy!?KA7>~5o6wY*EJMl@p=79-axpRN(YFYr+HsTxdByAzY3-v zs5b!GB7M1fpk5bfob=^zr5*M+SD>}hm%~XmEbkA^m%dzG$(yO#bMQ22mic3$fwlHr zJ5Aa%9hWP46Ux$>*j0$Ht~~6X;eF^ae}0xL4@>5|t~|_w z?5Ul*&Y%(1W+|O=eX2%OPc@><(KMolsu49$wZPCB(gNnV^cI*qLs|gZacX*XVae7c zICBhc7e{eKrR{s4HCoSfpBsKDLx1K>O0<(o^fQ%cf0bxEmFP&7=wg-VikXt=5LcoH zXKIO-Wh83O5^yUf>QJKUyk_hy@AI0ja2P|)xoZ|>8C6-1S6L2KS$0ubj#F8#R9T)% z2Aku`vQwFs<${bXN0mvI<3-tto+Iu^kDG2l)l zJY+~6x}Be`9lD*L1Di=|f4zE+zQ4Zx!>85jAf$f$C5LXO=E$MjH2hm%9Gi>dKWi+X z`>!~3o2&lPm`WZthJABsoSej%35*GcZd2w38yZ*V!WIGt!G>;F)W~qa*z4PE;>~iX0tb88jb81QmkIBwwKNy=bzoLV& zo-?36=1ClW7FnCDc`9RDf7&=R-+k1ydK;cjKv`%LBJ{&bxDj(fFzseYHXe_W=YNn;(lEb^*Z&qdf2-N=0p3e~IPnk`-gHCstkZ!GCu zv#X1|Yu0ixHe??R`Bt7jsy}srOux z?F_pA5=;wlNN5Dv&(J!flWD0lXpHVGsqFmuFnY7bP)cLT&p7fq9&MbgIf0gtH7C+M zS#uK3o70kUjhRciIVLZwV5t8?4fT^tp>xhH<>tYkB8*)Ix!5zvpElHS)sSWG0f9?L zAYjeGG_3iQ*usiib<;A4xt%B*OL`B8F3Y_KM9<|A&Rk5jUW(RPPC?hCTA&P28tNTa z&`@8yT&rJeT&53otiz?{UNyUpq3m_!K2D)FR$Q}*E1+i6Rv@)0d(957@UGcO1g$SH zkhK-9xr6NPRLy#>npPj_13G<$v#Tu0NF!m zts}{_)KJIhYgSb@)Hk3v2UtkyDET=~K2M-G_?64*pt`D1!DB{G%!KdoI#N#Kio4j#j zVHVifg{T84^!X{W=aOT`IJAz3^q%zr4f^`S@hCW(=)O)|^7~ zVDXX8J-&c5i4zm}+@OM8YX6xbuO~O3of-0eB=iNme3-GLGA4ZiyGNrJR$dDzuFEShTpZqE&DHi|5bWs^^M&@crRC*JqJ5vAO0C;paix~sTBTs?`oK7N z;Fc-|%sYnVyK+>#1AR#?fL`-CjA$E5KD^rKamaUyNTwcYKFU{~=}b53joVLl!QtCX zcEW8W+Z&U$ZQ6ePuqRqZK9-|($eJr?o~*r! z%B-O>Yi}V=g5q4HIKV-ib>w3`T8FIpIn9%`H&B^Pv}7|{`wO(@7MdsPfW;Rv>^}-e z`;$%vmWz6>TGPi^!@cdShIz21-$mGAl2oc6uv9|J%6_PNQ@o_`EK3>Fd z!&jrwp1&_Pi-pYsx0{}XI2kWu*nK|edJ)61^TD(iF`R+^1q-x?aR^ z!2gJF?X#Ah_T3ce`=2%mKLaJ58H|nNVB`4gEmyMV&fI3Qoo*x9;WWUv;Z|&swaJ>> zX$e`ItfQ9fpzWQkL)P306|Djn7}SqR^kd2sXYs7py}Uu%C>VV%*r2gTA=luUcrMtm zkw>x2fj8}3@X>}IB_DMSrrGfAoTFY00>6`LlzeSR+M(T`bIIM&uyeR4*oD=1$eO#U ziOAYy9kS*g+$`X$w&APB(DQWO55GQ2tMth8RB8NGlB=HMV6%aG;+o8=#m++tHn@ir z$eMd81+q3-2dn`v#MlafQ!m8mcoB1Vs4!Va&F>>uWUc))4^}@fsPMdO!G+}gpX!Ae zhgZVSc>Eoj(qBfC#}xd)-%DTm+t@PSXmS0^Ti9eW@z&Tr(F4>zWMgD)uyBIPX~OgJ zCR~&+H4rOc=dZsIW6{MRyxfvn`XF*z`|rY4M{$({tDp}Lp^cMuz$VY+;VJc(Rn@wT6*_~V^ec^OW$(-G zYmI98K!lw0*b2@?wB}`Wko{`o>dO#0P85~&zS`LOiucvVj?^4isnM^awakXt0c{&% z)^w3^GN3dQyIN68G<;S4sQuU#$mh%zX$ks?@VKkk5*^5=b~Rc3u6XFxjFup1BtlLX zOvmYt*6fK6vbV(Ms}OkyQB=~qCAwboZi!ykAe`NsYTp+FX(K9jEr`QxCKj;vh%FJ+DK;{jYOV;VsIaU&pOxn7g5H)spM(X2PYb5U@vK z8unPU&iINO=`zN=Nz?=^>D@?EZ+JIS*$oJ1O`=-I(3;aI=&V!=>;Y7bo13sP!Cygd zX!RS5%k+%_>oDY|SItJ;#HN@{?&ndcg%#Iq(@m(^cA}`Hcg?z(AmXlqTs#zJJRI}qITorO(cE_6RF+=JqIEsVhaW#5z)>fSQh?b!&KcyYp64P2o zseDd$16q4iGObj=vn^GA*|(5O=*`?rDUr3ekk75;Q`ucf&&JqRT;buZ;j1p&KCrnO z%zImfU=P@e8vt*q8{8VB?InNOR*$QqtwXNATHw;Y2sj5Qy~AkDV->gC^41V@Em2g` zyUTC3_U`hwZLn=mP~A_VwGtHc%Tx=DZ^JEctqpd$v9OI+zl*p`AIw;X<88cZmcUTv zC31g-LS3u4W>#CM*{HTiUB{B%HQV0SyJmY4bZ%fE$9xpWOKY<29tBrwuimyD*KAfh zkHL&J8Q)H;>y&oru|0Y*JE52CgDlZ5+hD#(P5_65x{&RL)`=$5QiBFY?)&=9L|g^lV&YhsK!>6%6LL)L@>_0h)hm2X273AfIC$Fxp`9rwwLY zwY!76%W>%e1k7QS-bl38sEXUIS4W6Bpd(VFv7~pGukGmFmqTHJjfFn_@b-pGBc&S6s7GouFptiJFtWW}`ZL z*K9&(Y?65x$XtNdvB@q;)odf6RI@gC$DVu7j5R6mtkv}fd0d8GtQ8ffKEF%0!Mvmk zrnQn%Sw(gYT629eEj5@idgrc{4dx#7kPToVrO(OF2J#7(4spTBg07*|AqnUN-t1;> zOcmJcDsYhsY)us~yQO=$)))Jn8m@OYZoxj?E7&^V2v0pBV|_R1(aqhsP1S*4cYHX4 zy`8GBZ6Ru9>+bH6q?UK2Co1frdhbJPA3z7$_b#)$L*#`-9mJB}TgkcZ-eaj8LGv&* z@KJ6U@1Ke)2>IQZp;DLZf7cVv#xSC?FJ+}b6*ec%(9-i zIT)9ENJr7F{!?+OzNxD|9n~|Vi>Ua7o|xZR>YNK`or{=j_Ac7h6S`;FvjneDsbFYU=0>9yQ3dV+1^-K?R%pAxb=JVuV~)`f5OBK&sg0LhF83w^ahR5 z&a^4^C7=4fhgRO~=RL67B4iJu$_+*9Sm+>oN6zREk>?UM3`=?s?9=_d2lfR7tr64) zpP@C!P|yjfmKZpITjDHk%njfr&{9jP`3c&@_4?7`y#q4pN6Qc4j>VZoL8ef^=@r+n z&p@c(Alz;oD(PLn^#i@@w;4fuCI+(0&{}iJE=bky3ZV3L6C32Uol$R%93*unISz-m zy%0S)iz-h4*r06N*%@-On9^BFb~##mWimD1EGXpc!If$Ysl+b@(MO} z^}zMj!LKUqJtPD#&C(yFB=<2583FY**H!LfYgQK{(1o+1au)-KX3JtM-hr>S&PhYL z&)VXXP#PFZhf4p@e(>f{EUAx4T6}(J#+an#mxp3*o2ccspf$H+p4qp#v7f@2oct+L zRMLA)?*G(#Oddth-bvlETW=89kF>Qy__c6-Bowh6*UI5)W$VvyK)ph!3gA_yVEpS=TLTIFhZ0VQL4dB@S2I28)Mf8`vw!$q{s79dl)QXc*P6|0t}& z3D?S2!)fJETxp+jt^8E2963tr$6E*Gy>)nHTgUF<;M6=#H3OU47NE7SDAz|RZo;*) z-v~&}-zFSg86%0F z9I)ausWZuSI7rQo=*jAgp0cOkWmLA2)Ds)s>_X{uCEFdX*)y3M4+09gYgA=}U_bRR z(2!Iw^3;dCk~RC%a&I%EhICYsZWGd>EOrF&g74f?ual)B+ZjGKSPfVjc(&Zo^QLphBwzWG$xM^WqI3m zhs#hP+uN>>j1Ogd+x4cYA-J;7(Ys9Wj@}BLH#8=~uX?@TwcV|v=!Yg`jlLbDI}|RZQNf@!{IRobMoX)XW`BuX8{L;gJ`c;avKvThrX}g3f|(i5A~OP z&xLk`$LP?gqyny&fFI5VE20jGei8Q@#`~Tw@k0= zZaoYAfCun1fts9bf^2l6?s>*kaF>{#bl-o5IOz!Yz$$m$XC0$yb)ogLY27;qFzu-CBEP`D|6uu9m$#b{;<8=vrrtQLgYBJcbQaFXz*dml_8Aoo^QfyeA0UE z=STqNo zQ?P1LTER)MD$5(^&&>_VOU2S&(_TIo?yJ8sH}se>ctz;{?v3+_RUxl8oSU1WC9IX$ z5;j=FxSm&V#0mrZ?rrw5FV{nzGA$Xv*Vu zT2qe6-jwqfK$9(5;N6~`7D7{QT=sw1l*hfBa{neARI9ujvCTq{M%?4oh<`2aR>m7vX-_qvNlK7=>I!C}LzEuJ+l zEX8`U`;!&8KV5-E>UO^o+|w%0cc^bU6ndA|dhP3>k{6FamwS?ZS9tEvum@=$ z?Ol`QD>7>`2A*mrHJPw7S(DZ7nmF4ks>!ZOYH}@WO`Mh4YBCaQVpB~r+kk%sI((HU z&1=V@2Xh1TY84za+g9G*8ytES{&X zR-QY#JeHbbyMa}qE0KS8&Yg%RfDe8ivdLw0i!5Koe zHYpC~1|tbKz4hFMVPL@(LSSYfB`8oc_={14NAWcB-Pibm1`U(1Y*yE-lketw^FwsB zbRFe(>)>!sX&%4gwyYALG3oGp0euZazew!5@!xf&t2m9dG6K{8$6&{5Zj&4Z} zi{q*W(0P+Mr2!5Pi!Kxc)=WSsCQviD5%QLX1$a2Hf!pcU(dn2L{5<|BrFA>OdvaUd zdhDrKar=K$@m-s4yW(@W;;Z+oA#&^K_rL9mmtn=ttuRb-anE^W6YUv~AEC+^t8uNB zT-$#$txfRSI5irqg)NJ$xsCRjV96W!TTcYcEI3LYVQxQCj#lQJlv$cAbClw4CvRlU z9XM~1wZUfjwp{v!=eGnz-9k~blQ*)GyO1<@QZ8g2vgR&YLe?Q`?Zzc>vI(;09x4MC zkJq(+`y*2b``dK(E>~sVhjU5f!>T(qGbhOsXQ4}4S zdsRj)x9N_uAHK}Y^q;-(j&1JzvzP6Q*;t%S_wD|&nRhGM9Nq3eo57fk&Dpfup=SeK zusAa;ES<8$?H?8nr$%;EBY*C8w9?bj6)#6)sD0Q`|DCRk)_XcyveP4@NmMmgB!RhzIYJtL_44lh@*e5Z#qSUiU+$nM7NPIq_fUzUzn^jmi`Yfom) zZ{3THb#u6G?e_j}>vs5GQ@38uzoKr-v2M}*Y8Xs&((4BOdeSRdSiavQIxJp`?qcF@ zU%I>7ITASM75{b|E#2?cT(|xWy%B3@a}E0(_}|yC{9jeWQ3wAuHQa_ZG!LjDvHW0q z4WW;3cqI(Wzx0R?i}#>Ai{14(l;N%oo@lziJb_z!D6=}S_#nD-z#Zgx5UoYlChMpr zhv?gytV7m1OiRd`M{qtyHcr+dYaOLBWX)qZZ;`dhI%Lh`REDfW);vK=$U0=Llei>K zHbK@rMPJcCOtvJP1@K}*OwWX-cgkxh_|o})5k9kS+mDnr&GYhIu- zWNotMm$ZbeP1d|fOUOE8qnB_=jI2%8ET=ML9kS+ST0+()>!>AHaJfU)yo&QSS%<87 z4MtWKxSC~*Jr<&q{8OP9jc%vuh;;pFJaRS;pN27^UF}+NETp~2clLQ$+rZd+EPX5) zb56l>k3+8GA@}ey68NZBE1Ai(k9d~77duP)7 zL}n%zF%ugyffgg1AZuRdR?=GG;0eqUw*kl#-i``$iz!){*+J>T%sEWBfpOzRdP=Zn zt!GlOV&ch+v|wqg)7V5FX`DF8X&g_cu~O1-B#m;FM%z;vX>81v#`IHOX>`Ce97qGU z_Zw&}vNl;qExAc!jI2Y}G#lfnBkPbgTjCOntWDNz)fkTE@g=jvPlsAGdKVtN_N;M( zDxF+2FSX|CS?niR1KE(ZT2l^u|F#>T+2a8WS*67jSIZcFHmfAM2N zsI&zqFU#_ysxetCN157rys#%9o(d)qmEH?RmV zr#CRl&t=IzR$=zj&bu2(%YHLvZ)5hZ7hoSf&)0l!I4eVD4!fvQ5*ChL$j zJJNEpHd%+P*@>2uwaGeU&Cax(tWDM-Yj&aKWNoqzS+grGCu@^+$eP_~Ia!;mL)Pq0 z%gNeg9kOPWmXo#78V*^r2QIhCI%K0gsU%sOY^)cRCu{b`d9x2%3vHg+m*&Yj189B- z?h)QF$}WdKG8Vw!^Nq4axZEbYl5Cu8Y%!EH?5CgX9Qe1r7c^pjNF~O+FqMsMEYw^&d2t_3nqYO$%$^TcdjI{07x)4+&In zlwXwp$Lim%{*war-#vF<%*lsZt_j?&7y5&%&^-V)DtMwsQKQ1TO`6ncQm4)%b_1`^rs{r}6UVgcG^T!|W8R!`p2>(Hg z)~?mCu&}UJt-@OHQMXauZ<~RZf%?zXZ4-E;#*>G0?y331W@mCQ=a_f&3w&{>8OZNb zbw}Q^K>yrbRenG8zMtO*O;Wvj{zLT&s^542OON0A$i2@s{mJ*f9{&D!>K4|j8@@N( z=)ouNY*xR1-Foz|UZhQ+e*N`RQ#5((+jZ+54EQd;A?K0t1;2Z6RbcBK zcYfn{_3G4_m-pho{oCJ*UTIp`w2<5MgX;D2zgN9+emFnXv#L!iE$~p`lliLx`PG_7 zbML%!ap0qmo`U}i3mY{meCegax^*A>p*F1vG;ZAZp@)9>!zN9hdg_Nid@2I#iuMHV z`)BB0MXP}Nui(yl!vl4nytD3;^@?iNIvzNHBfneVC7C@ONX^x5-h5!7X;bLp z!GXbn!l{A6x_=l5b7~%Dlgt0GAP|Yvs#Q{})&g(^(}KVY`0@Nx4?o;KP_O<&VCyf1 z8Th;(Kfx5%`fBIE1H%LP@PYj_FwibfDf(=eX9j9NUbEKMzy0;N*NYzXq6Z^$$GsRPCA#)&Di0!>Pez`Sr2y7T|6rW&TqAKdLu+=%L43JoVBa z+EiH^n2=lR{l>qmSxeJ@@Y2wG)e5^+dAVNAnhoncgmbBn`oDOl_Ad+b>;Iy5gKx1d zyz@br$^s9@0-XZidgzt>!UwlQzdiKWEBOzrk7l(#ek8wHjqiT^eKL36UA@I!EehUx z?zxv=e*N`YwQIlp@`oRetTM97;HrbGF3w$?+jL+c5h&W2TQoFxYEI#p+*X02dz&_W zplQ>lO$wUU8Jv49r%j+upyu7xYu+`eN{zQ*gREKU;J=Ym>$!Thd=zWaeTTaO#ffpUSoLpc-x3-7lA`f`s(-D)aLA`` zt2*>ize)WjKl|DH??3eve{rdg<^=`ec)$)M^6Z?_Xl^{$48(KnDg|L!UQkd_3?Jc0 z#Lk2NauQYWpP6Ill$1mRQ5f=ItHtjqisi(sIo0C1@u2zRg4lidpIIfI6U(u`?&Mlk z6S?FI+|g82P*e~u38zhwNH|;!9&?M(am2a5ptKbH<;HW+ja9|UOH_eWip)H#dOTDR zjs?s+%qp=e(W=n^IfY~+k)qao7x) z5Y5i9a_qcVP9iV*0Ms^-2ie90Ma5zJwPMH#Y95GJv8%+YS$COt#j8c{a%!uJkk4oU zoSHeMr6sU1Q7slo+-c>;3KAhZWK}V9?OZe0tX34wx2jpy68S~u1JU|sZlZcPnjeOC zp@s=30+Cpr@~PP{ z|I9mz%$#T-nq$I9v|%m=V-cbjMM|SNIFQ372?$f-jWYR*a=xM)?|bz9*U!%_%M}c5-ZJ*Elp$6gDHfN{JbW!hfZu(9IzS_Doi; zmE*uZ$_&Anh8-*n$%q9dV1tG}$+dIhFe2jl(VAwyT^9(K_-rl$KI^*li=f}i4H#>d|DYI)1>j$OFtKSlG(QM*9Zg>b z-3I>2gyrkNzXD!>x)~T#pN%Yo9_R4mzH=o z27^iB*`!kWn=@3r{|7wgFZ!Cx-*@xU<27?>iB}4F;w15OP3<*H#WR7Y_F^r31ZOl} z*T@&mR{Rd;MGIf5@Kk(FBX2QZr;3U%TKFi=z=R*o!04Ld&sFi?Wxj~D@NpNfYvhgj zieJgRXyHvLf)i?tZ=!$+HS#9&->%C2#TwVwfq%s~0~3BAuWRJv3sn5J%!|hI$j@{2 zpRSRQE>irxK^0&0bD-M*FVjCtWR?^JYhFB7XhDtfbzO-0orSS zZgcyOhxNF9ibmHsKJ@c2Si>zNmQ7PLM-{Q7g)U$r|`KB9#WLryrM#(cskU_y=K z$ylt$YZvB4<0?P(DPTUvylB6CnE7qYix!?Yw`BghuBbn6fW^Y*7o0FZY)@Tddz$QTCi@eO<^8m0l=+>^i}uS~%o}&9`iK@j40+&$ z+G{-6%s*EI6hG8KO_^P>Io&I-j}VP15S#~GOLgW_u%B@6uOYTH;4=1}6OQ%D;G>ivLykZoutJwD5YqUinAj zivKC|qJ^ixT6|q&{UaL`|AFwVg|94sbED$>GcQ{B5{QixYRta`1x%-{JGqU0^*PuG}Foc*n2f1>^JC7V?~SD6?6c7b<3 z30FS4#(avuQ2sgtPve8N-+UY{zlC|xNgj?PaYBvl8`U(%FWsr)SG!xq7cKmnJi?Q_ zu91&8ivJb!qC0^0>Ywi^cS(P`t`FOCn2*nUeAz>qV@mv3~uhYW*_Sqgiid{p+S`{V~=9Szl%S^QYDN>TqC+@&3yC z8?4J%H(;G${Zr6-{a$tHu2>%a89l2T*jC29>E&@*MaK(|LHXv$@$@`sJpNnnI$kK{ z{_X>%hMvN-i}Xb&cc6+NZ`-=sx9N^mCwf|KcyMjb|L+x~B1c zMEUzC`zvKFyyN0^jePMb#V=uA^l?`{U%x*+zn{4DpIlnv$8iQG{Gj|bjq$^0RQzth zV|$CnV%VN>I48jgHSwB8K5P=!A8t=!ZTmt0x~BY|Q~oEg|6;1FM zrTzN1*#DR8U$kF7#{734RP8I;FK;vd3G<@;@^R)@GcVdN?=auw>neZIe)$CRW0@E2 zmp6W;#`g~9Mf>Fon6Fk_Tk=Hfy zC0zcgZ>ao53$MrXiXUZu8uOxs*W-D`x0r7dR`Ep(4~uC+jeJ~CzB{bI?_<$e z9`_F=@DC@{$d{mi33Yui;bPVQE5eEwjq8zz#WbPziXUPAYFP22{qiNufA8NEFWN6} zGXEy?qW$s~^Ie!1?U%QipT@jszr4fzLl3F?i}uSK@P{HS+mm_Ge)%x-E0`DUmya-C z&b(;9dG7VG11`KHW^ z{t&cRJ`w19oG?G!J|ie#LQUKE3u=7yVt--Qi*D0j3G)f|C)#iOn9PSCR_!C&FK;pb zBJ-k!FQ(e3+C$ga9tq|@WnQ%KQ5UakIoHuD#m7cG1Q zlZ6R2#*d(Y2{pzyeyid?@GVt;(YOlhUjlzuzzH?-x<AUehC8u?P@ zhcPc&_)-_IYvdi~k1;RWFJJtI%D=`Vs{W#dkK+tX_<{A;HO3FWsrc^9i^lTUetLN? zKJk{~>wH_q7cG1-&cK8p$m<&8N8aZ4XI?ax$M|}AFFyK?;y+?uwD3hZ0~3BAuWO8N z|4H$um=}%ZF}{@p1}5QkjeN;_ivLGlRe#aKhh4m`kvBh3yzw2yix&QfuY<Cu%5{J9P1eCORSInLixL+fy(cmUn>1I)=#mn&pN{T zQPxGzsq#N#{d?B0fY#fqrAv=>X?#h!UOu;Bx_;cH+qpEnB`}S@ zFaI-_{=}unx%3W~zVoqke@$HaeV3l^(swmZ=l{#4kAtS`^}W^g`oiynz8ChdLzMmx z)(-0^>jdi+tc{_n{B_m^tOGE{o1@_gcN@(`z~>JhPuI;sdtUGVQ0O!t}%X$`IXFz79KV$nowi@ zx<=k%{{AK^f6*;K>-$&nXSnv)x+Z@uRQnDPf2@VKs;1|oYvj%UQv4O>MGOB-UOKO9 zc2ld0pf8nf0Rjz19Oy zs{BL?-;Ld#tuJs#Fy*T~yk zzV6ei{Y49}w-@rdM&5|3`v01F(ZUzF^4B%;1MzC+jqP880w&bhe-`tLm=}%fvHwcoA5N&f zcw@M#|7EE^YrlL6mv8V()qbLd*Y}qgU)Pv_(MT14I`g81*Y`Kb>l%6MGsV|`PQ@23 zd?b&mpRB*Gk$1)_eiiegg)hoU=XH&I!34$U|GSDWT6ha*V8Rc~U)S|>;ro}5S6^dZ zwD3!bW**9mZV%^qs#_$Gd&_c=bWhdi-Zy`XiT~ z?$QTc`hntff6ZOGze}%mY2*2HzL86tE~v+lvV zgf;e8b2L2RuxTy=K9@pyT^|AMb$lJ0sK(Q`UsU5sbXU-AG=CVX4*Y{=pb0gOFJ0sK zG$tv3Q`w(r;lo6y#;2~44>SMpODZ4H!kaE$*T`GU_hVl45zt=s(Rr+ot|_0%sy;U) zAJ&pj)Rm8}k&kitX20h4b@35&1QUK>d|e}-h^hG9nHP=au|L8%0~3BAuWRHBrYe3j z^P(U8jdy!QT>Bqgqrc+m%HK1<(4;z`EJ4Wcf;|)AJp}MhhI_J zV%-8Y><=B@AKIwzh4H}qyZqmQzTYrHKCdr44dt6-L-F)FXx#s8a$R32;{F^8>v24b zmi`Dcj~d65u5mmRGrxy<(ba#SzJ1km>E~VgW0xM{(iq>*_F*qq<9jjiSRc{C>*E>g zqid{BocYVlixyt5zgK%Cn1AFCD!ypp^>|+KjTI{YSD6>x19Tf`1DV8MoEM-*f4Zjn zu)k64FV0%{A{Vb~V@L?CPYvfCrZ_2#r!=Ux{ z`09VA>tDO{f4j8Ax4FWon}N|a#xJ_8>OUBG+CEqduh$oOT_bOD`8e~U{qk|<^Ilc) zMGGHwwV$pre#sS;|L>U>Exi8yhWYCnc?%vifn_@}FIsrp6<^mB|GMJmOMKSC$6eod zx<r~Mmi;r08kus*s*K3YrhCCrN!zQ7e< z*T`F8#m{11wD7OifJT7{HOAL9@H$ z%zwzdXuo_B^P`v-?U#=*f0}vGe)(eNzxjr$zi7XF3G?lk7cG1k8y_ar*#2P@Frmiw zH<{nSyl7lc+XEJc3AGn*F<-U0%3ri!-e$fT^P>Io4)d*;7wwlf8mRF*lX=m?>-%4< zzpk0RP|44Xs-tLnukMy+qi`We~%tew+0#eyjLTSeLWz!g|2V zYW+~w7V8nLJG`RS&tzTtJEd2#e);!G?*gs2-<{B~x_;87hq&|_m%a=d&&MMFsm{kn z|4C_+^{@Y&?*Ai~9_P}#UAo}ibpEF<{gF$LbLk5%{nUGqADj=GKCgfM1T*A)K;D*uZTpSAEYqEo!Ck+->ggAY{wMGIf* zimz+ri+-%)zs0<0;Vqnj2|qA@T_Yd=iQ?xnFB;2Z`xk}4z$Cn`kvD#+_%qCl7QQr( z@FcHm_z3TH~SMUyp@xlkFJp~{*B`IGA~+q z6K7z;k7i(WjePvKivP-ARDDEad2CM`XJEn)s{W#d*V_y8*ERAn=36o^ zdM;?M?E#;gg%kQmf4U}r?NmNT#UE=disPx^D_~#}Uf0OmLlpn*7Tlk#g*S0V<8_UE zfhxsrri+KCH#V{B@1-W6bwrUbOIfzR2qud7Jsr-+BDqV*YV1-;jCHe&ajLH)me7 z@Opi{>TkqU|8-+twD1X6`{^3%pJ0AA^P+`s=;C!ve?Q^#jkC;0UFRQf>O7o(h`#6J zR9|9|CtdnImmclXanN{v5%~{wJiedxRn`|+fAv4r`l|m>aV2SwGZV={W1-tPilB z`lecck@Z}7P$TAh$0w?O-*{W;2U+j`lhWT~UF*+E|Ah4&?<)Ok*5$0<1|0^!GWBrj z#V&oqr62sSbpEF<{ZE%31sea}6z-$WfA*uk7mio>{Nld@tO)3t0L-*p}D=^D4Ml4;8SbHJm2(ZcKdBiz1q zjeIHd|BrdmetDDmDa?!Z%SV|%#Jp&~yv2OI|EKCN+Akkt{%_2S_RHJMFJNA@Up~%! z@PAbPqW$s?^FLxSq*Z~v_Q@}*q`2j6e ze9^Fqj_>sHUVM!CMa+v9-UL55p+??B0TXJBUo=CFzmqLhe9^cbk1tE%A5N%|*ERAM z^IvJDc+tWayY|1jMm{l1#eb7|(W5}?`*-md#$;eZjroL8z=Rt86_hD|E7_lDT#xmM zz(1T&BOgHl6Kdp(nLo|EXk3qc82;ge+ADr3^G~)`?IHRlsEl5pwk|FHOLNG5(!Z`T zKWC1r-$>x``%1L%afK&&T_YcxtM~)Vi}uT#^AumyR>c?H3bbCo$u8}2zahxGOmf5oorZMsH(;SI`PAKLqZ{^3MCln;~Q?FBXScQY?q_=#HiW>8*qBPcJvu*j<}-OZ)TT>7|6KinzZ-^-x! z_g(Mt@4HOaAF!Uq`Y)_kxcG9H{#NI7{~v?K^P9KdQ^)6>SU>*0(t}x#WIc)X7}nE3 z>-FE`(sy)8U;m^_zwgpRTzZ8|pLOYaT_Jz?eOQ6d--o>c<(p$i@zfqP92j3(4L9(9f5+h+ck-4rj{FCS1n8;GfF;C+uJhG zVfKX|M{)h#u>K8ozWR1=r7hN>K1w^RJFqsItMZTZh4pZL8{_lYS6SOW&u@D|d3}4C z4H~zXJ+AGgXule7H(@<)FQWh0@Ak$^G5hNYJo*#8EsMWmZZqr;>_1)O__NqwmHx_~ z=%0c18qX1zKV73ghyDGP{fWl-b>LqZ{^5ig^9iGX2{rP@0o7hJm=|4RfOkH6ebAq- z(O)t9`wsBbUaZ>;O!qh0r7;!E*MxsKp+^5E3Ybu%|2X^G20Z!~jq8ywfPXllMqby* zJIv<~QoLxte1iEOGcS4#=r$BtnbR&U{v%ulHRh*l%&+L6>W{AuR{4qc%a<}gnt9QF z`55z!hp70XzW}Y*Py9t)_0cufCvr&Dr^-;}PxNBYUj9sU3=@7}`{)||*@uY${OQg``9jC*T@&2Qv89DiWe=s z9uMoIYvd!R6<;z+@uGz+ON{(>3z&;!x_lXU8gDwD5X7Jg@V|BqJ^(4fAf-xKWqxu zpSAFn#V;yXe1oZq7cG2c@e|A+W?r=LmBqI%tN7M56<@UQmBlZ)qWEev6fau%%HkJX zRs1aGMGGG{)P&lr{~hML%vAA33tw6M=rtAp$FmeKTKLN9UwmEhqstU8TKLN18#ff+ zY_{S>3tw6N*ZEw3*1}g7-^@|*f3`sJqJ^)l|0B7Ik1bTZXyGf1pJ4v?5D51_qJ^)l{&t>< z|GhF)<{jom`{fIQs{OvQM75u2zkG!Ge`j8_U%r(2PRxrIKAfXE z95wd8u5tWC?@;-Nm#X|l3-4&-1$kW~UwWtFUt(UgU%t4S;=3>}T6n{izpgQUadpMp z!n5|x*HC;yc-F#)tEdJ*jrG?x)&E|_e{Gp+zf#u1m*l1Mx<)?!fZ~6_ylCO$x#_&F zk+&XH{3pzd7QW!FbY9oU#~xAq9Ogv}Z{Z9~_|XiEu8}XUtN7QKtNM%X3AzoD${=3{ z{y9&jH2Tvu`YU=z`J2N2L<=9q8JO?`d0iuK|4H%tnHP=aF}_~ji!X*3F=N@Utl;{v z_RBl(DgH&~MGM~zXJEn)jIZnZpi4hce0%0aPY3PQo(1GB&t!ia*`Meux9Km+ z{vKMX+DG(HLElb(7W?}X`xD*oHvPre-{Io7W1{&sQ9A&@-gQBi+Rz0d7Jr7%!~HR$C>}$T9v~b6<@SpzKHoA%!~HRN0_hq zxr#5^FJH`jTjoXkRc$4Bq`{j)f)%IV`ylB6C z0rTTFtN5b*@?qwieW7^Ke)%Hi^R_5nv|m2L{0`HAzpCxOHS?nV@&(KvV_vjhKFs_pdsP0S{qjZ3 zPhwuQUp~To-d+`7v|qlM`BLUZ`{hfR-^aXYzkDh44IP!gXurJ4d~4=K`{kp|f5E(H zzr4kK-F+&5(SG?D^B*xU+AnW2KZ1GD!WY505l*P_{72Vxe#ZR&>{t0GSPNf3bc)wC z@VG+(ZW|2zm)kC%!?LYkLMNN zWd4i8D!yppD~lgve(Dj$ix$4J_%`#yjw)WX@Rh|+F#qRciWe<>W$}%_ss4ZFxZ*_% zUs?Pj=4+l%ylCMoiyvYB4D+IeuPlBk^RrK?_@afcEWXKnpHqq#EqrD1W6U37UbOI) z#kZM%=Cq10TKLN1Cz$WYylCMoi*J0S`u{TXqJ^(4ei8G(IK%zVTKLN1N4We%=0yu% zS^QGwA4qWj-(q}|%lBbkwBPtK<_|G1TKIxW_P;js&z$A{cjaH?;&qMt&jgpB#Jp&~ z@r}Q${{PlF6<@UQdOX~J>Kfx0G2e@M(ZUzF^4B%;5$5kcui}dqUXSM$zm)m*%!?LY zkB7XjF}}%sjSDKiXyGf1A7lPc%!?LYkLMNNW_~O4qJ^(4euDW&zf}2)7QV9h#>cAv zhcPc&_{!oJF@MiR6<@UQmBo)R-;a6G!dDi*l==KiD!yppD~oSReC9<9Us?PZ^QV~? zEqrD1ZRUSluJRWxd}Z+y%uixowD6V1H~yje|0|bOe9^*J7Qcx3511D%d}Z+?%x`C2 zwD6V1FJ->b74Co5!dDjGFF)<_|D0+AnYXQ}zF2 zaPJn5f6;#VF!Sx07wwmiFu#>~(SG?7=6{~2@)!O8Ir|rQ8LRh?{~xCu5<3Y=HA$kR zNhL)Zkwa;>Ns^=~k|Z`EDH;-@w29J5lZ1qZ6rma=e28|X^3lOml1kc1QK^3SHP`F< zv}XPNf9CtU9}mqut@U2lTKCL7duC^^oohZ$ekpl#uK5J{O69b^IoEuO{0-#Ix#rX4 z-y?6%H6I$q<9`H?Kh8BDrvIbl&AH~IECvVO*A0z)ad2_D$IQdys_57K0%_qpW%j5CKx#m;!|AD+Y*L>RMe>9K(|FM2( zv_Ae_s%hSwYyB|!1LV!Q=A+~n9i#QlmOtF*&qDI0t83nzYd%4~IeBxg`C{^u$eVM` zhsNmnPm?$2nvak_?pR&F+4An^z5L)WT{jL~K>kAVX3LiZZwciPOWw8Qqxb3jXOTBs z{&1gP3&>Ziq4PIeJ|@M3LoD@Ug5VHK{UrIt@ywPFdwJKAkCWd`-kfVbLH?pzx*l_``4suNrWwXwtO_C zhgi;^YdL>W@*8db*z$3W|L^*CE%_Aveck-$nPPa!jTgWeLbbU@m$MziAj1s zx(9jreuLTO6ZZ11GxH(;6!{dkeA3IimVDuZT0ceJYyJNC*Kf9b%*(r$e3JZ|XT1eeQbI6eB}p!>00tB`hP{XHc^7!?@hkAdT4u+7!#!F|Umhs|`>3F{|p853phaT^6Ki``7xQ^F7$Ooq=WS07J zeI?~iaLA3U&$Y}a^@QdhCU2Jhl26H<;E)^1yUwiVDb1(I$ML|^4!s`t`6=VMmhqD0 zpAGV|9&>OvGoM&+D~DL}F+p&MC7<`S&gWC|<|7&$dOpca`rq+f%XlfqYZ~NbK4z&W z=cmNWyUwg2cTJk02SCThdKJ4XPOFl25^>>js z=bDd@uh~$~pV{&;ufA)kUqpTqd9&r+`Q`_I>00th@+-)jbIli%|CYSj^6q@4zH6x; zc~;L~_0w5D&NW{|{|V&Hx#mmAze3(@dH4Ay^LH)tkImBgA0%(iHD63VdWNpwoNGS% zoYudOygAo=lKfio=3MjP*;>D0Bb~oF*L)HA@#M|9=0neG{rAY5bIli$uW_c%-<)ec zO@26ev*n9IdWhxu<653Sg>!WN&s%+LdH4BtsOMjr{y$iKFQ4@4yO#PzbG81Y0P^~6 zw)#;o?^^Q3P*vPx7&OTK|f(w7z+0;6uHCC@8A~$oMjzYZ))OK*xKU z@yya+z8=NA{Z(8`KJO*XuOV-?d_>Ft@9V2;$w$eb8PWBabIli$Ur64ZYd%4~#@Slm zoNKo=RJO|drO(y*n7ar5|1zHv#+%4^=3M6!S*(xmJLJul zPsp9%kemGAKdv+DS)%!q&SO2;@-Ybqhvj1#{rmnk^0Mapk~im?FCzaLd9&r?PCc2w zYngxEQmtRAsm}j@4s!DPk_i6DA>(D%pV7bbPm;fYyxHo9o&J({E%l4ZPa_@L&yzb& zeb0f8fQsezWCMUVYb+Pj1xw`{d1*FOWOIAvaRrwd6yaG=Ex@^N*z|^ZW~L<* zBemqi^lwexZ26eeU+TM-e4P9(p}d9&r+=a1BPE%hTGYQEMbI)Ag} zV{#`rvte;w!B*}U-~=aNj^&cVe)3n$DIC>cP;q@`8UX$E$_}( z@~$Ocuv6z>wymz;Z27QP-?iim$zMR;oNK;_`~dQ1%g4R?uBCq7w>tk<$(t?j&R5p& zTJjO{-;y`ynlB(gRp0^=~9^w!C}3CGT4D5%M$0n=K#n*6&*KMda6$H|Lr!A%B3p+44!R zzH6zU_(9iyaR)trX3K}Yylcs)$d4m$wtURXyOw--H_w0aX3NLDyz9*T$^T>X$CeL! zdDofw)Bo(tc>eq!^J)6`B5$_(?tJruzjQ72V?XNp7mznw-kq=HT}wVr{#Wv5%e#-a zKUHD5@69(l9ni$Z#crM_#Kf9NNj|9_&fRJQ!%@@+Y%oSSSYZg9zdKZv4TR!Z~ z-?ik^*Yjt#eAvso&di^D zTk=tyYd%K*JIR|Z@6I>q^8a)Fr^&xb-fVeyzLIy{SUT;~^_Ra=*Kf9bEa)PKSn@GJ zaEK)zBj1#~S=#0Ek9)mI-nHaQ$d4s&w!C}2NZxg({;xX!6047M%@@(aEK)zC11Id);CMLoWEG`M-H*%V}jriOFlvV z8uDgo&m|u^p!1(a-fa1#6blZq)ORiQljO^G*7=()AC_=%SU#N5zw<99e>Hh?uK5!3 zbI6-5@6Pv7^H2P)>#uN?&fjc#cfOK$E$dH_??>Kj`Ixg_$-9<(_z$iB3VE~T-RHaH zT}!@*e4Q>je{-(+(4SiWVe)3nyU%y2?^@~?9Mt@0e`vX3M+h zOY*KIUrc@=d2_D$$X}d)@@C5)?)j4@U#+Xo-)wnzy@y(V=x?pxle{_Ce3<-v@@C7s z=j%}CFHXLMyxH=HTYuyqo&Ocr==#l;Kiv8Y$j>KlwtP`Y53$VOwLJc5@_&&xTfWfC zyOw-G=!nc~Q`c@fe{-(+6#13p&6ans7n#3nsh?L`>;FvNZ27P^f7g#rnlwtU#jyOw;Me4U=0 ze{A`fmv=4sH2wRKH(TDFZ+`HXt|eboN$0Zd?oK%@=5YFZ_xRhbIli%zlFTn z@awK988Czr3GM$(`Vk8_B!Q z%%_UxC*P>~7`A+|mv=4sNS@|zy-D-tT=Su7n*W2m+44!RzH6zUJVx`^_2TiwmXFEe zgF`Iqj|qZ9Ecv|ZnqNcSEbVgs!ruQ+be&m$4b5NOoAqPMr@g%EO#S0DU+-qk=V8ki z%AMel8=1dr$;WGJ{x9-o>7UEzxitBHeYC#W^6q-2zH6x;Izj9IL*8t8cfFE#E&23G zn*ZPy>SN2h>y^A~$rqfg`Iq`?-fa0;Fhx1Ul8*_3LoE3u`4eu{yjj|FdHjn{(fTiw zH(TCauhe&)sb637ss=~r)&Lo{k6W?@+Fz-|JHXc`P3PjA4%SvYd+aX^IwxU=bBHPsrf#)>-^1@kI0?i zkQ+IFt~2XztohC4i?QY1^-A7#X8mVrzQX{mpTfE3lM&6w$(t>onYc55*HS-uw&uUJ zJhpsP?l^hZk}qkZ`GSEuf3xM?_2x@|9WFBs$*0fJ{5bMv%e(a??^^QV^EAJQyxH<@ zy+hT{YpVHZaAC>UPqXDS6Lr?_TI%PWuld(3k1c<=`k`i;zjBb)H|Lr!A^#M4v*q3S z%KBZ){7Wv-`gwzS{IKN@H~;j7ntztOIoEt~bIpH3-fVeyzK5EBaSP2~bcfF0Z27~@ zKXsAjCzCf@{&4kEEj53{5Up>veA0Qo%luu-`7gX!^Fzs-Enn>AT}wV1)%?%o&6aoT z9jbl_`Rj)A_+!hv^(60F>Ze+1{SU~SEq}QBg_mgl)L~lRygl$()-E?T-r*jP!qz%o z}V4^C=PhkwYx=NeF^NEctLx&F>*^mUhX<KQU%y}Lo29?x4|_evG(UEn<_oapOUeg>1czAayO#RVzM8*gyynf8559ep zIV|s5@&yAlUvUEUvE|+KovH6U9+~=sH2*dED7Jh;%l~iwt|gzQ|Dp%9zS;8b`Ih>w zB_F#(>yMtOd9&pYcmDH+Xujhl&6_PBE29e#OMTZ;zwl1YpYovQ&6Yph`HPLv{NLow zmUqvW)ORiQLw9R_!$Vr%YOX3Ix|CCVX|d{ht|V#&wIZzFG(cDer2!5=xql1~eQLoE5|IIaKa6s>QT zcF9NNPH@PLrDOmnm=guvE|d5>i^E) zwdC_&)cl&KbpB?`C%n9C$tTG-ep>Tp%g4OD>rDLxTK{|UdH8>Mxf2|6lOO!YKYxV_ zHQ#Th);C+;JztV{ovHtl=D#GLhb^C$;=v)7d|D73V#$}#f8jG)-z@F9ydD=Nwf^zJ z#N_?G+48Yq967{NKPCtcai%``Psx|yQ=dKb>q*3Wf8tuk3oq6AbPMt_AG6ex^`wJ8 za)@Oo_SWxO@@evk=XL&O%O||NYstso)cOa>n=K#n z@~$)W$HN)>ck3Ohew_Rg@@C7s^$t}(^sd%F`vt9U zw*2Ah7my!M-fa29)h~We>mNB^>zgg_KHp^it~2MaSo3YjN3i9KyvN_Qvt{r*jCMd zPTp+!n3n(F>$hvkr^we>pz}9dKJ3+ZE&24PT7MLIv*izW{v)4h{v+~c%SXNWyO#Qe zX(o|;U%5F+4AmsCGWa%;P4l^{*mO(mOtG53(0>( z-fVfd-l6Iz$X}S$`I{|&xb>&WKSSPZ`NPdWvR&7|jl9|Nhns(l{3(ld{$|S`ZvF}K z{mGjxUlh_qEa%U)Jbsb1&VL?xv*iz0zmWW1@@C5)Zv6@JEtc^3VapeI^LH)tFQNaP zbEuy8aY-v*nw3^<6g(zSldqQ~AtmbH$f+{$|Uw9fZDq2mM_)4qls6-8A2d zyxH>Q-1)H9io=3Pgs+3ov0H+(z0{Tk0N zdfx82`I_wfZqKj3lihyN+H61Id9&vW)@An}>-ihcPp;4IKj=T%{>^i{4cYBeJeS&- z-QLOb49{yl-}-KLzR{*^&-DDE=Q5kK`(NexNzdb#vh!DYe$4aho=^TTJAb+7>7L*4Tz*S-KH~W<&(C_^=ehky z+2f7({JrP8A7}T!*7LKTOFTzE$<9CH`4`Xaw`TWW;CYAVPJTLQH_PgxG`Z5v-^+q zyv=j{J;C!mFBIA}P_N%+_=rOFWw;*hfg9i(aVLBS?uLis(Rd=BfFH(-@w0e2o`b){ z%keJ!IzD<3uRpjJ-h$iUo%kmFJC5VZKk4~cj!(iRxCxF9)_RxXp12!+0N;j};!$`z zo`NsGL&uwq=i_BKiC5tR_&r=>h~~e-*Wq7r4F7?X_^1+H@25D7f5+$G&`=$}87{z= zxF6n&XW?>tb$y#~ zEqnljq~v@ z_%3|JK3&gjd>o#KPsC|_Hm()d@!R0m_!>L__rs6lk$4R*!aw2XaP84L{;T*>{2$yN zZ^m)_C0>sA;SyZ_S6%P%V|4u5xGg>t55iIW6ut_t!+r32d>ankr{j;p&F~c53(v-r z@iP1x-iUYL?YQb#9sd{H4wwH;*Ebj+kDtb8;q|yR{smuyPrP5pzYT|RA?}99;vzf) zufz-RPMpF=kJItD;1+lnz6Bq|eQ~M%y1oQH7H`E3ahdTt{zbSk?u4(!H{-GRF8mUH z2q*DWybI64kqKIF1s;kw0d?;Wuyz{s1?4P{-eiC*VJDF|P8vuD8NN+P^OD zi<{ykz6|feJ#l2R<_B9IkFz{}0&m8Pa4~)v*LqmTTZfzCPjNGx#&Nt4FUJ-B(DnU= z>)_*ybo>YoE&dg6!)H#_@%G@G zap^yGeSL9xoW#fD&G;-_jL*fj9?|jJX;Zb-!z7L0HYW^|Y z8NY}h!*Am6@Q1hrZ^aFs(eZZU5jgahuJ?Id9q-2t@Bw@#jwE!vR(K4)8ZX4R;(zc+ z9C}vsV{kM4D4vMt<0AYL-iqJGg|l?LPjH3j)IZ<^{s%Xkt?kGBt?Mtwr{O)gIj;P? z_P-M6;V!rv?u%>9(f;=YcE7*#qUZm5F85D%|8qUZJWuw#*z*?8`#e_&u5j*&d>6^+4CQs z8J=SO(n;JNmZ+5HE4 zUgP<9&y6c*=ZAP+;rTnywT{Zp=X)OOdB5i;t7PXduA1#7o`>aSw_kX4wjc1k)pN6I z+5KmD{?ha5$7J^(;dz7S{OZ~L%N(2S<(^yA$ZkKnX0~^FzPeU+`x?&&JU2QnyZ<21 zuX^6$xmxY)d^^wgc;4fA%JJFxbL(V#j^|rX$Zl_RVz%R+w|GA3r0o9vJg@a!H=N!7 z7S9VjAMo7fI_wVa@q36AxPdGn2-^Ozf&#OJxZ?j zJKx`P((^vgwVP+>M|u9rbLAG<{hNA@d*0yr7teJr${z1#&x<^N;yKhZJKw?cRL{S9 z?r?E-{%Ox8o?Az=`;YOw+H<{D+5P)_e$MkY&($u;&R^zvs^_0Qw`!f8pW->~`K&hC z{U>|g>$%;f+5MmLT;jP++wA`HJePPrtzCBio}M4|yxDV&_SyLxJkRj_zUN9Evh%Gy zKj?Xj=OZu6&R^nrV&MA61pgjl`ca`$!M{gbhZDHs<=P&8RNFh_7@mUDk869exO(vO zt25PAJF3&TGcLi?ap)QC{~6B1CtjiXFunmtZ~{m1SGWM5ny>j7?t=^Q3pkE<;v!t{ zO3f#5Z=A&QaSE5&I$4|o>|)E=kN05PH@OgChu7C z@vrpX504>lmTtM^i@w(U`{d1*&n(`l?^^1o$(OoX=l?%b-|a8+cP;tI4y}Jad2_Dy z(44$G%9QcFIuQ}bKMn=K!9`b&M+l24Iu z&{fZ$+43#PF@+G@8zl^+D`pfgj?SH6z>U+)av-xAo zAMW{E{DbCOUZd+bTRsxZK@PFhcP;Y|?biG)awj`L4k7?`f0#|HVo8Q~WeOVy^!G$CvQgcr_k|Kg28X zH+U!BkIT-}@hZl&eqDS#Zh*tM7&pOt@TK^;7j(RCxDCDy55%MJ6L<<v?c1hxkzWV)7Hon=PM|JHcUj*Rq~? zB|RUT$eS%6_42MIpE^?W^={Vrn=S9Y|B?B-mVDk(n!lC2+4Aws?Ejs=YsnXpe}}xe zPMrB3$=Ih*| z^-HkjFFH26zH7-xF4X*V@@C5iFS(gRoSDC4$w$erCvUcV*y%5M*OHHs|C78q*Lf!$KSO){)LRUjq%Ku z4|{pnk}o1(dw|ZzoNGQw{uc7)T=T``UnXz1e4#gg*E0WTD?Ojb4Al9XE&oDQ9Y8GS z&$Z-Bf)`Y28%*9Te<#;ZUhqc_vE*G#KE(bA^T?Ym9}c?6Vfk=IYPtRjx&FQ&Z?^no zr@vf(=JJKv&*v6_<@$S->#w8N{*1H-lRxJry*?Iu?K?dmKPY?rj)CR--wpo%e82m? zpuI{k>G7xN+Fr)*HBj%yH5;psAFTaT&D9-o&6et$ajDPLkKzvaCET!msm!@eev_(PH%!9NVJ)8y9?}?l462MT5&^#(My#@wZqu;F8Dg)S=ox z6l@43?v0ZR)$6T&k-GUX?H|SqaRUEk?JsHnEAC`HYt#?nyyj&y_15F$ICaJ0+CRBn zJrSqy8Fy)WG5!DtAAmFCO&X!?dHCqNsgIZ70({Orw11`fCvgG(5+`uok=j3vd*jg8 zntuZq;F|Yp{}TKxj_lC>XT`O>5Wj(w`1;Y>9{oo9*B+xz?Non?i*~8+yieQH->Wx` zRVRK>pE6Eev|F7RuP*peeZm9k=pOZpIEgz?)b`j<+CG1hI$WZ@@IiGk{s|ZTtnKq2 zBEMH%Fj<}Vi~5C!$>R%))bV}VUV@{)s^?E3|C_qgRCNl!@Cf<++J3<_b>x704=%y; zrfYlRcWpoBF?H+@^_w{FPxZ7J+MdQ89#qV0Gr*Rsu#EGl)>)%cs z>7qVzuI5wtY+Q7;ws*zhuIi!Ijvur3YqWg@F2-qW`vFy)r}ganJ7;2hKYA6muaEbL zWpDd2I{pk?3NON?@hV&fe}>EAvM=a(74Vrj4|m12@Vz*UU%(CUhd6@s=Ii*)a3|aj zKZU#EefVa4{)?I)gva8McnzL_D=g6dZ71mYsfXL+DDHr};>&Pvd^w(oJK|-y0B^@# zaCo8C?}cx~gYhgp8vlrkaN|Xqe+Cc4i*N$3z+3TJT=gZ*zmMDE_=9>rZo;GSa6AT& z!^QY*ycPe3)3{+$>+QnV;Szi=-iK%71NeP>5dV!s59xf*Sghlh#ocfPd_S&?m*70S z9aqPdm*{x4@CCRI?t{a48m@=m!VPc1unHZmE{=_%pGgoQ*O}HoS zg{R=&coV)E|AYJB#;@ymx8RnzFV4re;-0u49)NGdqi}yb8Q+dy#RKt=co6;z+x|Oe zy`l57{dam|+ka;ow*7ZDV%vY`7i|0QocgAYXZ!D5gKhtvaoG0Xc^%vSJA1M1zf(V@ zqKEJLL2cK6fRMgL_|HV=K1HKLag&)9GS8M*mN}4|z z|BTPU%`0pBrTAKW4SuJpw%>|N@ZGpUp0-cMSK(*zAiNYmjMw3HcpLr)|A<3J>-c+d zGh8nC94qIiE3Snn<1_HcYMO6}=iyFxE$)qX;5%{YV>CYzhw;<6B~IdH_-*_V{uqa< z>v-ScGw?y&0atxn*LMr9i|@zh;pcFByc%DJx8nggbgb4NjnBZ-a92DR567?JNAX6y z6n~CCz(3&(`sq|&G-hK#v}1w{3I^>j;{AdTm#oSPRDDA`{5S&V|*oUSx5WdgnQtjcp9F7 z-^EYj@9`pB;RGFTHLj1h;7<5kd@ue3KaG!CtLs~j!+0k?2OoW+)@zGf;A`$>}4Y(%$6`zie32VKJ@Y%QkUx|C+ z+wm|w2|s{ez)#_I_$B-eehcTFto66x2;PbF@d4Z)S6Z*@n~3Y+dAKoNi=%im?u>uO zy>ZRDI-gH6NoHE}VngF}tA-dXqzd*aASNqz7}7P$KrwbB|I8$!;j!{=j!;+;|N}c`{MuL1pW+f#6RKF z&(rZr7wh^Sz{ld%xB>nhH^*l;)qFl4hHu2v@DRKNkH^LM3A_g{#P!eD@l&`H{t(}T zcjBe^cf1`}eqY!37d{C$Xr|*g!B^o+@gUp{KZS3@EAS}16;Hvx;n}$H1zK+zz7}u5 zWAW#B7B0alT;>B^&lk7`K8PFQ+81iQ7PuL{5_iQn;URb^o{A^nBz_Wa#*6T7yc$<( zuJyOz2KZat7XN{JxJ*e!|)vZ0Dd1og@3{? z;o2ALcyHlm_#@mE@4`dypLi;+@{z7DiBHCx@ws?6Zig#HwSITp0N;+=;yCV&AHier z9Gt+*@kYD>=e5#$pW)_s5AK6QAM1Li;A(gku7|^y=y*->YTO>*)SC6-xwt>Rx{bDv z!cX8L-2PH+pM~$hOYw5N7MI|yxK?}3e~(+^gLnY0@`trUxVA=F}N#U zi2LFsz8&wnOvk$yA9J~S3T}yK<0yUsM>=Z%Rrosm9v+9k#2fK1_%~c`tFHIzD|Eb? z_&3}TSI^h>=J;ZK1-=vCfT!a@cpttGSG!Wjn~o!RF7At8!;j#N_#6B=&MVOIe!@55 zQvcQUZSAD($KW!Z)u-b2_t|cAfec9KBv$Zkw+6Ph1lp*HhaY;w`wjwcnuaSKzZ^>KpLeco6P= zqqg5??RYx=6VJubo3#H5JREPr=k(I{G_KoQ{R{pcAMvTKZ^_NtejHxeN8JdY)K`5m z{;Hq4Gp>D``et0Qzj`=6fG6R;w`=>;xY+>pOL#V3jpyODI5trGZ^gFX`S;lNJ3okR zzw;`e>3VIy^JB2>cYZ3i{mxIvw%>URZ2O(J!nWV}RoM1B?}lx^^M2U&J0FN`zw^=9 z_B$VkZNKvw*!DYr5!-&}Z(!T+{C#Zuo$tW5-}!!Q`<++%T+ff~cYXr4{mvuU_B(Hl zZNKxb*!DZW72AI21F-FPJ{sG8=hLw5cRm-}e&-9Y?RWkrw*AgOz_#D{H`w+&{~p_Z z=YL__?>z4dUBB&jehRkz&YNP}@4N%H{my$}+wXiJw*Ah>VB7C}I=21J=V9CLd?mL1 z&NpM*@BB+_`vF&%h4BLL^8?fzn{yDb&&P%ZEcU~r~>#_aLYhc^&ydk#z&RbyH@BB(^ z`<>r}ZNKxO*!DZ0fNj6?C$a5!z6jfX=c}>pcfJMNe&^p}+wc4jZ2O%b^`)-Q_B#(_ z+wc4wZ2O(J#kSx1wb=GM?~iT2^Lw%FcRm%{e&^3)+wXiiw*AgGV%zV$7~6j5Ut`ZNKxq*!DXw_qDFi_B*eIZNKvqud`Phi{cd=a+&&R@p1-}yRh`<;J^ZNKxMuUwRz^BUOpJ3k%Ue&;Q*?RVZ9+kWTQVB7EfHf;Ny7h>D* zd@Q#8&SzlT?|cEa{mxU^_B-E#ZNKwf*!DX=h;6^~yl-{Aw%>U@+;_5m{cMJlxFfdx z&STj2JHHv*e&=^#+wc4#Z2O&0#kSx19BliYufVq7`DSeUoqvUGzw>Xg?RWksw*Ahl z?$Y(ze&^M(?RVY)+kWRQuqu-}zE(`<=grZNKwP z*!DaB65D>~JF)F|{s*@G&Z~T<>$UyP>tfsQyeYQ*&M(8Z-+51L`<)NQw%_?UZ2O%* zfo;F@McDQ`e;M0;=j*WTcm651{m#?a_B-E)ZNKvh-|PBpzw?RUNe+kWS3vF&%h4cmU_+p+C;{tLGK&ddLx z>$UyPkH@y(`B~WZJ3klOe&_A6?RVY-+kWRaV%zV0D7O91AHcTX`P10;J70`#zw>vn z?RWlPZ2O)6h;6^~QoD71w%_>?*!DZGjcvd4#@O~Jh+^BHpfk4p33_AOpI{ia{Rt*u z+n?YGZ2J=|z_vfZ8`$+n=B< zw*3jN#kM~|e{A~`+>330f~nZ{CwLy){shah?N6`~+x`S!VEcL25^O)uT6&MJ$9|r* zI<}u@t&i>JS({n=LjC%4nYH5{*nXaGfcWU(_r2AqocZ^&vvCRDhGRYS=UW^8r2P|k zIF9zz_WC8-9>-g7te3WT`I$W4htqh-UTqKc*8bIh2`oQfTcmD{LsQkSny0Dv;skEA zPxEO!9EaI|aVfU_8GpvMKjS&SYTou|ya(I4`@D&+u;ZvjidN=T!8oC7(VTH9j_1%#c@0j7vWEF z0w4DW>&FE+h3~_~_${2q<^I%s32u)=?CX*?9~!i#VTPU8c( zW?3CC#LpLBfh*v#I1jJHwjbv|*!JUWUQWlepI06nxN5K$#d7M6z$rXN9Q+{Q!MghM z#tCuNcqm;?Uw=Qu#rU`*w0$e?hSO!W{|ua)cz^j z@5Uj<+kg}FuTxq3hbrp)2I3U$Z{cFj@0mw2K7Jgp$5nzKew4?r0{MI#!sBrX{a1^F z$G;grpS};zT~dn>(t$F+3xC*I9W@_dj&sQNBtwtJ6?TiH68z+#HIanru)tMQgD z>O#Dtn|cyH_ZsyaoVZ%O8n?Ve{TZ&;R=pq3Y@@Drtj@1eYxS9U^5eRm_ISwC>Rx!y zlj>2p`xENN@r3>ArFg)f>i6)j-__saE(g@*YUq4Qj@0L47=IjGB=Y=hjthcKAH-ep zs>nmV5*xIVrZx5fL|AEFN~^|_8W z4p+f*aL+EJRbkYt(<@ z1pQB`t@ZXDtK;>=_i+6`jz`th_APis4RzJyHUHEZ>ejd(*Z-Zk{+ZhTBCgv=y&cc& zr}L{`N5`wr_1^(E=&$XgaJ}2qFXKhMb-ed+Q?CD?aI-$ze$)v%{<$}+&%m`ht2^KX z*Z(be)>YbmKb}ed=kS<|wS6_N#Pz=&S8k>4f8h#I_3u{?lD8# zhvIIJsUN}b?o%(uUAX?=!(D&V_8)QQU)4vR#QCVG&&P&%71w_|{6-~hzZtKf|9u&U zLZzE)`*XB+=IhPdcmdb<*LZ1LtzRar^_O0%J_Ucw^S2F-(|$8v-$wh7!&UHH9Q{(; zH{#8_KKz6q#mAhi^?Ty;@wTfqf1SCt`d)k!eh%;9^F?CrahHzjQm5$nix%kk^>LL&>W+8- z{RiXH$7uUBJc0SYhW9bvb{u8?rRr(DO4T%f1|EmI;2HEEhWj$!len1kvl=JjI^NfK z$53^(Q>9)g)R*^TXJ#C{9_MNMb$IQI>Np-gUp*6FGF8vl>v;YY^#|hM@k~Fck7pW( zC#m<)|1BQ>GWB)+N3gzgaAVfj9q+na#~*)5?)AR9asxg874W&Z(PnM$ zf%~jfkIXn8>cRE-0)FBwo&SGuSNt9M*jmjW(@^WZw^4l&9{L~kt$62~>go9JW$HI@ zXU6+B<9KLtTHDKn<7?Xf9Qjr}e&6BF!KQD) z(>B!L46Qeu>!UCJnCIt8{OSw(d??>Y`+r-c`7ZeE;o3e6ZyBxr6Ys}YoT>RX)KB13 z$bW*LenrQx(pdXHNc}eW2|NPN!%5s=f#!GOADZdoTjwktuR89G?-`^0@4y3j{do>w z$@%*Nk6}I4B0An{qcz_SpGZE2`}2NrES|ypwRt#<-^B~)UxEjh((`%L*;;QV@7GSp z^>I7Ag#Nwp2;Ogw!E^ZflE97e8+Zl%Kf}|iQ@@GUPw{@OC2o%g;w|(~;1;KAegp2y z`?Yi)Ptj^hLLpN8wU)c*5uKJV97;g4xA#y8;|c<^*x{{cLc_iL5U)AiKH zVZ4O?=i>gnzP86Rc)!*IhjAfZK>x9LOL@J1X5bL-zZT#L6|_BttK%&h2iqlmtL=Mn zXI#6f%s&)*cel1T#yvNwJK(S0Ro|X*JS4v-P+q?tpuGX@vuQ7$qwT9{AG=ZW+i;xz zf8%1>k2_!I(+oGsIQV{CNXNU}{Ji=WJZG+YEct>TwBECL>38Zk>Hh>@KX>DOJN5BB zx|!BrwORYu$5TI1UxEuiQ+LCAIbZ!Uj)!XTdiDVR>TVr>KHkUc?SJvidvyN);BUIQgTt&(1g$x{UR`hKFs@^?ZaEZBze%pJ07| z;Sb)|_No`^`D*;0`efYX3w2YRw_V*C52L+r#_`a{BXxe0aBW_{-oS4))bq0o_vig_ zx#n6wlGgF-;wE2FABSk~f=hp+?R{_qJUrugXktfge+u`+Z{o&1wEZhQgZG!UTj=BU zU;~|R7rYHWj0<`EH{gkPYyWZ=X@1Elbt~NMF7+t<71!T8xZ@IS54F_%A4&CvxZ`5= zP&|Zs3viVAe2qh#|JoPpcsu!e+6mWXyh&L0d6L(IwYW3$`wMToNZT7nb-a44??$|c zukX`wZLWv^;IH_4{}=wFg^t&xm5x_>q`EKeI!rwuhwfB=k7vH5KJgOGcjWU>Cp;71 zkMo)DEBJfP-#2(3&(C99>v)s#rFaPA4aYNid=}sn`TX$(F5-Hq)<(zM6W8mb9bVs8 zeGe|n`?Xyq|v21UX5wmej{E({pr^Jh_-LQOQ`oJZp-UuqqaI;BYZvH z&3IFA4Za?(#jBXleq1_Vucs5*>3EHCYrOUfZSRkVq|}e$r)V$EI25YP_alC$y$0`3 zJG9sF2hY>T{~5dn|Axc(@($X+FZo$`7T?eR0ap)x&$~ST&%I3h?>?v=iI@MOUW-Re z)cQ3q*Zv9d9VEd!u?e-qTb4CocP}&M#J= z`B*~zHeP~H>!j^f@B_Fj`5*CyI+}0YS^KxBt9~3;537H|=@ZnKUZwpjJfVIL_kLXc z4}KN*=%W3r;bpix`RZ3|``{*;?}c}quU>*zou@9-Z@OY2EQ>xUHw|^KXI_SH(v6P&Tl@hg7@GUKBv3p zS3RixhvBl5)hqGX+thpUZ-wfH*J*z90CfyM(O>--erk&Pb9|skeR2=YUq*W$Jcsrd z@E+Rtn7e8I)ax}L>#6R6oAppXg3ESSZ@{CbtMhtle%my47u<;U$MFQ(Kf}eepL~Pn zyS3GPH@x9;^}~2p2lZM!pq=_JT;oN3{94C!ym9l@aF?Z2i3jsgH5#m3wYPr>L2liv^Tj~^N-R#6n{bc3S22q^FQNzj#W44 zqxmk!sBggGqt%b%u6%ua6F0(tWE}kdq!x^Ki;NcvwZT{5&3ru^j6ZIv{U5`#@G3k2 ze~H`UN_}z0P}eP&%RjuZ^i}q7krTMYu&2n=Uu)ZdKs?4`@y03 ziqZP`J&SwK(DC2H^?IvI@a{*{Rr~4q^KfH4gZwpk1&-s-@B+M}myWjycb%r*jjQ1! zZ_|23=WF{-cnN+DZ^g&-*Z#kK&+`*U`2J`T?{2K){e>4M)u-LA`QMwV;~9rSUnF(B z>39uZfVV8x_P6mK{3)J>_upd6$P5b4z!ONQOnQ=U{ zW4^xLj>ql!e7G2=_&oTDna@{$;k6;npHirgUv=^w@c=vwuX#cH&%h0+zY@3L^UyZj zx1sj`9d|3Gt~E&O?PI(PaX#Z+kAExD^~Q1cDeBp{+Lh`xIMiOf1J|d2`N3K*j?ciA z`2I;}Jc9rKG#bz2`ynsjEqs6F1H6;ZvsLcU@r(F8*&46l^Hm?*i_dotKwBL+p@%@-F8HYkAM)mr9hW1+B)UVOLkJradcmw_t zKh;M2|Bm0lM-P?xg+hIBqm1LBrPpZxwz!Dze@&);g#NSeAFZ|jtMtF8qpoiw-i_0E z9{v?q;(Rq8rt|q=gO1lT<9Mk3KkD)Ll5zTcOyZVf)&C{`Zi)6UeW#xPd_M2g!`nYLey8`C}j@4P_UpT@m-zHh;`@6`E~9iihzXg?S48m{fV@f|~Tys`N7 zL5z>1w7-fE4A%Dd@aH$Ff5OvvKV0E%tv{dklkrV4?SCO|SD@~W|K|Pc9k@E}58`*P z(EiWk$L8vK-og32-~0mirhPxI^St)YyGQ3YrJO#0BDg*84?EzVwBLkl1izy%xQs$~ zgutNo)<_4_#1R(K?dYn$B-B{^KgWevcTh{d=@hUyBQa&xLY*KAUlHXTACp zT!4?7Ao-wuowi?$i}9e0H!@uRYlzaC&KFcaU`T(X6*;H z{`WZcm-@tsj8|Rzcfm!q)i2^i1@%E(Qd)h*B+VDE)$#7Z1#8qV;@BVRZMbkf{U6kP zP@(q z{2ucXZ9l(A$1hB($Kc+*wSMU-wDbM#G5FP6wEc*w+CHI+dLnMwM_u(1Z6DD|Jq@Rr z|2w#EJ#F8Mqxa~1PMSvjf$EO<2-b5K9!vfU+<32^pVregUzg95%W!mxj#ukZZO7EpTku+AHU)`KkNBu_oU`itamytdRXg!jUzlC&wfh#uN|-R z8G{c7zu;3|mOjK)Sa0}g?f=w0+I~Ae7q7s@the+`?LUb1-h+>%|F0Pbzt8Ypy`G}a zNdMsX5q_#3n{hmp>Z;fO9NLRN)b{`4D6X8)eEI`zAB5xhXjlPg1>*-Yd1na3eOYO#Nhj9;_hsS0d54GU+cpfg?qmR#i9QsLp={%i(Y@hlO zTwF5d%-{2ewF!K_47Edoc7<3N5u7f^q8;tHh{ZZE63QwkgUz{k={tsJ!@~`3){XfS?^Yx3hw_D}Qv;Yl3l{QrnchHJj-O6{M*3vr0Y?{8d4{>oL%hyKfP99Ml^+r#8z zI7WUkF68-g!5i8?ieJJh@+ZBi?Rn%M#)Z_Yl_HNHHj@vn*7gGOgK&iYzv2+S%X4{#Cr(}K?l^8P(Z zy=gd(f5Hjsw^^tC!{i^w#UptB-~>KD_*^05$EbfNPB6b^co+YE<^2C>{|)$g+=Tc0 zc^kBSHtoZ445x9?mHK*k%SP(s&v1&@%gf)@_B5}TD{uk*FWIE+VZ0ot$v4=n?ZxD0 z;1bTyxc9U@g>NcW$M4ni)$DzBgzK@&2kPVyZT}0$@wN}OJxu=p;p$G{Wvu)Ek6*|Z za!5#MvSoMdOO{Cz5-0oKB>Q?0Nn*&BCC9!b#=fK+vL!TjBApN+O!lnD7E$~^=e%Fn z{rkJ_$K(CGf6x2#`F^kOb&O1%sylf42|2>`r1eQT$avo$axDG-Vn5z}O7$?~$DWqs7~kNG9L;)*Mq~%y#R1m8 z@lVzLj30bfPNcuZIXR5;oo7DAU&OJDUvWY8Am`^z92l$HBi}{poX-t$Jh$&)x4u!& zXLjSncsc5l#=lcgkN>UkOU2}c*vH?WX)mikfLr1a+h6RO?cc(&-)MVX{$jlg*V%V)!*QTp06y$hk3u_8t%gLjhC*ezgsTt-vFG*^ZCQL zDz1KA{W*DlG6BcptGFhvcticQ?`S=r;fwse`U{TxLF+GiQ~kcR@<<%DQcj(ydcr(; z6pmghr@Wo=tzsXunS*3%S+*`JTGf0*h&<0u|)Uinw!6Q~cs zvDEkD5cQY-Q@@{jcN}#@>)V8V9KXBR8Kdo&e9U^8uQQJ4`VqnouOA)95$ai=Xnch0 zQF9#ENAu6Y{-Aso2dEde*AGfj(SN9aA&$jq z?RCba?S)RO-UG+tUvc~?)k~*ReP!{1%Rx zpzRIC;gRwN>>n-P#PRgMnqKpTsK1A!C#ru2b~qol;UMS3Rd+n++Y8TXzIf_2aF}{m z9HKr22Y%7^{&4HlHJua1L@@)nN^QZClACC>c??Z1=SlxsXz3O=3k2w zAIRCWsP5o_II)t(U&GN))L%EN`h$<aF4wU4 z6_WNpzO=?K!vX5IaO9f$tGu9oAN~x7i)s8{ZvBG#OJ!Go?0LCA4pINXbqS5npF{mI z^moSz=QRF19CuNEH3c5KZgUjn7!|k zbi6{hRquxrN^1NK9OV3{^b-5S`7<0Rrd9s|9OitGNYyS4wkH5h_&WAfV;a~Mv z&ZF_Mcqk5YKCHrVoDXMkG|rq?oGs5{~BmxfhD6 zo={cwPOiDXZot7bs;4Wa{@5Dw2pn^OdU4f5tF*oe*jHZlGp@ORmoCBf@2USYoak5o zLmb>Ie_T@ie&+uNJ3OA$E~R=5*Mlk8d8GLxIKuPw*X?!O%yxZ?`c3n%zzNKst+eXl zQmVg=qqu$yck7om|Mzaamik|`*O8Ov5C1L?!?DbN1t%0$-B(uqiDxxmGaUL;9*<+{ ztN$8~-zhgK$Nn(?796Rf`W?6KUZ2XdK1cQUa6&!#M;x6Xzgj{44(CrCPAsGPZXD)% z_Aic2)cVU*)cE+7a!VXKCVz$l%jB=IZ?}9Mhk5>!xsv9KJEHo#I5bWE5=T#!!#HM& zd;y24KU)z_Ghkab1yW=?O;I_N z3vyS{db;2@aEq|&-SL%<^6&UaH@V(x8b73~{4Gw`M$TGQ^=7T*0XT0L`4Ya|Q*K*L z{R8nXyr{kEC911_`+a#D?!f!|X=|vywukCN@XYS=CEV^kImWO4mF?v3@d%E`Ib4f> zpPK)5^*7-C^Pc#R5gNY` zc(-{=^{w?Z-zeOBpZpJgyj$*FNBtG{%9rr>?0>7esyp013Ai2Wty53+?Qd&*KYWPw z?ZoZ)e8AAR)qib}`u+9gK73xF%{%hTobR(6$frI)jnfe#u@lEBl%~W5&=UuwtwcI~{ z!Mz%*zg%r1xo z>Yubn^UuJ&xjz@{p?VLlPc!ikjDLiOGya2~>L0}Q@-p7~t>*9BOZ6D`=Q?gQRP}DX zRj(P8FX7GfcZ^j%7e0qqaDQylNA*VBe!Fo2=Bw0K^`m@VZ#AyJT-z(qPxazF-p|Cf zm#LopL)ACoZ}0xLsa~7==P4XBR`WF-sQNP2 z`?Krbs#p71_2|~}H+X6*InN-~A86 z{*d`X_&LVEFhuq2+`q@+=a?_WP}MIE)b@tpT(jkSxX=f3&!GCV&6028F?j4S)pz5f z!|_+@UyS>*-fEwz-k0ma_xRx)^_L%^`f09Lhw!Eesy7&^`T*AZ6RyDiR3D}Kf%nzF z21nyUqg9_8P<=Koxl}GPM)fdWj=$jfRhKcmO0K9=#{;Q-@{j8lCr z_n#0BFkg=Gsz(pd{L}E}`EsTSsxRpzkHYIYKhl4pdQtip<1V=NMAf@2*7)r>8|!Ty zr}|^A-@oHIi`3tAlIokd{qEob<5iEHta{D`@^$>jhjRNVs*h?XAH!GL%JrwJ-T-gI zvw1x1J5BYuJU$ejE+6H5KZ$!y)_hZDsQx*RXLV-EX}Eqq!9Dk?|EpQ5pWZ2VnJwq# z`kektxxhBnkKuBA@wBUu>HO` zhUf3U<7UIOz1Nnje??c02d>BSjYoJp&j*^VQ2&q)>R*k=a{gufTJCB3x&Nd=C$vF4tbG{^`x- zx%j8{va?S0c>Z3RgX>IFJrNI{D%V=C{t@rV%kYB6a_tSO*J1l}@L=YiX zcO2g%y`J?pj(#A2frIDejX2?^d>022<>>FVeP5ciPSWSwo8n+xSNcAW4;)sN$ZFJ$Kj?SCA8)iwQ%k{xsw z4AuI^;bo2F9eC^z`7wTgi*MHY8`M+1Ek0XUo`7@mdABXN-MgwM;sD!!b&KZPM7=E@ z!F=O!F1EKBPvzgEUB%sSj;)$+FYA2^`@87&{0E2lJkke0sy{eI^`c=+{SzFhqTBmB z*LJ^1Iv+0JSe$bk<8gf)ho|5KydOt!p6wbR!kus!ufp;80ZzoP?$G#juj_a>#Bp{% zOHMm`ll9@TIM`VAJ=otxPQ;0w`Wsm&k>rC=Z9Nks+{iOM#%IkQ&g`@3pCFy1vi(?zgzhdWYIqiOpPpB!shQqJPu{dat z%SrPs!O^eFkKFOi+{lCt!#5KKnEM0oB{#sDAQtoLEl2ixWD_H4bWg zd}DcRvV%^nJ+3FM_Xk{n^XmeRP|y5J(s+A62v<(FDJ%lKKzg7_J|=4{LnH9*2_Zt+CIxljN^(JpFrdv^@_< zs^7t(khWL&i01R-wm2BA{>g3~@4?P|jsF)%F~0O~tPgj>KKvzi-qrX79Mw=xeN^Ma zY_Br*;hs2x=i?~+8?Mwv*W+@>G+&7NU>uEi;xOyW^1J$@aXaj1y%TXF&lkejNBtId z*q?mIHD4_rFW<#suCMcw?KlBGzjlUt)HAvsXE>qp3G`RQzO}l2M&f9E1V`a)CpA76 z`>`MQNVffZz6m=1i*bBV{)2vp=Qr8@NSe>qJ682~l5OWV^;tL?AH{xL;*`cmkJR{2 zk{xuC{@rfU`MHmJ{AfAHX{|qodMzB+K=nR2!tq*=Z2R|DJl;LPp^JLFtA9q@PrM<= zCEK>oXNIRi28SE%H4a&-{&Vsy}gq>fhjK=DY9u2h|%VvVG=Tg%g?Y zcCv#`h<|@t^j1>8eV+nupKLpxeRV#@;~;+G`V-Xyx3#^W}90 zE4y(FpEoIXUv-Dihs5C!{~q=cPUQ1*ogb**$Mz252%kqQ{EzD4h}JUuG^U8Xu&;IS$c3HrYwnE1f?-;HV0k|2hsnFZ=#Y zn$NEHdF7t2>&o-7@22Ma4F@W!p65S}j}(^Q$FY~xzZ8f5l&|8Lx71($vBt-hl|R8T z_2qRqmi1o6iMKUhmM4s_r2fV@=DO;Gl5M{i$lvFi@oAn<+{X`a87Fn}@kr$Llxa9{ zOOJOCaNIe$a0>ND^ZHC196YP~*Ep8vCl7G~^W{mY@iDxf<4?A|-of{;48u)=dOo%t z=f zWqa3;qTb&A zPEGnf%FF!Tn&F z%MSD3z`;41@2ecD2kEbwQ%+$1OE?%-|FjoX571vZmmH@56b}BV{T=s`>JIx`Dz_ZP zdJbdXM)eQNqk4$>3+9z0%)bvi&2@V`#xcB}SM6o>Kg<1dIPT8tReO@{IKe@BewV_R z)Njw<0`hA(d`0US>H3L$9Q*&33%#Q8zQ^(qoOoIO0ms~yGv`x(%-?bw9Q;RKi+z{m zTR6<$18?Nl{)Hy%e4l{B>va44gkzV;Q3cc=7cak!^YQ(K-{FL%s=ruJ{Q>%eI3}X{ zCY(t9Ub5}+&(6c7=j#OuY5x-Jyh(Bs9Ao#BBoD&8+D>bG%+ zd77_U5zYTQ9*PU$ZMe%!^{2Mi<{e6Me!&2r%~E|7*`)H|BJ^{uT+fvCakxNfc`NRM&*96_s;4Wd`CHwR3*rj=-cBc6fb(Y#&Pn|+ z9x+<`m#LKIE6Mp&6?dZE1J4<+{auP{bN(E|L#U^V)_hgwYW`;UJf4Mf<5Rf$4D}Z% zt?`#}0Q>M)I5bl0xq$0&{^Tp8@x!SHaQktZe-b{8H{d4tH1>18WG<`uHskWR3~qyq za=uK!i|}_iH$H*SF4Ouml+*leIDbmxBh*{qT%0eT-cak`;7paZy~(%|{&$r6-^YcyKaRo?>ML+I?te$HA3wwo#%X;oSJC#?e5Lu@ z;L~^-o{oRU>!+(f)oU7m7MI7faVMOU``=f%7EZwb@_isFt7^WC-2d|7!nit49INfO z#8>z|ijQ#`?vK;(LF)1N$YhOAz=`-8-iXsy(|X2p|9cfL!*AeN+z#(7tLyO)9Ko~Q z@pv8nqm=r8!w>K+9L5=|C#}bE>i?zwBDgB9jbpB>-WngleQ>RxRiA(dh_obKf>-G!r`%k@b(O1>K0#~8`B0fTYzSlK=4d18U1h4o=<45DZL*yUuA-)g# zCjNu|0yQ&UHosn>KSV#&F?tb*2o2LNn8at!HsY)=Iew9Q6G}*pmXCb%{PO3{65{D zJ8^@b+#eUl>+zuZx;+x{`i1h_ zZ)v{A3*>ot2)`F}2ydFBdZ9Y%Pl@~C$QbSaQk#*)%e0(zdGZwcrmVn z|G-(fe*J?##1-plzB0HMzRT~`jKj^ie(%HCu=BRY5C2;0%Y)D3)_4J)jIUJC?XwEk zuP9%~&*B30IbK{JU&kHrP@E61$KhE0J(l$yjSu18I3Dl8L7cvU`r~jt9Kqvo0zTln zx3+f+J4^KUZS#hjFJ`#vKjOhNw7&&nRDX!a;YJsAJWnLsaU#Fz{K@>T`h#q*B90lU z`H$kbkL6~K)E`+Q|BYillczOSJ#M^QsfnBrFUR4So$?u+$o8u=Re$tq)u-Z^9rAe` z86nqb#(Eh4365K;`Z1iq_#(~K@87QaP#n+tPh;O9)l0QdfA|-3N@qFCd#V@b-v>;=V?(NE52&7NqC6Xyni&s({Vj~6@OAog z@%Wj$i?)B4_XFzVbksk^-FW?OHI7@a^Rqx#jgQ_W&%}X^a@uaH$M2Wh;?O$1p7%BO z^ZxTW99LTPm%3|whxB6=L6W!`vp!< z_4{zSWZUtduI+bq&HEqo=ugS-&pg3%-`4do(2M=y_41#RZJ&SmM(fLM*OjE(H+qTO zJ=sBLAm{T;+^&JnhwpI#K3{(v*Ey~2-NeCMI$zqvYWp#-$Uouu=jF0}*x$l(9A1A_ z^L>vmuah6*mAGPGjSsF>y%CPvrQ3f6j-1r|Df+QJzQ3s@4)Fa-D{+YLPrB?nqVf4Z z)c6qJztj##m~R#i?$!3UVLzY$y@Y)uHQ&(wny+VF9p4qWB|e1f;zu|)|DHVe0F56{ zy)w>?+u%kVpU?0N>Pv8Nt8V{XA8EeP%wGe~!5wioJQ5GWi*Z~z&36*Vay+^Y)cny= z+W&|6TmF5>i}pC2IfcD{9#*{MsmZe=Of$)({8y{)I8F`M!j0IN=wz zkE3}%yv!$T|2y4&&2b{@?}G!owSNzA%tpEPV2uxMmS^HH$G7OGsz5GU zdQ>*8?;?)n{?UCX^YeL)12~?~o4*uP-N*S>9tSdLzGsH19?B?h#ewJKS@ygu>G((X zY5(7}=M71Y*(0a3=OsxF^wjleA`W+xU$W;_Np)XGIUYwZl8cT~J+xTfg#%n)>x@=C zuB+-l;$UyN`54t>K9G;$?PqlVzk#cBKBoL!{d+mz^Wg>bSHZ=rYkWgovZ(HlYq5Wn zj!*BgY`>RWcbpvikzBx@7bfk0Tr2q@jvXy;n4o&Fsy_eH@(VfANA=>Y=kmx&^yiUVOqLV!%f+Y2(b?rk*w<2CJyrFn59Kk_=>Jp>OqXKu0GRY$V6cmVNKY9lw+VTpwSVBRfr0f95MW)IdIq1I^^6 zbLnp(e=tvuye#`ea(p2Y;eMH)X3zl@tPUvWGVSH|&S-9P8ye!M?+4##qRdbC*c`#IlsFOdU- zwEvTr%E7jB%Vlyj=Udw4^!HQ!5DpHO=dMsa^q$=DYuVv^d48pQi^ro8xB=_^67Qk@ zEAG$Zed=#CK9=VjJ{+}H``;qTS?u!)Wilndzc>d6%F0J^sGR)Lx9Sg5{{RPTsUE_i zH|4`PQd`clO5+{e2nR1_NZx)N4qcLW;>cw=RXpSIn>hTk=AVuuKKT^(<&#UTW`AFi zM_^wH`Jh`*DL=PH{lQdnOB|xU6i4=GeYdf*PcCbZi^<3LCwV9iP(SF_7iUb~f5&c@ zr2fDXxiAhbmD}Pl^=UY=L-jq_*(Kk^{@rqcb<9t_4Gx}F{RZd7&i5Mcud8|m9KwU#`c>V&tKB;O8wU$$ynmDCi{P2AQ>%Uw`_st9 ze^7tufaZ_I&d>68*DJJt*Kq(B-pu&DsyD{YKKTpmza)R}_T#(QmreDTw`jf~ZiPdQ zRUe6+CUO`@%F0)^#6^0RaI}WL;ay@@^T!m zEvGeb>UaF|YV4~aN7>(TN&DwJt>e`dht9~ma5y68*v)+BH~1o9i8Nv4hM<|4ba2qwSx= zfw^+&U+AAF_s8M+@-EjQIeUWoBlLH}!5>s#hn+2Qs$bRb+bX|>17UfF>mTLII7olh zLySM6`e+JQYD+ui=PXVfpRf8DB)6 zh(pEXGp>uu(Z|&vrhi1T?e(Tns_(#&(Q@h&N&WUgu+Qacu1CmYv45O=!1Y);^GS^l zFuo~{e60EexBiK|7Y7H+|G550uJMQF3lEV8x&BmMk0Xq~m+YVuJfizg$y3^Y=cwEb z`;N(TTpyCp;lOeE<_$DXy={7qN3!E_qhtojdYJ*mqmrfg|g*|LM=MKO5vm zIJi-sZ=L))jxhcs986Gs5q1vAN3id( z{LuA5x%_3#ANWn~?D~j28wVMm;MV`s@%|4-9?K>E(tM7i@r_+SQvD0;PpNv?bqe_o z4lusR6^>_B)tli!b$JvH){s}at|DK;;n(FCuW~&7a(x_O{BZ2cqxvcw$}697$G$uQO^@nhO9Kc(#zmvvSNTeT+#o@N9r@p1Subtcm``gRMaR`^Wt$ycS z?Oz+$jpU)&cTeZbLL6zR`UxCvAU}JD?cY`ZYdG+>>P>O5zT6v!-jP4Y{_I-sLhNfL zZ*l7_V~=a@ z9~WHr(f((Cp!GSiax@OJ{(-L9|L<{x^*_QP_Alli%@<_7b8+O3&adm($NuJj$noL! zZ;1o!|3vJtzq@dxrPlk%t+T(SA8Eb_``aYh_U|Y9sed4j#dGNQcUOHA4&dK$gyUP_ zU(N61e5sUd#|e$s_yCUJVe|)C??N2Q@%kOdaJ|=dv?0v$deuv}HKQr#8{`ok}@w|qEoZq?Zec$Bq+@7s*LPw1sf`jb;uh=(A z^@3S6J}^@L5Qj#~-?$zjU%(N@=ds@bOWJ;r^W%N&XFW@>kMrxITj%_Wvd=9fub=t* zVL$U9!$HJPKNq1Zo0>)YejnJ@DT%uj!F?B{rVjU&wO*!y}(^ZRfN4lw?6 zx6by$Zk_Gj$062VGKc1iu>Z|*ko!x}t#dq<huB_C9Ata3t~+Uab8w)8ycb7tyzb%<`&-c7$4x$8xc@c94)c%1e&+iQ z`|w#DM>vFE z$;a`+b+E6e9uL395gz}t+WYKD>kIZ!eGv9BejyI<_`3~9==T-S_z?3A$A0P;ae(a? zFQ|S${t`R%KWFc2C#@%hhvPtBt#2bvz!$KCbHA$b5nK=Z+~*fK%>3WuAnVU)pHoTN zzK{C*ILv&*aD?m8V(jpIU_TCVeZGYQ+X#QCI1`fZk^PwA#@OU#B$A7N+rexde zk?!*i>drXTv)S*mB%g0QU#X7cTdUp|C%h*w!7O#L-oGrm8L!^^P4 z^WU3po%voX&i*rBcN~YmOt$SG$9FgN0M9pXQTMgbdh*!sk|p0>9G|+bo2Wh@*^c9D zDKDg+zxB@#&^eI{=Qp)Lp*;uo@_gRS#P>hT3--X!Lhg} z_Vai(5l1*5_PJ(%(?n~&2>VkDN3q^cIFY|Mm*51B$4MN`^Q-qtYrZI+U!BLXJiqEt zM)gFlcgJuv*Y~<*RZrl0_XCdqM8~T{IqIzELmba~w&N&{UzYN$hxP5oiCm8dS5Q5M z^_8f|{H*U+9L4%RtfYE8>&sDDj$?hBZ~}k7ZBKFG_pyJ4u`^EFe-j7U zzxFu5{tR>Lcs`CEukkx^i25ZQ$NXukYx}Vrk0Lml3{h8o)bOpZrhT#4gR8s}uawcLJ=M{^uCRr}i?`)0`Va18Y@4zd1per-R* z{?~QQ`p4k_=XV4<>~G1}H9o-k{V5J{et+lI+26mgkNthQrpAXyYrRczi1T|K_OZX) za5VdKKH2vDRNUU_-bk9yzW)LjPqux(%om!!9*)6Xu%F|*7T4r_*_&*8JmP#v#Bn%F zEv-M+y&hm6$Eyntv%k~bI>&1l4syIs;b@N6J)DR$y{YZRal8uRSdLdUoXGjpG}*TP zW!nGGsE1a_E3q?Q-izZo9+$Ciwd&Eewf*2)c@XwZm;b?`Y4YH=)E}bm)R801UmS`m`i`{xiuW;~~{2O*Szg}#`c-GSnhdAHn;t2hF zvBUhuT5G(I`6ptB_1?e{)>pBO`h&-{o}oCxe0#7%f9AHVkK^$H4m1Bo9O8JSYp4DY z<6p;qwl~nNv%OU~%=$0l0QaBF@3DW}e=6Z1_n-IOdc5}M2##!&%LO#vzf+#(IxOG9 zLGEuA-&cQ_``b_);r_A{`_^iFhW6@rI6q@>V6W;kaQFu~f_>ayi+;fVaewWN9o9b= zN7%muIKch&Ar7;>!W~#Y=W`S6!$BNkzLjpB`^zaDVgE99WPKcuYB=(Z_NO}z;n}Xa zKK+Fq)>pZc=8LeuBe0+S{T>IoKVQcVx7RD3HQwR&XoLeC-vv0lTkE^ydb?bs3&&@J z+#g52lUHCL$M=j||4H?1T{S+M?N`DvxH*pFcz=YW#%ugUcldUcnP(FggT(2KtAI~T9_0jf%Jl@p9A-2~y+4g#a`+URgU#j^Jxc*xH z8#~mC_SO7;#<#=1CF-Ay19&$MEmZv>b{JoxpXLkmd@6t)j>l3QV!k`r$9(xe)c62y zoNU`auJ=QzJM7PL>ds=V=Qnpe$0tR9*2D2DnQVJMmHyV${Tz>R)O|d^-Hap5cf+lp z)b{cZNSfc~3(2i;nCCB(l5OuVvEDEa604sg9o@rml8ts37C2e{r{ zaLsy(4_3d!dIsSLxBouu|6cPA`IPy2{4F;Gb3MO+BkR=v`B3IxBNq?KejZ6QQ*!QyP`G#wJ(2*NqKmWeuGaOo^*QdX7 z>-_tV4LI_r>c8UfbMjTUzk!_kGqzV!ei?@=X#4fCQ&;Zmnt$Ig3;PSGei(;R%V|bv z{s8}ep$ZN!*Y=vbb^d+AhuGoYA56lL=hgqM+uvB;k3(hU%kFsoJwe)$+P;r}KkzD! zxvk@04~Hsgy*+WHp8UD%YwBNueT7s%ii2t8C)j^b{Y6G;`=PJ3zN*;&liUzTF3at4 zn9ob}cl(>FJ_ZNN%U`W@&l-3uA1KCx-fW!ASf7vk_AKa?` z;W+Z8>KonqCiw>T9hVDyuJKM9xfKq+DaYY(L3www9Va|ozJdJ%uwpJD)ck zMm?s2>VM+sHnM-b<`3|B#CbTv=l@bnpw8zJJ7R~=6MgBL&l6t7K|W7d{R@qE_`Kj0 z?2Fd%+JXZ$<%sL^+TUj;YJ4b<>aStviPqm8hj*!e4)!fneZ5=XCMV!PM81OkndE2U zw7qbBIWKlf$d$04`(F$WaDVQGL*=#J894G5`|J8It@k|kf$n8HHhuOcAu21Or<(a1Woow2lzBq7C^M$c*v-&en z=XlIg{Y~uKD1U;(N9ENxluEwj_P-(LnW6at`Q^sRw$CH;dB2aagTJId#P#8O9KpwM zfZI3!OwAv@uJu<;w!Qxt)b`%PA?6R#AK>w60SdOG8lQR=^RLqU<*;vp>h;|^ zw|@s5;PGuR_Va%ARJWh&;Y#e}(0n_SZO`Aie%_`YXr_AB*;-EsS9i_%G8YH=yxxB} z!1n5Wsqub}=X4z4^J1H^!~3&o=CJ=koj=`hi1*Wf!2#Y+E%lZ91AN}+W9%?~I}Q!k zd>Q7d-@#3=kI#cG#sNORbI+~w`Ik56X?%$HFW2HA@2?gJsUG3|%ZWJ5eCKhnv({5- zzWV(i%Hwf}&r|KkLC%LV3z(nxS3}s(`>UB3G9T+ZkA19f(<0S_tZ&?6+2Qjz4VN&U z_gAwnl_R{r`Wp`O{_4zSs)xI3{X21x(?3|;CyI?eVk8UVu$nTq+92FO1)C!9oE+chgi=69AW##zEQuA z^?isVc(Yrl|Cw)DAM34;eQYm;!))&!cJQ04G~UnrL$Jf=E7rMnws#E&*KjvM}N1@@tBMK+}>GMYkY|Frwo z!uePS`}w@r1nlGUXGdJ~d9OTcHQwR#1)Xt#&wH)J5!Q1O`?_iS>DOs|nC(@>A-2~M z`#Y(B5{`6`x47fkpTBUB{mr#r^M}~KdN{)UbrAM<)O^cukok|{0LQ=32F>T^_z%D# zj{i37V}Jj~kc{cX7 zmJhmh`crOazNV^Iz`pn7t~h|_;2_Vx&fyUAmD-{C{LM7}J?!9#$+mwF!tvTf-N*i1 zpdM(U@mY3iK8MHK>dChE+gqyMow|?he@WfX=erJIXRP`k;}9;pD`|dv{?$nJZaB>2 z`TS(t>ysRx1RTUEceB47kD9Jo??*Vq{q+$Ja(@l((fA1WS7)yr;QrbVhq%99zdtmyT%sAb$U%E{^8+Ek44r{C>q^Jci$=IGk+9*|tx|C;e|p^Eu9azOT7bvV+b` zeBW{xoXGbne~s^csr6sN&G;u@_ohA@ie}Vcr*Tw?;}2o zU*P+M(;d@#Yx4cmEpT?ePkMf`gH9XPe-$s|`=RUnuJx_t`=00G=f>&#+3w-NtiSwm z^>Y`uiu_akjJm19(fKZjan2)jyZ@_r$~ay@6lx zNWSmC47;m4f+JMd-B|IB}?|0mA>)_4Ht|56<0{J(>L z=lrj6R^!*Q{<%0OzgO@#j-JT(^_^4y0@nWnUc&l)=T%R~_l1wbF%xwEIE<@Il6@D{ zpPTRV?uoau{!KV5=YQIZ>MvSG=SLHqX1V5Di@UM@OqbL@ob`9ccUk`t{DAdWxvc(H ztbaaU!1{0E@vOhvU+VAWejhnb!})(4cVPXmUQz#G*54nuVEsq&X4W5lRsBa;|2SNm z?|c6T*W>%#1J~5QlJ)P!cUgaq>#Cn-{he@_^{>MXSpPFO)W4qfH^v89{{s98>rZ)8 z{byKzYkZ&eufttgf4)TZ_hkKJ@Gq?YCeFeAx7scBr{MlO4xeNF$8jIl|LSe^A7}mj z@h#TB15f=&=hNRffQ#JG_}S@oel^9N@GxAft?nP+;wXF)Z_cgpFWuFAV{mKSp^WNN zaWwuJcj}}0)85ngGWc~opu5I*z%}t`9BHBY3cM2kjO*1_JrQTe&;QN-f2HkLz@2bQ zJoS<4gK+@Q!~fcYYSQzC?RYP~fCt@E{iXZb-dp%x989hC1@Sw072exI+dqS+;mi*- z--4VP-w5}{({R0#s{e{};7tE$eEpu9zaD-OkH&2}Yy3C32tJH=H&Oi`JO#h}Q1eIE zRQ*l--|KRB9Gs=?Pr~ou4S3Lf)lcEKaH>a||7->w-y(PwZio-@`xYPJxp*F4@}}nB zi~HhR*r}y@o`1Ey18>N6@z&eget$d`&&NAcYJYd*ID8c!XsY?L{HOV6;)?j<3mPAb z*Wl&&i(;yu#I10q$C@v$o96f9Hn<-Sb2-XU;@j!u9k|L9Ih&I<`R|1^xFhyw*7{cAjQAfM z`+>G!D}}~a#S?M+d>Vfpm&9+URR6P;R9}FPR+Rt289&ne@1|1!?*ruJICmfQU&fbX zN)lInx^sNa20&Xtxs3|&CKerf)`@nQhon#mMGP) zGyf1gpTCz@hc46jx_ASBPxZjRl+ylA#Qx9pdczake5UHXp4a>dygqRZhj@L$pH1}&ydJU) zKj8I`s25Z}!11YrbMbq1ALB9{pRaKO$0rdV;rNuy&h|JyJ#nsaI{&BP2OOU*_$G=324_v4)W9_=`sd#1+!f`_pFYR)w3F{w$bMX4bYCLPHj^BO!`sZ?me44K%ufGhy`&s`!{0r-UA;0=dkJk06J^qaK z&&1tW|3Tb<^*>WUKgd7baExE1SPlH|-mCn~i*A8`!FrjcJNsCqPRfdlkU z$A0Qta11{0_TvnNG@rxxGB}J|;&>dyIn!!AtFRwG_p0W59rwgF@j*N}oyJ!vto|?Y zJUkPpDx&&){4Sn`=i<5eDsIj8Y8BP^c6cssi|^o;xJ)ti$1&duJPYS9uKIL51JA?v z@B-YZg!-r8Rd^20SW@*#xIdna&)^xjRw?y|@MOFYpT<*h(P;I5g$LkP?C)CK2H(c- z;poyDAH)N382^C%%wMF8`W-w2`*51Fsz(?<00*dF#6jG=ocd!q|HdcT{(XDgFZw+7 z0UY{SPE(%w8Q%yOX8b(7jPw7dTW3A~3XG>d3CA%0A#Q;?S5$vA{uNikH7cp@$7^sM zT%@w`|CI5#rkwOrPV#@+dEDLOK^}kZ@hp#5c)Zo) zpFF2Z##PtW&`$D=&n?(q|kU#a%=d=))z?(txc=X)IX z_`1irsz1HG!X8)f_;rsPdfdk29v%<&IL_l89v}4hxX0%`PW1R+kJHt7dVjNd?DM#| z$CW&;<#CM1Z9VSc@eq$^d%V`;OCI0$_&<-+`Jdk3=RMBraS@Npd0fNedLB3RIN))2 zkH>qw(Bn-WANTlz$Eja`dVgQ`xTeQFJRa}yY>$_F{JqC}JwEC24UbdQe0sgvJTBmI zd5`OP+}z{t9tS=C!sEFfFZXz@$J;#q#p6>RU-tN!H=f@Ax*iYq_-l_(czoaEY_*=A zzof@?JRaxq4<7&RamhEIp1-}vGdw=(afaGYkN0~#(BpWI|MJ-P*3D4|x2i$A5dAvGLRE$>(t;j~ja2$>Sj&uk?7A$7ejw-sI`^ zyy|gfkKgvVk;g4P4tU(z<6g-Q{_pRH*&hGuak{2YueYSfO+6m!@d}T3CHw!jf6L=M z&62kFfAzOL9^&yjkFO=$rr+2fub_xE^+$0I!+@9|`hXM4QB;}ssS@pzNR+dbaz@vj~q^Z2aC zH$8sjajI6yx7Yt}pXWS&!Q(t0zv^)*k1Kgx-QzkQH}<%-$LU{moUE2?mKQ8}Ek4UD zmXeleOKD3rOD#)n%UhOrEsZTrENw0CSpt@xmfn_F%OJ~O%cqthmY`*rWt3%%<#Wqq z%QVYk%M#0S%Sy{PmUzo|mIIaq%Mr^7%PGsBmaCTQmK&D)mVYb{EopN(PI}9;mI9Wd zmSUEYmTH!smR^?LmRL(4OJ7Sr%ZHZ!mI0QJECVecTLxJ^u?)7%w#>17Wm#w0VA*In zZaHcB!;<19$EjqgY^h>-%~I7;%~IX+x}}!oElUeaD@zAUM@wf*tfh~opCxD+X8FwW zwdF_4Zp$9aAC^;=h^0bqo7)m&X>6HinQu8^xomly*KwX$oR=LZoh7~HSxW{>MoT8k zbC%4OC`%SgR?G92Y?c=+*)4@EMJ?qltt>+=V=U(^=Pen1HkT!bK1mKdX}Sh z4)n3{@%F#1wyd%2wB)zfFiTiUT1r`>EoH2?oTa>_f~AtBvgLJ4P0JgWK9+u#4=w#I zA6W)khFeBhMq0kGOti#VCRtWn)>zhB)>$@Nwpw;sc3bvXPFnu3WU%ukljS)}W=j@J zR!c!kDND4aw55!tti^9RYdLSZV7Y3!ZnL<%}g_`O|XN@|Wdg z9_z9EVz+yOWrf||t1R0rdn|h``z$|MZd>kH?pf|zGT3>L%kq-NXL-d^+EUw&=UbLK zmQO81EJH0p%P`ALOQI!}9gozO^p*^ktd<6rCYE!StCnk)>y{gqo0de&Bg?;*|13`| z8Ero@Su$IqEYDkfmeaOhXDkuRpO&+hbCwI1iz13AM9VG9ZOa|Y zUCTYo-fF#VsW)B`u{a(U#JdGM2KIa+dOz3YLnNN|wr&DwfwQRV~#l)h#tFe#`5YnwB># zwJdL1YFpm2)UnjF)VI82X<%t+iLtzEX=G_^X<}(@X=7~whdRlr} z`dbEAKC%q746+0*!!4g#Mp{N&##km=;w+OalPyy%vn_KhUs>i^=35q67Frfr7F(8B zmRgosmRnX>zP7Bid}I06vdR)~S#4Qk`OdP|vd*&Jvca;^^1Wq~gBmR~FhmR~K0EQc*eEWcTfT8>$Mw;Z>e zu$;8~VL4?vZ8>9!SpKw}wVbn@w_LDXv|O@Ww)|zeYPn{)Zn zNvx%_T`Rg+x>~wfx?6f!dRlr}dRzKf`da!~KD6|=46uA;`PeeZ@`+`zZDPk#VDQ+oYsbZ;WscxxZ@muOz z-nP`Yyklu-iLo@bG`F;{w6wIgw6VNz`M}b_($Uh{(#6u%(%sU-GR`vIGQl#%GSxEO zGQ%>{GRrdC@}*^tgBmR~HtS`JwbTYj?~ zv;1y3ZaHl^V~JSKTFzN6ST0&FS^lzIvD~!WvfQ@ZvD~x#ZFyw*&+^#v#FD}uJ5nY+ zeppgl(pYj@a#>!s_$;qjid#xps#|JU>RReq-nP`Yyklu#X=sVDylZJ>X>4g?X=-U^ zX>Ms@X=!O?X>Dm^X=`a`dCwBCyl-i5`M}b_($Uh%(%I6*($&(<(%sU-GR892GR`u| zGQ~30ve2^Fvc$5|@~vf+WveA@*=E^e*=PC5l3+PxIc#}iaqKa%sHK>txTS=pq@|Q4 z+EUt5#!}W&&Qjh|!BWvu!&1}ohUHC59ZPFVTg!Wv_bne-x>&kex?6f!dRls0KD6|= zd}JAD`PlM_Ww7N_%TUV?c1_r9Nn`iBw3c+1^pONn2p(QUT*(?UYo0z zIo7huvfKXma9YFHXtezNSh z9I_m?9I+g=9J8FWoVQ%CT(n%WT(MlWT(exa+_2oVBwB7+?pW?x?pgk}+_yZi{9}1& zd1U$5@}K32C5=7jdEQdVQrS|)@|vZprJAL>rG~|CdBal6Qv3h0_Z@JSB~{(~nK5BT z#ef-DoPPCUKNMwl=IzqV>`XJScYzhTyncPV`|iB7FZ9eT85EQtSr7$52_iudK~VYh zGy5qjND|4Cvw#v5`2JNlRXBCiyWP{X-}v(n%eBgz^i-DH`F9-e*cs1}E;7@_S0R9U2JK*nue*j(! z{3GyB!0Uk518)G{2)q?|JMcy5%G+SxeGl*f;Df-2fDZ#70X_Z=wtqG0WPou>;fKeBXD2LUkBI%Twoh`Jn#hIiNKS97XmK=UJSehcscL~z$<`P z0)Gg+3V1c}N5CHguK`{Q{1foc!0Uk51OEcN0eBJAiir?*iTnybpLk@B!e1 zz~_L^1786C8~7jKOTd?bE3o$d7w{FpR{~!Jd^PYjz}Es_2iywyM&O%(Zw77+d<*cc zz_$V44txjjoxpbiw*h___%Yzefu8_w58MH`BXA{fC!h*E6a0N2@F$?hHfM*xom9tAua zcnt7Z;8%dh0gnfs06Yw$j(-T=H2coXnu;4Q#gfqw(u2D}}32k=hdUBJ76_WJ_GzG@L#}ZfzJW|1AGzq67Xf< ziaTJw1787rCGb_iR|8)Iw18Eh4cr;{Y2asop9Ss;90jfdjseGktAT5Pd!XK*!hhcd zxEpYH;3RM@a0)mLtONG|&H!Ct1Go;j9=IoPFW}z54ZzO<_W^z$xG&%U_XB#sCeR1A z02kN>c7R>L18xM)0_&jZ{of5f0v`lE1bi6y2=GzhW5CCOPXM0;{sZ_F@M+*Pz<&b& z1$-9x9PoMI3&4K^{{wsx_!97C;0kUx0$%}qCGb_iHvr!V+#29^{kH?(0o(@Qw*74Z zZrA@Ha68~f0B+m=1i}``I22`~vWcz$1W1 z0>2D!d-gHFV}V}*9tS)gcp|{<+ou4(3Op5f8t`ktuLImK{7m3CfoB2F27U{84!~{U z=L5e3ya4!J;Dx}80d5<=6nGi%`@qYAKLB0{aR2hFfjZWp;4gr` z1pW&6Yv6AIZdd<3@DIRifqw-433wgA?d&%IZv@^1ycu{4@K%8Pu-^{619&I!F5un3 zzXR_D-Vb~L_#p5h;KRU2fsX;)k9}W&+t`}`x3RYY?$f>z;CA*1;5POY;QsABfZN$O z1Kh@b5Wwy0hXD@<9szJa<)eT{1D^-J0DKAfGH@%{ZQS1cW`O(7xE=S;ut#nKd*r); z+XCMQ{2*{U;KKml_kRN5`~6P?e6Rl%(2d^>d@pcYUx=K;?LUI6?q@FL*F z!0!Ps1%4lRIq(YLmB6cjR|BsDUJv{W@CM+Gz?*|2^;}dfC|8XDo_LJKm%w3EnpRB19t{~3ixT@F2K(KKMULyI0{?^90QI69pGx< z8sKig8gO^u1aJ~K1)K)ffqMW?27Vp7f$RT22L3nj5BTj(z*~TS$G<-hd;$1x;HQ2B z>j$_G-~nUcLBJz`M*@!m9t}JOcoFat;MPA1Sq6M7@Z-P=PyrZF1?~=f8+6odf$syp zANT>_2Z7(g-*$ftZ2>m|XMq7Q1V+FZm;g5cQ(y+nfd#M!oCD4S7l50A`vVUE9tb=L zcrfq~;Gw|dfX4$*0Gm2;Kjg8fZqdN3cL)s9s2o0zz+kzkAJ@$_ygb-z$<}21YQNa8u%mNkAXh{ zUIYAZ;7@@+1O5;2=fGb8e+m2*@YlfK0DlYo9q@mFzX$#ScrEacz&`>147?6_J@7BU z8-OV#kfv*6*68I|MtAVcpz83g8 z;8wub1K$9ABk)bYHv_i@z6JPJ;M;(22fhRNPT;$M+W_AUd=K!wz-@u=1HK>l0pJIL z+W|iW{4nq%z>fky2K+ei6Tt0(I{k1FAp`r~?h43ABJ!pbgv^ z_$lD0fx7@d1NtnV4s?L4fop)f0c*hBffK+<;9B4ma2i+#?g5+uy1)i- z9dJExPvBm_y@4Bmp9Ag#{5)`9zya=90e%$tG2q96p8#$T+yS^Fa3ydj z;3t72zzR?S7*GXjKpkiRO`rv=0&U>Vz)t}`4crCz8Q^Duy8=gntAJy`ai9ZS4O|1< z4Ojy&P5=V{|9970eGmEz@O{8{0zUw7+y94vBLKJa8E_ZiIB+#^4R8;D+w~j3&jZ|+ zzaKCJxZOShZU(rm{y^YC0Jqm43OoYfHv2CFPXwL9&G0xt*t0r+R& z4ZvH0w*&76J_2wX|Kq@C0dCiS0r*+bHIIop9e0-bzrW+cDfwb0lydca5=66 zdu`Z6cLpxUb-+&vK3tCLfUgz%h0Adr&=>F}Il%pZ9U zF7Q0y`M~c0F93cQcp>m2;Kjg8fZqdN3cL*Xecq(v?)L^OD8u1bv>17FhgaZiPkTf6 z+<1ESNbmNRipF=i!f|dm)euG7QPJjjF`q2v)hb<#H8?r$Xg~4MF^<~zIY>Vw##YYb#&*0*;;qbSbw)S zb>`EaH=nKbJNWaQ)i!%GuOCvk*57bC-G;M%qJL!4o6e6^uUHvR<^fZ^QGc-5a#wcx z{d#Mqf8~`cL8p>G+C+0J-gxGqDfh^3hL3%kPy}BW;6a>$~%U^NKZu5D_vVnqEE+ z+RASSU@`GUq4;jWYo7PKL31%$ z%pe##^12HMXuzoK^>eA7lXZh!6!-QgHk-vGUwb%^g)1p~s*K;^jK8E8hW zsnqh@vt}K9=!{>T8y7I3M_`S&GwKbT-QH*m=Cmvp#PApekElb{^ts4tK|Q@b*Yd}z z%4D#7#AQ}2U+9mHXQ@d@zqlq=on4sC-J#=7r{gJTfgLM%%s03CgWhZgOKm)Hr*qGR zF`$^*S|vuQ@>;_W8he=-6bj2TLSflO~2ISPi-v^RS7JoSFkpvI&~*w%s9bS&QOvsOy>GJ-(aB0a6f{zzJ8QBtma?`?hHI^_vgKxpi9wbD?3mv z{@8Kzn4WP3>FM7r2KI#SI|ycPwHC;vKwdJF%+cBbQg)UqwpNw(4`AB~}n$5XLKC;Sr7#V!zG!P0q z{zMV_>fh4FAo#jFGfcLFH4k;;v}Mq4bAGj{ zTL^*uu`?KN!dm4U+{lu0zE8WSmg|$L6 zMRZq4!M%)q9rh;ZYof@E_%i8v>Ef~mld>}u+^-9Ad>ajtN*0l!mTPEo&$4mUKWlAa zyEGkN2&P70W5#nsJ!R?-tbSkhL#=hGzExObJD8ULyn#VmotSQ>(vlhZ)03SzZsp@=jAzZ$;`ob}8Nn^}K zurpcXhEZ(0rx0Ir0^y{#X3$?^djzwL=Hd>pmaISg!8&syVYui5H`)h;EO4}5b#R8J zO^On^K#g&y)7tW8lQ9e}S?BM2tBmojs_!}C{;b$cXI&%E?uQ_TKK+vgNkeHP)1M(HZ@aHT5acUz=8hM-cqdK}w zeZ)A~tBZ|nSdG{?@q-58bkj|U=tH}C5PiZJ%v7A^#1&CSB8vylZn;F7IQ+!gJZl?U zKNv!MT(Vh^dpIJ>vgKC#W*zpJ7dl^UMOZy5Bh++gSnwTubg(aWJ&H*$DVUg_MqU1# z@VC;zS$M&!8hhRhy9;^$<-0ZlbCU;%f+Iz={1=t9{oWK|>j8i!Q^p9&lgRzud*KneDv;=GQ!-JP#G zXEudnY;D+`*ZJ;i?Zj~1+{8!QtWF0pY!#=A!=?V5&E{*}CIZ;z^#L|6Yr{^rCw}Ox zI@dyMa9`Ovk9iAQaYi`45nqV$mD@KPW!lyn=Or-7oV6{u+7VQ>hJR!FVBevyxH>|^ z##4OajHlQD3!?CC3Q_oioOF8i5%+ZK!1yo}5pp-nWixAn&)$f8bsUJ;n-=`k0wZ!U zxJ%Q5GcK+)WELF2NHgZ%w15hn_C`B`B?K8Ik3>r!3BD|<@yr(oE)JA{IMo$vARH<+ zekW2NB7#KP{rg9^2yEPgUmSaDOP~3!J)9eku?6>ap?_)^9pJw4#~ExT!nRRs+i!bUZ7pVqL^~m0`BbL3NZG8|oZA{9x7sjQbA2D|ifm=1 zj^r^|)#^$d16=tEa5nJy(*40X%eyDn}k92#Z@yIyE zrOtJA!dc}CvMe(r7FksY1v6%l7Omk4aXd=&cSL>EzQ|v$M5XqR&6*`qVUu}@g>3T0 zD&$RiB@)W5Ev-W(N;s;!fk+QKd@!vMgB95n%9h@rJ&B)d8#Y@BQllvv%4~%!6KTP$ z--lW@WU;ic618&H??bJe@%xlMXPD=tq7*X5Bw?xQLJpTWDM{M*Zw(|gXR2~mjpF1_ zISe~&+)Xcp~0E2dsc$W#P}&it5OvgI=sYwG8Oq7q8xMOUFXhrDJucO10(XLRQGUcC9o5BJWqLWG>GVnGOFo@Q_1Z}+^Qhf)c!nYF{)RVg z!?x|`2gJTSh#nF0JG}p>3vT-IBT1KU8;IJX3yFGlq$nk8^TkaVv_`xC$$}LgX6E0k zvj+%K++ae$1&qkipm}4qc&{ZMhFv#wX?7lFjXos#*jzdek*b!KfBJf`OFpVjAvy>r zVJ25nS+Y`hXi&E(X?bezQn+7876^X#O*x&t`{{OS8<)w3r0H&2Myg!2mo!W&wICyG zYE{;U7FO(b&mSXi)?t(OZR1l1=_XW}p_{ly5vz5}$m%l*LI0zmsblKxJ89;qpM@vK zW?YZ*U30<%nE7=8Zg8c1%mNb}Rvd1OStO`Z{p2J+JY#fFEmJ;?LhU&r#yOy})2!mA zm9~kCbun3-WPWfDAkeef%atHFNqQvRkW;^s)fH7+WMvX<$$HD2LR5XBorg>!IryG2 z)}CH!zAv$eEkrrJj@Bwf6sNQr=|c7Vg@moaaD}F~bq)vcZg}YzhxId@_SlckNeUQC zq`+8N&aOMat=Xs*b9kv{QfQV!2=#?-B_KTb*9(v?&!a&%a}`P<+8QWEQ&97VIu`}u zq_P&GmQqAlwxJ1FBMm{ua{h!bP);yHDksM+NC5+c%on;h5cOt|OhXTn!4E0%DELCi zn|&pL4%!GVmh5lKc>^ZE52$C$ofq3uw1&A+lH68Fur*B&yHg!0hTa$3e>6<&4oEeS zbt^%wwBT%=YKjtq!D_a(m?SoGl}V9Xx#|j}gRP8hG&{zTaD}fk!nc$#D8y!n90g0w z`fi9U8yuXNP1$?K`(b`hkDjk~eC}l|lWFua)^*fZI=R|cW~sTyr2FaX0>7QiWrQBc zRVEW}vbHaejaepf{L}U$*aA=c9NLTWCYaQE7s?X~pz2GkVJ%xxtI? zxT7j;8*U_z@ON?Hm#TlDsvY>?>N0n(TGfwjZywfe-Apl))M}Vpv}K%NhkP`Z58_(h=|8E3S<&TqPh}} z;3&oefl>oVJ;B{gwb7j8BrFGQ6M{iC_`|G>heoBuAzPPp+}~W8ajnGdu?gT zm(tm)0v3DTIr5Xu3Y=_8g?**FMAl@H!zk!aa3m?nVyl6m6OH-eNYWDg*A;OHDiOnv zKNI5?w*7jNKk~ofd3O@)LZ%s>q&oSdS@03J?)NIrs9JaO^fgv}sjLY!Ti#Ywg{ZXB z@S{d}+^|T~jWpQ4d!_GZ4-ZpZ_xV+8B_&33HM>DIaz3Br5=d7Tl;MfjEKD)TT|aRy zwN!f^rnqDkk$ulMul=)9esbh)c}PUZRTQ@&MGT3QoIs6rhXQLLrq4uLkf>r~nZ1^y$RR* zxSit9T0M3}=Y|#}AdjKUSN}c_U#mPlq_B3u^m#rU?QQ<}2gRp|DK0LmxZA(s@p{s*d^$%U@3PHGeVD zU8$Hqs>@6eGKq|StvuJVSA?2j(?ok_-1ctxwu^5BzyeerF@ZhEuFSc0GP%5cIc^{!XZ25yBskR(ZrK7!7K769I7dpAUx%x?qb+)R#8-o>OnN0TK7ZGq zdr6>_l@LR$4}>h2a>frERTYgLHYzF{b(_xYFv2}mo+!iH*hH%9QA)b`$V1y3?BIC~ zQj(g&!gy3|&wqciCLg6FO$xJuY%NC})ZE^pw6Q%;LguGDQ@prw0jqMcYC3BPR^GFel(HzzKINz%2q%Rdo&u-Qed$vGWej! z7x?>uNZKI%>(cac=)Mso8Zv$&9UR72=8ZmPK8(oBpbOSCTQog1%*>L++D5^uNqv=Z zIUen~;<;jIAb*a8o3r>s>-zT#5Sv_M76}r}4^wJ3NzoHfTDq2XR)-BF&T4Sa+z4qK z7NqImrnESp%$d7H-=m^AGN?q|+1eUZqd{W%GDL!qrM9@D0^1%Jk70(-i}UZ2UdVtk zZr|IAMpC0aBJ)ZlaGWmswud{k*%G+g{InF72sAapseXTx(vEr~{;k9mV?k@CsJ*OJ zQ`lP8`ygG{%efWMD3U4)Ig;_dx>iwUKZagz`CIC0jcI0`#!Agxh=ppf-Qq7`IU@1% zcxnwzCa0axTDg4YOEH8vBWm-1@`Hty^bg@WvcG^ubk5EQf7bF;*GR@afFB|#U94s5 z-iEzxv)h^}C=Hl85A5F={mJubxGOcbIlHKdB3g^ma*+m6`8`CFXY zXnVpc_z%R>@YjE9^&p(M*YER3Zsud;-GuYb+d{y?v^T_CrSaQkA~4SnC>r5U!6*8| zu|^XkZy?fx2AiPnyy<6y4>hmEUxRP_U0tbzQPSveIC<)6p1&P&LECGm@V|FP3#Whn zJZm|~YK<&GgE+Y_p5`+4dFc&C)FPya=h5a@1UqmNRh^o%=`}Zb+w-+e{zKgvZhQ6q zaGR}d;yW(oYQY0_Tsewj$D9U#le3CUsHmYg-B~;7v7kbR*v@S{4TY4d4iEakt=YBi z-9&r%V#Dd4;s3vZv#)uzi6qKf;~|~~6yp}ff$_IK(?e?bV^?93C|-JT1u~-j|HX& zCP?tGV&E;p@qE=e?mu_s^cLsWPHt8@9Zd1y39L2ba9?sIAxS*`Zx1u;XqXT@tg-7X zvpmCvf*kWvCUkV6leR+n8f$^5_)6*0edHt^|JswG!SBW?jqw5(eCUdlgb?Z8^+Dg*D zVuu?Rjpv~B?nYxYp6^0Ya{bNavY;=}cA_n1=hz;NeeFJzzl$r@Hny#^u8ZepctE8; zo&93UjTL3bs`suITL2xrW~(Rm&iQ#vr@qCf>^@u8ZrycbI!#QEPu0&qjlNQsTWr&h zkfYf@O&epvry~_1=b%ZCR6>5h#h>J+$Hp{6{V&am)4tS4K7ARO7MwD(xdr842#pdx z>8~YA@?;F1i${r;IrR@x&D!$+#Rnyf%%F{A_zL}1cC$Mj<3_@KF&%|AAk0glHKNyR z@K0P>T#Obx?UMMv&>RlflN?kbEucsd(d1P#lUH@5w`{oCtB@DDzQbMT;Uka?%{+W$ zW{hIaKE!3s!1%!=N%d=CE8${MLst$TldYTe16$5vjJ2^}jR!V{ zR37!3zC zp;T3V7?~=wFrMTG%b#!v4=I0AZ6Cw55yPHVOh0_G9Un#hz#`X*W74E*f}^Cs&)J$T z@PgdXt@Q`JFi;zAM!u_=j0ax-!m7APg?|gl#+-Ik6@T=dzc>eX+FrO9hTn4251wJo zrhMMy??;2iR?yfAcXo;vwEP|+MR>PtwC7F7qak9pSPieb;opG+l|NbFKjuEgqvS!f zPP<`m5Jgv{>IyW8E!0`}!Ypj9Ua4mEGI7VF?_65qQa2uHko?K4forNr#17Ac?@(s7 z=m+ir;~557HSkykcQ@<&DR8dY29EF3>KyTA)83J0qZY6&tb#kwMCF=SA{-d&RACLi zpPtO2B)7b64}Mg*ON`w{P4Z%MM>oRohH!$q__*${hW6JrxN}pkLW)_a81$@$zW1k| z=m*|tI@3J{r_3p2;YTAahx?6>iU-5C7!v8TfzhojI{V_=f1k!SjsRjk{NzAAf~YKiSH}yUxe7RymnQV0+kLl zr49>|BF7BOForO4lu6MHbix^oO2+9Y5f~ouCe1-(0@ynw9V=Hat5#pNVp~HBDrpo_ zrpaZl@`)Y(Uj~CkGuv*-le-z&jpDwQZX8}@<1#caZ=q}8(q{e=mJ+6wu7_C5+d;UE z>kPe_pYB9#WP%wG*a|IqQ<5{%Ef|=IsqB03}%(Hi9H@}Fi#=KfNx?u#3mN|PwCIZCN}&4yC_kEVytzq z5pAIQ;Lox3D*hB|gcK>0i?0T^ica;m2)GX)Ls8~>1sBY>;|Ac@S&>%aK=PvWZ~{|hevRz>l|9wNJ9kiPn}tRYP= zsxISv>#JsQ`0HDj*oAgg>_YRm0wXj49GC(UE1jVrQ^7JPK8K`gjLUs-9aE^QUE!(iRp)LHUG zOx4l3SE-aL<=_`6ZdYg3dkSB&5q)`WV!AA`HnVZLyk#jKDmbK8rgi$2vLd~FOE2}T z(5@s6e_0Fp2C}ZfBr-EDwuAL)S$w>q}EGgu?C=igF77~GbdHR`R(lSrWpa|9}mvKFc#H{&_}-181vM8v2h zC=w`ah*Fyi4{05}(e^lNIb3n#FCEM-;Q58=bUe-6V7<4%#YK^n#o5~2$=Y5G7od<| zi@#{r>z~b7ieI^%yM4U8hC7Ytd5|a~OfyrOKDD?zahbU#PpP`>e@GZGKier-h-1f$ zY(PGEJaKduEO7gLR;f>uB()X9Y$7j1R+g{w2+M@;F;UKRJ;ZRQC*G7k)$}eowdK#X z07U+MojH8&%so848Q#Cgzs4hRlSV`>BeM|ycg6FR#a{QV9Dlc*z^(N8;!7dT(^YT= z;r9I1jzVWcJ{hvpiHoAhPjSXuU+(K}b6eDaRvMT=5qdE&bE}NO-J7|0`mU zrgj;_3cw^2Qn7w+w>L+V)|dg2enm{fs6N#z6JLCg$dQt>guw@qHDakpgwHo|X=1@I zHt?(Xh#$X@T&K7%fiK+^y<9>gRpxD>1w`UQL-6I~N9Sg3DZZbfPQXw{uZE-~R~UX3 z5gLpVYi{;<{^IkXZr~t7dae$U{1?4!NP_()0=n*0q3|c;DIayd#n5JlC`*LkGX8q) zWIWp9X?bvGAZ6EXpHO_vv`_#Mqi@VWp0{M`&3A`-H#1%HsN>nCNQ_3SDr9onMG=Jj zELVZXAWfo{S-B+M$|YKrg3H#86RG7m3V#7zfv)zXYkKwYmU>m(_7Q<7;azZOc*U+Z zE^P4+R>PP^5vw9rbi6H(HQ4?%Db9iqxJ`a^cEC;2Hpj)FLS9M-&Iaxcx)_|-mbpPh zs8m?pk2MSxm*!N^3|hS_*=msoK;wnAg3V%0X$E`dN(Py~^z<)Dc@bse@I{nJuMy|d z$S+`6Hp0A4eqgpY!mb^c@OU=8gQt;8wL?!N#NeT)k(Qg61ljUBKm3e_ zWWFT0s*AK`sa_`YfF#Z0^gB7F8Ba<{^a+lAe(OD>d^056#qO1uO_z8d_{eB$_!iJ3 zWD8i#c|O44*&@E|FY#^(J$8xr!8aH#@lJ?D3j5jztAR{xERtoQwI*V7Sg}`zp0{aND9`ZkgLeh{b;}xX~kOMUcqcJe&q~6QhSBxb5fVidKNx*wRRakg|*(%(h0ZkxtbvD5fI@o%Y$^NlA?}%J^hsZoHJ=f(S>RZMHnaQdov)icfMyt@4rjqa3H`c+M$pvE`8Sz|b{Na(+$A!Wg?845a^MQ}#)>pBv zTq5IC$USl>S5u*$lrl-(HqUF|TibDHhw!GD#K{?k~;CF3~t> zDRlr+n%duf@=bf0L&NLaUy2oWsZPQ&JCe}M0rt-{8cQ85rISQkrS>$tgU;}iE-|o6 zw0dB@Us4Grb&*$nVEtHD&?j}Ie3_rrnzArT6EX!`Jh1UodQFIf16hW~L38=@mvXW% zX;$%}wN+dC_)!flsmN{gm#)uk4V57~D83x5+$dobY)6UZj0D(`IvuH74|S1~FS_3$ zqQ#k!LmU1CBqShiNcev+QdD!@WZt^)gVvKB|KSEKx=~`BL5E*ZvAJ>RI@gcd*-^HF zTwW9^s0vxb)LFhxRb4G#AE5}eN^=j@5{g6`@YIQXFt;B>tf@JUwwJ;7=RSm(#|PUa z@3%JB4xRvNavm%dLJ%BmlR~FudHb&HJ3eYRLqQoWNsXlN@4nefUo50+6h?x1-;w@U zx@4(-ka9s({W!M_(>j|_9>Zn%xL9075yJg3uqW2F5ZE#TH~7^Sd0?$JSE)5}CwTj8)J3~Tzcala-L&n$)v?iQCPpV%oQ>@L7^+6&tW$5l8k_wB5##$V$ecu0wP4!OUO<&+<{SyHxjtO?B8 z{1Wvx(CHNL{6o(I=jGS^FFfKVsA)U;rg#jLmEinYimf>RA1tUfpGO^}e2zlDzf zbbCX7W6wI{_H9ArC(j>*aJd@00X}lx46pBXdvR8?#96rM&1WmT%#nG&FHObNCK81* zn#VlKal{-FuGA{2j<`bA?#M}|s+$W}>Y-#F?HKlMfO3T1v33I7h*iArI%G-?QEN$j z9IckLIb+;D4QmzJfLd4DN=^ShGH$zG$;rex!O z39zNqZq!vh`CPbKA|YmBk*!>`ImpVwF0i>SQG* z$g(U5iQe}i4IA3$AypaHjy9#otBQFLs>_BH27%p^i%lnTn9tNFA;OQVv)$el87)M@ zi*PXnlPAf3KBkI}P`q;^BHoT^^;teryQjP!4Iv#CisE*RO-lHM*0#zV`XkoFBNkhW zKHhr>(v@3wkc6#VZAa-hqtZ^0my^2(V4^SwCmbpHwbkUr-0ZVw+_p7nF--jZy}B1} zPu*e98*TA-N9er#q2+^-? zxRrQMn{xVG*n`h`p4TDT^hSH=TL)?7@X)1w!~!NNnecOr7HjPGMq4mchu%y$J(LBX z#7nXCtX3^Cwsa1BK81pJYP7|ytW)`En`{e}kvk3hnq@{fwnmS_3?isI>GS=vn3LM1 zNK_@E(j&9`Ngqq0b7Q#R{KpsKHKo+NZ=KIYp!%^gxg;gPr=u;rOvDDMS}Ca-dnn*? zb(BDca2jN%!p0Cy_2?-vbzff+vobXyIdDv0P?6fXU@n77;k+rEpQ>}oBs9r*s=*DZ zNb*?8xi_ty=p!j>r?bgD=H^pk8~79dOU+r^sNjDeydN{?`ypKHP;LrJ0pxv~Bo=8g z2M4pYes|80tF1TXX8>?{!ryxWF5ffwIdBP&14rG-{-kotLFs4I$vY74SEjc_`iT6ZjobBB?yby#cLl}>cX0`8Cfl0bA&UuH|_66(jl;{ zicusf?+n!NxxQ3$x(dzMrfQm`x!qtLIZ+@{*F$7WO!a`wscy z#59MKSl&&?*@i1`ZT&<)@YqVz0Php`w$9<%J-qH4sxVA(JOPSjj{iS%0+w%gUTp?1 zR`&XRyyffQ`)Lm`OwPQwBk@F)ZmL_bj>w8($6sTa4gH32XJIyTZGrYIepf$oCv&Y8 zzgGS#p`}8387rM4wj55vL(u2VDyfb1H$e zK9s(42V$=~2AL~`1`L5!=UP0k0*RsQHsxZ$t^@9T)hY}2Nqs+TMo7oNV1XkNkG6n> zm4F(N3_B7?-8n3%O>DeeH>6vdl|;2rWs{yaUE>muON5ZR97p)*FlSg7=N$bxLqtsX zDs1YcxF*gI{3Q5+`Hi!Xb-ou233WzzFgZoTf-!0o+pU z*0f7H+l$we)LWV!V+BYWm{>54?6oA(LU2Cm^X!d=egczp+fh#P%wp1sA`JE+fA<70 zoLaB_`4fw#m#~Wik60`Ol%a2FuZ;T*C(JpzfXZ1i0OlCeeRy_u!A4V6U^Xcsi=Xa{ zn~&+DAzRI~{Nc`_Y^}&Vw~7)}r&$M?i>dsVi6T&~`4BS0;kWn#aYlhxeXbtY4n2-)B6Q`jqE=pm% zQd!~QQ);mEeC0eX2!A@c(X&^O`I09J&fl^mF1CUfpq9l=Mv9fMo$3>+) zqs?I(GHgUjFg!f5u2Y?r%SaB9+a-(JL$)EUcDt82C2c|hrBvq2ZJFy9pWD|E`FWms z1D==Qi?G*{v!_X)>+8whsGVQ737kBV7U5zH zq2*0?m0kIkr=nI3((E(QT)D|Lhs`EHlA1}> z5*FE#T%XFyCB;r+Q<6kF)BzC)!MT=)QzBei#FWli6bd9FY(y|q_XLkLy~?>FJyFeU zK5(`dqyF3*kB;mHp*c~N+2V5!GP;O0c2MA5N#6Yt8$URpe5~n+F?)kai!U<+ZU=p!z`U~ki zF0F+)23F;Pdb@7_EcWlC&Tt(OJHdP}x1Cx%&b(P^XFO1!6KawdxLnG z*ZKA4Ht54x`;it1Mnlx8zs9jDof$%O)>3N;g4;5(sIENJB5}IyaDH)mxM5R=gA`Gj z$X$S7y$N!AaaJOB&i_jk+U@5yYw|+XNww42Ljddve(Q_#m&d<4&SJE)=uNj!(=DcB zr%p(G%g6qzVMXreEY+>GsI5z5rW)kOa^cdStq0n<AqE|EEF zFzXgIX%Dn_g=Z}f&*!p^E2grwzfyPJIf=_5JpLRSpNwlxJPqIMB*cxHr@)B5r2SsU zs?hH#d2=kWrL0Xvs`2cYsL%*jwQVH%9eYtCc5{Xo$CV2amUuNI1jg?u8Mv}cR~uSf zoUNNw%*b+Gw0dLVgw8bu>;Y6uF-CVlBn3<@(U6r5gM3^_2xHg}>a?|`oxmK3?F6B{qK;&V}D9e#x{>69totgzK`plp??FC;_D;i#97b=G5v{a;R+ zpLB`Uq}H_DsB5Y(x)32H>uOBhnTyRl*U5UaRb?s~_Ahj$gu0J*4;W5GYvD_3|Vbi^hts9xYO@*mPb4W zAfkW24~F-N>YC&9wr*S?x?$JlNng@V#Pc1dW;)9rEVG*ZDbzj5^~**zYgi5Ms~=L+ zowtX*v+l*~y=}eZJ;_HpAJGZql;UZCF3LzQ*%w*mw0UU7EnrkcxX64u7Tp<)#}{dd zEjco={YC__s2WSe;S#QG5do~;&_UM9UXX#%4^ye}gD1EQar##0VR8-rx&We@3jU`b z4ka>O?XQr_Xls@#=tTI=e#)+lomzfo1>1uCmR|?cpM#QN2h$tPy4hbjma$7XEnGJC zEi#z7(%e_`C+mjh5)%yvvjvT3-@eO+gXz$L35SE}PCPybVC7_9Nu`Mg#H=$oK6uo( zGdqXP(aBAQOw;kdOWiE-z+TBW0J{g_QAb52PWNj3m%LX#08dk?+f8Mk43>&y-R18$ z6KEdf^sfZlN<>Qg+e%?=?W?xfZ{qjMR7{}Twh}F_AZ3>9r^GLnWSQ#y+O(ER@PSF~ z1gfnzT;kLS%(lW?P}q%;C$$cd8tyb9dJp*jrGxX}=3KQoaL;?l+sR*Q#~ba=z#Br- zY&o-OpL)eW=%OkzVo&kd4FW{OG5x!y=sFDl|r z>F#uVE`H5`Q)9kv&yU>UyN*H`)G}J!Ldc>@$RfB6=FZmG;s2f7TR+6YjAiJsmQtCA zCo8Q%zslLO{+hNL7Lv&Nq!aZf!gC9UjPU)C*~eg^2g`-L4km&>5@{A^>~s)YVmwG3 zIvnS0D)$uu-_fK`?qy!G#H~yoco3x9C)UN1FY`9~gYn4qbJ1_`*LnFn(Ff96FbBeg zv|qADj_=aNOxSjYMJ!cwQP;0RhdmhPuq<7P+{3+U6+%l`uzqw~IKlR7a_jD?B__C5 z)kU4;1}%qwqH81{?#XTtTlR!!s{>&VP2D-J^3J@Sk-N3VT^H&LkVF2!(;3(V>nC7G zV>_H71HoVngVgn{N_Q6IAXt92@epOWRD4Pid-z*W4VC9klk^678fyQMP03I8UIT1{hj0@mKV*wa7721R;vl-!!xn{F> z(PlGm`B2Yhu=3E)X3$vLY|eghL%fe1#n^I}2A;|a^TEUs`r^bLiCE^&+?~x0J;eRX z+zX;UofstEP=#b-tg$+S^M=9u_ifY{)%<$})_#HMoOb?5v`Ra|f8r$_?spSu&k%H6 zfIyY;inY5hOqW|o4WeGUKgL0f7>)90l75D@A3cLMDr+ib2)VbjUR`d+{WJesvHuQ` zatF+R=~Vad5ZBjYsUR+h2+yaOrqRPR-1`+hJ7$q6ylh$g%5ts3&M>QRz)hyID9mtM zDTzSp3B!08R2g9v&iX5NX%i*X1@cX;L;)?hCDH>~GJ=|uahW#46oS~F5HCE&?2%-A z87v5@<3h@o2`^hem5Ra?cxjzc$6A)wg8Q7RGCHY@v(ZY)V{EBE>-efHv8$BQ`9e44 zGbbc|`9-GdE@G9XO&UoxmBECdy5(1ZQc>0wAS;eCdK1>?cPFHx$hfIBg)<;+a3n2L zMt6ehmLD9YqL3|dNdHM>q~s@ayS>ql>-6vlXK!n(vwpqj9T6E0`Af-17;83RM_+UD z^i@YsI?imd>8!!A6l^2>i_HA}v)Pfp|Gxc3S2IAk$<3$-g@s{He@Wh>G9GyS3v|tl$xl|2)k)?Q`FGKmCiW+bp*xy8+r2(sYqm5ewi?Xa!iU~A&T{#s zy+rzWfiwc*6a@->q3@$Ln>gZ4dY--yhnNlm%+&`UZCQRWSNt2?G>a`+e27=0XxgzF4v>CR>k@g zQ@l8dT8nc360$0&WXgqXS;wfwrnQ}6?o+j-%zi2vm%i$fr;5@&;w>)Jru9TAVaPRm z4lb3g(Wf9Ma%$uO)IEwAmmp6YJtinsf>E znHF4*ik4qn$&Dq@ZCk9#6)Gm5%vN&|dxvGE!eMr4t2EJp!@UYYV$xi*KLVv1IO>ej z^%)vb=HK$GCxvXwt0X!dD%E~8NOY*dcWaV1lCK|=8&R!~QqkmHNnw*u_(5Z`F7?I2 zm6+lgz7!OgLa;UiMRD0HS$^5smPE1;v8+aWWeHtRT%@{#{;()A zVd@xu{YzW7`GKcq2>sz!cl1asy>Ru3mr!BK>P@Mss{9n%#M@k{aYH^m*Vt{v_ z>hOllO+KSD0#6j1%IvN-f)U#jxn?&g<8DjeC_OHt8&ciI9JKZzI2Xt?wk$fxnNPhT z4!JSL)pN5lI$}RiNEtfao2L*H^IdafDqoesd#(QL{4Xee46YDz$2#W4M7PnTUC|hy z>JEj1EH}Lw38GUOV=FHp2;%cgRVwIHE2~h5;wELkh&DmO7-g-_Yfo z?JcKJglwtu*4l)^NOPd9%&r(thwHRUBws?RcT3Ykj{ znnH7NohXqk$zN@|Q$8O|f|p`O4&fGdcz^~A6jNp(%I9T`Qa+Cw2_mi^@;$3WL=Cf+n7TJD zyeal48B45&1u{0!7$Q2zn;^)rw~4#38CzjBrC7$cs_~#_Zm6Y=Naljgh}VATli#!M z{3K#Ty)l36hFdA2@m-(J=N@DHKf`Bjs{9{Y&hB`yMa9LLQG0cyBA>%9Z_ap9@+GU6 z-Z}ImKs#ktPx`NxX#g^8nc|yEm4+~q)SYHKE<=`A9$B)junb9RUp3Xf6uASc^flLq zDpxN~Zm%0j~I zT$atVeVjT{Go^4mV~6&cd9?p$pBA5H^6oPm&90Tt%fRupvrmz6f&p$kv%_BF?j1$k^T&I6-&_6fnpIh|LZG#9#binKZtC|IC=1+C=r-u1c)BLGr{WHebwwt)$B~w>`cuZikjJvn%R$_Xk_Lfz~_-Rwf$>_Xk_Lfz~_-5h|1NqxhlzF|_|FsW~t z)Hh7(8z%J)llq29eZ!=_X;R-bsc)LpH%;oBCiP8|dffTfg_^)iiniH>w%G+%G5f$OW+zz1>;S3&J#)uvj;M7$`!MGpKTdr-T}3gdS&vB4>mqXM`$egf3@J z<<1E0&Y<2cl@enFEpPdl7$ZX2GeX-lLftb$-!nqtGeYAtsC=48Lh1IZ@`7U=lL!}|5S&LbxVNzRmi^G^iX}KapCdl-frd+XF zbp0Kf1{9ObgbInDTUB>dit1Tbrf}`j7_SjjO}>Y_3P3-ss5zR zccY|=tg<}=Vc{B3=8r84VTSs`5hquEiJ~Yen`t5ql=N9DC7`j84!fQqS+@^FAMj{j zY$;x9Qs8h|-l94cuFK?3DUv8lDnnxd7T$^#Q=ADR-c}**0OVG;VVRJNGM`MHnvzsF zoL~D;iLTU=>CW@DRnLV@P`yem6!LSwH5Q1}W(wJ2srm_R?t@^z1V}7V_n70BEWa|3 zYT-SP7}ZOA%dV?O~&*^xc@$ z*CKW6+QUY-CU|8&n%=hpl~|QbN?o}WR!Uvr$ddA>M0v=!57Mw*1g&OJaM*R+K@fa^ zBb+QH$@xc_42AVyX_@Q8<#&teP$&bEJ0y!gn{KoV8%-x2KvQ9_a?@>Ic+I`*Qutu0 zkD@O{r|LBoQGO++<_{Nw%;6NpsP~|_ip^0|Ha%;pkm}@86^7$ZO1zTgvDqh$;Up21 z*j>)qsohvV{QFDc?K}vo4|>3p1#jl*u#^@yXJyexWWvRH%j#7qA(DF~OWjQR*kt?u zDrIYXVgKYFP}%H}bit~5lfEbGHzGY!pRouhmqKP))#!WBu&*@jdA_zPr?3gCU#W#c zx=0C8q7dVWHq^*tvc*zW6xuxOd%^u7abL$RS$bt2)xw%au6f;3+YRvfJf@&QUXx{vIRqYr$6OFiA!^zmR?Ut&vG2(-P1TyT7^1=OFS79 zGA*QSiK;@X!kLnoeU*BBCZwfs1qKC)53!hL4>^C0S1Pjj48pF&(vuPSQ@eT#aUn`838Iv9r0|^zAJr3 zY4w-I+GKuZ<$9#;Ls4QKpXkeQBn!^1!V1`!TvAOTO;+k*h$+LL`e9gO!Cn?M{ESY< z6@?U8Nyq7awmya*hBX%KBdXC_T)Lu=B5NPROpTcRacpN>3r>X~HTbc%5~g zus0*eC9<>DnM!947Gxzef0ZGX*+xFTE3Z+sWbs2XUE&#urJ+rckWs0mhMA9Z&MdW9 zYHP|!n+w@WWzlld0w{$`3LW@Iys8uftCY1b)u;_>y3(B22YAXtO~-AoFW<1)yREIR zY@@k+b>tx1t6gGn;yI*LZ*CozXd|9ddbOp@f|N>^mL4QKu6#zyDNsY2CMc@14> z|EbDS%?d@poXhYpSkwv zMxiR$nWLwUpT5@Vb~?ukRZu&9-NyQL8%}W=R!^S3rZ5-Vyl`<2R(SE^q_gJn&PM0h zhI4J_T2OKHM6pE?)^hc_)4A8N&U&$-Y#uwhaqMnR_ugHnbLPzHGsS4BTy@>r$>Yx2 zsjE*Hnh%Yu&VUc-N9Pz{;dd)m34c^j$ldMn6wk62ssxHdNb9%;O5!qI`>?q?n>+Kd z1FZy!&uTMA`X!s(XX%w>qNTApb$e&=q=(yw0-W!1dRj9_`!yp?*(=LLTd2+`&6uTv zMBSKI7}t+p2VDTo27!G1s%whO7x2{`PUaUnR}8$(*$N-?mD#kvvcS8s{tTEcyt#X% zKbc&yvY1U*2IGEju!4^{HpgSkn)uu8Dc(6gH=dq7(z|{9t6#(T4zwNA67#Izn{i7B zCXqXB?0GY9-Z^tZ7*^4rJ6DM2d>TDGG-(j&fk?{MYKuBJLC2~H0;)LFd8+um9)0QX zXe^qeQgy7<>R4sVow%c|nKK@B*1OCRy*bek{f^D0xP7+T-*x+E@scku=8pQFizh%+ zc)(iTsE-u}hP&q{&UVimbZ#Weu!>-Z7{BJ!9gg?h&XA@_{) z+7kGav9jEq%UEx&i4jN_A>IR9f;D3m2Eo{yhIWO_Tw2W&wOOaRE-kZvSh0y!(=Iw5 zejB>$){RB4^ol#(YB>M364OoLLRx*D# zplc3{Ih3X9br?&}j9#jPvGgOP3QP44-pCMieGQKh2 zZZe++G9LyqpOY}(12SKcusk+HyqiN%PQ2A*(oVh9WKxfJnv9ovO!}z@nuzzAOzMf( znTW@k@HP`4*YJ2C-Y5_f%%1|`5k#?1jrmEmoZ%aN4imLl=P=O$V-8z*LVag0SJfNe zn!2;a0H$?+JQxV6CiqBg__OFW!&LX*Uge``de@h!P~Fp?9}Xnn5X4)7UAv_pXeXK@y7f}jrZFafujJ(+{>K_|!0i(nbn`6Mw-}LI*#$MV#0oq)6gDohU?Xe&; zXD@xjMR-xRy|Ax=y&i2mEk&k;T3 z9d}rpyI{fG@hEs-8UHJ9Z>+YOeJCQ!O0a9f+R!bUfn+xr6bzBqEDa z*j?j9f}kI zzBa=u=Czqhs$gBZ$w=6!hFNJ^s70-7&RNseO5yB=X>p~LFu7$fAj`~>g>Pq-&#!rJ zXJ(ra7n>~8NK;M$i`!{NHI^fofC1GC=agQkTHPA^Au9YxlB)v$3&lMzyiqn&Os_Gt z#+EP{8+&L>BidI=PX$ufmi`BhGnsfjbaX5d+t493+wWU-a zDP3JzCyqv-;!Q;mazGqkhf|+REYqcu*g$4=(8fvb&cL0IN5Z|%+TqAXTRmsq>8!$C zH1Cc2I9BPb&UanzKAIacy23}_E?eojBq+6u*Q7$G6lXZ5lV`a*Z6?MNWZLGQVlW=z zD&(;NJYwx+wT7)6_bcHHOxXWm$KLoX0@eJpB>nqZHTeFVH{a!oH*3LawKtviE?7RV zGx*`=5K4Wt@6A1a!sm;q-e?PlBxrQe7b2_T@k2Rvw(%7uHozFOsmrU!Xp&h?!z&O@GdgU`1PXr3jWZwP90vKHE;v$H?*}Wsxq|^_%wyTJ@Q}(O{ScE&^#^HEw;oNQn428 z<65x3;N)nDHLyx^RGFo0RrQG^&#{L3@!Z@5>;(=&y6xC8%A!O;6)_K;`5JQEBicZr zuF7t9rwDL!5%(~1&Q0M&z`W(xo^YxzpM=F(@c5;a_(;pQaFTBU#tS%&ylQ6hsw#PL zt{g$$B|u;_naFlFHFnYXzE55~pzn4JA-LtNGjZ2IQa zA!nb}ZFf*?iUB<3vGi5!XoZ<0HnYr$uT1c0B^V_2-gIY=pJs^Iv}tG4 z7f7txl;%U&Ok&EK3XkpGfn_tj&bhUS#bAPN&2mD@uaZ(7*oF6O6#l?@ad?Jin)4rJ<3QvxZkp zk2|aq@nzn@?I!)t)tv>m)Hpq;LiqsIi5l3<<=xCF;hzFI zkN?^`b7I4{7mcV;-BWBcIEA|7hXLY(5@_e)up(pzds_SmU%H4I>A<(#9|$q%`_Q@P z8J=qN-yh-z^Y!vlltkNyrKzdyWidG>ilI`M{eO z>yCPT*Z+&bp-#8$@R=XTmS&3(ze2W@O*~W9X?Y!J+d9zPT0s03n;aR213FD%Q8SQH zXTadpnPCized1o0+MJu=|HV?9SZ_H-{4!TVj`IIb=4y5!dnmcuj4TY_!K#@N7ugI+ zV}5oacA5FPZNN0kPe_*e>}NZ9qhzkX!OLLa`={cWgI1 zcCBI1vy?`YY@LA2RoRhLoXm`Kwy|$plH=ia;Z%23Y)LxAmIS*A>CeQLB>Vsd{V80M zS52MnHKGkvAN)BsL=YTV%Lz5&dbX`Ui>M#C?8{u36Nva`PN_{=i7>7LJ{;Acl~4jU!npa3*}iP zz~JHufR^trrCc(`JWV3=^7=2n{*(Ax*79#v6i?tGTK*z^8qSpx)PI&Wr0GR9-+R9G zRkNf*(02i`pXjRCPvlG6RwcVtU6k^SOAhaV7?TKx09iX}`u;n@2ySyr`lv9puO=!#Pi2f)+0;7SKl7RS+5YjFB*V8_DagZ%fz<a4i^L+st_ zJk!_u^`0jcVt!bsdP@iqh7%;do)U>O^b19C@=O2zvRct((DTB(la7BUE56>QeX3pc z2<`)^9~n0~62J1V)dd+pbi&2`z&S!VXJj2w1SRJ|$`?a)GVK%pHd4x0k&Z~CNlv_^ za>#bC-2BRR>99LL$=Vao?YrkZk)9NCj9)3^rab>!4Vn3HF^&guB2YN^wdtRiOXmJb zo^dm{pN8W;KVydYyEH?qxXiZYZugL827E?NPd_%$KNR%6g0WyZ$(n1YuJ;p)Uv~TiZygvUP1(CG}-^0ic0luHU|i>MTq_yjP^SJh2K>6$EdTu z*R48;S9YAMuRC>YW9{@QM?}uj6+oOc{lH-4hajp#-iSO^1*y;ETIqTbP)pUT-Js-w z=<+?tAk#8}pm)bxJUueeORb7(-S3`b+`-IJ8E1LLk3>SKum}i^*ws0+;UI3)Y4{U6 z3o)z_5EEV?O{XDkEtarO+n78Edq=WIEN#TMy8Li{%2kH43gfS;mGCRb$eR|f{Bg#m zP0z-qr}Gv$iF2%n^UGEsPyHnq)P-efLCg`cq%GXQRIl?Jy^L*7$3qAue$yFOR{J(_ z5*Oep5uNeojmQutZj@A*R^`pqNt??c~hl%?Y6}oHm$1Kms)jS{9@_by+^Km23$IUz+xAJ_v zn&;zo%Exti1X+AykLr;Vffb=p9xU#E?v`gPh+s$b_C z%W5!|nH6YD-nD$*ba5`JA z#da&9sYY)Ts;k$>BTfg>UM+5qKN^+PyZtiYeFL;PbcdVpLyJI8oyxM-Khg!1Fb4d#aCFWx2zB`3Ls>;@4IK04}K7MXprPl)MRiOW_4BS|k?ZK{r)xI`^5l#CKJy!3GkS zd}{{#JcWg2|2r5GaWh{TiuP#ipB!1z-D(5ZI_tU<|K%wp_d4s2{9-z}RIIMjEUUy< z?PWt=KA2LQj?A@epR>Ap5iet@hIVO6E|!&f_C84Y2ZnOZNhPN4O$(1Zv@({!fuLU? zV*`yLJl7s>i}!_BHe)OBXi2 zLD4{vXwrBotuK>$ydk7d4rc6I?LUS5r(~DU1 zB!!t5K3&=zl)5?f>z2;c&CWoa&<&X*lTD^H%*loHaQb{})ahmsv}Sy2%K3)bkA|fm z4YMCjbBUKK2+b}ag`nOmq_r}BG9^2NDmgmH!J(IKnd`h|StKoUJX+?wYMK3LS>{#C z>`cq-Ov@aKRm&n-H9NCv&Z||kAFF0RR?U8_n&Yu*b^#egbSAHwU1(dnfV>oX>9%D& z+Gao6mi1wdyV;D%D6@W(O(vI2CJ{U`J8Ar~|GP<@(TBriHF>;@{?z+;IChQZ9NBO4 z*W@a#0Cj%Ry3hE^T;L_EJ-x-k8m~#LSaUcs>lvM{%qqqxXiA&R+Qq2LlsK6ci(c2I zrBih3X?0?JW%3@H#Q4gbIc;<1v`yY4*NR@(#Z^cbw{??2CVxzMaVFN6J`IHW!7x|a&c{|!$uD^N9YMbP;Ro4@Szap41sgmy4`Q<)*PyA<3i2_v#9xt z*`Q^kRHFruWv|qrzqajR>90-seaUZU$Z?{d8rOw5+=O&#)5xIrI&^7MksjJ(GSg1V zd~!ziz0{)ta}@qR-5bFhs88KX-VvyG=n!wv$eB*N|MXs6lwBH0Z)W$O-i4C4Y9w)m z_iJrRp%E&%Vk%{ZoQis1S;gFOvWh8(81nR)WldqqDyA-ANIFL{fmMjkkm{M}3}JpU z>Wmx-wG6_U#k9b!a^hp6M|e%etd!^sG6@;q5t^FeM33eWajwUzM311YEfo+wB97S^ zp|Ba@qGUMUqZ=aPTNn}G!iW<-h9f>prNpeOSqwl%C~`)e^)bT3$p|&hh?71>obfZ_ zke}6wF(Pz1!%3epK?qMLvmNuXIx*|u@ub;Fgb*;|ypItFe#~~_#|Q@~YuLt!IQe6Q zvS)<0XT-T5BM$yplMr)63M0^D!OaMll12P;08nc8r z1Z0GtmJ!E*%ytgQh=V`|hb`T6!XRKc5Hu(yOag|}K)O=mOppgm-rsd`m)x5<{Q-Z{RLb*`sT3Yj z84N@z;?4J^E*WKc4PLzqQKg@87Sx3gHp`uA&-wGH;$_H6zy@3%3UU@OynO9$A^d-i zJQ(7+Y5x{koVA8k2fdpwI6)QwygZ0Bl|*JSJe7^inibCc=#4`DgWn=g_tF{O+-dv& z#BCiu0*9X3DN?H;zkyFJG4g3QuF85!R-Ji=@;;bz!-hGP50*b+`-hZ2H^_I&>-^DT zaj$%iJR(DWpV7Z&F8(Pmj-WRuqm-8JbUL159XbrD)ZG4J?u|!0O&T6z#s6Xz@ps&= z+j4PflwS~x{>Cqnt{=s!to=Xs-nF@r8%Y;_f0Bx%DCwiu!`aog*Y1#d_T4>SDtIZX z%gu|1q|}ms{dp3o3vP)5P(`+S;y4^_Hw$?|W+IUQ5{Vr3tnv*Ww#`rTr`Z@)IaHGB z;MZ^N9rN`8Zj}7T>+JUQm7ZBXippB`Smt2w@RaT{6td&JbiyUyu8-vculIrz&oB-hLfEi z=;7YIEQ%v#EI+O0r@46Xb~M(i+O-AwR75n@pvdGcQG;=dJE~&nxo?Nxk^#?A`~h;9 zw8o69*RJ+WnF1$RT{5TPQlGf9o8|*vOh#=v3}d(L=(i>HUI&5PScL|Izz_`Vp8$H) z`1|+&?i$=QtT@Ne4UOUaybW~?nrL{)AgYW*>QrNza2;xNa+&P>y7+c5kO1Q3S<{No z$#xMOZiu+}JflM&{{wXzfBEf8{`ln=qY70s>NCTU8t!5I_#c1#|M};KKmPq;_V~yQ zSU-xJ$6x+?ChI|d{^iS;*~9NiXhvUVk6#}1FMs3@|474-p$q?jG=BZ#Z`BidW;M(X zVF1DBKTxCa@&5NuX?>^={5JdV*>6c0#ubLY|MBo&zkEqTkv;tK```ZfFH}~ZF||HB z#4!HjA74KI<4c~-!|iW>{Clz#?+7?uf>#8d&U!Ze+w9Bi*Dv{h&Hf8q{PHPnP}Erd z{yCrh&#$x3X{wz5`pcJJ|093=-^YCR@bJe&8ZTG>_K$m%s=NRF?|&p2)b+nTKo01~ z?AIJ4{6Er=Abyqspe$*egai?+2pjhYJTNOTxIC_9-dR<*I6u7X5OQVXW3K!X7JycD zM^T29MH0lz^#W_JZ&*7OOGM(Quf)&IF*kk<WJJ1Biu`Yk}0&ok7p|1TH+eI<`Ix}xgkc@ule;zQ-<&uEqZAE(Bf+R#pwyFom)_IhBU zntDm#O&5aU7omh!p$*re4a?AmZ=ns}`G(TXiYi9RlQ-jCxe>b_nEIy2W;2g;EdlD{ zL|KL{rt+}gQGNGpjJ+e;a;lFND4r0${vCK4#npxujtMM$E8dUYNJe)h%Ag%^c5$L2 z{x72HysUIiTYGo}CCh1xRM`V_oLNx)^QN*CJ)APjes?o{HhTYiS$d=2|F|r{@&C>q zFHCX2D=tfM@>g-#>m(Js(~i%Yu>lirb{pH#rhtu~QNbLe?6{mi7c1Hr<=*t6L$x`g zE9`r6Oxz)geA*PJ{SFlaaVT}&P74&npLB1j?d!XkGtuGkQ+?a8H%7!TN0b=DCi#9N zD|+@v+4i~Ge2qu>(wwADWvsiz;^8@8&&$odS;a8BF^UA1D_zW9{kKtY7C`D2VKy|3 zqI~k5lKgzMno^6_ixhsMROwZZOnr5FC%gGplvx(r_hf?s@Dw#f0xI!>4ryuA|CR?0 zJPV}bxeOOf@OvKu7$U`9>sLC-5%R+EUi*94yB}tI@h%IdMWb@^ucMiWDrrGdKPkdA z{o7S|Q`B({WZ-X|49sTTOkx+VlRLEOWD9LP{4_@8W2kB5f|vS&moGkX zEZ`GIYsJ%A@wD)XqlHf#tu;?;&C|jsjut*~v`U^<$G{yst^3*kOevyP{kCS;bVHX>|njUDTn zw$L^0I^@{4^Rw5s^UKb+D(GU_7dxnNpF=7>(2kDzKqLD~5khPyMN|>lI{_2fEddkU zpGMs=9a4b0tgaQh3KZNW70A;kBbYJl#)xO^uO4=csK$Ub0vqeAPdY|;W5as-YXmt4 ztP$tfUp@Ubq8$U)2zacozWy3vj}7bTuMzwhutxl2fA#d&h=L4QBM`E_`ub~xLpH41 zU*wXJXJ_Z!+vY8t=II>G|2V#Dyt%%sQgMA(`MYcA%k2s)1aURcIB+&lS#UN`c;Max zQsuz4Q8{7TD9o^J-27;hGQ*G7hT%tVGr@uia>9qEKL!^Uh#v-f~zY8>h2A8#*p3rjxG z)FrIt>jR0RLtraxq}HpEnx%UF`|ZzLUVm02r~a%~oy6`R=rJpo$W2_VruBv{q3bOe zp<9gtdgv6VD;#NL+X@7SE#ghuEZ;(L`1h|yG4Q{?W;C>F6;;odRYMHX7xD}2*2X@q zuMvl$7J`dHsr@)vVrkv@f(hQDl8Ik5=*9D2a0KGTu$s^6M}N0Iwf$1sTOIQ?qprEX zE1hE+w5l^n@<>e>&<|`5P(v71}Z|Gsm07 zdNaq<%bo_}F}_+NMmzRNX1(2r&i_yExi~7NfwldrHyCR#{E>BHfZfzr8GUWlnN&V3 zt>aQ%PW4?L)z(i>d%8C{ek-5zWAQvc%;^pY9m!UYKsV<%5+}}SgRxF=_*cn8o(4kS z=&cx1GhHsDak+cm%<+P=iC<<1iSbODpO7M?&?u9SE~=3P$MnLWCOyeM1PmoSjvGHE zdLh3pUjbOFyPc4f7SGS-&)*MtFHP5((kG39Tk-7o*Wzuai|`IovBlAVQq*%#T{6f1 zANY;#^-=>Qx8RxU0(XS&zvQzC#i*FVuiIW4Sl|n~!6y#zMm(wTreA8VD+RH1<6_A~ zNuDl%y{R8p+tVaupGiB8wM7tXmf{Fob<1)>cg@-WH%@+cW}kV)fl|B;!5Ak?8|7<= z3M_Md#2veCD_2~B93&KxcMdHJiURa_D7=E20EKBa0SdEj0u-$%V)}LbJ{NC(N^b=t zdZimOinv4r&*%{C6!zXlVKk~P#?&4!1I@E+Qq5bw1ZW(sl}_lZ7wZI z-z;x_v&iThD%10oxZu<{ATf|Z)D4M`u27Go6VoTRo%3+ z_|vzgWjlQ{y7|rGPv3Z!?ey*D`Zt?DeQUXCr|>5yp6m))+Q@vwn&3zge;rOczB-pd zvfcRkbZ8@f`CH{Z##n1IpJ=a<;HBPk z?Ov;qP|lU19Q^25*-5P88_?-&<5xo;a{ElKcM(^$yGk`0y$4)_X7;$sD@~9?X7N?c zMR(n;XnCoeYPT|EnhR7e?)2U4rdRszb@MYtqz)PAo7h!rn6NG2kw+!;%>`ko#I|8I zJ3$f`=4@(L*fHcLwW(`f+PDot>aDf!G|xHilB=rF6&wIkDVb}@+kE-v@e%lFc_jSi z@tpWt>N3GE@AWTr`6F3RX#a9p7IGiw^K#>9BZpb*Ivi*)!Zx#6YgBcUOb!B3!h=LC z6- zj`D7pI#>-KuNp+)fYo3^N30GMIAnF8z%i=VlEOdZ?aiIYO4h$0}zVEJ?uT6ue5-!)W?yw~xqt$xzazq&#GiEhf z$#YRG8mxF;Z+J^(eV_J+cUVpbPO>d=HF(-& zC|5y6%!%@+bmL-MY!}4=>!DX=Nz@P?0qtr!cd1{nG=XdfQ5YuY zVGybNkiAsxawtjKbp_olB2i|dvCMlB9QCs1AcWzj5r8hrenar}EkcZHhm}pjnj)F%sRa& z!sY{ICtTkqoSDPsx`)L!oA}0FWEhbkBk4mT)UJEcI7cs%tUs<7p#vfgYv>q>#2Pqk zBC#fpBsh4(=}!h6LV?(mtS$(5>YxcjJ}BRV3=@X$)bYWfOC1;-y2KH|p^F|0^%Qlc zu@Hwo(x_sP$B%|6?89>2b3FJtj~@_zeDNcq17Gxz=)e~+CKmccfXsoE*gpVEr=4`- z2r=YtBuRWko27$~5bJY*g&3I&EWnmrU;!qx(oF_gB`GEofTdGaoj5{FrW;8TAJHb` z;3LFj9AF_P;{ppX85dZ9$*gsgLB4&8$pm2OR8=RA5R>UflEg=}$vF53F&PI~h{?FX z0!+pQ7GN@^ZZf!Rkzz6dSUOeJi6g{hx{)OD5p6OKK0-{!0TyC1F0cTTae)Px%$sg9 z$ZJe7nE))Es_MiMVlv%GlK6-=83!LBCgT7LF&P(FfXTSP0!-#zHyPx-rkG3smQGc5 z;s`OBZX`*3M4OC*j}Vh_fQ6Wh3oO87Two59xo*z6kNy-{v!UapyuKT4o~yQJ=~atc zx=(%FqqOno<+ii6>(t&t=~95z$R%#Okwdt4BZny4MpeoHm+W9SWbz&ChE2+YM{E^! zzu4+VA^q@+t-|Cwb+-6-oZWF(jc@VN^qvwotTa;t0@cL3n>JeseA}DKIPV`zJjYa9 zsC~=9fmdmO(fvl}?zkEDpnJngin3t#H{c`p= z#~(C%1&JaaZIIyN(T0jS7PC-FTU)@=N-RFF4x^FT8ow>q^2K==%x{aU*{pJnc+SBv zJ*8zNT^+9?9C<}>V=}p3E@{YtE*{> zACWcF$fNlkd3fzDpB6`(byT&~Z!gsiwJUepj}BtSeWtd#Nlf$hlD_8KHS| z*U;Yy+>qAG(^--eEr3L^L6e+l!izwB=KHQ+=y%W;z4elpw&QG48HcZ*Y7?%bY8zKi zo9~PQo9}#Q)Fv7mH+YBg`}`nE3(6~eqOcuZVEp4tJ7Cmidh*DFNW1H7j&P+a9mt`r zS?q3Tnn-=!jqb+Mxx0rMhXnwLu3m9K4mJqi^O9dY$a}0#4XhsIZC2;Uw+DHr)%o%LLEdcDKKhnjbs&mMjR<_z!g=)<)zF*Y zlyyTLf||>n=67Rt)BJ8PX6jGG%wA`vUa;UxWMJULqjjoY!YG|WT)N7a^WzC#vvC8> zk7~Ts{;0H6^15L@TrET88LWER*8%m>-99PTvgB>A^6qV@_Q&6l?PE3MLV46@5*JOq zq6pK1Wv3aYoic7(^3rOW@N#OK@GSAJvRi732QrMpCrKZar!O8x)p4Wi#G-}uT0*}F z%A*OBHEJHw6VW_GLybP;`k;UXbwX($)C;w}yBpd=o(`{qqBI;J!vRXsxFNKsKpmt+ zMdZeLD%OGmHAsX4rZfy&7=8Y!F_0! zgeJs_gIIGPnlhm#s%DeV{O~7-N<7?0J7*@uiGz6KJ~Ruf=Z#(!Ls_wzpBkYYD*e=Z z^r9MzTxB;UOszJJ609$c7OXEk#YPVnOrr?vOQQ+vOQQFu!6Uk(SQ?Db>=wOV3OjI!0sd?Q|x)OrJEm3L`JhvJzYoZJ+z1rZpY z!Wd=6pYhTv_5`-58gm8`cl7A(kR6CsI49~zrE_Q~t0vHPl;L(wHDpd0#95w++Hb4o zX>A(WJ{y?5e*PjiaQy=&iJEN>=Om}w#=w+>oeYeVY-V7TWIqF=6s{uKO2qD7Jaoqx zXf0ZKZF#c9q(w!iuEZ%JEPs?wUv@7?Ji?8CM3K1>N`vdo$mvgV@tz&E@{fiTxWB{U;!|8oGLZBdnx)2OejV+xiQoF4tIq{PW zTe8veYq9)>iD~zA`a0XPT)AM!m@1cFF>jv`g6#MnIbbKp_uaDESaZn00dcKvY=(hM zt6s@faTv^PdCZIL^XWaRI|AyTh-AcNxaQIKtcn(wGE%&!3M?@ahUWE2(1kAw;b>rl z&2lwNx{=n|oO0UO?@p(DRh;JK25AbygsJR@SgKvYQ<|etuHjlIn2k2`zuxm|FB(F* z&RxpdiooQGTvZjj$sZ&|@hHPqKBwd7uprxLGC+98ruIsM`5pvw4dY!E>vD&+fe=Th z_0%s)RP2v7D6orJMr_94uPAi*lH&=N>Nw2V>Mf|%JJ)Kr-(fNLK3{B#Jj;~7HA!YQ zRpp!B(lnFN@%?xzw#}Qo_4Y`ONc-F#*;k(@Lb;IOs@Py{rH7%)q;1c}>a^WV%Vq>& zq9?hSZLUvW5Bu*ZcDyW}Pvw3`JY-WkBvJK)IsdhJUZ-N-0eNbc#y4vWmzP7~0<^Hh z_u#nnbVo*>m%Ft&9oqnEK10Qh)yVW0c7u9jjKxr&8?_Cv=oc@s$dWT8EN!toRhF3h zO}TuZ{Z=9?#ka@drkna2TQ0}j*mOVM#-=Oc8dnv`5SZMFcjARV z#UFnbOT5L!dUrY{fMBY+s9l2TN2Ge7=-fmo(7HofDKvkYKgrGTbI}Y|e5&NkXqGj@ zP6Ez3x>Em8n(@)75;%Kn!cXJ($La9Ocat1W_YD3{KY=~#wJ3g9ol;!oqbp_bot zUUqa!agFVPXVl26PnK9MgrmHfuU7PeoW8=g?K1-70nso5q~S11=ce!R^x+WrIwpni z-gb}da9lErva6pl6N8jom6yp{OB6;i0}sh#_W+FHuUj8c*gEHJ2Aj(lgqd*+LZOSU zNk0N%vMOBNP1b}HS(hS4SF|^fFZNhEwaeidJvMjO1Y1b(H-g8TVkh`#hc6FWh;WEqJ#Sqrxf}7&4SiaC^LB8GZN`#f! z7`xEeo;{XNyE!F9(1~}u19sOOCfs9>UfpQ7QB}VbeQ=nD1O3$uH{!n)m(b7$3@U8e zY>iDXKZw}K2>}6eQFXYQj+gsY(Y-55(!0tV1~q}X_`;fIP$Hwz^5uZ{V3lDYH|c~{ z8wp}HjB_A$9`t1_&_0AVY5E#NY@v7!U5_T!aI(4}hh@Wky*6Z=n|lw8if-Zbm@cbf zRUtxcj89rPX;JM^OgINK&qMVPrJSY5Q)6QU*97v-kJ$pctFweC$B zn&aL2IlICim7vBb<|+~+=F4SqJmN?Vi%J}$l}c)erZfw|uG~z@-LZZ=MzT4>(1Kg?4B!aNy%^E{Hfj*43G>1O};JiH3$G zDSijZ;lX5MJt;6Nz@U%_eBBD7!605hl?;qVWl%>}i^hpW4vF(&6^XMTK1bKZ+X?puY3JR;aPc5h&Jr_IO3;fGzv|T3b$mBzvTmB=y8t3av{MUf zjO6VRw9&vbJOQuf-KBiOG z8@j$mi^P1r+0T)gWmQ#JQSt|A9!8MmkJYQ@(y!Ltygok57c(#k(s5)q`VQX;wD#T` z2XeDQa@Aq~uEl+9;~2~krOVDto{jAWjx-}~3!9thRLc8!SXQY^l>eN`vvo)i+28Xg zeXp|S<3-TgGv|~#Y-|D;2^{E=2%>ruKSRt6oIfI%E0)uEsgxKfRg&;Ac)CIy}ZDH6V6q$n^AB1KyFpI3@RVMr+wzG0*&Fr`S5yNNiwi}X_JAyqHlB>_-8Caot4A-5gau|YbhSMI?_PyHnJ zK6!wo(o6MFVf5@}(+^Uw&B#UcYm+^*f*l0Us$qS_^<$K)^Kc2h>J-nbQiIme+B{F} z#(4)p?MxbyE7iIpkG@s!-~IH>5)$jsQa?*9#|eFac+Q7#12mJ(T_n?N8;m_`~Rky?L zK`P1s`p`Lpp_IQP-z=MoN)RQ|g^^3T!C^c$gofF}3hb_jjq{m}hv+#}>LYhH&E8Zs zK9FzrLsjeMp3dd$bvjbU_x~l7!13^rdi4QEowbGXuRZJr=j+UgJe6Z1y)`yQZT9B^wFFRV2`t~75OHxlh*l0=XL-1%p zq}Tu45=dh850G#{Q)73JZrkgiFFU<C5y5LjMf75gLYRI~b<-5KP+5W?2)%yxxpk z&h5XWT(2Bb-$%Q(?qaU)KQD2tF~W=FC`*r9u=B%V{$5|bl+TjKUB*nJ;We8ijEq&K z;c^D8x0rTleG%!R7wmYYwRvwimtNNaz>I=CY=$O zd;?2M9Ao5#Q(~n!m#eM_M?zkp>%0!J|a6r@}!SxFYhN18kieOM~!tsdw1=T^Ci42#fZ_H>H7l1Og@w5?MRh9Ru zI!xl3gwxmZI8$FOsZ8u{v&>8J>IegOMIJG8Lop6$6#qPB{>~~w#BorAW_1L$597mws+nyFb zE$0-lvP1Vn%bcR%pM~?W=GPElArjKcbO-q`9gDFPO~IfqK!Y$$s_6j5td{%33NE^1 zY$73-08DMxy zSkDpn9Xd~x8VEFn9t<~L(4+|1yX^jdF)=8*s7&qW}$hRE| zI%j4WZ|=S}Bfl5U{(M>^aR^2oNPBat4dMZqH1MVHM?+t}WkVIw@0v%;`MJ!iY=Mq5 z&j84jF2D(-$x;BOP=sqpqbLBwDY7fG80sD*Nt~DiBSPB>D;Aa%UR3)}Vnag^$N@}T zgnIUPQ8$!X-w5zfR;g(yQ>V$MJc@uQ)SF}b4y*VGOMdJ_W4L~pmNPp?M?6FZ>xpW7 z=ja53zYqW9-bvh(-gcv7>cbP_%VAj35cS~*^U5$BX^8r8gn4HejxB*t?z#Re{tUI}_J zacDi4HgJ*jHlP<1h1T>MxIlV~UL;FR znLR`hVa!Q(UA%5iFFuI}$+2H4p8R>4Z?t#H#m}w>%w>C|O&qlLoUxymrhC|&m!|%} zfTrtf96w`It=X~gZU!@gpW)dAZr7HxnnCC?GocXXFa$i>8iqi+YK+k5a=Hm5+(S8` z6w>X)S4s%-WPOAnk5L63mpkVO>8d)8Xo7tfPbNyv9yBo$^`J?R zoogaJi}aj?Qsn1GlpsMjq8J$>=ivh8$5M%s9*-qPbUc=LxjE%8VvL~%uH@E9CqZ^@ zJn_ZhsP&BGnEmG zT^xE-F7Et*B=hGJr9?uaj)yHNPeimyMakv4~XBrz|$%4o)J&VR3X(M(+Ol&^z15 z;`a>NJH<@r2aE&UGBW}Yb24u29IAHJmpKhrJYW79fD?~D_Tr$tGl2&vzE|FGiKFBVnnqc< z!bxhmE|+tvn%wPGIS5a0Mlz^0Lmb0Z8f&#|{CwE2UY12J?nTm}ai*uz(hpNnnBl;k zt&Yw^+Bs=5OVmUb?iy*m9PzL>E-$b5NeAaNFQ@U~3Fp!f`g}r?qC5+wKn_ixdP%E` zrhNvpvv~Lsc4sot-|$R~{VmVJ*w^2w6Wj%@E{g2%2B(q#0k)>n?`>u(vfdV^AxkhW z#4hJGqYwgv7z`1*jA?*UiV*-TMco9Jpjc#^oi!8+z(0suLFY1BT_h>hAH{RwiFZ?n zjX}yYt26-rASwl&%c!(WQmKEr#HrN3UgDrOXI5zd{y|gSB$+~-qnrn2eD zZJTUbugL4Qsa%v>uP`wZY%zIePo)t*S1OI%+q2E1gAAqiyPJqYKz|FhKGRSd=os3I zg7$QOhhlAoc$^AZ1So59rIu6EKB~tk?FZwW@2=d-YHr8uYE`_J*eW^ApMY9}ZX1o3 zoBdH#4DvP`uQx9^xL<5K(2c87a*LPsn)ba%>t$6|DZ5&hyZpF+IV_8rU0e>gES50G ztNdCVMa*WC{WDVCA&^PF*(k=NbZ|IgcSKB7@Vpd7Bg8yQuM9gs4-MVY!)T1>3)l(H zG*L)!_swSw)BVc{CsTdRA%WlkCXqlj$t)7+B$-AEofPx9Zq4ID?jnWa00xpmHpxO# z2ql?F5+T+`t~Yx;$Xfo@J@4E;?~kQ8t2piR{d#>YPH-!eHGaO&vOM3y;ml7|Ezdob zK$)j`AiE)0vKjwd69^dX)g;UE8RF*P& zVRLjl0-p%6JnAuOd$u-rZ9`i9iUD?Xg9k6Six*x!kEf{^!v#t_K~ESqdVJdiqSrPa zqYr&hSv`tCMwu~e{CxfWfRf3Y(hRm~K*I8oQxiR|+Q=ENQlp$3oSI0PZI=^bb$^X& z#Zn7`{m($ZGAAL~KYp_c@@!jmWh zHlqm0*mgFmjDwv+)72!BhKw&n)sk^E-E1*Oa{bF`F<*Y`F!pS@DR85Dy_r89scHlH z9z1H%{%CoiiQfZd#app_K_CZ@D16~)v@Ny^6ml0~f`U%Cx#r{{sE54_bei0Q?MeO28Xlshc~q>a>D(L4&skHlLT9&&-KWZ37V;9E;+c*u4nn zzT|WpJj_Z13GD>i-=VYil_K0F=F`z)?E~2)7#vKdB8%ce# z5Y@ZQ=TAc#D*PT2aI}{-ZQmPi_Y&RIzZVdWZdG*bK6+6Z(aw)?3ltHzrk$<&Oc^&JJ|SH2Dr`oM;PJ`t}Z{w9ZU>8 z%pD|t%s{sp=|9wMoZW-nOjn>~O0T0K>c-<;M<~*ls_E3Ql%%!f`3c)14kaD7B+5p} zMafTxmm)9r>)FD4@EM5mno#bFVui&yrATxHcVSqi)1nMxeOWXB!?%*(x6|x%SBMW+ccmxUXoxNdSaiy?ArKpcW_X%I56>ozb$vKGsYm{l#UWcoD_B+^u~uc9Bz=dr1S z9mHbkAC>xJE4E`9nBW)(7?%|=l`y$1#pYt) zHFvSEo)`ue?&R`rqY6L$M_vPWQzp04#%-N@?+tbbrhY>k9Jqipd+R)!xHwz548&Xt zid!EHEVA4EYjId__TM`WREH+pu3yBVpDUifL2BtG)pXa)HJ9~Cch8i}yq=ev%j)2c zMvI(QyN~iNstEFxKVZH`!FRk0CI-Vroo46Sd*H#>xkw+HUe{`VXnI}C{w{jPG7=6t zlXntjV*Zj|S(OC?n#I)_7b+>-47gZHAwTGXC7pqR7A+|Z47+ei;$YClO9BV|7cdD# z2Ux@;QSH5uNuWC1VkU+701KJ~vV$yYQs|0Pw!s!Q2^?H%ag)m0r4~2|{0+6pNg;iS zg-!xrgDrMaXb-jENuhnQMNblQ11)?~Xb-jcNub?(0hBU6ew1kcCka;bB)sDJ)!SX_U;{rPf9%3=Xw8N}_#<)lmv#gDsDeh!3?s zN+N!-1yUM!1Fevfh!3?yN+I5Rjg&&P_aZ5YXx~**649<@(p{A$`u#9}M&Y`)#8G)y3GPcvLRi}RWX0>A5Yc>gFm^rE$8>~1a7hTQ;A&e1+cy(t}j#sl?G;9 znqt5>ba2_r&M(PmPy09@tM;83bry-!Jl!}U&G&V<-4}H}3|~F<8YVHl&Z}HWyv}Z_ zpTz~N!79s^{=zY%D?Ebo)D$nuzwS3kfs}W^+%=4F?W#N+JJR+O&`ys9N{O%hskaGu zyVlJKDA`w!s=EVxVN<$)>n&V0jNZjH-)Wr39%0+udWE80<*E-lq4;p;Lldgk@jVMs zi)>ix#yoO)1}r}kz`}&K7T8I9Hlr5|9;dV?kV6~gQ9MjiuEmwrJ5&`ro>qCezekhV z?6oQr?Q`8WJxgroC+QH>&_t&%yAH`dU}=YnToc*w88y49s5U)IAd787?l<09Fn~k{ zg#-eYw$9QGo67J#aTvi_`r@L~uQxr)K*(1xD5KDCTm4CRFEjK&e=}dLP^IGNpR;=q zz&v&?-n(l0_27EdQ9U9CwKe)?=P(OtcUjcka*k{ER1wARb!9u+t?p_kN;indQrKN>+6nOm zsduvegNei%FNt^@a`IuKCv8Q%T^;%@s~3}aK{z1d>UG%&ZkKpW@M(W|_Zg%O=359i zt?N@1bS#n07DLOY=WNwMnP*hK$I5?~B}dpL6qC3rU;Dk^VAVt~D>~L!`3)_v=G)>P z@9f}B;I8#mA|HW|dQKD3^X8I>kk1ZCMaaf`4upma;FRmni%ZAbLs@~G|C+(oj8Q1M zd6BkyT^k7kv@>h(11NU-Z;5sq$Xk@^LvhAv-*ViX{(I;tn1-#XQX1AdH5JTVl&-?D za@wlTj7>NFvMW)wuQ;BvEBZ4(zTol7F_w@sk>zqHexydT?VoByz{AlV0p7K2A@iqV zM{i2*53_C*sJ^yE@r&8ElNcPQAT*Y*7%ZV%Y?|MHTI%&FoQy&W$*`v4oCM6Mv2Bzs z=k(U&?wA+<6wEGMoKTH6ql93KVzin6^`2L52e;<&jxoJTpat_xYY0s%m&7$21vTSE zp|QvdLvLmTBnofB3bCnyH}{U1I`DuX+gr7%Ikz$x`7tq4u|5Ar+d}%QZ!JdK3^Ae( z@ODG5zZ=8^9UdM%b$m1h4A^ful&aM~5lUX>+ zN5HRRoBi9}3koK}1BCbZPRM9etmAZ}fJO8lh8SZ2RddD%+TBNcSmx2~GM&vCUtzbM zKN4y^Q%TX>x_raF{1(ZVfdn)>Ij+WPf;9P_?y93~qqT#$JsWk73~S_G&>eBpl?^GWMQuw0gSpQ083OvM8y zeDQv9EDk7+Rfj95`2nE`!@3TUiNCHzRBVBPA`W7-k6yx&4z67 zYBcolsFU{axSfA1#G(yD9I~l|MMa~jX5E#{JwR#LRdGW7Ivj()95F=XJe=8cJSW`4 z%MQ6GMUD)hb@`NC(G0%cAGUKN&q%RH10*}lcdPvtFQ@VDb7H|1&+xZ7QlN~jY!4k_ z%cuwoT&%(jI-`T6BV!Uy%O=oq{#xYE^V6v~1XCJUl;UJJK7QSQr=k61pXTzC7(>-~ z37rZ(TW_)RP!my3S9pPZwRj2@;baGi%a_oX`xUzaH8p&_z;VVmOhd(zM9EIZ7MzgC z;-%amrDnI@hq5`v*8K7-NjeTz6NlTNKm_>_ZXhYN*Hsg*;%We~Up=?e{%A?n9yEr09z(ErvtlN((3` zvb3Pat!&_cXejy?zWS=7^Bel3>Yp7-VM#O{o3!*zH~sziBk3>q0)FlJ_T zFg19#5CwC$vSFXuaw)enqPw{{vg0gFP8EU_!ZKdWw9VH*X921b zdW;b+HVuQhZQ-ijKsO}4KTO-a2rMWJq?JBBu~2z(#*a9FT2EOCI%F2{6(XZx|xXar3_>T^mvtV7Z#$5UEcIr2zCfq5MuBvTYEaEjG%-^6nlW{azkqF zu^yG6DzZK+QVUz$n$!Y^gW@(u17+jUo+(Ct)p(nKF63Rfg4gm+;Qq^bCt9HgvGWqSqIY4FrYo>TF6uk5MXu`|*!VHvYRnG;_msrD zn%mO>TkQwzW;Z^kT6$``iw|N3w}(Enp5?L1tr&Tp(jVtGlCQh%{D?V2_EoyS6EAsZ zYgY7k^@@7A-)yj*Egev|A92EkI1(pdkSB3Mrn(X*vS450hVJi7+<23{i4$GAJLy6f z=}%nfJZ9}MRNg_{o%Y{~U5-;~kz1N04OHF&8QsW?P)x5#O3L+S_e&bwcg^7_ozuvi zIq{YdJvN31HSvxR{#hakNw@;X@&UOy$f_7+*bVwVKj3Pz^j0`I7Vp!Jv1fJv`SBJB zJyd<-amK7E@VHf#f7=EJqpU7Pfx}Zmyu%p`&f=?MUSTT2Pq~*VE|jbkN7$>8+ijI| z$iEgF+Ld4ZKR-PM=HPGe*7@_OPGW;R$s^Imb@mUD2Cd477R^*yZ6{W1*~~G6fNpS2(%@Cr@V-1dRo8Uejqr zKHTlRX!KG!Ig3R)72{hRPS&A2b3W|hOz!e(@qayV6xQ4;G!I&3=5D512j0jo3&+(6 zFqSEHEc5;78qA|B8q8W+45snXRXrJ1UmBKu{bg`v2CgtwGss3OJT^^PP?Y>6Q!?pr zN}H0&7RY-h@G4_tVN80@#kQbgPig37)}e~N7RDg>yX?a)(@ql^Q7l$&uqaA)`Xdg< z2#KG#RsDP@kmpBA;~bWEtgz@WGO@7KBWD*DkK)*yfmlUCXPja}*y%OTL=mX^8xRUr z&XC96cPe8sN6%+Grk2OrLpUa%v@tQj%*OE@F}-mpI(-=9NxHq*^9G4=Lrrxf23z7} z$Dtc+x?>5nhSqPw;|L5l&(1BP4}em z&at>I<(jlm7<8sTST5#$k~b=ZbR>x5#`NdEzrJGYLofdkfr9T}OWkv@*YG&H7wfH? zD*t+niw;xl%-~AQ3|p(YTCE9}jrEL^>cUyG$I~RhcQY49cC6ExJ7|Mv%{8rUrr57Ab>+a(G_=;@aV()-9uL3XozIUKMxsa#%jXY{Ht z*3l?)??;6>px%HuP_2bi`A!)ZHa|M|YE(RJoEmp7ui!xbRK-h!OkUj3&at~VVX-LZ z)?GMoovGoa5rLdj;^abyW(_8zSITZx2S0R1HrtXP$|emGQRCOW2i?kaOxOHAo10he zd#?u6wyTxAd*!*vbnQOMYw384SKP_U?x+1uR!cDN6U=5^1zox^;0`b|syd0YSB+aU z^LTu@Thhev{6$o^We6jnlTCC$n1$oqbqEr)oT19;&nS9w%=a)QuBuCG%-K!3TOx-A z`6$KPbH2vCTBe#&3*(Vggw;1g!y}axbo^qdp~zc9v$o16&AP5GOOHDe^^Ie&%vfR| z0)DCuMZiwHp$HPX;7N6DgG5VmzGbn4*^w=8S{bV==4>)QJiXSr31LfTK8M!D`q`L> zQQJUF7>gZWy7U=E;o#!(vQQRdKSm4&1DBP6KUMxbx|cLB+fQt{Tza$%l9%lz_Ixhg zOF{Coy~L)|rF$tz2K4e8r-!F@>ZvG+aauOv-u>^C8HQ+wii}WQl(OI*S}xKqhU>BmX`enj@x^pn2JVL04Y7#%9mb!HQA7&IhE)}; zQBxeXa@Mptj07M$S81#XkN!OV8?(QoIPTg^KMem-TKqU%{}5ZT7Fa)cns0H*ilqA2~e7^Yoly*wOC@; z@#`En?+^15Rp-j>^M;;f85RGWE!|a5+YJ;Re1iOWJfVX$-EBIO>898{p*$|3>DURy zondjIO|EU5i~jr>Z?l@^AiIw}N3v>gb6SifcS>|Q%n#X^@_cfL^N4B#-CJ5bChTKz znE+i9VYvfNChhNs7LV^LueOz-a)$LV8 zMcW+FZ=`TJa&=@Lbmpv^R*oSom zNi^>YYyk6%C;=}*M7anN+A50fDunJTgzh?u?mC3-I)rW+MYjy0TZYhmi=z7$Lia6% z?t2v7_Yk`899?>p=Lu=dbbV*?{cH1@kC&=J}jLeq330XBjEMxi}Bpx}w`fdU-V1)3`DF<8BV z>k{^&6|1*Z5Ota`qo}WfsIO*0)M?s`qP`BIz7C^KlV=q5GKhK^MxCb6DC%!P)ZfCW z(?l9Y{XK~KyPNuW{e9IgCuYC>nN4S_*{a_0BrC6*)WheuKX1(@lRuC99rjEqKenl> zeI=7ikJzWG_Ou9_vuUgml9wCloy}HZMAu=>zJ@iEd$pas{TYT$zU17A?G%RXEv(slNV90GkvlO> zSFT0uxqMwzM>EC;ZRAY22ozgG*k3>_xW^M{3IV3Qx$Puqa&2i0<@>eDp57Ewa2WmB zEPyZ?c_`MSt(#=i(o3^#VP$_#}j5q33`tfWHKCn*f82d@3OotCRplq{1j zufG0koKyU^$Y!$7Np#DJ24rh!&Z2_|uTy*}*m+-WH6ELyS> zB1)tZBu1M-lBJwiY5$bK+tZiR~OC62o3otXs!dP2bw~O5%Y!X>EZID$D zU-{8si!gw7y60LRQ8pR}$vt>((Zn)an_36AO|zctT6m)QHKYB;Qo00gMf?h6-(Go` zs!{juC@nYqCS~=IKx+Dl_T|Odqfd=Q(=s#Ze30 z!O=Aqr^i!vy?>@h7f^XY=8cunC zPwzw`1WaVT#~*Z%f&@e=QDPAg6RH5OL*{c)xxu~kuZR8j!RVZB%RTmbkY0R4rR!dh zluyyYu$^%e3GNGuc(26^v^jQ{pnO zEsnyTMB&%BWg&bA-mDi7wrD_gskAJ^3nM5{V`s!j)0XS%-yLwkuAq`*+c5jOSHdyS%azht`Ut^|ZxBc0L>=fP+_1w8 za3}7Ow4?gHr#MS;V!W0Zj|Eldr-Nv>dGf=^g>|@5TD_H#O>ndV$BiT5scw}<(bRWS zIncT|J04RNu3rQS>a!(qX4jZAC_u^QtNAku5#9fe4R#Ges+Va~a8aINUA@RR?6^)L zKkV2};b7qLox;MCi5iv!;bnS76u;n zNjwZa?o*f;WZn2)rw|Vw`=e}$^uq&^@a9h}&5_BKrU+53|@l zpPC#|n+RU&hB~+N=V$DViQ|E~>c>*8XLec9YY?M2c!8N38d<-qXVSg~Zq81{)jMSiU@!%fC*@ zUd2u{UKMTXM`^p_$~bb>kNG9bauo3Jjw&bI=sFEhyIhxXeEQQ*2l;}>mkp|#HTBi<6HYh9 zZ!=k;#`5j0d1trsnG5;uSg~7{MU$y+x}LW37!nU(@W4d$I}|d#+*oWk9yktvecqux zbTJ@-jt3S(DKVAoHpglPkQ>kHWZ|B;TjB5+=@iW>T_w?Zixh3=Z}OUEwPg*jx_;gt z@8Qn!Ez(uzClp?oEnnYi&AA(F%UN}+@9{JhkCGHJn?OGG$?Wk6 zaXz+1H13gZJwur*y!Vbeai7G_w6La-hL5Mw)p~#UK0mB-gsS2=DnHGiY6Mf2Qa*oq zb5X;JdX(c?!wm}1(S^qfm|lb@*1*_EXACbW=D(rbqev>L%`3aAwz2CB4mCGGIdevR zGnf@5HM=FNq7^`8@ZiINS3NhOhse2PFM*Z-!}q)_;Lg(A&S`Kd+()p&Un6-NGy@{)to{q%6{L%fqJ<>SUW@-c_2) zD`fT#ST;gCSsk&$$snZCwhy0{JjHR*T!6O8i0TS(Rd5S3p|sO#wc<< z%j{Xe%;1ol%D#^$pm?qwu;Lo+MZbuHYL5&H+`X2#0Y`ZO;;kI~y-BcrogYe31xlQ+ zV_YR&)hw~9KT`;#MMVk z+mnW75K?xQ>4Vid$HXC2XBZu_aZ-%bl=&qNP?=rg0F}AL3;5Y~7|QmZ@C{>FvSP@x zi_MIrW0w^=YU^nlDd0UF6)}^I5ge7fBbLGB4riUy*Ekn36)dr;UDn%Q8ZsH6Q}ag} zDOKI9mcPfm9)pSt3v%hiA~_|BCZi>Gor}edlcT{_PO)mlBV>pzNK7}iL#YK{yI$Lx zo$emXIn&9IsKg5EM{=b)sUOY|Sq?EFR&23S!QzT$Kcd|hu$2!;M6U6YS^JhUVG0~-)6n6dS9M6q;?g;x4B7KF^J)lS<5 zM?^FhXEFN)B92!iAtH)+Jl*B@;tB)p#AB+JsnhENuDX2RAHIouRN3VDQ0|f3^`7q! zD*}W!6#)!ZxpZ4b6#XKDZo-nwvf&(DKZX~-o**1Q}D7D8vwo(vh=t>cRhf^s{OyN|@5M*OD z0$!n!v-9Ow2bieUQI{3@m0py2ti$D|+6aD@CoP!$%^Q#sq^f5EN7q~x)p2RR3uI!H zrdM?ZPoWL(JNX>f5dSlmz=GLvCRR)!7L`m#C2{562@p>($;P@ z*0I~Hj`aVu#sdxU{3w=e!@8-6kyI~UbVaJBD%bB7^kb-`WO#K?6daJXEyOP3ig7wyyehs(vf zGw5(JxW=h34U>Gc-wzxCM~szC|G|RTm=-LUTZ9WZbGHJ=%g@%YfHCtkb;&bs*lzIi z30L<}k*6mNcPi&cqx zrt9)RNBTeK)T%|I7wTA`!|3S;e?ZRyT*lAUDUZ|OI>P%5H8ve#v*~5`^nxT(+_FJY zlT%3ri_S2L0*$TD&JD6v#ggvflj?Ua*2Ms;`$>D}F~7)dL#RkBjtmuDt5%2`d~`KX zE}4e4L{CQ|$59ipju6_lBj{gjop<5R1^Nh1Rk5qs%l0n7J^Xwf8*V_Uvl3;;-s9%% zC%6k-n5d5zD5=)<^Yi}ueNk$8a&(4r*l+i^S2L2&!c%4n;;QOb%A^0E;{ib=u0M!^ zrQ*dCkzS7!aq%KJUPR7iqBiM;jvh*5N z=yz-Ja@ykwf7#(^N;XH&kqW({@Z1jnUDx%nTTHh_kQX&Y@(sLW$WhmAufsISDRfGl z<|S%Cb%g$(?5=dD8oGDWe}|IC`J$XIi1z7zK|f6L?Yf*Sx9jYF0Xw0~Vq^89>kKQM zU-N595+30uGcce)+x>4PUT(n`B<3PGWvp4`#G6Cw#uT-!zyAn~Nh!8QG8}G5rW>-i-K{^e^ctX13 zJyFc^vWj;E4*4KzBqXhcP~^U;u-Wn|a;U<{3na>eN?Kn!@gQb#%YgFGNi{wuYT&B# zfgnA44T7oNZC{f~>8}AD)ZrE;smBI*f`;qM0}i|Av_A1_y&GXAm>y`-WaWA0DcxdB zq_93tZj@2Yj}}XAEv8CfDe%KcO0beVs9F)V=Gt3E7OGewsR;T?$-)&o5OMF)>2dHo zV=*;^?6$XEeD8oRN!u%?8~B~+Mhzjm;cXY+4WLWv#+vB{erLK-L&$D;+r@VS=#sjD zJGoAy!tYEsY6#g4Z@c(z09{fy-k5ISccvRPgzSd5U3@oyE~y*uOgHd5(~TNJcEj5) zz8gRn+zli2b%YAS&Lp2^c-sx!n~!?Ntr##uOpXCS^`P9ke6{bLq+75)wA&d~*49$q z!jwb4l7tar*^;n=4i(do9CigW0j$LZAzp;77OFv6$;*haf^nou$~TD{#ABvp1JpOi z+D%jY;+p~uDlrq90qUEf?53%G@l7BGm6++k0QLEIyJ>J=Zkw%w=4Iw84(QrMU?D@o zStoMg8v~&0H&gT~<*0xxlgo(z>H@p^9?ffs+gr3BTfY>roV6hBq?&?UK4_uL%w0&3 z7;3SYjp!*7xo0$gia<8P{d=>&*|n$>SpJoOZ#;6~8?QI0eUpFogvH$F@@iKD?&Y42QZhmq8E?Vkd4f3}YZ3-2E)04)6vy zjR3^Sw$Y6{);PQvds;^T?sWgrjl8FQ@GB_8WaOPo$5ccgf_$N8jpd@Aay@4$fbC_Wsw3>HLZ2B_aGqG9y@)I#_@Jw_n;~O6P&{oGuYjAV( z5*p0TYA1VMLkprZgr$WL>S1af=!dhlAVNK+*4CGXQ0ifANTpN*bL?Qbycd4%o<@08 zhUN6bCe0%mM;{w-^{|&;VG;Jw=t|cpHWpnP)lTua*@#DFXtW zhDQ5glNwFN(MO}M9`@2Gi?D}A-*k=Q#KEOe{MltmbzQRS2ZIy6t;9ot0uMs5hW zp*JI+A^?NbRXiMLV!&h^i};xcQFaK1jx|mIibRDvN24gZ-FjFT^#;yVp`I4v1Fduy z4!|lcqwALHoWPJx)fPG%GzxuWqxI9SSRF&nCo~f!tMZ9_;)8P}-rgoyflm<$!?&Bg z{fCIRA!L~&DsO*UPW1&=-2>;px}vf4W>o4i2A6$^*DWW zZ(~VRzJ(}G`xf{B>Q{00(!Y%;)c`C^aTb7mR(lrLHeZ!N-ZVBe+SOhvuB#QNp9LTF z0cE5b8i;Ut*C26%#dfDHSZxnf5p2`g5Nua_DcG)7oM2bHV1Y7Hunk1GU~7;#!D83Z z7Ob`vsR*`dYzVfiy%cO$D^9R$Ua&wJDcA-gT(C7roM5r}XA4%_5mW@*G&Tg=)m{p= zs}(2Mk{2vcMhdop2p4P(5+_*f!P$b3HF^AEKo)Ywt)y2Yz@*SSeZ$tT`~Bva z-OBvyT)bz5*Hnx77UF)~SIeew2-FspPqOaio2(KSUn@W(aHl4lpXTKz!;5CbOZ8?p zY6sM^zgm`55&Y$_EbyR!UQD4XhVY0Hj6R5`a&ckaOrfqZu_W}|c$UguP|+n7(UI%s z_CVj>RN47g`E|K_emTw5cv(>=vz@j6%6HeN2 zC(0mk^eA*(1okOTMKQ!HJ>7>?HW6a=w8Yw;Z_=**JZ;R~0(J8)0!(Z&1hsFuVtL1+ zia}McW^9qv;kf;!)};NV4v6e8^^7jRWa4=}y#9CCA5_j-OBRpJD?A%vgySSCps}u8 z8)Yj=FEVTEjZv|KfN312mc1Y?dzv~87+u%KM_t{Ar_J--W8nz6m1|wT)W+H#mj6?pUnS}gFGX(jQrhfU8ru2I9R_FUxB=y&J@T0Ql zH{)8P(3`uZ;y~&K?9HiK$a*$Hb^Fd{iN#|ks?)inDq{~LwNeZgVleQgV<44RIfD9S zIW_dhz(%|Fp`C15toxgc&Xv~L-6dD*U^kR2J*^wcl>*fbZhH|BH*icsZWH*^M z%O2Ep70XRu8(K`#lGJK*Q$gQ1F}ONZZz{O^$2z2Sf5ltaa?uJh6tQe(C^3W=5I?e@Fn{`pX*=H*+XdnicHPh1Rz;i2&It^31M$5)>SmcWrdY@GtNSQjbGMh2<40g3IF$?cV7m z=Xl|`ZqSg`n~Zns=j;l9R9YO}RIe7FNDn9}T8cMgFt|^6{#_$q2XEKM=X|+;*@3)6 z`E{!sr4^|?$Fpyb`DiTXGpdE2>yw(L2S29TC1oP8UgfB}{<1B0cr6Ndjb3);No*Ns z#v_WRt_PuE)>u9V5w-a7K=>bzLx~*osWFBU<%$V)7(|;yL}G%wp}9>N26zl0Symjv zRFQG``gC}dDKq-~AjdvBeTI=l?1zyXW>5vw>p#AHqheBbN*xFtY3UQ#h0f)c2a74)fRIa72%(!R`K;B8@o(Y-ozD+mG|jOM!R-F~svhL=uC_aIj8UPUc^sSDGvP**ip@ z^Jnh^9QDuM1?D3;$4XwDCZ`8#~*hCC&n z^1weXRHJdVt#d4&;Ffb{g;zWFEGu@ehFPvG`Kwjfj<43QEg;8-h!~sX5OibdFdrj1N2Z3WKvle;-^M3t3aTW^{o# zEEOam(PSP5Zw)t=T|Cl9ud~r&Ce$+VtPS#KtYO%Pge9ioX=qX$1U(6v5NQWoatkg_ z7MK7B!GjSp2p)`>9(dRhGz?C|R0ct+*hVV8$0I@7TSlFhumGIBRP6*S0T$sA>tVhD zScF3aV_^;ltb{cLac4uh&Jr6fw8bh8PT-U>EI5_j7kQo{es&#?$oArWF7^DyNAg;3 zxZ)jfxvxWxkhNfjpC0%PYaX0{V%bCBemo9{#ihY0QR0Z-X&(tldh=2a!OKPM{bnIPyB`b9A;jw_WS=EL;Pp0=W7ZrmsUB<;hA%>MK?nm?$Kmqp zj)U?lj|1{*j|1`z>$@g!a{IXU;KOMI95@c@mxb70*U>6@CD!GUd+Vl<>*|Z6mFs;6 zSF@gZG|l}U!}BP8@}%m7=E~sCOZ6m25}ELPn1JrMZwuL?t@4XB3u&cNpOtHOcp~ou zDOrYcfgXWAO!7*mVl;(Np$GJ0xS(=5`P`R=`a&Zm(}n`0&K>mFaqQ(=g_gnI3-0vfL+CC(P(N9%g)%05ge)nT+CLrtu)R(IB5hGOWX( zd6RYtU!u8%ds=-zU>N4lhy8PLIK8`eY&(?y$&8`9+W+a{wKYSTG0KlEnFs?9TbP&E zEH813-aTPN9P{lSX*&CZXXM-p4i*KivYk1zO7HHrNQW|rqNP{Nz zbDB|B!pvN9hg*72ILY7du*j#10=g*Hj6$j%3@n8feKZFUzpf66} zahiB;xnol)%0&BX8rFSbirCHyq3BApZ3l9dX3IIbc2L-8N_kQwT#BAXn~u$yCL4iH z$rx?>IE3H${qZ_34faPcZ8@5sfosh(eRPJ&m3?#`;rl*1i*S}7oke)pL>3>9V(dQ# z*W>ZDtUbK5Nqhg9C#YPPHt&H~lZP8Me9`uU45$VpTWV$^f6|OY{-l|N z{7Ewe`IDx8`IDyf`s_rl8qkWQ{@M_6bL>+IOQL^=TytLSQJQ|dBHf0YtrXG)mrfs7gFsW_qdOX@!s~(U0 zYg#=Xfy=1JBYsoHHdJHAVXZ7&?KIu#4O&y?P$;vtNmVro1Fd7|1+{MZVVY}BULmS^ zdgXV`-7CLqK41A=bNtHht@oE(!(sJ!9;-Z@tg9YR+t9AZ(|oh*om5JzSn64iN2SxR z9*-YWn{RTadOSmr*Qf62dOSn0V0paAdOR%;O$J$gr_ZX#)7`dTJ)QyZJB!{lUZNfX zR#%x4I_~O0#&`-v=44IB#nt0!1jEh{zm>WST5x5sSduAmT7wYljf|9JD(YphP5qf7+x(nw@AV|qU~Z1gI_r|=_wA(yTh=ghLUp7Cd#foyNK(W zxWwSd*iV)fhcH!S9KJps=2F~LC`y5&{@K-ldEsa8f;ezJn<0^%Y74D8aP3jI$FSdy zx;=I4W<3#Gx5q|c)$OsGh|>?fXliJ66hmGO+Yu-&_uU_-<~)tu+tX?E0VFIj4NpUp;vncr z$b?8c2$Re5IB{bF90U(W$RKzyVtU|VN6;`h4O1BesbU+c_{_RJ!J|U2+Y=0?*X;=g z)9dzhg26Jw91ct`tRZa6*-&iUOwL-j$Ly^jIbhwM6#RxY`-{IM5Kt_82;5zDd%`%Z zu(&FD_^iWHRY%>PFlHo@-n>-V*jA0Hs19}3?QwU>ELh{;nB<3_Rry9oWZ0^=XI_>R zql`krMm2IIn>0D+KX;1!^QfLAE45yo@F z*X?mhhTE>y?bp1E#8MAK7d{+<@P!Qu4wZLka6mr&axlJO;;q}`)EieSCRK4^_#!kH zgfLKb94^1^I4H03I3Ta~I3VA!HVf~VT5bx;+kLo}xNxCM%n0V%9N+r!g{soTS2=_;f%kiFNM?IIVZ0Y}}Q^d5$)#ID=pq}deJ zsZ8CfsS^mr`7lVbA<-7#F&?q?(`dn1B5K_p2Qo*Uod82IRsgMErgT=b4p5jSM4=4T zG>cTP+tbLU&9SoT_Bh%&>h`!=X}9UM8CBVJbCfw@n@W}DYMC1c-Lbf2tk>;vG;`MN zakX>R?QyiTYC3S;@Yn5eV3v;$S#^6HEnQ_`w7NZ^FlybNP#CptPcV#9w7ju7W1q z$YJaDIPmgydt8l;Qao+l9=ox>ZjYnAziy8W&{emGh49tw;eot$dpuyix;-|SQdY;V z+v9EStlQ&-aM$f|fKYukrK+5xg;9OS^6}<8+svb8=^dAu2Lt1FidHE~m?sZy)a`L} ztF6@0l+cmy>fv&7TMC1xz{B(YMo9{6i1x3fBFZV5du36K55$ADP4feo(6)9iOrQ3J zE=&@eN*AUG>%K5WY-fc~bfww016i%xtj zwTE{$Y41r359w}WUc$DDx`ctzTqF0>y4tr~u>kdvkBzFn!EJx3?{M2+>bTPWQs3jY zztlIm{hK@yvVw*+H*WxkfzQYJhj%*vZtxdfYCK)eAJa^ zeAM-4eAHEFeAKmQeAE@mR^gE{(EGmGY1EA7@8+K;VP zOgmI{!?!mS?`qgGV58KOEP*xE%AYia%AYhf%AYjl$)7Zp)ki1#hPbieFGOFrWQ*6- zo{i4j-9>Q1@WAhD2$Ui?T?lHa_Q1gF-ax7p!RchnL<$2juqnB}5!mYfCZl7E;CPu} zi{N;n*djPyD6Dc+Yk-NX1BNq7wg`@w7Fz^IKq*EIo=nfs`Vm(t3wWjHL=tq zO_zm%)?st1M~QSP(>(yXXT1U_>z6)ICE8;=H&)8*2S@Aj`u=~ z*f&m^1b~|R2=w|)!4+j`(ijpbgr21Od(oU@b4TS4&KxJj;U~{w_`<};Yu~|QsJtqq z{~f$A^0cfSnzKpkLWE0mw=w;b<ni-WpL`(6suZMb0=ga8FeJ#=1m}h#x3hNh|)Fd#V*FYQ0!vN3&k$Ryin|7OoM7miI!^A&$Q9XjjCu!w}<`8kmW*tC=<7Hd7{HWenX|B0o z<#){wE5B>bSovM^$ja}UTULH=eRIr$^S_$~;bOi*4$B)JpWfui&8psNYQJ*}Mq1I; zv+#KruidyRKkJsl_l%>}7wNo|^O} ztDHnLYV)2nWDv0XOD&#(nlp!NKp86OTCEJDbIb-TwK#+f2kVsOWK!$NeWYG# zuIy*;kj!CAtC06mlmbWnv#SB~!q46Xkt26DLn1qMu9kX~TCDB2S%$aJLg$Fy!uYVGsW3P@nD@c8(T%m*)hsd)hoyo9B$~{_ z;H?3~vKvs@(7Z@P_2rb}iJcZ2K*AE!@H8|j4uYP9Y}DFIlLe-hXx1a z(=P|(8z$c3iB7$7_4-m37ltoFb3q6LRmb7->yCr+Dvty5YL5f*4QsRdp{eEeD8o6{ zIdHRhVvV*<7VrIbs9F3kj)a~k$EBh>>bb>{3C*vzYq;5T>Rf_BviB3vhl#Ao-cO(q zDy=4apQjO1gpkM5RTVHG!#_r|UF5J=@-UgsNhUK+hiT9W?w_NZR4of=V;}so#$xgtexj-=c=9OXlK<`(xwn)o5^20 z&w-h#o#$xjDu<@k&I^T6Yv+Z+sI~KgVU*f=p)hLgyigdWc3vomQadjYq^ovb6q=6O zd7-$>5K6H_m$5Xp^IZ6u+IehKc%CAEEsy1Cf6%wl6fRsv#ki5f*TZx0fc#Xu;24A1 zUk}elKJwSYvjMv5;js|DdU!mLw;rAc%vTT32J_a#^EP+Z!*f9JHQH$Zs(yi$om7;> zqNZG1RU?ic7cL-~bb?%@mS}VyjiXjm6ypQ&V67&902A5@^uqLM`FdfJSo>a>BCPwu z6tU_Kq1e z7}J)c`5Cy@Jkv*Km|WRM=Mlc|qq7KS`O#T~cTHpQ>n@w-%{?pb9#!JqrN3RxUWGe6 zFO@8e3Ug7)b+;*$@fegXm!ru5635}Jbt?`ttit(O$prR>5s;JlP}ZYx)_lHR<-6<( zg8wvHFSD!H`R1j_>4X(AyII&_IzJxEr`_!H>*r6>egmLqvq-S!vSuut=Spc`R1~A7 z<7j#mhhz~&auwBj9o4#wYW)_~`kiY%x{^kzT$i;?al0q;me-zZ$07PW8lY#kST2N zdg$6rKFQJMFB>GroDXelAARvPCN~s=z8Z>WqoEGO-V$kDNF$tqQ=am!phTGA>7PD<0SNXlO_9N%aJw=uHzBh1_(mBk|UTtt&}Zi0g;g9H4Ch zD}$E97sPhLq!r{0(uveU3-JaqR65;346;st5QD7KA;ci-^awG?I$c5xvQD3%A)8_Y zX5i@H^QUDSAB5r$@Cw+Fj6z&nxG_{6{w5l;IaXu*LT_S0j-dyYT5chpA&N|=YlyBH~f^@e%#01v!a6 zWNOicc!@YVoo*ryU8kRjL)Ymj;?Q+^ia2zgt|AUyr>`*3-C(n@x3d_@eTG~-K|Rw> zAw%)IeMK+CwY@uCML*1uo?=*HoTC_uN-a0WPo$G^xruaaE-#Ue&E+K0vAKLiIyRS! zNXO>#5Ii=@%7B09NI__FA!vs&5JXLN@Pa5=BAw{bHUMv9;URptjYBZ=o}tZk@$|xX zS`pMUlRlh98est#*W*S~(Ii#KE}Dz({-8-0mQ^!?#6;9U0BL)ENIe&<*geF znsi}#@5X{AE-c2QCYW`N-FW9<>xPP<#TXt(gz*-3^Ts{{`_Q%z$>#Ri8Z8%so zM}E7*5vnhX3)XoAkZ1je7q$^xuqG9zRp0=*GmgaIkMSi&E5@DJtpfOBoQi>q@he6v z#>qKN{j;>MKH!KoK8iX!I;+n$*2m-Bxvh(=i9 z{ZT>Kp13`n7AClkP-lzHIpw}xG z!!-o@Axz=Wxx^sVyL^oBd9wz(qgE)z$2(T zHr`^WyTBu;J2vWKsJp-&)V*24E_!}|Knm_a$A#J*XX-7Rk>1U3+q9EYZ}jL`lp8$p z&fd8m?||k4&=9bgo;LCc(U2k`70yr39h55la7U&}19y0;H}Lb|4pbEk?r2qM;0{^! z27Vsg!K;G79l4%dBUDyZ+JSr`x9344ORF0cPX4y z?_PygM?rc zlj{jMFNouk&T_NgsrO*%oU=bQR|xKrXtGuezJ8yPK5VP2Rejyt7TtW$QPG;`H^f|881SZ+dQP zcaWPPF}gQ3W+ZD9z*z~Y&S?-rZut%0A%>3GAD>6cu2u!+q?aWXSp3}9vLHD);OI(E zAV4$J!y!BlDjf-VsTAmj|4{HnAemKQyLDi@GO*oSV7qs|T~z~so!*3L?B6v*a>Ky? zhcs@K5Z2mbKxqiX6c@y3OS<7Xq>q^7I?-d6>uiH*uCop1xz0A2=sMeArgOBJ)}?cd z6Jl_#Yk1-lLp;6z4 zh7*A)L%;*p*h4IwX`$^&UCV-E>^>GuRAlT8JBmey;b?jkhXgf$YRM_K%#lRxpNQ6| z0Tj_1wSXd8qb5*9Yt#mEw7#vT<&G@lJJm@y9@-B)o5evj+KU7;ZAdZ4o|woQlTkF? ziNdjnA-IZZypCyH#x#D5Y5dMKzN<>-bQoebS?-_TwU|M@^y0@t6JHW|qsvrykBtt6 zl8m)KuBNAH$S6XHmoS9~@lX^S#6wYF5D!IBK|B|`#;4!OY9Arlczzy?((2Fo4tFUJ4ux4dgv$wEj?_4vv6*k_jpR+6c zk;|jE@vhtmZ9=QlW8UgjHlG|$r!vdv&k6wVaN{ql{Of+RDh~Iskoqxe@ie3TfTA>( zq0n1zE)I&`^(tat0=N6;Q@P*GHzX_NVG#2j?{m?y>Xe^}kXBlJI2z(TgPs=Js(|YL z42F!}1n7y3w};^nn+7l#W>w>TkV3`1z)zD+c|6hZY8CAtYxJ!6P2N*|kKJ@l(Tj)N zFF;t;%o%CY*d$SkD!Lk>r9KICu=LnCJ$#Tf}1)_Xomin$I-PDYzQ92zu$`YV;73iUAa3Ihi4pc=kvqU3vrao ziu~fC2`o2rk!jyP>^NS`kL5C7g2Qt6bpL5No6$Qt?Q}(UmHqBw_-xev_mb2`zyEPb za^wG0vYf>pkDY)bK89GZtXfVvI6Cwt;5Xt71KW*_?9N z>^3jnfMN9g7z}^Ad)aJqa6y#m|2fEK3<-?p<8uC7tY#07dwP5}`@gkaOLy`%6V6Y1 zfdFCooz@FZ-ljR2cF~QFuw`)LTP-<|f8S?xv4w$PCttG&wyYURqtRSt>#{=>u{`iv zpL%f}*Ggh>WkQt&Y(e0-II*-74YbD9L0tH|9Uc3~uASrf9ejwgTpr)}ErhMOVR>25 znUqYOhdu6%xI2w-!5dXF6=B*dmhcq5>tvRd5zkoN6e`WdWXbEAe=t=SPD z&l3B7Lz=}|rRp0@F=|vU0Px=r>uyW`&v8wcM)R;^st&Z){`+|w(PVF=m*1-Q-Yd9B zYTLs%f{7JP1E8U6-H{Z-z`QWxd2?}w#HP+P7sp(0P-0bG?&-7>aAOWqpG4Fs!485W zTJ}Ij3mGvFEaz$QfOu+6VbouZq}?=y_(_Y5fd43tX%Vvxq=ZKH*UNJ#C)0!qGcFZv z)WqjB^PJe8o=v$5+MCCiD{i*l(X&U|+S%RCBO{m{=pqxvULCp$%c#sNUL$X7KG;b( z(o>6GO{R<)lO{=_$Syrn`K43 z@|2d6xJ@ic6E(Hy@e(YJylRR_VXTu`ETS}ro~lZi72SlMS5k+vk-Uf{lcKs_>1kh= zO@%>rkL}>moon<8X2R{Are5Ev9KFB3Tg;l!zu0||FZ#}XQ0FC#f1SE&=?tIn4>tM> zx-X%*GYcwAaV7wdgV#t~S$Md>0bnK8ue;Z$ZOameFm-i)nFg;zSE6Q~Fm<~`(L&e7 z)azm`gU!xXrt8?dPQ2^XyZ+m|)U0Mp! zr6mwuTKdqXB@bO%>d>Vn4qaN>(4{2}^aT4~hQ-7VSYovlPB4J?YNELo#nc!~> zCUxvMjEX}h@=ATcp>_)cYG;OGlQTqh32e{{I4jyB>ogBE4Kx-KOu+7T;hi_!J+DRL zDJctybHTh0KueW1-wW4k4Ln@{xrFa+lorD>W)j`vyG&ROWs$9@*H{=}ggozc!xQ(R z#CsWnJ4J(AQA64Q#*S~EKxI2w63PXypy{yMpnYu(SA<6F9HEvyh0m{Liu_ve0!TGG zMA*g-7R81sS3s6)>Q23o0X0BmX?jano z)z9wsqsbZ!S{YC`$phg&ipVkUz_#YFmh#Gp*r7mazH0e8WyE(q+4K2xhAijHb&NJqAlurcN zdXpVSA@U`x^B0DBR-biY9HuLM80g&%=)*uvoyn{ww)aCJTdQR>WXEk*pf4lDRgk7> zxzLtloQ^MTiAS?1=8{lz_7fQ>R=`d%-YWR)P?m3SvVK@gS>3Kpc3xBH`mQmsQp_TR zdOSXFec{J7JZGpwcoKQjY5FUNMd^!us47^&G^G=Uk!JKXnet3+QoUA*MeFbk{#B9vj*IjZGW&J zT(H+?7*1Mm8+7^&T5yx$1I-wCuw<-zz{$^ZPoCIjhkT6?U`lvCl$iudh_|-9Wlti` z*^>_9toSxSS`2Gq<+_`ddn7@1I1tu?=>Qx)I~eQE-FjRij$bCM=EYug(A~glMDQ}& zp2`wrKC}l%Y}Hk02eL7trBF>*Em=%tK>Ly{qTLO6Eaw)*EJ7GpQ}QuF&)p?DYcJs_ zW>=#{pRs{~T{RMe;gL{l1i`!@7uN5V^(@g)WfIjcLa0}oiMHUiIe5)Z!B{|Ux;GZ= zi>)2n)~+lj6QjH`M!TYxM5f&uFYsZ&TPsgORo^2OZ6!eVbZtqsu|pmWXFCtLE1gFO zs+9z;!B!G%tOun#djq%`cB&>N;_PqJEC6tvj4O zsTW=Cd;U(_z!&D2TKWQ41MHluQQ%s?VFS>`g%xsi40&$VaFR{BqWv0-yVdq9-Dq=;nsfOE zDX&pW1%X^wRIHGiL*)k$h}WPUg1yljvg?{86k9H!yb`^$2uYO$0V>E+`ayJ_28{nY zLG-{7^FmJkfu)iw1=)$zp%%P2!79qp7X4OKE^>NN^#OUsBL)RM2a?Kk&m(%d!(3(x zZU^-P<@nIk{%=BnYm7+$A~I)+EVQb16C@lcMUFbEM%VRkp&!vsn+NvZj^teyZcxWa VQkD24L;6ECJGR5l0FZ?K{sjqxGMxYb diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt deleted file mode 100644 index 16ac56b..0000000 --- a/vendor/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_subdirectory( libssh2-1.4.2 ) -#add_subdirectory( zlib-1.2.7) -#add_subdirectory( sigar ) diff --git a/include/boost/atomic.hpp b/vendor/boost_1.51/include/boost/atomic.hpp similarity index 100% rename from include/boost/atomic.hpp rename to vendor/boost_1.51/include/boost/atomic.hpp diff --git a/include/boost/atomic/detail/base.hpp b/vendor/boost_1.51/include/boost/atomic/detail/base.hpp similarity index 100% rename from include/boost/atomic/detail/base.hpp rename to vendor/boost_1.51/include/boost/atomic/detail/base.hpp diff --git a/include/boost/atomic/detail/builder.hpp b/vendor/boost_1.51/include/boost/atomic/detail/builder.hpp similarity index 100% rename from include/boost/atomic/detail/builder.hpp rename to vendor/boost_1.51/include/boost/atomic/detail/builder.hpp diff --git a/include/boost/atomic/detail/fallback.hpp b/vendor/boost_1.51/include/boost/atomic/detail/fallback.hpp similarity index 100% rename from include/boost/atomic/detail/fallback.hpp rename to vendor/boost_1.51/include/boost/atomic/detail/fallback.hpp diff --git a/include/boost/atomic/detail/gcc-alpha.hpp b/vendor/boost_1.51/include/boost/atomic/detail/gcc-alpha.hpp similarity index 100% rename from include/boost/atomic/detail/gcc-alpha.hpp rename to vendor/boost_1.51/include/boost/atomic/detail/gcc-alpha.hpp diff --git a/include/boost/atomic/detail/gcc-armv6+.hpp b/vendor/boost_1.51/include/boost/atomic/detail/gcc-armv6+.hpp similarity index 100% rename from include/boost/atomic/detail/gcc-armv6+.hpp rename to vendor/boost_1.51/include/boost/atomic/detail/gcc-armv6+.hpp diff --git a/include/boost/atomic/detail/gcc-ppc.hpp b/vendor/boost_1.51/include/boost/atomic/detail/gcc-ppc.hpp similarity index 100% rename from include/boost/atomic/detail/gcc-ppc.hpp rename to vendor/boost_1.51/include/boost/atomic/detail/gcc-ppc.hpp diff --git a/include/boost/atomic/detail/gcc-x86.hpp b/vendor/boost_1.51/include/boost/atomic/detail/gcc-x86.hpp similarity index 100% rename from include/boost/atomic/detail/gcc-x86.hpp rename to vendor/boost_1.51/include/boost/atomic/detail/gcc-x86.hpp diff --git a/include/boost/atomic/detail/generic-cas.hpp b/vendor/boost_1.51/include/boost/atomic/detail/generic-cas.hpp similarity index 100% rename from include/boost/atomic/detail/generic-cas.hpp rename to vendor/boost_1.51/include/boost/atomic/detail/generic-cas.hpp diff --git a/include/boost/atomic/detail/integral-casts.hpp b/vendor/boost_1.51/include/boost/atomic/detail/integral-casts.hpp similarity index 100% rename from include/boost/atomic/detail/integral-casts.hpp rename to vendor/boost_1.51/include/boost/atomic/detail/integral-casts.hpp diff --git a/include/boost/atomic/detail/interlocked.hpp b/vendor/boost_1.51/include/boost/atomic/detail/interlocked.hpp similarity index 100% rename from include/boost/atomic/detail/interlocked.hpp rename to vendor/boost_1.51/include/boost/atomic/detail/interlocked.hpp diff --git a/include/boost/atomic/detail/linux-arm.hpp b/vendor/boost_1.51/include/boost/atomic/detail/linux-arm.hpp similarity index 100% rename from include/boost/atomic/detail/linux-arm.hpp rename to vendor/boost_1.51/include/boost/atomic/detail/linux-arm.hpp diff --git a/include/boost/atomic/detail/valid_integral_types.hpp b/vendor/boost_1.51/include/boost/atomic/detail/valid_integral_types.hpp similarity index 100% rename from include/boost/atomic/detail/valid_integral_types.hpp rename to vendor/boost_1.51/include/boost/atomic/detail/valid_integral_types.hpp diff --git a/include/boost/atomic/platform.hpp b/vendor/boost_1.51/include/boost/atomic/platform.hpp similarity index 100% rename from include/boost/atomic/platform.hpp rename to vendor/boost_1.51/include/boost/atomic/platform.hpp diff --git a/vendor/boost_1.51/include/boost/context/all.hpp b/vendor/boost_1.51/include/boost/context/all.hpp new file mode 100644 index 0000000..f9a4c71 --- /dev/null +++ b/vendor/boost_1.51/include/boost/context/all.hpp @@ -0,0 +1,14 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the 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 BOOST_CTX_ALL_H +#define BOOST_CTX_ALL_H + +#include +#include +#include + +#endif // BOOST_CTX_ALL_H diff --git a/vendor/boost_1.51/include/boost/context/detail/config.hpp b/vendor/boost_1.51/include/boost/context/detail/config.hpp new file mode 100644 index 0000000..50ada3c --- /dev/null +++ b/vendor/boost_1.51/include/boost/context/detail/config.hpp @@ -0,0 +1,42 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the 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 BOOST_CTX_DETAIL_CONFIG_H +#define BOOST_CTX_DETAIL_CONFIG_H + +#include +#include + +#ifdef BOOST_CONTEXT_DECL +# undef BOOST_CONTEXT_DECL +#endif + +#if defined(BOOST_HAS_DECLSPEC) +# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTEXT_DYN_LINK) +# if ! defined(BOOST_DYN_LINK) +# define BOOST_DYN_LINK +# endif +# if defined(BOOST_CONTEXT_SOURCE) +# define BOOST_CONTEXT_DECL BOOST_SYMBOL_EXPORT +# else +# define BOOST_CONTEXT_DECL BOOST_SYMBOL_IMPORT +# endif +# endif +#endif + +#if ! defined(BOOST_CONTEXT_DECL) +# define BOOST_CONTEXT_DECL +#endif + +#if ! defined(BOOST_CONTEXT_SOURCE) && ! defined(BOOST_ALL_NO_LIB) && ! defined(BOOST_CONTEXT_NO_LIB) +# define BOOST_LIB_NAME boost_context +# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTEXT_DYN_LINK) +# define BOOST_DYN_LINK +# endif +# include +#endif + +#endif // BOOST_CTX_DETAIL_CONFIG_H diff --git a/vendor/boost_1.51/include/boost/context/detail/fcontext_arm.hpp b/vendor/boost_1.51/include/boost/context/detail/fcontext_arm.hpp new file mode 100644 index 0000000..b4ed2fa --- /dev/null +++ b/vendor/boost_1.51/include/boost/context/detail/fcontext_arm.hpp @@ -0,0 +1,66 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the 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 BOOST_CTX_DETAIL_FCONTEXT_ARM_H +#define BOOST_CTX_DETAIL_FCONTEXT_ARM_H + +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +extern "C" { + +#define BOOST_CONTEXT_CALLDECL + +struct stack_t +{ + void * base; + void * limit; + + stack_t() : + base( 0), limit( 0) + {} +}; + +struct fp_t +{ + boost::uint32_t fc_freg[16]; + + fp_t() : + fc_freg() + {} +}; + +struct fcontext_t +{ + boost::uint32_t fc_greg[11]; + stack_t fc_stack; + fp_t fc_fp; + + fcontext_t() : + fc_greg(), + fc_stack(), + fc_fp() + {} +}; + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CTX_DETAIL_FCONTEXT_ARM_H diff --git a/vendor/boost_1.51/include/boost/context/detail/fcontext_i386.hpp b/vendor/boost_1.51/include/boost/context/detail/fcontext_i386.hpp new file mode 100644 index 0000000..573a22c --- /dev/null +++ b/vendor/boost_1.51/include/boost/context/detail/fcontext_i386.hpp @@ -0,0 +1,68 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the 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 BOOST_CTX_DETAIL_FCONTEXT_I386H +#define BOOST_CTX_DETAIL_FCONTEXT_I386H + +#include + +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +extern "C" { + +#define BOOST_CONTEXT_CALLDECL __attribute__((cdecl)) + +struct stack_t +{ + void * base; + void * limit; + + stack_t() : + base( 0), limit( 0) + {} +}; + +struct fp_t +{ + boost::uint32_t fc_freg[2]; + + fp_t() : + fc_freg() + {} +}; + +struct fcontext_t +{ + boost::uint32_t fc_greg[6]; + stack_t fc_stack; + fp_t fc_fp; + + fcontext_t() : + fc_greg(), + fc_stack(), + fc_fp() + {} +}; + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CTX_DETAIL_FCONTEXT_I386_H diff --git a/vendor/boost_1.51/include/boost/context/detail/fcontext_i386_win.hpp b/vendor/boost_1.51/include/boost/context/detail/fcontext_i386_win.hpp new file mode 100644 index 0000000..e250ec5 --- /dev/null +++ b/vendor/boost_1.51/include/boost/context/detail/fcontext_i386_win.hpp @@ -0,0 +1,83 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the 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 BOOST_CTX_DETAIL_FCONTEXT_I386H +#define BOOST_CTX_DETAIL_FCONTEXT_I386H + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include +#include + +#include + +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable:4351) +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +extern "C" { + +#define BOOST_CONTEXT_CALLDECL __cdecl + +struct stack_t +{ + void * base; + void * limit; + + stack_t() : + base( 0), limit( 0) + {} +}; + +struct fp_t +{ + boost::uint32_t fc_freg[2]; + + fp_t() : + fc_freg() + {} +}; + +struct fcontext_t +{ + boost::uint32_t fc_greg[6]; + stack_t fc_stack; + void * fc_excpt_lst; + void * fc_local_storage; + fp_t fc_fp; + + fcontext_t() : + fc_greg(), + fc_stack(), + fc_excpt_lst( 0), + fc_local_storage( 0), + fc_fp() + {} +}; + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif // BOOST_CTX_DETAIL_FCONTEXT_I386_H diff --git a/vendor/boost_1.51/include/boost/context/detail/fcontext_mips.hpp b/vendor/boost_1.51/include/boost/context/detail/fcontext_mips.hpp new file mode 100644 index 0000000..1645adf --- /dev/null +++ b/vendor/boost_1.51/include/boost/context/detail/fcontext_mips.hpp @@ -0,0 +1,68 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the 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 BOOST_CTX_DETAIL_FCONTEXT_MIPS_H +#define BOOST_CTX_DETAIL_FCONTEXT_MIPS_H + +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +extern "C" { + +#define BOOST_CONTEXT_CALLDECL + +// on MIPS we assume 64bit regsiters - even for 32bit ABIs + +struct stack_t +{ + void * base; + void * limit; + + stack_t() : + base( 0), limit( 0) + {} +}; + +struct fp_t +{ + boost::uint64_t fc_freg[6]; + + fp_t() : + fc_freg() + {} +}; + +struct fcontext_t +{ + boost::uint64_t fc_greg[13]; + stack_t fc_stack; + fp_t fc_fp; + + fcontext_t() : + fc_greg(), + fc_stack(), + fc_fp() + {} +}; + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CTX_DETAIL_FCONTEXT_MIPS_H diff --git a/vendor/boost_1.51/include/boost/context/detail/fcontext_ppc.hpp b/vendor/boost_1.51/include/boost/context/detail/fcontext_ppc.hpp new file mode 100644 index 0000000..5e6c64c --- /dev/null +++ b/vendor/boost_1.51/include/boost/context/detail/fcontext_ppc.hpp @@ -0,0 +1,70 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the 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 BOOST_CTX_DETAIL_FCONTEXT_PPC_H +#define BOOST_CTX_DETAIL_FCONTEXT_PPC_H + +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +extern "C" { + +#define BOOST_CONTEXT_CALLDECL + +struct stack_t +{ + void * base; + void * limit; + + stack_t() : + base( 0), limit( 0) + {} +}; + +struct fp_t +{ + boost::uint64_t fc_freg[19]; + + fp_t() : + fc_freg() + {} +}; + +struct fcontext_t +{ +# if defined(__powerpc64__) + boost::uint64_t fc_greg[23]; +# else + boost::uint32_t fc_greg[23]; +# endif + stack_t fc_stack; + fp_t fc_fp; + + fcontext_t() : + fc_greg(), + fc_stack(), + fc_fp() + {} +}; + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CTX_DETAIL_FCONTEXT_PPC_H diff --git a/vendor/boost_1.51/include/boost/context/detail/fcontext_x86_64.hpp b/vendor/boost_1.51/include/boost/context/detail/fcontext_x86_64.hpp new file mode 100644 index 0000000..106ee74 --- /dev/null +++ b/vendor/boost_1.51/include/boost/context/detail/fcontext_x86_64.hpp @@ -0,0 +1,66 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the 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 BOOST_CTX_DETAIL_FCONTEXT_X86_64_H +#define BOOST_CTX_DETAIL_FCONTEXT_X86_64_H + +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +extern "C" { + +#define BOOST_CONTEXT_CALLDECL + +struct stack_t +{ + void * base; + void * limit; + + stack_t() : + base( 0), limit( 0) + {} +}; + +struct fp_t +{ + boost::uint32_t fc_freg[2]; + + fp_t() : + fc_freg() + {} +}; + +struct fcontext_t +{ + boost::uint64_t fc_greg[8]; + stack_t fc_stack; + fp_t fc_fp; + + fcontext_t() : + fc_greg(), + fc_stack(), + fc_fp() + {} +}; + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CTX_DETAIL_FCONTEXT_X86_64_H diff --git a/vendor/boost_1.51/include/boost/context/detail/fcontext_x86_64_win.hpp b/vendor/boost_1.51/include/boost/context/detail/fcontext_x86_64_win.hpp new file mode 100644 index 0000000..96f153b --- /dev/null +++ b/vendor/boost_1.51/include/boost/context/detail/fcontext_x86_64_win.hpp @@ -0,0 +1,90 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the 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 BOOST_CTX_DETAIL_FCONTEXT_X86_64_H +#define BOOST_CTX_DETAIL_FCONTEXT_X86_64_H + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include +#include +#include + +#include + +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable:4351) +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +extern "C" { + +#define BOOST_CONTEXT_CALLDECL + +struct stack_t +{ + void * base; + void * limit; + + stack_t() : + base( 0), limit( 0) + {} +}; + +struct fp_t +{ + boost::uint32_t fc_freg[2]; + void * fc_xmm; + char fc_buffer[175]; + + fp_t() : + fc_freg(), + fc_xmm( 0), + fc_buffer() + { + fc_xmm = fc_buffer; + if ( 0 != ( ( ( uintptr_t) fc_xmm) & 15) ) + fc_xmm = ( char *) ( ( ( ( uintptr_t) fc_xmm) + 15) & ~0x0F); + } +}; + +struct fcontext_t +{ + boost::uint64_t fc_greg[10]; + stack_t fc_stack; + void * fc_local_storage; + fp_t fc_fp; + + fcontext_t() : + fc_greg(), + fc_stack(), + fc_local_storage( 0), + fc_fp() + {} +}; + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif // BOOST_CTX_DETAIL_FCONTEXT_X86_64_H diff --git a/vendor/boost_1.51/include/boost/context/fcontext.hpp b/vendor/boost_1.51/include/boost/context/fcontext.hpp new file mode 100644 index 0000000..d2cc030 --- /dev/null +++ b/vendor/boost_1.51/include/boost/context/fcontext.hpp @@ -0,0 +1,82 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the 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 BOOST_CTX_FCONTEXT_H +#define BOOST_CTX_FCONTEXT_H + +#if defined(__PGI) +#include +#endif + +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +// x86_64 +// test x86_64 before i386 because icc might +// define __i686__ for x86_64 too +#if defined(__x86_64__) || defined(__x86_64) \ + || defined(__amd64__) || defined(__amd64) \ + || defined(_M_X64) || defined(_M_AMD64) +# if defined(BOOST_WINDOWS) +# include +# else +# include +# endif +// i386 +#elif defined(i386) || defined(__i386__) || defined(__i386) \ + || defined(__i486__) || defined(__i586__) || defined(__i686__) \ + || defined(__X86__) || defined(_X86_) || defined(__THW_INTEL__) \ + || defined(__I86__) || defined(__INTEL__) || defined(__IA32__) \ + || defined(_M_IX86) || defined(_I86_) +# if defined(BOOST_WINDOWS) +# include +# else +# include +# endif +// arm +#elif defined(__arm__) || defined(__thumb__) || defined(__TARGET_ARCH_ARM) \ + || defined(__TARGET_ARCH_THUMB) || defined(_ARM) +# include +// mips +#elif (defined(__mips) && __mips == 1) || defined(_MIPS_ISA_MIPS1) \ + || defined(_R3000) +# include +// powerpc +#elif defined(__powerpc) || defined(__powerpc__) || defined(__ppc) \ + || defined(__ppc__) || defined(_ARCH_PPC) || defined(__POWERPC__) \ + || defined(__PPCGECKO__) || defined(__PPCBROADWAY) || defined(_XENON) +# include +#else +# error "platform not supported" +#endif + +namespace boost { +namespace ctx { +namespace detail { + +extern "C" BOOST_CONTEXT_DECL void * BOOST_CONTEXT_CALLDECL align_stack( void * vp); + +} + +extern "C" BOOST_CONTEXT_DECL +intptr_t BOOST_CONTEXT_CALLDECL jump_fcontext( fcontext_t * ofc, fcontext_t const* nfc, intptr_t vp, bool preserve_fpu = true); +extern "C" BOOST_CONTEXT_DECL +void BOOST_CONTEXT_CALLDECL make_fcontext( fcontext_t * fc, void (* fn)( intptr_t) ); + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CTX_FCONTEXT_H + diff --git a/vendor/boost_1.51/include/boost/context/stack_allocator.hpp b/vendor/boost_1.51/include/boost/context/stack_allocator.hpp new file mode 100644 index 0000000..0db5015 --- /dev/null +++ b/vendor/boost_1.51/include/boost/context/stack_allocator.hpp @@ -0,0 +1,37 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the 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 BOOST_CTX_STACK_ALLOCATOR_H +#define BOOST_CTX_STACK_ALLOCATOR_H + +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +class BOOST_CONTEXT_DECL stack_allocator +{ +public: + void * allocate( std::size_t) const; + + void deallocate( void *, std::size_t) const; +}; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CTX_STACK_ALLOCATOR_H diff --git a/vendor/boost_1.51/include/boost/context/stack_utils.hpp b/vendor/boost_1.51/include/boost/context/stack_utils.hpp new file mode 100644 index 0000000..ca3ed21 --- /dev/null +++ b/vendor/boost_1.51/include/boost/context/stack_utils.hpp @@ -0,0 +1,41 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the 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 BOOST_CTX_STACK_UTILS_H +#define BOOST_CTX_STACK_UTILS_H + +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +BOOST_CONTEXT_DECL std::size_t default_stacksize(); + +BOOST_CONTEXT_DECL std::size_t minimum_stacksize(); + +BOOST_CONTEXT_DECL std::size_t maximum_stacksize(); + +BOOST_CONTEXT_DECL std::size_t pagesize(); + +BOOST_CONTEXT_DECL std::size_t page_count( std::size_t stacksize); + +BOOST_CONTEXT_DECL bool is_stack_unbound(); + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CTX_STACK_UTILS_H diff --git a/include/boost/process.hpp b/vendor/boost_1.51/include/boost/process.hpp similarity index 100% rename from include/boost/process.hpp rename to vendor/boost_1.51/include/boost/process.hpp diff --git a/include/boost/process/all.hpp b/vendor/boost_1.51/include/boost/process/all.hpp similarity index 100% rename from include/boost/process/all.hpp rename to vendor/boost_1.51/include/boost/process/all.hpp diff --git a/include/boost/process/child.hpp b/vendor/boost_1.51/include/boost/process/child.hpp similarity index 100% rename from include/boost/process/child.hpp rename to vendor/boost_1.51/include/boost/process/child.hpp diff --git a/include/boost/process/config.hpp b/vendor/boost_1.51/include/boost/process/config.hpp similarity index 100% rename from include/boost/process/config.hpp rename to vendor/boost_1.51/include/boost/process/config.hpp diff --git a/include/boost/process/context.hpp b/vendor/boost_1.51/include/boost/process/context.hpp similarity index 100% rename from include/boost/process/context.hpp rename to vendor/boost_1.51/include/boost/process/context.hpp diff --git a/include/boost/process/detail/basic_status.hpp b/vendor/boost_1.51/include/boost/process/detail/basic_status.hpp similarity index 100% rename from include/boost/process/detail/basic_status.hpp rename to vendor/boost_1.51/include/boost/process/detail/basic_status.hpp diff --git a/include/boost/process/detail/basic_status_service.hpp b/vendor/boost_1.51/include/boost/process/detail/basic_status_service.hpp similarity index 94% rename from include/boost/process/detail/basic_status_service.hpp rename to vendor/boost_1.51/include/boost/process/detail/basic_status_service.hpp index 97c8162..2fd1a39 100644 --- a/include/boost/process/detail/basic_status_service.hpp +++ b/vendor/boost_1.51/include/boost/process/detail/basic_status_service.hpp @@ -152,6 +152,11 @@ public: boost::unique_lock lock(work_thread_mutex_); if (++pids_ == 1) { + // if there was a previous worker thread that exited because + // pids_ dropped to 0, we must join it now to free the thread's + // memory before launching a new worker thread + if (work_thread_.joinable()) + work_thread_.join(); work_.reset(new boost::asio::io_service::work( this->get_io_service())); work_thread_ = boost::thread( diff --git a/include/boost/process/detail/posix_helpers.hpp b/vendor/boost_1.51/include/boost/process/detail/posix_helpers.hpp similarity index 100% rename from include/boost/process/detail/posix_helpers.hpp rename to vendor/boost_1.51/include/boost/process/detail/posix_helpers.hpp diff --git a/include/boost/process/detail/status_impl.hpp b/vendor/boost_1.51/include/boost/process/detail/status_impl.hpp similarity index 100% rename from include/boost/process/detail/status_impl.hpp rename to vendor/boost_1.51/include/boost/process/detail/status_impl.hpp diff --git a/include/boost/process/detail/systembuf.hpp b/vendor/boost_1.51/include/boost/process/detail/systembuf.hpp similarity index 100% rename from include/boost/process/detail/systembuf.hpp rename to vendor/boost_1.51/include/boost/process/detail/systembuf.hpp diff --git a/include/boost/process/detail/windows_helpers.hpp b/vendor/boost_1.51/include/boost/process/detail/windows_helpers.hpp similarity index 100% rename from include/boost/process/detail/windows_helpers.hpp rename to vendor/boost_1.51/include/boost/process/detail/windows_helpers.hpp diff --git a/include/boost/process/environment.hpp b/vendor/boost_1.51/include/boost/process/environment.hpp similarity index 100% rename from include/boost/process/environment.hpp rename to vendor/boost_1.51/include/boost/process/environment.hpp diff --git a/include/boost/process/handle.hpp b/vendor/boost_1.51/include/boost/process/handle.hpp similarity index 100% rename from include/boost/process/handle.hpp rename to vendor/boost_1.51/include/boost/process/handle.hpp diff --git a/include/boost/process/operations.hpp b/vendor/boost_1.51/include/boost/process/operations.hpp similarity index 93% rename from include/boost/process/operations.hpp rename to vendor/boost_1.51/include/boost/process/operations.hpp index 5fcdd04..0c8f96a 100644 --- a/include/boost/process/operations.hpp +++ b/vendor/boost_1.51/include/boost/process/operations.hpp @@ -239,8 +239,8 @@ inline child create_child(const std::string &executable, Arguments args, { if (chdir(work_dir) == -1) { - write(STDERR_FILENO, "chdir() failed\n", 15); - _exit(127); + auto r = write(STDERR_FILENO, "chdir() failed\n", 15); + if( r || !r ) _exit(127); } for (handles_t::iterator it = handles.begin(); it != handles.end(); @@ -258,7 +258,8 @@ inline child create_child(const std::string &executable, Arguments args, it->first + 1); if (fd == -1) { - write(STDERR_FILENO, "fcntl() failed\n", 15); + auto r = write(STDERR_FILENO, "chdir() failed\n", 15); + (void)r; _exit(127); } it2->second.child = fd; @@ -267,8 +268,8 @@ inline child create_child(const std::string &executable, Arguments args, if (dup2(it->second.child.native(), it->first) == -1) { - write(STDERR_FILENO, "dup2() failed\n", 14); - _exit(127); + auto r = write(STDERR_FILENO, "chdir() failed\n", 15); + if( r || !r ) _exit(127); } closeflags[it->first] = false; } @@ -287,7 +288,8 @@ inline child create_child(const std::string &executable, Arguments args, // Actually we should delete argv and envp data. As we must not // call any non-async-signal-safe functions though we simply exit. - write(STDERR_FILENO, "execve() failed\n", 16); + auto r = write(STDERR_FILENO, "execve() failed\n", 16); + if( r || !r ) _exit(127); _exit(127); } else diff --git a/include/boost/process/pid_type.hpp b/vendor/boost_1.51/include/boost/process/pid_type.hpp similarity index 100% rename from include/boost/process/pid_type.hpp rename to vendor/boost_1.51/include/boost/process/pid_type.hpp diff --git a/include/boost/process/pipe.hpp b/vendor/boost_1.51/include/boost/process/pipe.hpp similarity index 100% rename from include/boost/process/pipe.hpp rename to vendor/boost_1.51/include/boost/process/pipe.hpp diff --git a/include/boost/process/pistream.hpp b/vendor/boost_1.51/include/boost/process/pistream.hpp similarity index 100% rename from include/boost/process/pistream.hpp rename to vendor/boost_1.51/include/boost/process/pistream.hpp diff --git a/include/boost/process/postream.hpp b/vendor/boost_1.51/include/boost/process/postream.hpp similarity index 100% rename from include/boost/process/postream.hpp rename to vendor/boost_1.51/include/boost/process/postream.hpp diff --git a/include/boost/process/process.hpp b/vendor/boost_1.51/include/boost/process/process.hpp similarity index 100% rename from include/boost/process/process.hpp rename to vendor/boost_1.51/include/boost/process/process.hpp diff --git a/include/boost/process/self.hpp b/vendor/boost_1.51/include/boost/process/self.hpp similarity index 100% rename from include/boost/process/self.hpp rename to vendor/boost_1.51/include/boost/process/self.hpp diff --git a/include/boost/process/status.hpp b/vendor/boost_1.51/include/boost/process/status.hpp similarity index 100% rename from include/boost/process/status.hpp rename to vendor/boost_1.51/include/boost/process/status.hpp diff --git a/include/boost/process/stream_behavior.hpp b/vendor/boost_1.51/include/boost/process/stream_behavior.hpp similarity index 100% rename from include/boost/process/stream_behavior.hpp rename to vendor/boost_1.51/include/boost/process/stream_behavior.hpp diff --git a/include/boost/process/stream_ends.hpp b/vendor/boost_1.51/include/boost/process/stream_ends.hpp similarity index 100% rename from include/boost/process/stream_ends.hpp rename to vendor/boost_1.51/include/boost/process/stream_ends.hpp diff --git a/include/boost/process/stream_id.hpp b/vendor/boost_1.51/include/boost/process/stream_id.hpp similarity index 100% rename from include/boost/process/stream_id.hpp rename to vendor/boost_1.51/include/boost/process/stream_id.hpp diff --git a/include/boost/process/stream_type.hpp b/vendor/boost_1.51/include/boost/process/stream_type.hpp similarity index 100% rename from include/boost/process/stream_type.hpp rename to vendor/boost_1.51/include/boost/process/stream_type.hpp diff --git a/vendor/boost_1.51/libs/context/asm/fcontext_arm_aapcs_elf_gas.S b/vendor/boost_1.51/libs/context/asm/fcontext_arm_aapcs_elf_gas.S new file mode 100644 index 0000000..7724441 --- /dev/null +++ b/vendor/boost_1.51/libs/context/asm/fcontext_arm_aapcs_elf_gas.S @@ -0,0 +1,101 @@ +/* + Copyright Oliver Kowalke 2009. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +*/ + +/******************************************************************* + * * + * ------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | * + * ------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| 0x20| 0x24| * + * ------------------------------------------------------------- * + * | v1 | v2 | v3 | v4 | v5 | v6 | v7 | v8 | sp | lr | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 10 | | * + * ------------------------------------------------------------- * + * | 0x28| | * + * ------------------------------------------------------------- * + * | pc | | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 11 | 12 | | * + * ------------------------------------------------------------- * + * | 0x2c| 0x30| | * + * ------------------------------------------------------------- * + * |sbase|slimit| | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | * + * ------------------------------------------------------------- * + * | 0x34| 0x38|0x3c| 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58 | * + * ------------------------------------------------------------- * + * | s16 | s17 | s18 | s19 | s20 | s21 | s22 | s23 | s24 | s25 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 23 | 24 | 25 | 26 | 27 | 28 | | * + * ------------------------------------------------------------- * + * | 0x5c| 0x60| 0x64| 0x68| 0x6c| 0x70| | * + * ------------------------------------------------------------- * + * | s26 | s27 | s28 | s29 | s30 | s31 | | * + * ------------------------------------------------------------- * + * * + * *****************************************************************/ + +.text +.globl jump_fcontext +.align 2 +.type jump_fcontext,%function +jump_fcontext: + stmia a1, {v1-v8,sp-lr} @ save V1-V8,SP-LR + str lr, [a1,#40] @ save LR as PC + +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + cmp a4, #0 @ test if fpu env should be preserved + beq 1f + + mov a4, a1 + add a4, #52 + fstmiax a4, {d8-d15} @ save S16-S31 + + mov a4, a2 + add a4, #52 + fldmiax a4, {d8-d15} @ restore S16-S31 +1: +#endif + + mov a1, a3 @ use third arg as return value after jump + @ and as first arg in context function + ldmia a2, {v1-v8,sp-pc} @ restore v1-V8,SP-PC +.size jump_fcontext,.-jump_fcontext + +.text +.globl make_fcontext +.align 2 +.type make_fcontext,%function +make_fcontext: + str a1, [a1,#0] @ save the address of passed context + str a2, [a1,#40] @ save address of the context function + ldr a2, [a1,#44] @ load the stack base + + push {a1,lr} @ save pointer to fcontext_t + mov a1, a2 @ stack pointer as arg for align_stack + bl align_stack@PLT @ align stack + mov a2, a1 @ begin of aligned stack + pop {a1,lr} @ restore pointer to fcontext_t + + str a2, [a1,#32] @ save the aligned stack base + + adr a2, finish @ address of finish; called after context function returns + str a2, [a1,#36] + + mov a1, #0 + bx lr + +finish: + mov a1, #0 @ exit code is zero + bl _exit@PLT @ exit application +.size make_fcontext,.-make_fcontext diff --git a/vendor/boost_1.51/libs/context/asm/fcontext_i386_ms_pe_masm.asm b/vendor/boost_1.51/libs/context/asm/fcontext_i386_ms_pe_masm.asm new file mode 100644 index 0000000..0f4dd67 --- /dev/null +++ b/vendor/boost_1.51/libs/context/asm/fcontext_i386_ms_pe_masm.asm @@ -0,0 +1,151 @@ + +; Copyright Oliver Kowalke 2009. +; Distributed under the Boost Software License, Version 1.0. +; (See accompanying file LICENSE_1_0.txt or copy at +; http://www.boost.org/LICENSE_1_0.txt) + +; -------------------------------------------------------------- +; | 0 | 1 | 2 | 3 | 4 | 5 | +; -------------------------------------------------------------- +; | 0h | 04h | 08h | 0ch | 010h | 014h | +; -------------------------------------------------------------- +; | EDI | ESI | EBX | EBP | ESP | EIP | +; -------------------------------------------------------------- +; -------------------------------------------------------------- +; | 6 | 7 | | +; -------------------------------------------------------------- +; | 018h | 01ch | | +; -------------------------------------------------------------- +; | ss_base | ss_limit| | +; -------------------------------------------------------------- +; -------------------------------------------------------------- +; | 8 | | +; -------------------------------------------------------------- +; | 020h | | +; -------------------------------------------------------------- +; |fc_execpt| | +; -------------------------------------------------------------- +; -------------------------------------------------------------- +; | 9 | | +; -------------------------------------------------------------- +; | 024h | | +; -------------------------------------------------------------- +; |fc_strage| | +; -------------------------------------------------------------- +; -------------------------------------------------------------- +; | 10 | 11 | | +; -------------------------------------------------------------- +; | 028h | 02ch | | +; -------------------------------------------------------------- +; | fc_mxcsr|fc_x87_cw| | +; -------------------------------------------------------------- + +.386 +.XMM +.model flat, c +_exit PROTO, value:SDWORD +align_stack PROTO, vp:DWORD +seh_fcontext PROTO, except:DWORD, frame:DWORD, context:DWORD, dispatch:DWORD +.code + +jump_fcontext PROC EXPORT + mov ecx, [esp+04h] ; load address of the first fcontext_t arg + mov [ecx], edi ; save EDI + mov [ecx+04h], esi ; save ESI + mov [ecx+08h], ebx ; save EBX + mov [ecx+0ch], ebp ; save EBP + + assume fs:nothing + mov edx, fs:[018h] ; load NT_TIB + assume fs:error + mov eax, [edx] ; load current SEH exception list + mov [ecx+020h], eax ; save current exception list + mov eax, [edx+04h] ; load current stack base + mov [ecx+018h], eax ; save current stack base + mov eax, [edx+08h] ; load current stack limit + mov [ecx+01ch], eax ; save current stack limit + mov eax, [edx+010h] ; load fiber local storage + mov [ecx+024h], eax ; save fiber local storage + + lea eax, [esp+04h] ; exclude the return address + mov [ecx+010h], eax ; save as stack pointer + mov eax, [esp] ; load return address + mov [ecx+014h], eax ; save return address + + mov edx, [esp+08h] ; load address of the second fcontext_t arg + mov edi, [edx] ; restore EDI + mov esi, [edx+04h] ; restore ESI + mov ebx, [edx+08h] ; restore EBX + mov ebp, [edx+0ch] ; restore EBP + + mov eax, [esp+010h] ; check if fpu enve preserving was requested + test eax, eax + je nxt + + stmxcsr [ecx+028h] ; save MMX control word + fnstcw [ecx+02ch] ; save x87 control word + ldmxcsr [edx+028h] ; restore MMX control word + fldcw [edx+02ch] ; restore x87 control word +nxt: + mov ecx, edx + assume fs:nothing + mov edx, fs:[018h] ; load NT_TIB + assume fs:error + mov eax, [ecx+020h] ; load SEH exception list + mov [edx], eax ; restore next SEH item + mov eax, [ecx+018h] ; load stack base + mov [edx+04h], eax ; restore stack base + mov eax, [ecx+01ch] ; load stack limit + mov [edx+08h], eax ; restore stack limit + mov eax, [ecx+024h] ; load fiber local storage + mov [edx+010h], eax ; restore fiber local storage + + mov eax, [esp+0ch] ; use third arg as return value after jump + + mov esp, [ecx+010h] ; restore ESP + mov [esp+04h], eax ; use third arg as first arg in context function + mov ecx, [ecx+014h] ; fetch the address to return to + + jmp ecx ; indirect jump to context +jump_fcontext ENDP + +make_fcontext PROC EXPORT + mov eax, [esp+04h] ; load address of the fcontext_t arg0 + mov [eax], eax ; save the address of passed context + mov ecx, [esp+08h] ; load the address of the context function + mov [eax+014h], ecx ; save the address of the context function + mov edx, [eax+018h] ; load the stack base + + push eax ; save pointer to fcontext_t + push edx ; stack pointer as arg for align_stack + call align_stack ; align stack + mov edx, eax ; begin of aligned stack + pop eax ; remove arg for align_stack + pop eax ; restore pointer to fcontext_t + + lea edx, [edx-014h] ; reserve space for last frame on stack, (ESP + 4) & 15 == 0 + mov [eax+010h], edx ; save the aligned stack + + mov ecx, seh_fcontext ; set ECX to exception-handler + mov [edx+0ch], ecx ; save ECX as SEH handler + mov ecx, 0ffffffffh ; set ECX to -1 + mov [edx+08h], ecx ; save ECX as next SEH item + lea ecx, [edx+08h] ; load address of next SEH item + mov [eax+02ch], ecx ; save next SEH + + stmxcsr [eax+028h] ; save MMX control word + fnstcw [eax+02ch] ; save x87 control word + + mov ecx, finish ; address of finish + mov [edx], ecx + + xor eax, eax + ret + +finish: + xor eax, eax + push eax ; exit code is zero + call _exit ; exit application + hlt +make_fcontext ENDP +END diff --git a/vendor/boost_1.51/libs/context/asm/fcontext_i386_sysv_elf_gas.S b/vendor/boost_1.51/libs/context/asm/fcontext_i386_sysv_elf_gas.S new file mode 100644 index 0000000..7c94ea0 --- /dev/null +++ b/vendor/boost_1.51/libs/context/asm/fcontext_i386_sysv_elf_gas.S @@ -0,0 +1,122 @@ +/* + Copyright Oliver Kowalke 2009. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +*/ + +/******************************************************************** + * * + * -------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | * + * -------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | * + * -------------------------------------------------------------- * + * | EDI | ESI | EBX | EBP | ESP | EIP | * + * -------------------------------------------------------------- * + * -------------------------------------------------------------- * + * | 6 | 7 | | * + * -------------------------------------------------------------- * + * | 0x18 | 0x1c | | * + * -------------------------------------------------------------- * + * | sbase | slimit | | * + * -------------------------------------------------------------- * + * -------------------------------------------------------------- * + * | 8 | 9 | | * + * -------------------------------------------------------------- * + * | 0x20 | 0x24 | | * + * -------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| | * + * -------------------------------------------------------------- * + * * + * *****************************************************************/ + +.text +.globl jump_fcontext +.align 2 +.type jump_fcontext,@function +jump_fcontext: + movl 0x4(%esp), %ecx /* load address of the first fcontext_t arg */ + movl %edi, (%ecx) /* save EDI */ + movl %esi, 0x4(%ecx) /* save ESI */ + movl %ebx, 0x8(%ecx) /* save EBX */ + movl %ebp, 0xc(%ecx) /* save EBP */ + + leal 0x4(%esp), %eax /* exclude the return address */ + movl %eax, 0x10(%ecx) /* save as stack pointer */ + movl (%esp), %eax /* load return address */ + movl %eax, 0x14(%ecx) /* save return address */ + + movl 0x8(%esp), %edx /* load address of the second fcontext_t arg */ + movl (%edx), %edi /* restore EDI */ + movl 0x4(%edx), %esi /* restore ESI */ + movl 0x8(%edx), %ebx /* restore EBX */ + movl 0xc(%edx), %ebp /* restore EBP */ + + movl 0x10(%esp), %eax /* check if fpu enve preserving was requested */ + test %eax, %eax + je 1f + + stmxcsr 0x20(%ecx) /* save MMX control and status word */ + fnstcw 0x24(%ecx) /* save x87 control word */ + ldmxcsr 0x20(%edx) /* restore MMX control and status word */ + fldcw 0x24(%edx) /* restore x87 control word */ +1: + movl 0xc(%esp), %eax /* use third arg as return value after jump */ + + movl 0x10(%edx), %esp /* restore ESP */ + movl %eax, 0x4(%esp) /* use third arg as first arg in context function */ + movl 0x14(%edx), %edx /* fetch the address to return to */ + + jmp *%edx /* indirect jump to context */ +.size jump_fcontext,.-jump_fcontext + +.text +.globl make_fcontext +.align 2 +.type make_fcontext,@function +make_fcontext: + movl 0x4(%esp), %eax /* load address of the fcontext_t */ + movl %eax, (%eax) /* save the address of current context */ + movl 0x8(%esp), %ecx /* load the address of the context function */ + movl %ecx, 0x14(%eax) /* save the address of the context function */ + movl 0x18(%eax), %edx /* load the stack base */ + + pushl %eax /* save pointer to fcontext_t */ + pushl %ebx /* save EBX */ + pushl %edx /* stack pointer as arg for align_stack */ + call 1f +1: popl %ebx /* address of label 1 */ + addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx /* compute address of GOT and store it in EBX */ + call align_stack@PLT /* align stack */ + movl %eax, %edx /* begin of aligned stack */ + popl %eax /* remove arg for align_stack */ + popl %ebx /* restore EBX */ + popl %eax /* restore pointer to fcontext_t */ + + leal -0x14(%edx), %edx /* reserve space for the last frame on stack, (ESP + 4) % 16 == 0 */ + movl %edx, 0x10(%eax) /* save the aligned stack base */ + + stmxcsr 0x20(%eax) /* save MMX control and status word */ + fnstcw 0x24(%eax) /* save x87 control word */ + + call 2f +2: popl %ecx /* address of label 2 */ + addl $finish-2b, %ecx /* helper code executed after context function returns */ + movl %ecx, (%edx) + + xorl %eax, %eax + ret + +finish: + leal -0xc(%esp), %esp + + call 3f +3: popl %ebx /* address of label 3 */ + addl $_GLOBAL_OFFSET_TABLE_+[.-3b], %ebx /* compute address of GOT and store it in EBX */ + + xorl %eax, %eax + pushl %eax /* exit code is zero */ + call _exit@PLT /* exit application */ + hlt +.size make_fcontext,.-make_fcontext diff --git a/vendor/boost_1.51/libs/context/asm/fcontext_i386_sysv_macho_gas.S b/vendor/boost_1.51/libs/context/asm/fcontext_i386_sysv_macho_gas.S new file mode 100644 index 0000000..a28c875 --- /dev/null +++ b/vendor/boost_1.51/libs/context/asm/fcontext_i386_sysv_macho_gas.S @@ -0,0 +1,118 @@ +/* + Copyright Oliver Kowalke 2009. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +*/ + +/******************************************************************** + * * + * -------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | * + * -------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | * + * -------------------------------------------------------------- * + * | EDI | ESI | EBX | EBP | ESP | EIP | * + * -------------------------------------------------------------- * + * -------------------------------------------------------------- * + * | 6 | 7 | | * + * -------------------------------------------------------------- * + * | 0x18 | 0x1c | | * + * -------------------------------------------------------------- * + * | sbase | slimit | | * + * -------------------------------------------------------------- * + * -------------------------------------------------------------- * + * | 8 | 9 | | * + * -------------------------------------------------------------- * + * | 0x20 | 0x24 | | * + * -------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| | * + * -------------------------------------------------------------- * + * * + * *****************************************************************/ + +.text +.globl _jump_fcontext +.align 2 +_jump_fcontext: + movl 0x4(%esp), %ecx /* load address of the first fcontext_t arg */ + movl %edi, (%ecx) /* save EDI */ + movl %esi, 0x4(%ecx) /* save ESI */ + movl %ebx, 0x8(%ecx) /* save EBX */ + movl %ebp, 0xc(%ecx) /* save EBP */ + + leal 0x4(%esp), %eax /* exclude the return address */ + movl %eax, 0x10(%ecx) /* save as stack pointer */ + movl (%esp), %eax /* load return address */ + movl %eax, 0x14(%ecx) /* save return address */ + + movl 0x8(%esp), %edx /* load address of the second fcontext_t arg */ + movl (%edx), %edi /* restore EDI */ + movl 0x4(%edx), %esi /* restore ESI */ + movl 0x8(%edx), %ebx /* restore EBX */ + movl 0xc(%edx), %ebp /* restore EBP */ + + movl 0x10(%esp), %eax /* check if fpu enve preserving was requested */ + test %eax, %eax + je 1f + + stmxcsr 0x20(%ecx) /* save MMX control and status word */ + fnstcw 0x24(%ecx) /* save x87 control word */ + ldmxcsr 0x20(%edx) /* restore MMX control and status word */ + fldcw 0x24(%edx) /* restore x87 control word */ +1: + movl 0xc(%esp), %eax /* use third arg as return value after jump */ + + movl 0x10(%edx), %esp /* restore ESP */ + movl %eax, 0x4(%esp) /* use third arg as first arg in context function */ + movl 0x14(%edx), %edx /* fetch the address to return to */ + + jmp *%edx /* indirect jump to context */ + +.text +.globl _make_fcontext +.align 2 +_make_fcontext: + movl 0x4(%esp), %eax /* load address of the fcontext_t */ + movl %eax, (%eax) /* save the address of current context */ + movl 0x8(%esp), %ecx /* load the address of the context function */ + movl %ecx, 0x14(%eax) /* save the address of the context function */ + movl 0x18(%eax), %edx /* load the stack base */ + + pushl %eax /* save pointer to fcontext_t */ + pushl %ebx /* save EBX */ + pushl %edx /* stack pointer as arg for align_stack */ + call 1f +1: popl %ebx /* address of label 1 */ + addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx /* compute address of GOT and store it in EBX */ + call align_stack@PLT /* align stack */ + movl %eax, %edx /* begin of aligned stack */ + popl %eax /* remove arg for align_stack */ + popl %ebx /* restore EBX */ + popl %eax /* restore pointer to fcontext_t */ + + leal -0x14(%edx), %edx /* reserve space for the last frame on stack, (ESP + 4) % 16 == 0 */ + movl %edx, 0x10(%eax) /* save the aligned stack base */ + + stmxcsr 0x20(%eax) /* save MMX control and status word */ + fnstcw 0x24(%eax) /* save x87 control word */ + + call 2f +2: popl %ecx /* address of label 2 */ + addl $finish-2b, %ecx /* helper code executed after context function returns */ + movl %ecx, (%edx) + + xorl %eax, %eax + ret + +finish: + leal -0xc(%esp), %esp + + call 3f +3: popl %ebx /* address of label 3 */ + addl $_GLOBAL_OFFSET_TABLE_+[.-3b], %ebx /* compute address of GOT and store it in EBX */ + + xorl %eax, %eax + pushl %eax /* exit code is zero */ + call _exit@PLT /* exit application */ + hlt diff --git a/vendor/boost_1.51/libs/context/asm/fcontext_mips32_o32_elf_gas.S b/vendor/boost_1.51/libs/context/asm/fcontext_mips32_o32_elf_gas.S new file mode 100644 index 0000000..be86f18 --- /dev/null +++ b/vendor/boost_1.51/libs/context/asm/fcontext_mips32_o32_elf_gas.S @@ -0,0 +1,144 @@ +/* + Copyright Oliver Kowalke 2009. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +*/ + +/******************************************************************* + * * + * ------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | * + * ------------------------------------------------------------- * + * | 0 | 8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | * + * ------------------------------------------------------------- * + * | S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | GP | SP | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 10 | 11 | 12 | | * + * ------------------------------------------------------------- * + * | 80 | 88 | 96 | | * + * ------------------------------------------------------------- * + * | S8 | RA | PC | | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 13 | 14 | | * + * ------------------------------------------------------------- * + * | 104 | 112 | | * + * ------------------------------------------------------------- * + * |sbase|slimt| | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 15 | 16 | 17 | 18 | 19 | 20 | | * + * ------------------------------------------------------------- * + * | 120 | 128 | 136 | 144 | 152 | 160 | | * + * ------------------------------------------------------------- * + * | F20 | F22 | F24 | F26 | F28 | F30 | | * + * ------------------------------------------------------------- * + * * + * *****************************************************************/ + +.text +.globl jump_fcontext +.align 2 +.type jump_fcontext,@function +.ent jump_fcontext +jump_fcontext: + sw $s0, ($a0) # save S0 + sw $s1, 8($a0) # save S1 + sw $s2, 16($a0) # save S2 + sw $s3, 24($a0) # save S3 + sw $s4, 32($a0) # save S4 + sw $s5, 40($a0) # save S5 + sw $s6, 48($a0) # save S6 + sw $s7, 56($a0) # save S7 + sw $gp, 64($a0) # save GP + sw $sp, 72($a0) # save SP + sw $s8, 80($a0) # save S8 + sw $ra, 88($a0) # save RA + sw $ra, 96($a0) # save RA as PC + +#if defined(__mips_hard_float) + beqz $a3, 1f # test if fpu env should be preserved + s.d $f20, 120($a0) # save F20 + s.d $f22, 128($a0) # save F22 + s.d $f24, 136($a0) # save F24 + s.d $f26, 144($a0) # save F26 + s.d $f28, 152($a0) # save F28 + s.d $f30, 160($a0) # save F30 + + l.d $f20, 120($a1) # restore F20 + l.d $f22, 128($a1) # restore F22 + l.d $f24, 136($a1) # restore F24 + l.d $f26, 144($a1) # restore F26 + l.d $f28, 152($a1) # restore F28 + l.d $f30, 160($a1) # restore F30 +1: +#endif + + lw $s0, ($a1) # restore S0 + lw $s1, 8($a1) # restore S1 + lw $s2, 16($a1) # restore S2 + lw $s3, 24($a1) # restore S3 + lw $s4, 32($a1) # restore S4 + lw $s5, 40($a1) # restore S5 + lw $s6, 48($a1) # restore S6 + lw $s7, 56($a1) # restore S7 + lw $gp, 64($a1) # restore GP + lw $sp, 72($a1) # restore SP + lw $s8, 80($a1) # restore S8 + lw $ra, 88($a1) # restore RA + move $a0, $s2 # restore void pointer as argument + + move $v0, $a2 # use third arg as return value after jump + move $a0, $a2 # use third arg as first arg in context function + + lw $t9, 96($a1) # load PC + jr $t9 # jump to context +.end jump_fcontext +.size jump_fcontext, .-jump_fcontext + +.text +.globl make_fcontext +.align 2 +.type make_fcontext,@function +.ent make_fcontext +make_fcontext: +#ifdef __PIC__ +.set noreorder +.cpload $t9 +.set reorder +#endif + sw $a0, ($a0) # save the current context + sw $gp, 24($a0) # save global pointer + sw $a1, 96($a0) # save the address of the context function + lw $t0, 104($a0) # load the stack base + + sub $sp, $sp, 28 + sw $ra, 24($sp) + sw $a0, 20($sp) + move $a0, $t0 # stack pointer as arg for align_stack + lw $t9, %call16(align_stack)($gp) # align stack + jalr $t9 + nop + move $t0, $v0 # begin of aligned stack + lw $ra, 24($sp) + lw $a0, 20($sp) + addi $sp, $sp, 28 + + sub $t0, $t0, 16 # reserve 16 byte of argument space + sw $t0, 72($a0) # save the algned stack base + + la $t9, finish # helper code executed after context function returns + sw $t9, 88($a0) + + move $v0, $zero + jr $ra + +finish: + move $gp, $s3 # restore GP (global pointer) + move $a0, $zero # exit code is zero + lw $t9, %call16(_exit)($gp) # exit application + jalr $t9 +.end make_fcontext +.size make_fcontext, .-make_fcontext diff --git a/vendor/boost_1.51/libs/context/asm/fcontext_ppc32_sysv_elf_gas.S b/vendor/boost_1.51/libs/context/asm/fcontext_ppc32_sysv_elf_gas.S new file mode 100644 index 0000000..69b6ed9 --- /dev/null +++ b/vendor/boost_1.51/libs/context/asm/fcontext_ppc32_sysv_elf_gas.S @@ -0,0 +1,222 @@ +/* + Copyright Oliver Kowalke 2009. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +*/ + +/******************************************************************* + * * + * ------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | * + * ------------------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | * + * ------------------------------------------------------------- * + * | R13 | R14 | R15 | R16 | R17 | R18 | R19 | R20 | R21 | R22 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | * + * ------------------------------------------------------------- * + * | 40 | 44 | 48 | 52 | 56 | 60 | 64 | 68 | 72 | 76 | * + * ------------------------------------------------------------- * + * | R23 | R24 | R25 | R26 | R27 | R28 | R29 | R30 | R31 | SP | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 20 | 21 | 22 | | * + * ------------------------------------------------------------- * + * | 80 | 84 | 88 | | * + * ------------------------------------------------------------- * + * | CR | LR | PC | | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 23 | 24 | | * + * ------------------------------------------------------------- * + * | 92 | 96 | | * + * ------------------------------------------------------------- * + * |sbase|slimt| | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | * + * ------------------------------------------------------------- * + * | 100 | 104 | 108 | 112 | 116 | 120 | 124 | 128 | 132 | 136 | * + * ------------------------------------------------------------- * + * | F14 | F15 | F16 | F17 | F18 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | * + * ------------------------------------------------------------- * + * | 140 | 144 | 148 | 152 | 156 | 160 | 164 | 168 | 172 | 176 | * + * ------------------------------------------------------------- * + * | F19 | F20 | F21 | F22 | F23 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | * + * ------------------------------------------------------------- * + * | 180 | 184 | 188 | 192 | 196 | 200 | 204 | 208 | 212 | 216 | * + * ------------------------------------------------------------- * + * | F24 | F25 | F26 | F27 | F28 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | | * + * ------------------------------------------------------------- * + * | 220 | 224 | 228 | 232 | 236 | 240 | 244 | 248 | | * + * ------------------------------------------------------------- * + * | F29 | F30 | F31 | fpscr | | * + * ------------------------------------------------------------- * + * * + * *****************************************************************/ + +.text +.globl jump_fcontext +.align 2 +.type jump_fcontext,@function +jump_fcontext: + stw %r13, 0(%r3) # save R13 + stw %r14, 4(%r3) # save R14 + stw %r15, 8(%r3) # save R15 + stw %r16, 12(%r3) # save R16 + stw %r17, 16(%r3) # save R17 + stw %r18, 20(%r3) # save R18 + stw %r19, 24(%r3) # save R19 + stw %r20, 28(%r3) # save R20 + stw %r21, 32(%r3) # save R21 + stw %r22, 36(%r3) # save R22 + stw %r23, 40(%r3) # save R23 + stw %r24, 44(%r3) # save R24 + stw %r25, 48(%r3) # save R25 + stw %r26, 52(%r3) # save R26 + stw %r27, 56(%r3) # save R27 + stw %r28, 60(%r3) # save R28 + stw %r29, 64(%r3) # save R29 + stw %r30, 68(%r3) # save R30 + stw %r31, 72(%r3) # save R31 + stw %r1, 76(%r3) # save SP + + mfcr %r0 # load CR + stw %r0, 80(%r3) # save CR + mflr %r0 # load LR + stw %r0, 84(%r3) # save LR + stw %r0, 88(%r3) # save LR as PC + + cmpwi cr7, %r6, 0 # test if fpu env should be preserved + beq cr7, 1f + + stfd %f14, 100(%r3) # save F14 + stfd %f15, 108(%r3) # save F15 + stfd %f16, 116(%r3) # save F16 + stfd %f17, 124(%r3) # save F17 + stfd %f18, 132(%r3) # save F18 + stfd %f19, 140(%r3) # save F19 + stfd %f20, 148(%r3) # save F20 + stfd %f21, 156(%r3) # save F21 + stfd %f22, 164(%r3) # save F22 + stfd %f23, 172(%r3) # save F23 + stfd %f24, 180(%r3) # save F24 + stfd %f25, 188(%r3) # save F25 + stfd %f26, 196(%r3) # save F26 + stfd %f27, 204(%r3) # save F27 + stfd %f28, 212(%r3) # save F28 + stfd %f29, 220(%r3) # save F29 + stfd %f30, 228(%r3) # save F30 + stfd %f31, 236(%r3) # save F31 + mffs %f0 # load FPSCR + stfd %f0, 244(%r3) # save FPSCR + + lfd %f14, 100(%r4) # restore F14 + lfd %f15, 108(%r4) # restore F15 + lfd %f16, 116(%r4) # restore F16 + lfd %f17, 124(%r4) # restore F17 + lfd %f18, 132(%r4) # restore F18 + lfd %f19, 140(%r4) # restore F19 + lfd %f20, 148(%r4) # restore F20 + lfd %f21, 156(%r4) # restore F21 + lfd %f22, 164(%r4) # restore F22 + lfd %f23, 172(%r4) # restore F23 + lfd %f24, 180(%r4) # restore F24 + lfd %f25, 188(%r4) # restore F25 + lfd %f26, 196(%r4) # restore F26 + lfd %f27, 204(%r4) # restore F27 + lfd %f28, 212(%r4) # restore F28 + lfd %f29, 220(%r4) # restore F29 + lfd %f30, 228(%r4) # restore F30 + lfd %f31, 236(%r4) # restore F31 + lfd %f0, 244(%r4) # load FPSCR + mtfsf 0xff, %f0 # restore FPSCR +1: + + lwz %r13, 0(%r4) # restore R13 + lwz %r14, 4(%r4) # restore R14 + lwz %r15, 8(%r4) # restore R15 + lwz %r16, 12(%r4) # restore R16 + lwz %r17, 16(%r4) # restore R17 + lwz %r18, 20(%r4) # restore R18 + lwz %r19, 24(%r4) # restore R19 + lwz %r20, 28(%r4) # restore R20 + lwz %r21, 32(%r4) # restore R21 + lwz %r22, 36(%r4) # restore R22 + lwz %r23, 40(%r4) # restore R23 + lwz %r24, 44(%r4) # restore R24 + lwz %r25, 48(%r4) # restore R25 + lwz %r26, 52(%r4) # restore R26 + lwz %r27, 56(%r4) # restore R27 + lwz %r28, 60(%r4) # restore R28 + lwz %r29, 64(%r4) # restore R29 + lwz %r30, 68(%r4) # restore R30 + lwz %r31, 72(%r4) # restore R31 + lwz %r1, 76(%r4) # restore SP + + lwz %r0, 80(%r4) # load CR + mtcr %r0 # restore CR + lwz %r0, 84(%r4) # load LR + mtlr %r0 # restore LR + + mr. %r3, %r5 # use third arg as return value after jump + # and as first arg in context function + + lwz %r0, 88(%r4) # load PC + mtctr %r0 # restore CTR + + bctr # jump to context +.size jump_fcontext, .-jump_fcontext + +.text +.globl make_fcontext +.align 2 +.type make_fcontext,@function +make_fcontext: + stw %r3, 0(%r3) # save the current context + stw %r4, 88(%r3) # save the address of the context function + lwz %r0, 92(%r3) # load the stack base + + li %r4, 28 + subf %r1, %r4, %r1 # reserve space on stack + stw %r3, 24(%r1) # store pointer to fcontext_t on stack + mflr %r4 # load LR + stw %r4, 20(%r1) # store LR on stack + mr. %r3, %r0 # context stack as arg to align_stack + bl align_stack@plt # call align_stack + mr. %r0, %r3 # load result into R0 + lwz %r4, 20(%r1) # pop LR from stack + mtlr %r4 # restore LR + lwz %r3, 24(%r1) # pop pointer to fcontext_t from stack + addi %r1, %r1, 28 # release space on stack + + li %r4, 32 + subf %r0, %r4, %r0 # 32 bytes on stack for parameter area(== 8 registers) + stw %r0, 76(%r3) # save the aligned stack base + + mflr %r0 # load LR + bl 1f # jump to label 1 +1: + mflr %r4 # load LR + addi %r4, %r4, finish - 1b # address of finish; called after context function returns + mtlr %r0 # restore LR + stw %r4, 84(%r3) + + li %r3, 0 + blr + +finish: + li %r3, 0 # exit code is zero + bl _exit@plt # exit application +.size make_fcontext, .-make_fcontext diff --git a/vendor/boost_1.51/libs/context/asm/fcontext_ppc64_sysv_elf_gas.S b/vendor/boost_1.51/libs/context/asm/fcontext_ppc64_sysv_elf_gas.S new file mode 100644 index 0000000..0fcb387 --- /dev/null +++ b/vendor/boost_1.51/libs/context/asm/fcontext_ppc64_sysv_elf_gas.S @@ -0,0 +1,250 @@ +/* + Copyright Oliver Kowalke 2009. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +*/ + +/******************************************************************* + * * + * ------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | * + * ------------------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | * + * ------------------------------------------------------------- * + * | R13 | R14 | R15 | R16 | R17 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | * + * ------------------------------------------------------------- * + * | 40 | 44 | 48 | 52 | 56 | 60 | 64 | 68 | 72 | 76 | * + * ------------------------------------------------------------- * + * | R18 | R19 | R20 | R21 | R22 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | * + * ------------------------------------------------------------- * + * | 80 | 84 | 88 | 92 | 96 | 100 | 104 | 108 | 112 | 116 | * + * ------------------------------------------------------------- * + * | R23 | R24 | R25 | R26 | R27 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------------------- * + * | 120 | 124 | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------------------- * + * | R28 | R29 | R30 | R31 | SP | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | | * + * ------------------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | | * + * ------------------------------------------------------------- * + * | CR | LR | PC | | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 46 | 47 | 48 | 49 | | * + * ------------------------------------------------------------- * + * | 184 | 188 | 192 | 196 | | * + * ------------------------------------------------------------- * + * | sbase | slimt | | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | * + * ------------------------------------------------------------- * + * | 200 | 204 | 208 | 212 | 216 | 220 | 224 | 228 | 232 | 236 | * + * ------------------------------------------------------------- * + * | F14 | F15 | F16 | F17 | F18 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | * + * ------------------------------------------------------------- * + * | 240 | 244 | 248 | 252 | 256 | 260 | 264 | 268 | 272 | 276 | * + * ------------------------------------------------------------- * + * | F19 | F20 | F21 | F22 | F23 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | * + * ------------------------------------------------------------- * + * | 280 | 284 | 288 | 292 | 296 | 300 | 304 | 308 | 312 | 316 | * + * ------------------------------------------------------------- * + * | F24 | F25 | F26 | F27 | F28 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | | * + * ------------------------------------------------------------- * + * | 320 | 324 | 328 | 332 | 336 | 340 | 344 | 348 | | * + * ------------------------------------------------------------- * + * | F29 | F30 | F31 | fpscr | | * + * ------------------------------------------------------------- * + * * + * *****************************************************************/ + +.section ".text" +.align 2 +.globl jump_fcontext +.section ".opd","aw" +.align 3 +jump_fcontext: +.quad .jump_fcontext,.TOC.@tocbase,0 +.previous +.size jump_fcontext,24 +.type .jump_fcontext,@function +.globl .jump_fcontext +.jump_fcontext: + std %r13, 0(%r3) # save R13 + std %r14, 8(%r3) # save R14 + std %r15, 16(%r3) # save R15 + std %r16, 24(%r3) # save R16 + std %r17, 32(%r3) # save R17 + std %r18, 40(%r3) # save R18 + std %r19, 48(%r3) # save R19 + std %r20, 56(%r3) # save R20 + std %r21, 64(%r3) # save R21 + std %r22, 72(%r3) # save R22 + std %r23, 80(%r3) # save R23 + std %r24, 88(%r3) # save R24 + std %r25, 96(%r3) # save R25 + std %r26, 104(%r3) # save R26 + std %r27, 112(%r3) # save R27 + std %r28, 120(%r3) # save R28 + std %r29, 128(%r3) # save R29 + std %r30, 136(%r3) # save R30 + std %r31, 144(%r3) # save R31 + std %r1, 152(%r3) # save SP + + mfcr %r0 # load CR + std %r0, 160(%r3) # save CR + mflr %r0 # load LR + std %r0, 168(%r3) # save LR + std %r0, 176(%r3) # save LR as PC + + cmpwi cr7, %r6, 0 # test if fpu env should be preserved + beq cr7, 1f + + stfd %f14, 200(%r3) # save F14 + stfd %f15, 208(%r3) # save F15 + stfd %f16, 216(%r3) # save F16 + stfd %f17, 224(%r3) # save F17 + stfd %f18, 232(%r3) # save F18 + stfd %f19, 240(%r3) # save F19 + stfd %f20, 248(%r3) # save F20 + stfd %f21, 256(%r3) # save F21 + stfd %f22, 264(%r3) # save F22 + stfd %f23, 272(%r3) # save F23 + stfd %f24, 280(%r3) # save F24 + stfd %f25, 288(%r3) # save F25 + stfd %f26, 296(%r3) # save F26 + stfd %f27, 304(%r3) # save F27 + stfd %f28, 312(%r3) # save F28 + stfd %f29, 320(%r3) # save F29 + stfd %f30, 328(%r3) # save F30 + stfd %f31, 336(%r3) # save F31 + mffs %f0 # load FPSCR + stfd %f0, 344(%r3) # save FPSCR + + lfd %f14, 200(%r4) # restore F14 + lfd %f15, 208(%r4) # restore F15 + lfd %f16, 216(%r4) # restore F16 + lfd %f17, 224(%r4) # restore F17 + lfd %f18, 232(%r4) # restore F18 + lfd %f19, 240(%r4) # restore F19 + lfd %f20, 248(%r4) # restore F20 + lfd %f21, 256(%r4) # restore F21 + lfd %f22, 264(%r4) # restore F22 + lfd %f23, 272(%r4) # restore F23 + lfd %f24, 280(%r4) # restore F24 + lfd %f25, 288(%r4) # restore F25 + lfd %f26, 296(%r4) # restore F26 + lfd %f27, 304(%r4) # restore F27 + lfd %f28, 312(%r4) # restore F28 + lfd %f29, 320(%r4) # restore F29 + lfd %f30, 328(%r4) # restore F30 + lfd %f31, 336(%r4) # restore F31 + lfd %f0, 344(%r4) # load FPSCR + mtfsf 0xff, %f0 # restore FPSCR +1: + + ld %r13, 0(%r4) # restore R13 + ld %r14, 8(%r4) # restore R14 + ld %r15, 16(%r4) # restore R15 + ld %r16, 24(%r4) # restore R16 + ld %r17, 32(%r4) # restore R17 + ld %r18, 40(%r4) # restore R18 + ld %r19, 48(%r4) # restore R19 + ld %r20, 56(%r4) # restore R20 + ld %r21, 64(%r4) # restore R21 + ld %r22, 72(%r4) # restore R22 + ld %r23, 80(%r4) # restore R23 + ld %r24, 88(%r4) # restore R24 + ld %r25, 96(%r4) # restore R25 + ld %r26, 104(%r4) # restore R26 + ld %r27, 112(%r4) # restore R27 + ld %r28, 120(%r4) # restore R28 + ld %r29, 128(%r4) # restore R29 + ld %r30, 136(%r4) # restore r30 + ld %r31, 144(%r4) # restore r31 + ld %r1, 152(%r4) # restore SP + + ld %r0, 160(%r4) # load CR + mtcr %r0 # restore CR + ld %r0, 168(%r4) # load LR + mtlr %r0 # restore LR + + mr. %r3, %r5 # use third arg as return value after jump + # and as first arg in context function + + ld %r0, 176(%r4) # load PC + mtctr %r0 # restore CTR + + bctr # jump to context +.size .jump_fcontext, .-.jump_fcontext + +.section ".text" +.align 2 +.globl make_fcontext +.section ".opd","aw" +.align 3 +make_fcontext: +.quad .make_fcontext,.TOC.@tocbase,0 +.previous +.size make_fcontext,24 +.type .make_fcontext,@function +.globl .make_fcontext +.make_fcontext: + std %r3, 0(%r3) # save the current context + std %r4, 176(%r3) # save the address of the function supposed to be run + ld %r0, 184(%r3) # load the stack base + + li %r4, 56 + subf %r1, %r4, %r1 # reserve space on stack + stw %r3, 48(%r1) # store pointer to fcontext_t on stack + mflr %r4 # load LR + stw %r4, 40(%r1) # store LR on stack + mr. %r3, %r0 # context stack as arg to align_stack + bl align_stack@plt # call align_stack + mr. %r0, %r3 # load result into R0 + lwz %r4, 40(%r1) # pop LR from stack + mtlr %r4 # restore LR + lwz %r3, 48(%r1) # pop pointer to fcontext_t from stack + addi %r1, %r1, 56 # release space on stack + + li %r4, 64 + subf %r0, %r4, %r0 # 64 bytes on stack for parameter area (== 8 registers) + std %r0, 152(%r3) # save the stack base + + mflr %r0 # load LR + bl 1f # jump to label 1 +1: + mflr %r4 # load LR + addi %r4, %r4, finish - 1b # calulate absolute address of finish + mtlr %r0 # restore LR + std %r4, 168(%r3) # save address of finish + + li %r3, 0 # set return value to zero + blr + +finish: + li %r3, 0 # set return value to zero + bl _exit@plt # exit application +.size .make_fcontext, .-.make_fcontext diff --git a/vendor/boost_1.51/libs/context/asm/fcontext_x86_64_ms_pe_masm.asm b/vendor/boost_1.51/libs/context/asm/fcontext_x86_64_ms_pe_masm.asm new file mode 100644 index 0000000..f1f8ca1 --- /dev/null +++ b/vendor/boost_1.51/libs/context/asm/fcontext_x86_64_ms_pe_masm.asm @@ -0,0 +1,207 @@ + +; Copyright Oliver Kowalke 2009. +; Distributed under the Boost Software License, Version 1.0. +; (See accompanying file LICENSE_1_0.txt or copy at +; http://www.boost.org/LICENSE_1_0.txt) + +; ---------------------------------------------------------------------------------- +; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | +; ---------------------------------------------------------------------------------- +; | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | +; ---------------------------------------------------------------------------------- +; | R12 | R13 | R14 | R15 | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | +; ---------------------------------------------------------------------------------- +; | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | +; ---------------------------------------------------------------------------------- +; | RDI | RSI | RBX | RBP | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 16 | 17 | 18 | 19 | | +; ---------------------------------------------------------------------------------- +; | 0x40 | 0x44 | 0x48 | 0x4c | | +; ---------------------------------------------------------------------------------- +; | RSP | RIP | | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 20 | 21 | 22 | 23 | | +; ---------------------------------------------------------------------------------- +; | 0x50 | 0x54 | 0x58 | 0x5c | | +; ---------------------------------------------------------------------------------- +; | sbase | slimit | | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 24 | 25 | | +; ---------------------------------------------------------------------------------- +; | 0x60 | 0x64 | | +; ---------------------------------------------------------------------------------- +; | fbr_strg | | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 26 | 27 | 28 | 29 | | +; ---------------------------------------------------------------------------------- +; | 0x68 | 0x6c | 0x70 | 0x74 | | +; ---------------------------------------------------------------------------------- +; | fc_mxcsr|fc_x87_cw| fc_xmm | | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | +; ---------------------------------------------------------------------------------- +; | 0x78 | 0x7c | 0x80 | 0x84 | 0x88 | 0x8c | 0x90 | 0x94 | +; ---------------------------------------------------------------------------------- +; | XMM6 | XMM7 | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | +; ---------------------------------------------------------------------------------- +; | 0x98 | 0x9c | 0x100 | 0x104 | 0x108 | 0x10c | 0x110 | 0x114 | +; ---------------------------------------------------------------------------------- +; | XMM8 | XMM9 | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | +; ---------------------------------------------------------------------------------- +; | 0x118 | 0x11c | 0x120 | 0x124 | 0x128 | 0x12c | 0x130 | 0x134 | +; ---------------------------------------------------------------------------------- +; | XMM10 | XMM11 | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | +; ---------------------------------------------------------------------------------- +; | 0x138 | 0x13c | 0x140 | 0x144 | 0x148 | 0x14c | 0x150 | 0x154 | +; ---------------------------------------------------------------------------------- +; | XMM12 | XMM13 | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | +; ---------------------------------------------------------------------------------- +; | 0x158 | 0x15c | 0x160 | 0x164 | 0x168 | 0x16c | 0x170 | 0x174 | +; ---------------------------------------------------------------------------------- +; | XMM14 | XMM15 | +; ---------------------------------------------------------------------------------- + +EXTERN _exit:PROC ; standard C library function +EXTERN align_stack:PROC ; stack alignment +EXTERN seh_fcontext:PROC ; exception handler +.code + +jump_fcontext PROC EXPORT FRAME:seh_fcontext + .endprolog + + mov [rcx], r12 ; save R12 + mov [rcx+08h], r13 ; save R13 + mov [rcx+010h], r14 ; save R14 + mov [rcx+018h], r15 ; save R15 + mov [rcx+020h], rdi ; save RDI + mov [rcx+028h], rsi ; save RSI + mov [rcx+030h], rbx ; save RBX + mov [rcx+038h], rbp ; save RBP + + mov r10, gs:[030h] ; load NT_TIB + mov rax, [r10+08h] ; load current stack base + mov [rcx+050h], rax ; save current stack base + mov rax, [r10+010h] ; load current stack limit + mov [rcx+058h], rax ; save current stack limit + mov rax, [r10+018h] ; load fiber local storage + mov [rcx+060h], rax ; save fiber local storage + + test r9, r9 + je nxt + + stmxcsr [rcx+068h] ; save MMX control and status word + fnstcw [rcx+06ch] ; save x87 control word + mov r10, [rcx+070h] ; address of aligned XMM storage + movaps [r10], xmm6 + movaps [r10+010h], xmm7 + movaps [r10+020h], xmm8 + movaps [r10+030h], xmm9 + movaps [r10+040h], xmm10 + movaps [r10+050h], xmm11 + movaps [r10+060h], xmm12 + movaps [r10+070h], xmm13 + movaps [r10+080h], xmm14 + movaps [r10+090h], xmm15 + + ldmxcsr [rdx+068h] ; restore MMX control and status word + fldcw [rdx+06ch] ; restore x87 control word + mov r10, [rdx+070h] ; address of aligned XMM storage + movaps xmm6, [r10] + movaps xmm7, [r10+010h] + movaps xmm8, [r10+020h] + movaps xmm9, [r10+030h] + movaps xmm10, [r10+040h] + movaps xmm11, [r10+050h] + movaps xmm12, [r10+060h] + movaps xmm13, [r10+070h] + movaps xmm14, [r10+080h] + movaps xmm15, [r10+090h] +nxt: + + lea rax, [rsp+08h] ; exclude the return address + mov [rcx+040h], rax ; save as stack pointer + mov rax, [rsp] ; load return address + mov [rcx+048h], rax ; save return address + + mov r12, [rdx] ; restore R12 + mov r13, [rdx+08h] ; restore R13 + mov r14, [rdx+010h] ; restore R14 + mov r15, [rdx+018h] ; restore R15 + mov rdi, [rdx+020h] ; restore RDI + mov rsi, [rdx+028h] ; restore RSI + mov rbx, [rdx+030h] ; restore RBX + mov rbp, [rdx+038h] ; restore RBP + + mov r10, gs:[030h] ; load NT_TIB + mov rax, [rdx+050h] ; load stack base + mov [r10+08h], rax ; restore stack base + mov rax, [rdx+058h] ; load stack limit + mov [r10+010h], rax ; restore stack limit + mov rax, [rdx+060h] ; load fiber local storage + mov [r10+018h], rax ; restore fiber local storage + + mov rsp, [rdx+040h] ; restore RSP + mov r10, [rdx+048h] ; fetch the address to returned to + + mov rax, r8 ; use third arg as return value after jump + mov rcx, r8 ; use third arg as first arg in context function + + jmp r10 ; indirect jump to caller +jump_fcontext ENDP + +make_fcontext PROC EXPORT FRAME ; generate function table entry in .pdata and unwind information in E + .endprolog ; .xdata for a function's structured exception handling unwind behavior + + mov [rcx], rcx ; store the address of current context + mov [rcx+048h], rdx ; save the address of the function supposed to run + mov rdx, [rcx+050h] ; load the address where the context stack beginns + + push rcx ; save pointer to fcontext_t + sub rsp, 028h ; reserve shadow space for align_stack + mov rcx, rdx ; stack pointer as arg for align_stack + mov [rsp+8], rcx + call align_stack ; align stack + mov rdx, rax ; begin of aligned stack + add rsp, 028h + pop rcx ; restore pointer to fcontext_t + + lea rdx, [rdx-028h] ; reserve 32byte shadow space + return address on stack, (RSP + 8) % 16 == 0 + mov [rcx+040h], rdx ; save the address where the context stack beginns + + stmxcsr [rcx+068h] ; save MMX control and status word + fnstcw [rcx+06ch] ; save x87 control word + + lea rax, finish ; helper code executed after fn() returns + mov [rdx], rax ; store address off the helper function as return address + + xor rax, rax ; set RAX to zero + ret + +finish: + xor rcx, rcx + mov [rsp+08h], rcx + call _exit ; exit application + hlt +make_fcontext ENDP +END diff --git a/vendor/boost_1.51/libs/context/asm/fcontext_x86_64_sysv_elf_gas.S b/vendor/boost_1.51/libs/context/asm/fcontext_x86_64_sysv_elf_gas.S new file mode 100644 index 0000000..ad2d42b --- /dev/null +++ b/vendor/boost_1.51/libs/context/asm/fcontext_x86_64_sysv_elf_gas.S @@ -0,0 +1,116 @@ +/* + Copyright Oliver Kowalke 2009. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +*/ + +/**************************************************************************************** + * * + * ---------------------------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ---------------------------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * + * ---------------------------------------------------------------------------------- * + * | RBX | R12 | R13 | R14 | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ---------------------------------------------------------------------------------- * + * | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | * + * ---------------------------------------------------------------------------------- * + * | R15 | RBP | RSP | RIP | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 16 | 17 | 18 | 19 | | * + * ---------------------------------------------------------------------------------- * + * | 0x40 | 0x44 | 0x48 | 0x4c | | * + * ---------------------------------------------------------------------------------- * + * | sbase | slimit | | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 20 | 21 | | * + * ---------------------------------------------------------------------------------- * + * | 0x50 | 0x54 | | * + * ---------------------------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| | * + * ---------------------------------------------------------------------------------- * + * * + * **************************************************************************************/ + +.text +.globl jump_fcontext +.type jump_fcontext,@function +.align 16 +jump_fcontext: + movq %rbx, (%rdi) /* save RBX */ + movq %r12, 0x8(%rdi) /* save R12 */ + movq %r13, 0x10(%rdi) /* save R13 */ + movq %r14, 0x18(%rdi) /* save R14 */ + movq %r15, 0x20(%rdi) /* save R15 */ + movq %rbp, 0x28(%rdi) /* save RBP */ + + cmp $0, %rcx + je 1f + + stmxcsr 0x50(%rdi) /* save MMX control and status word */ + fnstcw 0x54(%rdi) /* save x87 control word */ + + ldmxcsr 0x50(%rsi) /* restore MMX control and status word */ + fldcw 0x54(%rsi) /* restore x87 control word */ +1: + + leaq 0x8(%rsp), %rax /* exclude the return address and save as stack pointer */ + movq %rax, 0x30(%rdi) /* save as stack pointer */ + movq (%rsp), %rax /* save return address */ + movq %rax, 0x38(%rdi) /* save return address as RIP */ + + movq (%rsi), %rbx /* restore RBX */ + movq 0x8(%rsi), %r12 /* restore R12 */ + movq 0x10(%rsi), %r13 /* restore R13 */ + movq 0x18(%rsi), %r14 /* restore R14 */ + movq 0x20(%rsi), %r15 /* restore R15 */ + movq 0x28(%rsi), %rbp /* restore RBP */ + + movq 0x30(%rsi), %rsp /* restore RSP */ + movq 0x38(%rsi), %rcx /* fetch the address to return to */ + + movq %rdx, %rax /* use third arg as return value after jump */ + movq %rdx, %rdi /* use third arg as first arg in context function */ + + jmp *%rcx /* indirect jump to context */ +.size jump_fcontext,.-jump_fcontext + +.text +.globl make_fcontext +.type make_fcontext,@function +.align 16 +make_fcontext: + movq %rdi, (%rdi) /* save the address of passed context */ + movq %rsi, 0x38(%rdi) /* save the address of the context function */ + movq 0x40(%rdi), %rdx /* load the stack base */ + + pushq %rdi /* save pointer to fcontext_t */ + movq %rdx, %rdi /* stack pointer as arg for align_stack */ + call align_stack@PLT /* align stack */ + movq %rax, %rdx /* begin of aligned stack */ + popq %rdi /* restore pointer to fcontext_t */ + + leaq -0x8(%rdx), %rdx /* reserve space for the last frame on stack, (RSP + 8) & 15 == 0 */ + movq %rdx, 0x30(%rdi) /* save the algined stack base */ + + stmxcsr 0x50(%rdi) /* save MMX control and status word */ + fnstcw 0x54(%rdi) /* save x87 control word */ + + leaq finish(%rip), %rcx /* address of finish; called after context function returns */ + movq %rcx, (%rdx) + + xorq %rax, %rax + ret + +finish: + xorq %rdi, %rdi /* exit code is zero */ + call _exit@PLT /* exit application */ + hlt +.size make_fcontext,.-make_fcontext + diff --git a/vendor/boost_1.51/libs/context/asm/fcontext_x86_64_sysv_macho_gas.S b/vendor/boost_1.51/libs/context/asm/fcontext_x86_64_sysv_macho_gas.S new file mode 100644 index 0000000..eea76e4 --- /dev/null +++ b/vendor/boost_1.51/libs/context/asm/fcontext_x86_64_sysv_macho_gas.S @@ -0,0 +1,111 @@ +/* + Copyright Oliver Kowalke 2009. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +*/ + +/**************************************************************************************** + * * + * ---------------------------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ---------------------------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * + * ---------------------------------------------------------------------------------- * + * | RBX | R12 | R13 | R14 | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ---------------------------------------------------------------------------------- * + * | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | * + * ---------------------------------------------------------------------------------- * + * | R15 | RBP | RSP | RIP | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 16 | 17 | 18 | 19 | | * + * ---------------------------------------------------------------------------------- * + * | 0x40 | 0x44 | 0x48 | 0x4c | | * + * ---------------------------------------------------------------------------------- * + * | sbase | slimit | | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 20 | 21 | | * + * ---------------------------------------------------------------------------------- * + * | 0x50 | 0x54 | | * + * ---------------------------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| | * + * ---------------------------------------------------------------------------------- * + * * + * **************************************************************************************/ + +.text +.globl _jump_fcontext +.align 8 +_jump_fcontext: + movq %rbx, (%rdi) /* save RBX */ + movq %r12, 0x8(%rdi) /* save R12 */ + movq %r13, 0x10(%rdi) /* save R13 */ + movq %r14, 0x18(%rdi) /* save R14 */ + movq %r15, 0x20(%rdi) /* save R15 */ + movq %rbp, 0x28(%rdi) /* save RBP */ + + cmp $0, %rcx + je 1f + + stmxcsr 0x50(%rdi) /* save MMX control and status word */ + fnstcw 0x54(%rdi) /* save x87 control word */ + + ldmxcsr 0x50(%rsi) /* restore MMX control and status word */ + fldcw 0x54(%rsi) /* restore x87 control word */ +1: + + leaq 0x8(%rsp), %rax /* exclude the return address and save as stack pointer */ + movq %rax, 0x30(%rdi) /* save as stack pointer */ + movq (%rsp), %rax /* save return address */ + movq %rax, 0x38(%rdi) /* save return address as RIP */ + + movq (%rsi), %rbx /* restore RBX */ + movq 0x8(%rsi), %r12 /* restore R12 */ + movq 0x10(%rsi), %r13 /* restore R13 */ + movq 0x18(%rsi), %r14 /* restore R14 */ + movq 0x20(%rsi), %r15 /* restore R15 */ + movq 0x28(%rsi), %rbp /* restore RBP */ + + movq 0x30(%rsi), %rsp /* restore RSP */ + movq 0x38(%rsi), %rcx /* fetch the address to return to */ + + movq %rdx, %rax /* use third arg as return value after jump */ + movq %rdx, %rdi /* use third arg as first arg in context function */ + + jmp *%rcx /* indirect jump to context */ + +.text +.globl _make_fcontext +.align 8 +_make_fcontext: + movq %rdi, (%rdi) /* save the address of current context */ + movq %rsi, 0x38(%rdi) /* save the address of the function supposed to run */ + movq 0x40(%rdi), %rdx /* load the stack base */ + + pushq %rdi /* save pointer to fcontext_t */ + movq %rdx, %rdi /* stack pointer as arg for align_stack */ + call _align_stack /* align stack */ + movq %rax, %rdx /* begin of aligned stack */ + popq %rdi /* restore pointer to fcontext_t */ + + leaq -0x8(%rdx), %rdx /* reserve space for the last frame on stack, (RSP + 8) % 16 == 0 */ + movq %rdx, 0x30(%rdi) /* save the address */ + + stmxcsr 0x50(%rdi) /* save MMX control and status word */ + fnstcw 0x54(%rdi) /* save x87 control word */ + + leaq finish(%rip), %rcx /* helper code executed after context function returns */ + movq %rcx, (%rdx) + + xorq %rax, %rax /* set RAX to zero */ + ret + +finish: + xorq %rdi, %rdi /* exit code is zero */ + call _exit /* exit application */ + hlt diff --git a/vendor/boost_1.51/libs/context/fcontext.cpp b/vendor/boost_1.51/libs/context/fcontext.cpp new file mode 100644 index 0000000..596cbd8 --- /dev/null +++ b/vendor/boost_1.51/libs/context/fcontext.cpp @@ -0,0 +1,36 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_CONTEXT_SOURCE + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { +namespace detail { + +extern "C" BOOST_CONTEXT_DECL +void * BOOST_CONTEXT_CALLDECL align_stack( void * vp) +{ + void * base = vp; + if ( 0 != ( ( ( uintptr_t) base) & 15) ) + base = ( char * ) ( ( ( ( uintptr_t) base) - 15) & ~0x0F); + return base; +} + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif diff --git a/vendor/boost_1.51/libs/context/seh.cpp b/vendor/boost_1.51/libs/context/seh.cpp new file mode 100644 index 0000000..9363805 --- /dev/null +++ b/vendor/boost_1.51/libs/context/seh.cpp @@ -0,0 +1,83 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_CONTEXT_SOURCE + +extern "C" { + +#include +#include + +#include +#include +#include + +#if defined(_MSC_VER) +# define SNPRINTF _snprintf +#else +# define SNPRINTF snprintf +#endif + +static const char * exception_description( + _EXCEPTION_RECORD const* record, char * description, size_t len) +{ + const DWORD code = record->ExceptionCode; + const ULONG_PTR * info = record->ExceptionInformation; + + switch ( code) + { + case EXCEPTION_ACCESS_VIOLATION: + { + const char * accessType = ( info[0]) ? "writing" : "reading"; + const ULONG_PTR address = info[1]; + SNPRINTF( description, len, "Access violation %s %p", accessType, reinterpret_cast< void * >( address) ); + return description; + } + case EXCEPTION_DATATYPE_MISALIGNMENT: return "Datatype misalignment"; + case EXCEPTION_BREAKPOINT: return "Breakpoint"; + case EXCEPTION_SINGLE_STEP: return "Single step"; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "Array bounds exceeded"; + case EXCEPTION_FLT_DENORMAL_OPERAND: return "FPU denormal operand"; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "FPU divide by zero"; + case EXCEPTION_FLT_INEXACT_RESULT: return "FPU inexact result"; + case EXCEPTION_FLT_INVALID_OPERATION: return "FPU invalid operation"; + case EXCEPTION_FLT_OVERFLOW: return "FPU overflow"; + case EXCEPTION_FLT_STACK_CHECK: return "FPU stack check"; + case EXCEPTION_FLT_UNDERFLOW: return "FPU underflow"; + case EXCEPTION_INT_DIVIDE_BY_ZERO: return "Integer divide by zero"; + case EXCEPTION_INT_OVERFLOW: return "Integer overflow"; + case EXCEPTION_PRIV_INSTRUCTION: return "Privileged instruction"; + case EXCEPTION_IN_PAGE_ERROR: return "In page error"; + case EXCEPTION_ILLEGAL_INSTRUCTION: return "Illegal instruction"; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "Noncontinuable exception"; + case EXCEPTION_STACK_OVERFLOW: return "Stack overflow"; + case EXCEPTION_INVALID_DISPOSITION: return "Invalid disposition"; + case EXCEPTION_GUARD_PAGE: return "Guard page"; + case EXCEPTION_INVALID_HANDLE: return "Invalid handle"; + } + + SNPRINTF( description, len, "Unknown (0x%08lX)", code); + return description; +} + +EXCEPTION_DISPOSITION seh_fcontext( + struct _EXCEPTION_RECORD * record, + void *, + struct _CONTEXT *, + void *) +{ + char description[255]; + + fprintf( stderr, "exception: %s (%08lX)\n", + exception_description( record, description, sizeof( description) ), + record->ExceptionCode); + + ExitProcess( -1); + + return ExceptionContinueSearch; // never reached +} + +} diff --git a/vendor/boost_1.51/libs/context/stack_allocator_posix.cpp b/vendor/boost_1.51/libs/context/stack_allocator_posix.cpp new file mode 100644 index 0000000..64291e7 --- /dev/null +++ b/vendor/boost_1.51/libs/context/stack_allocator_posix.cpp @@ -0,0 +1,85 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_CONTEXT_SOURCE + +#include + +extern "C" { +#include +#include +#include +#include +#include +} + +#include + +#include +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +void * +stack_allocator::allocate( std::size_t size) const +{ + if ( minimum_stacksize() > size) + throw std::invalid_argument( + boost::str( boost::format("invalid stack size: must be at least %d bytes") + % minimum_stacksize() ) ); + + if ( ! is_stack_unbound() && ( maximum_stacksize() < size) ) + throw std::invalid_argument( + boost::str( boost::format("invalid stack size: must not be larger than %d bytes") + % maximum_stacksize() ) ); + + const std::size_t pages( page_count( size) + 1); // add +1 for guard page + std::size_t size_ = pages * pagesize(); + + +# if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) + void * limit = ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); +# else + const int fd( ::open("/dev/zero", O_RDONLY) ); + BOOST_ASSERT( -1 != fd); + void * limit = ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + ::close( fd); +# endif + if ( ! limit) throw std::bad_alloc(); + + const int result( ::mprotect( limit, pagesize(), PROT_NONE) ); + BOOST_ASSERT( 0 == result); + (void)result; // unused in release build + + return static_cast< char * >( limit) + size_; +} + +void +stack_allocator::deallocate( void * vp, std::size_t size) const +{ + if ( vp) + { + const std::size_t pages( page_count( size) + 1); // add +1 for guard page + std::size_t size_ = pages * pagesize(); + BOOST_ASSERT( 0 < size && 0 < size_); + void * limit = static_cast< char * >( vp) - size_; + ::munmap( limit, size_); + } +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif diff --git a/vendor/boost_1.51/libs/context/stack_allocator_windows.cpp b/vendor/boost_1.51/libs/context/stack_allocator_windows.cpp new file mode 100644 index 0000000..518239f --- /dev/null +++ b/vendor/boost_1.51/libs/context/stack_allocator_windows.cpp @@ -0,0 +1,86 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_CONTEXT_SOURCE + +#include + +extern "C" { +#include +} + +#include + +#include +#include +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +# if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable:4244 4267) +# endif + +namespace boost { +namespace ctx { + +void * +stack_allocator::allocate( std::size_t size) const +{ + if ( minimum_stacksize() > size) + throw std::invalid_argument( + boost::str( boost::format("invalid stack size: must be at least %d bytes") + % minimum_stacksize() ) ); + + if ( ! is_stack_unbound() && ( maximum_stacksize() < size) ) + throw std::invalid_argument( + boost::str( boost::format("invalid stack size: must not be larger than %d bytes") + % maximum_stacksize() ) ); + + const std::size_t pages( page_count( size) + 1); // add +1 for guard page + std::size_t size_ = pages * pagesize(); + +#ifndef BOOST_CONTEXT_FIBER + void * limit = ::VirtualAlloc( 0, size_, MEM_COMMIT, PAGE_READWRITE); + if ( ! limit) throw std::bad_alloc(); + + DWORD old_options; + const BOOL result = ::VirtualProtect( + limit, pagesize(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options); + BOOST_ASSERT( FALSE != result); + + return static_cast< char * >( limit) + size_; +#endif +} + +void +stack_allocator::deallocate( void * vp, std::size_t size) const +{ + if ( vp) + { + const std::size_t pages( page_count( size) + 1); // add +1 for guard page + std::size_t size_ = pages * pagesize(); + BOOST_ASSERT( 0 < size && 0 < size_); + void * limit = static_cast< char * >( vp) - size_; + ::VirtualFree( limit, 0, MEM_RELEASE); + } +} + +}} + +# if defined(BOOST_MSVC) +# pragma warning(pop) +# endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif diff --git a/vendor/boost_1.51/libs/context/stack_utils_posix.cpp b/vendor/boost_1.51/libs/context/stack_utils_posix.cpp new file mode 100644 index 0000000..13c4e4e --- /dev/null +++ b/vendor/boost_1.51/libs/context/stack_utils_posix.cpp @@ -0,0 +1,81 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_CONTEXT_SOURCE + +#include + +extern "C" { +#include +#include +#include +#include +} + +#include + +#include + +namespace { + +static rlimit stacksize_limit_() +{ + rlimit limit; + const int result = ::getrlimit( RLIMIT_STACK, & limit); + BOOST_ASSERT( 0 == result); + (void)result; // unused when in release mode... + return limit; +} + +static rlimit stacksize_limit() +{ + static rlimit limit = stacksize_limit_(); + return limit; +} + +} + +namespace boost { +namespace ctx { + +BOOST_CONTEXT_DECL +std::size_t default_stacksize() +{ + static std::size_t size = 256 * 1024; + return size; +} + +BOOST_CONTEXT_DECL +std::size_t minimum_stacksize() +{ return SIGSTKSZ; } + +BOOST_CONTEXT_DECL +std::size_t maximum_stacksize() +{ + BOOST_ASSERT( ! is_stack_unbound() ); + return static_cast< std::size_t >( stacksize_limit().rlim_max); +} + +BOOST_CONTEXT_DECL +bool is_stack_unbound() +{ return RLIM_INFINITY == stacksize_limit().rlim_max; } + +BOOST_CONTEXT_DECL +std::size_t pagesize() +{ + static std::size_t pagesize( ::getpagesize() ); + return pagesize; +} + +BOOST_CONTEXT_DECL +std::size_t page_count( std::size_t stacksize) +{ + return static_cast< std::size_t >( + std::ceil( + static_cast< float >( stacksize) / pagesize() ) ); +} + +}} diff --git a/vendor/boost_1.51/libs/context/stack_utils_windows.cpp b/vendor/boost_1.51/libs/context/stack_utils_windows.cpp new file mode 100644 index 0000000..373033d --- /dev/null +++ b/vendor/boost_1.51/libs/context/stack_utils_windows.cpp @@ -0,0 +1,84 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_CONTEXT_SOURCE + +#include + +extern "C" { +#include +} + +#include +#include + +#include + +namespace { + +static SYSTEM_INFO system_info_() +{ + SYSTEM_INFO si; + ::GetSystemInfo( & si); + return si; +} + +static SYSTEM_INFO system_info() +{ + static SYSTEM_INFO si = system_info_(); + return si; +} + +} + +namespace boost { +namespace ctx { + +BOOST_CONTEXT_DECL +std::size_t default_stacksize() +{ + static std::size_t size = 256 * 1024; + return size; +} + +BOOST_CONTEXT_DECL +std::size_t minimum_stacksize() +{ + static std::size_t stacksize( + static_cast< std::size_t >( system_info().dwAllocationGranularity) ); + return stacksize; +} + +BOOST_CONTEXT_DECL +std::size_t maximum_stacksize() +{ + BOOST_ASSERT( ! is_stack_unbound() ); + static std::size_t stacksize = 8 * 1024 * 1024; + return stacksize; +} + +// Windows seams not to provide a limit for the stacksize +BOOST_CONTEXT_DECL +bool is_stack_unbound() +{ return true; } + +BOOST_CONTEXT_DECL +std::size_t pagesize() +{ + static std::size_t pagesize( + static_cast< std::size_t >( system_info().dwPageSize) ); + return pagesize; +} + +BOOST_CONTEXT_DECL +std::size_t page_count( std::size_t stacksize) +{ + return static_cast< std::size_t >( + std::ceil( + static_cast< float >( stacksize) / pagesize() ) ); +} + +}} diff --git a/vendor/libssh2-1.4.2/AUTHORS b/vendor/libssh2-1.4.2/AUTHORS deleted file mode 100644 index 214fca9..0000000 --- a/vendor/libssh2-1.4.2/AUTHORS +++ /dev/null @@ -1,48 +0,0 @@ - libssh2 is the result of many friendly people. This list is an attempt to - mention all contributors. If we've missed anyone, tell us! - - This list of names is a-z sorted. - -Adam Gobiowski -Alexander Holyapin -Alexander Lamaison -Ben Kibbey -Bjorn Stenborg -Carlo Bramini -Dan Casey -Dan Fandrich -Daniel Stenberg -David J Sullivan -David Robins -Edink Kadribasic -Erik Brossler -Francois Dupoux -Guenter Knauf -Heiner Steven -James Housleys -Jean-Louis Charton -Jussi Mononen -Mark McPherson -Markus Moeller -Mike Protts -Mikhail Gusarov -Neil Gierman -Olivier Hervieu -Paul Veldkamp -Peter Krempa -Peter O'Gorman -Peter Stuge -Romain Bondue -Sara Golemon -Satish Mittal -Sean Peterson -Selcuk Gueney -Simon Hart -Simon Josefsson -Steven Ayre -Steven Van Ingelgem -Tor Arntsen -Vincent Jaulin -Vlad Grachov -Wez Furlong -Yang Tse diff --git a/vendor/libssh2-1.4.2/CMakeLists.txt b/vendor/libssh2-1.4.2/CMakeLists.txt deleted file mode 100644 index 9ce81c1..0000000 --- a/vendor/libssh2-1.4.2/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -include_directories(include) -include_directories( ${OPENSSL_INCLUDE_DIR} ) -SET( sources - src/agent.c - src/channel.c - src/comp.c - src/crypt.c - src/global.c - src/hostkey.c - src/keepalive.c - src/kex.c - src/knownhost.c - src/libgcrypt.c - src/mac.c - src/misc.c - src/openssl.c - src/packet.c - src/pem.c - src/publickey.c - src/scp.c - src/session.c - src/sftp.c - src/transport.c - src/userauth.c - src/version.c -) -add_definitions( -DLIBSSH2DEBUG ) -SETUP_LIBRARY( ssh2 SOURCES ${sources} LIBRARIES ${libraries} LIBRARY_TYPE STATIC ) diff --git a/vendor/libssh2-1.4.2/COPYING b/vendor/libssh2-1.4.2/COPYING deleted file mode 100644 index 1bd78c9..0000000 --- a/vendor/libssh2-1.4.2/COPYING +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (c) 2004-2007 Sara Golemon - * Copyright (c) 2005,2006 Mikhail Gusarov - * Copyright (c) 2006-2007 The Written Word, Inc. - * Copyright (c) 2007 Eli Fant - * Copyright (c) 2009 Daniel Stenberg - * Copyright (C) 2008, 2009 Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - diff --git a/vendor/libssh2-1.4.2/ChangeLog b/vendor/libssh2-1.4.2/ChangeLog deleted file mode 100644 index 404c887..0000000 --- a/vendor/libssh2-1.4.2/ChangeLog +++ /dev/null @@ -1 +0,0 @@ -see NEWS diff --git a/vendor/libssh2-1.4.2/HACKING b/vendor/libssh2-1.4.2/HACKING deleted file mode 100644 index 5da8e66..0000000 --- a/vendor/libssh2-1.4.2/HACKING +++ /dev/null @@ -1,13 +0,0 @@ - -libssh2 source code style guide: - - - 4 level indent - - spaces-only (no tabs) - - open braces on the if/for line: - - if (banana) { - go_nuts(); - } - - - keep source lines shorter than 80 columns - - See libssh2-style.el for how to achieve this within Emacs diff --git a/vendor/libssh2-1.4.2/README b/vendor/libssh2-1.4.2/README deleted file mode 100644 index d297f31..0000000 --- a/vendor/libssh2-1.4.2/README +++ /dev/null @@ -1,102 +0,0 @@ -libssh2 - SSH2 library -====================== - -libssh2 is a library implementing the SSH2 protocol, available under -the revised BSD license. - -Web site: http://www.libssh2.org/ - -Mailing list: http://cool.haxx.se/mailman/listinfo/libssh2-devel - -The rest of this readme does not apply as the build system has been replaced -with CMake for use in mace on windows/linux and mac. - - - -Generic installation instructions are in INSTALL. Some ./configure -options deserve additional comments: - - * --enable-crypt-none - - The SSH2 Transport allows for unencrypted data - transmission using the "none" cipher. Because this is - such a huge security hole, it is typically disabled on - SSH2 implementations and is disabled in libssh2 by - default as well. - - Enabling this option will allow for "none" as a - negotiable method, however it still requires that the - method be advertized by the remote end and that no - more-preferable methods are available. - - * --enable-mac-none - - The SSH2 Transport also allows implementations to - forego a message authentication code. While this is - less of a security risk than using a "none" cipher, it - is still not recommended as disabling MAC hashes - removes a layer of security. - - Enabling this option will allow for "none" as a - negotiable method, however it still requires that the - method be advertized by the remote end and that no - more-preferable methods are available. - - * --disable-gex-new - - The diffie-hellman-group-exchange-sha1 (dh-gex) key - exchange method originally defined an exchange - negotiation using packet type 30 to request a - generation pair based on a single target value. Later - refinement of dh-gex provided for range and target - values. By default libssh2 will use the newer range - method. - - If you experience trouble connecting to an old SSH - server using dh-gex, try this option to fallback on - the older more reliable method. - - * --with-libgcrypt - * --without-libgcrypt - * --with-libgcrypt-prefix=DIR - - libssh2 can use the Libgcrypt library - (http://www.gnupg.org/) for cryptographic operations. - Either Libgcrypt or OpenSSL is required. - - Configure will attempt to locate Libgcrypt - automatically. - - If your installation of Libgcrypt is in another - location, specify it using --with-libgcrypt-prefix. - - * --with-openssl - * --without-openssl - * --with-libssl-prefix=[DIR] - - libssh2 can use the OpenSSL library - (http://www.openssl.org) for cryptographic operations. - Either Libgcrypt or OpenSSL is required. - - Configure will attempt to locate OpenSSL in the - default location. - - If your installation of OpenSSL is in another - location, specify it using --with-libssl-prefix. - - * --with-libz - * --without-libz - * --with-libz-prefix=[DIR] - - If present, libssh2 will attempt to use the zlib - (http://www.zlib.org) for payload compression, however - zlib is not required. - - If your installation of Libz is in another location, - specify it using --with-libz-prefix. - - * --enable-debug - - Will make the build use more pedantic and strict compiler - options as well as enable the libssh2_trace() function (for - showing debug traces). diff --git a/vendor/libssh2-1.4.2/RELEASE-NOTES b/vendor/libssh2-1.4.2/RELEASE-NOTES deleted file mode 100644 index ee52e8c..0000000 --- a/vendor/libssh2-1.4.2/RELEASE-NOTES +++ /dev/null @@ -1,21 +0,0 @@ -libssh2 1.4.2 - -This release includes the following bugfixes: - - o Return LIBSSH2_ERROR_SOCKET_DISCONNECT on EOF when reading banner - o userauth.c: fread() from public key file to correctly detect any errors - o configure.ac: Add option to disable build of the example applications - o Added 'Requires.private:' line to libssh2.pc - o SFTP: filter off incoming "zombie" responses - o gettimeofday: no need for a replacement under cygwin - o SSH_MSG_CHANNEL_REQUEST: default to want_reply - o win32/libssh2_config.h: Remove hardcoded #define LIBSSH2_HAVE_ZLIB - -This release would not have looked like this without help, code, reports and -advice from friends like these: - - Alexander Lamaison, Rafael Kitover, Guenter Knauf, Peter Stuge, - Oleksiy Zagorskyi - - Thanks! (and sorry if I forgot to mention someone) - diff --git a/vendor/libssh2-1.4.2/include/libssh2.h b/vendor/libssh2-1.4.2/include/libssh2.h deleted file mode 100644 index 6af0028..0000000 --- a/vendor/libssh2-1.4.2/include/libssh2.h +++ /dev/null @@ -1,1188 +0,0 @@ -/* Copyright (c) 2004-2009, Sara Golemon - * Copyright (c) 2009-2012 Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#ifndef LIBSSH2_H -#define LIBSSH2_H 1 - -#define LIBSSH2_COPYRIGHT "2004-2012 The libssh2 project and its contributors." - -/* We use underscore instead of dash when appending DEV in dev versions just - to make the BANNER define (used by src/session.c) be a valid SSH - banner. Release versions have no appended strings and may of course not - have dashes either. */ -#define LIBSSH2_VERSION "1.4.2" - -/* The numeric version number is also available "in parts" by using these - defines: */ -#define LIBSSH2_VERSION_MAJOR 1 -#define LIBSSH2_VERSION_MINOR 4 -#define LIBSSH2_VERSION_PATCH 2 - -/* This is the numeric version of the libssh2 version number, meant for easier - parsing and comparions by programs. The LIBSSH2_VERSION_NUM define will - always follow this syntax: - - 0xXXYYZZ - - Where XX, YY and ZZ are the main version, release and patch numbers in - hexadecimal (using 8 bits each). All three numbers are always represented - using two digits. 1.2 would appear as "0x010200" while version 9.11.7 - appears as "0x090b07". - - This 6-digit (24 bits) hexadecimal number does not show pre-release number, - and it is always a greater number in a more recent release. It makes - comparisons with greater than and less than work. -*/ -#define LIBSSH2_VERSION_NUM 0x010402 - -/* - * This is the date and time when the full source package was created. The - * timestamp is not stored in the source code repo, as the timestamp is - * properly set in the tarballs by the maketgz script. - * - * The format of the date should follow this template: - * - * "Mon Feb 12 11:35:33 UTC 2007" - */ -#define LIBSSH2_TIMESTAMP "Fri May 18 21:30:56 UTC 2012" - -#ifndef RC_INVOKED - -#ifdef __cplusplus -extern "C" { -#endif -#ifdef _WIN32 -# include -# include -#endif - -#include -#include -#include -#include - -/* Allow alternate API prefix from CFLAGS or calling app */ -#ifndef LIBSSH2_API -# ifdef LIBSSH2_WIN32 -# ifdef LIBSSH2_LIBRARY -# define LIBSSH2_API __declspec(dllexport) -# else -# define LIBSSH2_API __declspec(dllimport) -# endif /* LIBSSH2_LIBRARY */ -# else /* !LIBSSH2_WIN32 */ -# define LIBSSH2_API -# endif /* LIBSSH2_WIN32 */ -#endif /* LIBSSH2_API */ - -#if defined(LIBSSH2_DARWIN) -# include -#endif - -#if (defined(NETWARE) && !defined(__NOVELL_LIBC__)) -# include -typedef unsigned char uint8_t; -typedef unsigned int uint32_t; -#endif - -#ifdef _MSC_VER -typedef unsigned char uint8_t; -typedef unsigned int uint32_t; -typedef unsigned __int64 libssh2_uint64_t; -typedef __int64 libssh2_int64_t; -#ifndef ssize_t -typedef SSIZE_T ssize_t; -#endif -#else -typedef unsigned long long libssh2_uint64_t; -typedef long long libssh2_int64_t; -#endif - -#ifdef WIN32 -typedef SOCKET libssh2_socket_t; -#define LIBSSH2_INVALID_SOCKET INVALID_SOCKET -#else /* !WIN32 */ -typedef int libssh2_socket_t; -#define LIBSSH2_INVALID_SOCKET -1 -#endif /* WIN32 */ - -/* Part of every banner, user specified or not */ -#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION - -/* We *could* add a comment here if we so chose */ -#define LIBSSH2_SSH_DEFAULT_BANNER LIBSSH2_SSH_BANNER -#define LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF LIBSSH2_SSH_DEFAULT_BANNER "\r\n" - -/* Default generate and safe prime sizes for diffie-hellman-group-exchange-sha1 */ -#define LIBSSH2_DH_GEX_MINGROUP 1024 -#define LIBSSH2_DH_GEX_OPTGROUP 1536 -#define LIBSSH2_DH_GEX_MAXGROUP 2048 - -/* Defaults for pty requests */ -#define LIBSSH2_TERM_WIDTH 80 -#define LIBSSH2_TERM_HEIGHT 24 -#define LIBSSH2_TERM_WIDTH_PX 0 -#define LIBSSH2_TERM_HEIGHT_PX 0 - -/* 1/4 second */ -#define LIBSSH2_SOCKET_POLL_UDELAY 250000 -/* 0.25 * 120 == 30 seconds */ -#define LIBSSH2_SOCKET_POLL_MAXLOOPS 120 - -/* Maximum size to allow a payload to compress to, plays it safe by falling - short of spec limits */ -#define LIBSSH2_PACKET_MAXCOMP 32000 - -/* Maximum size to allow a payload to deccompress to, plays it safe by - allowing more than spec requires */ -#define LIBSSH2_PACKET_MAXDECOMP 40000 - -/* Maximum size for an inbound compressed payload, plays it safe by - overshooting spec limits */ -#define LIBSSH2_PACKET_MAXPAYLOAD 40000 - -/* Malloc callbacks */ -#define LIBSSH2_ALLOC_FUNC(name) void *name(size_t count, void **abstract) -#define LIBSSH2_REALLOC_FUNC(name) void *name(void *ptr, size_t count, \ - void **abstract) -#define LIBSSH2_FREE_FUNC(name) void name(void *ptr, void **abstract) - -typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT -{ - char* text; - unsigned int length; - unsigned char echo; -} LIBSSH2_USERAUTH_KBDINT_PROMPT; - -typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE -{ - char* text; - unsigned int length; -} LIBSSH2_USERAUTH_KBDINT_RESPONSE; - -/* 'publickey' authentication callback */ -#define LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC(name) \ - int name(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, \ - const unsigned char *data, size_t data_len, void **abstract) - -/* 'keyboard-interactive' authentication callback */ -#define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) \ - void name_(const char* name, int name_len, const char* instruction, \ - int instruction_len, int num_prompts, \ - const LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts, \ - LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses, void **abstract) - -/* Callbacks for special SSH packets */ -#define LIBSSH2_IGNORE_FUNC(name) \ - void name(LIBSSH2_SESSION *session, const char *message, int message_len, \ - void **abstract) - -#define LIBSSH2_DEBUG_FUNC(name) \ - void name(LIBSSH2_SESSION *session, int always_display, const char *message, \ - int message_len, const char *language, int language_len, \ - void **abstract) - -#define LIBSSH2_DISCONNECT_FUNC(name) \ - void name(LIBSSH2_SESSION *session, int reason, const char *message, \ - int message_len, const char *language, int language_len, \ - void **abstract) - -#define LIBSSH2_PASSWD_CHANGEREQ_FUNC(name) \ - void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, \ - void **abstract) - -#define LIBSSH2_MACERROR_FUNC(name) \ - int name(LIBSSH2_SESSION *session, const char *packet, int packet_len, \ - void **abstract) - -#define LIBSSH2_X11_OPEN_FUNC(name) \ - void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, \ - const char *shost, int sport, void **abstract) - -#define LIBSSH2_CHANNEL_CLOSE_FUNC(name) \ - void name(LIBSSH2_SESSION *session, void **session_abstract, \ - LIBSSH2_CHANNEL *channel, void **channel_abstract) - -/* I/O callbacks */ -#define LIBSSH2_RECV_FUNC(name) ssize_t name(libssh2_socket_t socket, \ - void *buffer, size_t length, \ - int flags, void **abstract) -#define LIBSSH2_SEND_FUNC(name) ssize_t name(libssh2_socket_t socket, \ - const void *buffer, size_t length,\ - int flags, void **abstract) - -/* libssh2_session_callback_set() constants */ -#define LIBSSH2_CALLBACK_IGNORE 0 -#define LIBSSH2_CALLBACK_DEBUG 1 -#define LIBSSH2_CALLBACK_DISCONNECT 2 -#define LIBSSH2_CALLBACK_MACERROR 3 -#define LIBSSH2_CALLBACK_X11 4 -#define LIBSSH2_CALLBACK_SEND 5 -#define LIBSSH2_CALLBACK_RECV 6 - -/* libssh2_session_method_pref() constants */ -#define LIBSSH2_METHOD_KEX 0 -#define LIBSSH2_METHOD_HOSTKEY 1 -#define LIBSSH2_METHOD_CRYPT_CS 2 -#define LIBSSH2_METHOD_CRYPT_SC 3 -#define LIBSSH2_METHOD_MAC_CS 4 -#define LIBSSH2_METHOD_MAC_SC 5 -#define LIBSSH2_METHOD_COMP_CS 6 -#define LIBSSH2_METHOD_COMP_SC 7 -#define LIBSSH2_METHOD_LANG_CS 8 -#define LIBSSH2_METHOD_LANG_SC 9 - -/* flags */ -#define LIBSSH2_FLAG_SIGPIPE 1 -#define LIBSSH2_FLAG_COMPRESS 2 - -typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION; -typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL; -typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER; -typedef struct _LIBSSH2_KNOWNHOSTS LIBSSH2_KNOWNHOSTS; -typedef struct _LIBSSH2_AGENT LIBSSH2_AGENT; - -typedef struct _LIBSSH2_POLLFD { - unsigned char type; /* LIBSSH2_POLLFD_* below */ - - union { - int socket; /* File descriptors -- examined with system select() call */ - LIBSSH2_CHANNEL *channel; /* Examined by checking internal state */ - LIBSSH2_LISTENER *listener; /* Read polls only -- are inbound - connections waiting to be accepted? */ - } fd; - - unsigned long events; /* Requested Events */ - unsigned long revents; /* Returned Events */ -} LIBSSH2_POLLFD; - -/* Poll FD Descriptor Types */ -#define LIBSSH2_POLLFD_SOCKET 1 -#define LIBSSH2_POLLFD_CHANNEL 2 -#define LIBSSH2_POLLFD_LISTENER 3 - -/* Note: Win32 Doesn't actually have a poll() implementation, so some of these - values are faked with select() data */ -/* Poll FD events/revents -- Match sys/poll.h where possible */ -#define LIBSSH2_POLLFD_POLLIN 0x0001 /* Data available to be read or - connection available -- - All */ -#define LIBSSH2_POLLFD_POLLPRI 0x0002 /* Priority data available to - be read -- Socket only */ -#define LIBSSH2_POLLFD_POLLEXT 0x0002 /* Extended data available to - be read -- Channel only */ -#define LIBSSH2_POLLFD_POLLOUT 0x0004 /* Can may be written -- - Socket/Channel */ -/* revents only */ -#define LIBSSH2_POLLFD_POLLERR 0x0008 /* Error Condition -- Socket */ -#define LIBSSH2_POLLFD_POLLHUP 0x0010 /* HangUp/EOF -- Socket */ -#define LIBSSH2_POLLFD_SESSION_CLOSED 0x0010 /* Session Disconnect */ -#define LIBSSH2_POLLFD_POLLNVAL 0x0020 /* Invalid request -- Socket - Only */ -#define LIBSSH2_POLLFD_POLLEX 0x0040 /* Exception Condition -- - Socket/Win32 */ -#define LIBSSH2_POLLFD_CHANNEL_CLOSED 0x0080 /* Channel Disconnect */ -#define LIBSSH2_POLLFD_LISTENER_CLOSED 0x0080 /* Listener Disconnect */ - -#define HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION -/* Block Direction Types */ -#define LIBSSH2_SESSION_BLOCK_INBOUND 0x0001 -#define LIBSSH2_SESSION_BLOCK_OUTBOUND 0x0002 - -/* Hash Types */ -#define LIBSSH2_HOSTKEY_HASH_MD5 1 -#define LIBSSH2_HOSTKEY_HASH_SHA1 2 - -/* Hostkey Types */ -#define LIBSSH2_HOSTKEY_TYPE_UNKNOWN 0 -#define LIBSSH2_HOSTKEY_TYPE_RSA 1 -#define LIBSSH2_HOSTKEY_TYPE_DSS 2 - -/* Disconnect Codes (defined by SSH protocol) */ -#define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 -#define SSH_DISCONNECT_PROTOCOL_ERROR 2 -#define SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3 -#define SSH_DISCONNECT_RESERVED 4 -#define SSH_DISCONNECT_MAC_ERROR 5 -#define SSH_DISCONNECT_COMPRESSION_ERROR 6 -#define SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7 -#define SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 -#define SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 -#define SSH_DISCONNECT_CONNECTION_LOST 10 -#define SSH_DISCONNECT_BY_APPLICATION 11 -#define SSH_DISCONNECT_TOO_MANY_CONNECTIONS 12 -#define SSH_DISCONNECT_AUTH_CANCELLED_BY_USER 13 -#define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 -#define SSH_DISCONNECT_ILLEGAL_USER_NAME 15 - -/* Error Codes (defined by libssh2) */ -#define LIBSSH2_ERROR_NONE 0 - -/* The library once used -1 as a generic error return value on numerous places - through the code, which subsequently was converted to - LIBSSH2_ERROR_SOCKET_NONE uses over time. As this is a generic error code, - the goal is to never ever return this code but instead make sure that a - more accurate and descriptive error code is used. */ -#define LIBSSH2_ERROR_SOCKET_NONE -1 - -#define LIBSSH2_ERROR_BANNER_RECV -2 -#define LIBSSH2_ERROR_BANNER_SEND -3 -#define LIBSSH2_ERROR_INVALID_MAC -4 -#define LIBSSH2_ERROR_KEX_FAILURE -5 -#define LIBSSH2_ERROR_ALLOC -6 -#define LIBSSH2_ERROR_SOCKET_SEND -7 -#define LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE -8 -#define LIBSSH2_ERROR_TIMEOUT -9 -#define LIBSSH2_ERROR_HOSTKEY_INIT -10 -#define LIBSSH2_ERROR_HOSTKEY_SIGN -11 -#define LIBSSH2_ERROR_DECRYPT -12 -#define LIBSSH2_ERROR_SOCKET_DISCONNECT -13 -#define LIBSSH2_ERROR_PROTO -14 -#define LIBSSH2_ERROR_PASSWORD_EXPIRED -15 -#define LIBSSH2_ERROR_FILE -16 -#define LIBSSH2_ERROR_METHOD_NONE -17 -#define LIBSSH2_ERROR_AUTHENTICATION_FAILED -18 -#define LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED LIBSSH2_ERROR_AUTHENTICATION_FAILED -#define LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED -19 -#define LIBSSH2_ERROR_CHANNEL_OUTOFORDER -20 -#define LIBSSH2_ERROR_CHANNEL_FAILURE -21 -#define LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED -22 -#define LIBSSH2_ERROR_CHANNEL_UNKNOWN -23 -#define LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED -24 -#define LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED -25 -#define LIBSSH2_ERROR_CHANNEL_CLOSED -26 -#define LIBSSH2_ERROR_CHANNEL_EOF_SENT -27 -#define LIBSSH2_ERROR_SCP_PROTOCOL -28 -#define LIBSSH2_ERROR_ZLIB -29 -#define LIBSSH2_ERROR_SOCKET_TIMEOUT -30 -#define LIBSSH2_ERROR_SFTP_PROTOCOL -31 -#define LIBSSH2_ERROR_REQUEST_DENIED -32 -#define LIBSSH2_ERROR_METHOD_NOT_SUPPORTED -33 -#define LIBSSH2_ERROR_INVAL -34 -#define LIBSSH2_ERROR_INVALID_POLL_TYPE -35 -#define LIBSSH2_ERROR_PUBLICKEY_PROTOCOL -36 -#define LIBSSH2_ERROR_EAGAIN -37 -#define LIBSSH2_ERROR_BUFFER_TOO_SMALL -38 -#define LIBSSH2_ERROR_BAD_USE -39 -#define LIBSSH2_ERROR_COMPRESS -40 -#define LIBSSH2_ERROR_OUT_OF_BOUNDARY -41 -#define LIBSSH2_ERROR_AGENT_PROTOCOL -42 -#define LIBSSH2_ERROR_SOCKET_RECV -43 -#define LIBSSH2_ERROR_ENCRYPT -44 -#define LIBSSH2_ERROR_BAD_SOCKET -45 - -/* this is a define to provide the old (<= 1.2.7) name */ -#define LIBSSH2_ERROR_BANNER_NONE LIBSSH2_ERROR_BANNER_RECV - -/* Global API */ -#define LIBSSH2_INIT_NO_CRYPTO 0x0001 - -/* - * libssh2_init() - * - * Initialize the libssh2 functions. This typically initialize the - * crypto library. It uses a global state, and is not thread safe -- - * you must make sure this function is not called concurrently. - * - * Flags can be: - * 0: Normal initialize - * LIBSSH2_INIT_NO_CRYPTO: Do not initialize the crypto library (ie. - * OPENSSL_add_cipher_algoritms() for OpenSSL - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int libssh2_init(int flags); - -/* - * libssh2_exit() - * - * Exit the libssh2 functions and free's all memory used internal. - */ -LIBSSH2_API void libssh2_exit(void); - -/* - * libssh2_free() - * - * Deallocate memory allocated by earlier call to libssh2 functions. - */ -LIBSSH2_API void libssh2_free(LIBSSH2_SESSION *session, void *ptr); - -/* - * libssh2_session_supported_algs() - * - * Fills algs with a list of supported acryptographic algorithms. Returns a - * non-negative number (number of supported algorithms) on success or a - * negative number (an eror code) on failure. - * - * NOTE: on success, algs must be deallocated (by calling libssh2_free) when - * not needed anymore - */ -LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session, - int method_type, - const char*** algs); - -/* Session API */ -LIBSSH2_API LIBSSH2_SESSION * -libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), - LIBSSH2_FREE_FUNC((*my_free)), - LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract); -#define libssh2_session_init() libssh2_session_init_ex(NULL, NULL, NULL, NULL) - -LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session); - -LIBSSH2_API void *libssh2_session_callback_set(LIBSSH2_SESSION *session, - int cbtype, void *callback); -LIBSSH2_API int libssh2_session_banner_set(LIBSSH2_SESSION *session, - const char *banner); -LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, - const char *banner); - -LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int sock); -LIBSSH2_API int libssh2_session_handshake(LIBSSH2_SESSION *session, - libssh2_socket_t sock); -LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, - int reason, - const char *description, - const char *lang); -#define libssh2_session_disconnect(session, description) \ - libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, \ - (description), "") - -LIBSSH2_API int libssh2_session_free(LIBSSH2_SESSION *session); - -LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, - int hash_type); - -LIBSSH2_API const char *libssh2_session_hostkey(LIBSSH2_SESSION *session, - size_t *len, int *type); - -LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, - int method_type, - const char *prefs); -LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, - int method_type); -LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, - char **errmsg, - int *errmsg_len, int want_buf); -LIBSSH2_API int libssh2_session_last_errno(LIBSSH2_SESSION *session); -LIBSSH2_API int libssh2_session_block_directions(LIBSSH2_SESSION *session); - -LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, - int value); -LIBSSH2_API const char *libssh2_session_banner_get(LIBSSH2_SESSION *session); - -/* Userauth API */ -LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, - const char *username, - unsigned int username_len); -LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session); - -LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, - const char *username, - unsigned int username_len, - const char *password, - unsigned int password_len, - LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb))); - -#define libssh2_userauth_password(session, username, password) \ - libssh2_userauth_password_ex((session), (username), strlen(username), \ - (password), strlen(password), NULL) - -LIBSSH2_API int -libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, - const char *username, - unsigned int username_len, - const char *publickey, - const char *privatekey, - const char *passphrase); - -#define libssh2_userauth_publickey_fromfile(session, username, publickey, \ - privatekey, passphrase) \ - libssh2_userauth_publickey_fromfile_ex((session), (username), \ - strlen(username), (publickey), \ - (privatekey), (passphrase)) - -LIBSSH2_API int -libssh2_userauth_publickey(LIBSSH2_SESSION *session, - const char *username, - const unsigned char *pubkeydata, - size_t pubkeydata_len, - LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)), - void **abstract); - -LIBSSH2_API int -libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, - const char *username, - unsigned int username_len, - const char *publickey, - const char *privatekey, - const char *passphrase, - const char *hostname, - unsigned int hostname_len, - const char *local_username, - unsigned int local_username_len); - -#define libssh2_userauth_hostbased_fromfile(session, username, publickey, \ - privatekey, passphrase, hostname) \ - libssh2_userauth_hostbased_fromfile_ex((session), (username), \ - strlen(username), (publickey), \ - (privatekey), (passphrase), \ - (hostname), strlen(hostname), \ - (username), strlen(username)) - -/* - * response_callback is provided with filled by library prompts array, - * but client must allocate and fill individual responses. Responses - * array is already allocated. Responses data will be freed by libssh2 - * after callback return, but before subsequent callback invokation. - */ -LIBSSH2_API int -libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION* session, - const char *username, - unsigned int username_len, - LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback))); - -#define libssh2_userauth_keyboard_interactive(session, username, \ - response_callback) \ - libssh2_userauth_keyboard_interactive_ex((session), (username), \ - strlen(username), (response_callback)) - -LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, - long timeout); - -/* Channel API */ -#define LIBSSH2_CHANNEL_WINDOW_DEFAULT (256*1024) -#define LIBSSH2_CHANNEL_PACKET_DEFAULT 32768 -#define LIBSSH2_CHANNEL_MINADJUST 1024 - -/* Extended Data Handling */ -#define LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL 0 -#define LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE 1 -#define LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE 2 - -#define SSH_EXTENDED_DATA_STDERR 1 - -/* Returned by any function that would block during a read/write opperation */ -#define LIBSSH2CHANNEL_EAGAIN LIBSSH2_ERROR_EAGAIN - -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *channel_type, - unsigned int channel_type_len, - unsigned int window_size, unsigned int packet_size, - const char *message, unsigned int message_len); - -#define libssh2_channel_open_session(session) \ - libssh2_channel_open_ex((session), "session", sizeof("session") - 1, \ - LIBSSH2_CHANNEL_WINDOW_DEFAULT, \ - LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0) - -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, - int port, const char *shost, int sport); -#define libssh2_channel_direct_tcpip(session, host, port) \ - libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22) - -LIBSSH2_API LIBSSH2_LISTENER * -libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, const char *host, - int port, int *bound_port, int queue_maxsize); -#define libssh2_channel_forward_listen(session, port) \ - libssh2_channel_forward_listen_ex((session), NULL, (port), NULL, 16) - -LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener); - -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener); - -LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, - const char *varname, - unsigned int varname_len, - const char *value, - unsigned int value_len); - -#define libssh2_channel_setenv(channel, varname, value) \ - libssh2_channel_setenv_ex((channel), (varname), strlen(varname), (value), \ - strlen(value)) - -LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, - const char *term, - unsigned int term_len, - const char *modes, - unsigned int modes_len, - int width, int height, - int width_px, int height_px); -#define libssh2_channel_request_pty(channel, term) \ - libssh2_channel_request_pty_ex((channel), (term), strlen(term), NULL, 0, \ - LIBSSH2_TERM_WIDTH, LIBSSH2_TERM_HEIGHT, \ - LIBSSH2_TERM_WIDTH_PX, LIBSSH2_TERM_HEIGHT_PX) - -LIBSSH2_API int libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL *channel, - int width, int height, - int width_px, - int height_px); -#define libssh2_channel_request_pty_size(channel, width, height) \ - libssh2_channel_request_pty_size_ex( (channel), (width), (height), 0, 0) - -LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, - int single_connection, - const char *auth_proto, - const char *auth_cookie, - int screen_number); -#define libssh2_channel_x11_req(channel, screen_number) \ - libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number)) - -LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, - const char *request, - unsigned int request_len, - const char *message, - unsigned int message_len); -#define libssh2_channel_shell(channel) \ - libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, \ - NULL, 0) -#define libssh2_channel_exec(channel, command) \ - libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, \ - (command), strlen(command)) -#define libssh2_channel_subsystem(channel, subsystem) \ - libssh2_channel_process_startup((channel), "subsystem", \ - sizeof("subsystem") - 1, (subsystem), \ - strlen(subsystem)) - -LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, - int stream_id, char *buf, - size_t buflen); -#define libssh2_channel_read(channel, buf, buflen) \ - libssh2_channel_read_ex((channel), 0, (buf), (buflen)) -#define libssh2_channel_read_stderr(channel, buf, buflen) \ - libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen)) - -LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, - int extended); - -LIBSSH2_API unsigned long -libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, - unsigned long *read_avail, - unsigned long *window_size_initial); -#define libssh2_channel_window_read(channel) \ - libssh2_channel_window_read_ex((channel), NULL, NULL) - -/* libssh2_channel_receive_window_adjust is DEPRECATED, do not use! */ -LIBSSH2_API unsigned long -libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, - unsigned long adjustment, - unsigned char force); - -LIBSSH2_API int -libssh2_channel_receive_window_adjust2(LIBSSH2_CHANNEL *channel, - unsigned long adjustment, - unsigned char force, - unsigned int *storewindow); - -LIBSSH2_API ssize_t libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, - int stream_id, const char *buf, - size_t buflen); - -#define libssh2_channel_write(channel, buf, buflen) \ - libssh2_channel_write_ex((channel), 0, (buf), (buflen)) -#define libssh2_channel_write_stderr(channel, buf, buflen) \ - libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen)) - -LIBSSH2_API unsigned long -libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, - unsigned long *window_size_initial); -#define libssh2_channel_window_write(channel) \ - libssh2_channel_window_write_ex((channel), NULL) - -LIBSSH2_API void libssh2_session_set_blocking(LIBSSH2_SESSION* session, - int blocking); -LIBSSH2_API int libssh2_session_get_blocking(LIBSSH2_SESSION* session); - -LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, - int blocking); - -LIBSSH2_API void libssh2_session_set_timeout(LIBSSH2_SESSION* session, - long timeout); -LIBSSH2_API long libssh2_session_get_timeout(LIBSSH2_SESSION* session); - -/* libssh2_channel_handle_extended_data is DEPRECATED, do not use! */ -LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, - int ignore_mode); -LIBSSH2_API int libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, - int ignore_mode); - -/* libssh2_channel_ignore_extended_data() is defined below for BC with version - * 0.1 - * - * Future uses should use libssh2_channel_handle_extended_data() directly if - * LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE is passed, extended data will be read - * (FIFO) from the standard data channel - */ -/* DEPRECATED */ -#define libssh2_channel_ignore_extended_data(channel, ignore) \ - libssh2_channel_handle_extended_data((channel), \ - (ignore) ? \ - LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE : \ - LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL ) - -#define LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA -1 -#define LIBSSH2_CHANNEL_FLUSH_ALL -2 -LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, - int streamid); -#define libssh2_channel_flush(channel) libssh2_channel_flush_ex((channel), 0) -#define libssh2_channel_flush_stderr(channel) \ - libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR) - -LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel); -LIBSSH2_API int libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL* channel, - char **exitsignal, - size_t *exitsignal_len, - char **errmsg, - size_t *errmsg_len, - char **langtag, - size_t *langtag_len); -LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel); -LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel); -LIBSSH2_API int libssh2_channel_wait_eof(LIBSSH2_CHANNEL *channel); -LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel); -LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel); -LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel); - -LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, - const char *path, - struct stat *sb); -LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, - const char *path, int mode, - size_t size, long mtime, - long atime); -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_scp_send64(LIBSSH2_SESSION *session, const char *path, int mode, - libssh2_int64_t size, time_t mtime, time_t atime); - -#define libssh2_scp_send(session, path, mode, size) \ - libssh2_scp_send_ex((session), (path), (mode), (size), 0, 0) - -LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, - unsigned int *dest_len, - const char *src, unsigned int src_len); - -LIBSSH2_API -const char *libssh2_version(int req_version_num); - -#define HAVE_LIBSSH2_KNOWNHOST_API 0x010101 /* since 1.1.1 */ -#define HAVE_LIBSSH2_VERSION_API 0x010100 /* libssh2_version since 1.1 */ - -struct libssh2_knownhost { - unsigned int magic; /* magic stored by the library */ - void *node; /* handle to the internal representation of this host */ - char *name; /* this is NULL if no plain text host name exists */ - char *key; /* key in base64/printable format */ - int typemask; -}; - -/* - * libssh2_knownhost_init - * - * Init a collection of known hosts. Returns the pointer to a collection. - * - */ -LIBSSH2_API LIBSSH2_KNOWNHOSTS * -libssh2_knownhost_init(LIBSSH2_SESSION *session); - -/* - * libssh2_knownhost_add - * - * Add a host and its associated key to the collection of known hosts. - * - * The 'type' argument specifies on what format the given host and keys are: - * - * plain - ascii "hostname.domain.tld" - * sha1 - SHA1( ) base64-encoded! - * custom - another hash - * - * If 'sha1' is selected as type, the salt must be provided to the salt - * argument. This too base64 encoded. - * - * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If - * a custom type is used, salt is ignored and you must provide the host - * pre-hashed when checking for it in the libssh2_knownhost_check() function. - * - * The keylen parameter may be omitted (zero) if the key is provided as a - * NULL-terminated base64-encoded string. - */ - -/* host format (2 bits) */ -#define LIBSSH2_KNOWNHOST_TYPE_MASK 0xffff -#define LIBSSH2_KNOWNHOST_TYPE_PLAIN 1 -#define LIBSSH2_KNOWNHOST_TYPE_SHA1 2 /* always base64 encoded */ -#define LIBSSH2_KNOWNHOST_TYPE_CUSTOM 3 - -/* key format (2 bits) */ -#define LIBSSH2_KNOWNHOST_KEYENC_MASK (3<<16) -#define LIBSSH2_KNOWNHOST_KEYENC_RAW (1<<16) -#define LIBSSH2_KNOWNHOST_KEYENC_BASE64 (2<<16) - -/* type of key (2 bits) */ -#define LIBSSH2_KNOWNHOST_KEY_MASK (3<<18) -#define LIBSSH2_KNOWNHOST_KEY_SHIFT 18 -#define LIBSSH2_KNOWNHOST_KEY_RSA1 (1<<18) -#define LIBSSH2_KNOWNHOST_KEY_SSHRSA (2<<18) -#define LIBSSH2_KNOWNHOST_KEY_SSHDSS (3<<18) - -LIBSSH2_API int -libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, - const char *salt, - const char *key, size_t keylen, int typemask, - struct libssh2_knownhost **store); - -/* - * libssh2_knownhost_addc - * - * Add a host and its associated key to the collection of known hosts. - * - * Takes a comment argument that may be NULL. A NULL comment indicates - * there is no comment and the entry will end directly after the key - * when written out to a file. An empty string "" comment will indicate an - * empty comment which will cause a single space to be written after the key. - * - * The 'type' argument specifies on what format the given host and keys are: - * - * plain - ascii "hostname.domain.tld" - * sha1 - SHA1( ) base64-encoded! - * custom - another hash - * - * If 'sha1' is selected as type, the salt must be provided to the salt - * argument. This too base64 encoded. - * - * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If - * a custom type is used, salt is ignored and you must provide the host - * pre-hashed when checking for it in the libssh2_knownhost_check() function. - * - * The keylen parameter may be omitted (zero) if the key is provided as a - * NULL-terminated base64-encoded string. - */ - -LIBSSH2_API int -libssh2_knownhost_addc(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, - const char *salt, - const char *key, size_t keylen, - const char *comment, size_t commentlen, int typemask, - struct libssh2_knownhost **store); - -/* - * libssh2_knownhost_check - * - * Check a host and its associated key against the collection of known hosts. - * - * The type is the type/format of the given host name. - * - * plain - ascii "hostname.domain.tld" - * custom - prehashed base64 encoded. Note that this cannot use any salts. - * - * - * 'knownhost' may be set to NULL if you don't care about that info. - * - * Returns: - * - * LIBSSH2_KNOWNHOST_CHECK_* values, see below - * - */ - -#define LIBSSH2_KNOWNHOST_CHECK_MATCH 0 -#define LIBSSH2_KNOWNHOST_CHECK_MISMATCH 1 -#define LIBSSH2_KNOWNHOST_CHECK_NOTFOUND 2 -#define LIBSSH2_KNOWNHOST_CHECK_FAILURE 3 - -LIBSSH2_API int -libssh2_knownhost_check(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, const char *key, size_t keylen, - int typemask, - struct libssh2_knownhost **knownhost); - -/* this function is identital to the above one, but also takes a port - argument that allows libssh2 to do a better check */ -LIBSSH2_API int -libssh2_knownhost_checkp(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, int port, - const char *key, size_t keylen, - int typemask, - struct libssh2_knownhost **knownhost); - -/* - * libssh2_knownhost_del - * - * Remove a host from the collection of known hosts. The 'entry' struct is - * retrieved by a call to libssh2_knownhost_check(). - * - */ -LIBSSH2_API int -libssh2_knownhost_del(LIBSSH2_KNOWNHOSTS *hosts, - struct libssh2_knownhost *entry); - -/* - * libssh2_knownhost_free - * - * Free an entire collection of known hosts. - * - */ -LIBSSH2_API void -libssh2_knownhost_free(LIBSSH2_KNOWNHOSTS *hosts); - -/* - * libssh2_knownhost_readline() - * - * Pass in a line of a file of 'type'. It makes libssh2 read this line. - * - * LIBSSH2_KNOWNHOST_FILE_OPENSSH is the only supported type. - * - */ -LIBSSH2_API int -libssh2_knownhost_readline(LIBSSH2_KNOWNHOSTS *hosts, - const char *line, size_t len, int type); - -/* - * libssh2_knownhost_readfile - * - * Add hosts+key pairs from a given file. - * - * Returns a negative value for error or number of successfully added hosts. - * - * This implementation currently only knows one 'type' (openssh), all others - * are reserved for future use. - */ - -#define LIBSSH2_KNOWNHOST_FILE_OPENSSH 1 - -LIBSSH2_API int -libssh2_knownhost_readfile(LIBSSH2_KNOWNHOSTS *hosts, - const char *filename, int type); - -/* - * libssh2_knownhost_writeline() - * - * Ask libssh2 to convert a known host to an output line for storage. - * - * Note that this function returns LIBSSH2_ERROR_BUFFER_TOO_SMALL if the given - * output buffer is too small to hold the desired output. - * - * This implementation currently only knows one 'type' (openssh), all others - * are reserved for future use. - * - */ -LIBSSH2_API int -libssh2_knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, - struct libssh2_knownhost *known, - char *buffer, size_t buflen, - size_t *outlen, /* the amount of written data */ - int type); - -/* - * libssh2_knownhost_writefile - * - * Write hosts+key pairs to a given file. - * - * This implementation currently only knows one 'type' (openssh), all others - * are reserved for future use. - */ - -LIBSSH2_API int -libssh2_knownhost_writefile(LIBSSH2_KNOWNHOSTS *hosts, - const char *filename, int type); - -/* - * libssh2_knownhost_get() - * - * Traverse the internal list of known hosts. Pass NULL to 'prev' to get - * the first one. Or pass a poiner to the previously returned one to get the - * next. - * - * Returns: - * 0 if a fine host was stored in 'store' - * 1 if end of hosts - * [negative] on errors - */ -LIBSSH2_API int -libssh2_knownhost_get(LIBSSH2_KNOWNHOSTS *hosts, - struct libssh2_knownhost **store, - struct libssh2_knownhost *prev); - -#define HAVE_LIBSSH2_AGENT_API 0x010202 /* since 1.2.2 */ - -struct libssh2_agent_publickey { - unsigned int magic; /* magic stored by the library */ - void *node; /* handle to the internal representation of key */ - unsigned char *blob; /* public key blob */ - size_t blob_len; /* length of the public key blob */ - char *comment; /* comment in printable format */ -}; - -/* - * libssh2_agent_init - * - * Init an ssh-agent handle. Returns the pointer to the handle. - * - */ -LIBSSH2_API LIBSSH2_AGENT * -libssh2_agent_init(LIBSSH2_SESSION *session); - -/* - * libssh2_agent_connect() - * - * Connect to an ssh-agent. - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int -libssh2_agent_connect(LIBSSH2_AGENT *agent); - -/* - * libssh2_agent_list_identities() - * - * Request an ssh-agent to list identities. - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int -libssh2_agent_list_identities(LIBSSH2_AGENT *agent); - -/* - * libssh2_agent_get_identity() - * - * Traverse the internal list of public keys. Pass NULL to 'prev' to get - * the first one. Or pass a poiner to the previously returned one to get the - * next. - * - * Returns: - * 0 if a fine public key was stored in 'store' - * 1 if end of public keys - * [negative] on errors - */ -LIBSSH2_API int -libssh2_agent_get_identity(LIBSSH2_AGENT *agent, - struct libssh2_agent_publickey **store, - struct libssh2_agent_publickey *prev); - -/* - * libssh2_agent_userauth() - * - * Do publickey user authentication with the help of ssh-agent. - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int -libssh2_agent_userauth(LIBSSH2_AGENT *agent, - const char *username, - struct libssh2_agent_publickey *identity); - -/* - * libssh2_agent_disconnect() - * - * Close a connection to an ssh-agent. - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int -libssh2_agent_disconnect(LIBSSH2_AGENT *agent); - -/* - * libssh2_agent_free() - * - * Free an ssh-agent handle. This function also frees the internal - * collection of public keys. - */ -LIBSSH2_API void -libssh2_agent_free(LIBSSH2_AGENT *agent); - - -/* - * libssh2_keepalive_config() - * - * Set how often keepalive messages should be sent. WANT_REPLY - * indicates whether the keepalive messages should request a response - * from the server. INTERVAL is number of seconds that can pass - * without any I/O, use 0 (the default) to disable keepalives. To - * avoid some busy-loop corner-cases, if you specify an interval of 1 - * it will be treated as 2. - * - * Note that non-blocking applications are responsible for sending the - * keepalive messages using libssh2_keepalive_send(). - */ -LIBSSH2_API void libssh2_keepalive_config (LIBSSH2_SESSION *session, - int want_reply, - unsigned interval); - -/* - * libssh2_keepalive_send() - * - * Send a keepalive message if needed. SECONDS_TO_NEXT indicates how - * many seconds you can sleep after this call before you need to call - * it again. Returns 0 on success, or LIBSSH2_ERROR_SOCKET_SEND on - * I/O errors. - */ -LIBSSH2_API int libssh2_keepalive_send (LIBSSH2_SESSION *session, - int *seconds_to_next); - -/* NOTE NOTE NOTE - libssh2_trace() has no function in builds that aren't built with debug - enabled - */ -LIBSSH2_API int libssh2_trace(LIBSSH2_SESSION *session, int bitmask); -#define LIBSSH2_TRACE_TRANS (1<<1) -#define LIBSSH2_TRACE_KEX (1<<2) -#define LIBSSH2_TRACE_AUTH (1<<3) -#define LIBSSH2_TRACE_CONN (1<<4) -#define LIBSSH2_TRACE_SCP (1<<5) -#define LIBSSH2_TRACE_SFTP (1<<6) -#define LIBSSH2_TRACE_ERROR (1<<7) -#define LIBSSH2_TRACE_PUBLICKEY (1<<8) -#define LIBSSH2_TRACE_SOCKET (1<<9) - -typedef void (*libssh2_trace_handler_func)(LIBSSH2_SESSION*, - void*, - const char *, - size_t); -LIBSSH2_API int libssh2_trace_sethandler(LIBSSH2_SESSION *session, - void* context, - libssh2_trace_handler_func callback); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* !RC_INVOKED */ - -#endif /* LIBSSH2_H */ diff --git a/vendor/libssh2-1.4.2/include/libssh2_publickey.h b/vendor/libssh2-1.4.2/include/libssh2_publickey.h deleted file mode 100644 index 7350e9f..0000000 --- a/vendor/libssh2-1.4.2/include/libssh2_publickey.h +++ /dev/null @@ -1,118 +0,0 @@ -/* Copyright (c) 2004-2006, Sara Golemon - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -/* Note: This include file is only needed for using the - * publickey SUBSYSTEM which is not the same as publickey - * authentication. For authentication you only need libssh2.h - * - * For more information on the publickey subsystem, - * refer to IETF draft: secsh-publickey - */ - -#ifndef LIBSSH2_PUBLICKEY_H -#define LIBSSH2_PUBLICKEY_H 1 - -#include "libssh2.h" - -typedef struct _LIBSSH2_PUBLICKEY LIBSSH2_PUBLICKEY; - -typedef struct _libssh2_publickey_attribute { - const char *name; - unsigned long name_len; - const char *value; - unsigned long value_len; - char mandatory; -} libssh2_publickey_attribute; - -typedef struct _libssh2_publickey_list { - unsigned char *packet; /* For freeing */ - - const unsigned char *name; - unsigned long name_len; - const unsigned char *blob; - unsigned long blob_len; - unsigned long num_attrs; - libssh2_publickey_attribute *attrs; /* free me */ -} libssh2_publickey_list; - -/* Generally use the first macro here, but if both name and value are string literals, you can use _fast() to take advantage of preprocessing */ -#define libssh2_publickey_attribute(name, value, mandatory) \ - { (name), strlen(name), (value), strlen(value), (mandatory) }, -#define libssh2_publickey_attribute_fast(name, value, mandatory) \ - { (name), sizeof(name) - 1, (value), sizeof(value) - 1, (mandatory) }, - -#ifdef __cplusplus -extern "C" { -#endif - -/* Publickey Subsystem */ -LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session); - -LIBSSH2_API int libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, - const unsigned char *name, - unsigned long name_len, - const unsigned char *blob, - unsigned long blob_len, char overwrite, - unsigned long num_attrs, - const libssh2_publickey_attribute attrs[]); -#define libssh2_publickey_add(pkey, name, blob, blob_len, overwrite, \ - num_attrs, attrs) \ - libssh2_publickey_add_ex((pkey), (name), strlen(name), (blob), (blob_len), \ - (overwrite), (num_attrs), (attrs)) - -LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, - const unsigned char *name, - unsigned long name_len, - const unsigned char *blob, - unsigned long blob_len); -#define libssh2_publickey_remove(pkey, name, blob, blob_len) \ - libssh2_publickey_remove_ex((pkey), (name), strlen(name), (blob), (blob_len)) - -LIBSSH2_API int -libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, - unsigned long *num_keys, - libssh2_publickey_list **pkey_list); -LIBSSH2_API void libssh2_publickey_list_free(LIBSSH2_PUBLICKEY *pkey, - libssh2_publickey_list *pkey_list); - -LIBSSH2_API int libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* ifndef: LIBSSH2_PUBLICKEY_H */ diff --git a/vendor/libssh2-1.4.2/include/libssh2_sftp.h b/vendor/libssh2-1.4.2/include/libssh2_sftp.h deleted file mode 100644 index 74884fb..0000000 --- a/vendor/libssh2-1.4.2/include/libssh2_sftp.h +++ /dev/null @@ -1,345 +0,0 @@ -/* Copyright (c) 2004-2008, Sara Golemon - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#ifndef LIBSSH2_SFTP_H -#define LIBSSH2_SFTP_H 1 - -#include "libssh2.h" - -#ifndef WIN32 -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Note: Version 6 was documented at the time of writing - * However it was marked as "DO NOT IMPLEMENT" due to pending changes - * - * Let's start with Version 3 (The version found in OpenSSH) and go from there - */ -#define LIBSSH2_SFTP_VERSION 3 - -typedef struct _LIBSSH2_SFTP LIBSSH2_SFTP; -typedef struct _LIBSSH2_SFTP_HANDLE LIBSSH2_SFTP_HANDLE; -typedef struct _LIBSSH2_SFTP_ATTRIBUTES LIBSSH2_SFTP_ATTRIBUTES; -typedef struct _LIBSSH2_SFTP_STATVFS LIBSSH2_SFTP_STATVFS; - -/* Flags for open_ex() */ -#define LIBSSH2_SFTP_OPENFILE 0 -#define LIBSSH2_SFTP_OPENDIR 1 - -/* Flags for rename_ex() */ -#define LIBSSH2_SFTP_RENAME_OVERWRITE 0x00000001 -#define LIBSSH2_SFTP_RENAME_ATOMIC 0x00000002 -#define LIBSSH2_SFTP_RENAME_NATIVE 0x00000004 - -/* Flags for stat_ex() */ -#define LIBSSH2_SFTP_STAT 0 -#define LIBSSH2_SFTP_LSTAT 1 -#define LIBSSH2_SFTP_SETSTAT 2 - -/* Flags for symlink_ex() */ -#define LIBSSH2_SFTP_SYMLINK 0 -#define LIBSSH2_SFTP_READLINK 1 -#define LIBSSH2_SFTP_REALPATH 2 - -/* SFTP attribute flag bits */ -#define LIBSSH2_SFTP_ATTR_SIZE 0x00000001 -#define LIBSSH2_SFTP_ATTR_UIDGID 0x00000002 -#define LIBSSH2_SFTP_ATTR_PERMISSIONS 0x00000004 -#define LIBSSH2_SFTP_ATTR_ACMODTIME 0x00000008 -#define LIBSSH2_SFTP_ATTR_EXTENDED 0x80000000 - -/* SFTP statvfs flag bits */ -#define LIBSSH2_SFTP_ST_RDONLY 0x00000001 -#define LIBSSH2_SFTP_ST_NOSUID 0x00000002 - -struct _LIBSSH2_SFTP_ATTRIBUTES { - /* If flags & ATTR_* bit is set, then the value in this struct will be - * meaningful Otherwise it should be ignored - */ - unsigned long flags; - - libssh2_uint64_t filesize; - unsigned long uid, gid; - unsigned long permissions; - unsigned long atime, mtime; -}; - -struct _LIBSSH2_SFTP_STATVFS { - libssh2_uint64_t f_bsize; /* file system block size */ - libssh2_uint64_t f_frsize; /* fragment size */ - libssh2_uint64_t f_blocks; /* size of fs in f_frsize units */ - libssh2_uint64_t f_bfree; /* # free blocks */ - libssh2_uint64_t f_bavail; /* # free blocks for non-root */ - libssh2_uint64_t f_files; /* # inodes */ - libssh2_uint64_t f_ffree; /* # free inodes */ - libssh2_uint64_t f_favail; /* # free inodes for non-root */ - libssh2_uint64_t f_fsid; /* file system ID */ - libssh2_uint64_t f_flag; /* mount flags */ - libssh2_uint64_t f_namemax; /* maximum filename length */ -}; - -/* SFTP filetypes */ -#define LIBSSH2_SFTP_TYPE_REGULAR 1 -#define LIBSSH2_SFTP_TYPE_DIRECTORY 2 -#define LIBSSH2_SFTP_TYPE_SYMLINK 3 -#define LIBSSH2_SFTP_TYPE_SPECIAL 4 -#define LIBSSH2_SFTP_TYPE_UNKNOWN 5 -#define LIBSSH2_SFTP_TYPE_SOCKET 6 -#define LIBSSH2_SFTP_TYPE_CHAR_DEVICE 7 -#define LIBSSH2_SFTP_TYPE_BLOCK_DEVICE 8 -#define LIBSSH2_SFTP_TYPE_FIFO 9 - -/* - * Reproduce the POSIX file modes here for systems that are not POSIX - * compliant. - * - * These is used in "permissions" of "struct _LIBSSH2_SFTP_ATTRIBUTES" - */ -/* File type */ -#define LIBSSH2_SFTP_S_IFMT 0170000 /* type of file mask */ -#define LIBSSH2_SFTP_S_IFIFO 0010000 /* named pipe (fifo) */ -#define LIBSSH2_SFTP_S_IFCHR 0020000 /* character special */ -#define LIBSSH2_SFTP_S_IFDIR 0040000 /* directory */ -#define LIBSSH2_SFTP_S_IFBLK 0060000 /* block special */ -#define LIBSSH2_SFTP_S_IFREG 0100000 /* regular */ -#define LIBSSH2_SFTP_S_IFLNK 0120000 /* symbolic link */ -#define LIBSSH2_SFTP_S_IFSOCK 0140000 /* socket */ - -/* File mode */ -/* Read, write, execute/search by owner */ -#define LIBSSH2_SFTP_S_IRWXU 0000700 /* RWX mask for owner */ -#define LIBSSH2_SFTP_S_IRUSR 0000400 /* R for owner */ -#define LIBSSH2_SFTP_S_IWUSR 0000200 /* W for owner */ -#define LIBSSH2_SFTP_S_IXUSR 0000100 /* X for owner */ -/* Read, write, execute/search by group */ -#define LIBSSH2_SFTP_S_IRWXG 0000070 /* RWX mask for group */ -#define LIBSSH2_SFTP_S_IRGRP 0000040 /* R for group */ -#define LIBSSH2_SFTP_S_IWGRP 0000020 /* W for group */ -#define LIBSSH2_SFTP_S_IXGRP 0000010 /* X for group */ -/* Read, write, execute/search by others */ -#define LIBSSH2_SFTP_S_IRWXO 0000007 /* RWX mask for other */ -#define LIBSSH2_SFTP_S_IROTH 0000004 /* R for other */ -#define LIBSSH2_SFTP_S_IWOTH 0000002 /* W for other */ -#define LIBSSH2_SFTP_S_IXOTH 0000001 /* X for other */ - -/* macros to check for specific file types, added in 1.2.5 */ -#define LIBSSH2_SFTP_S_ISLNK(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFLNK) -#define LIBSSH2_SFTP_S_ISREG(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFREG) -#define LIBSSH2_SFTP_S_ISDIR(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFDIR) -#define LIBSSH2_SFTP_S_ISCHR(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFCHR) -#define LIBSSH2_SFTP_S_ISBLK(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFBLK) -#define LIBSSH2_SFTP_S_ISFIFO(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFIFO) -#define LIBSSH2_SFTP_S_ISSOCK(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFSOCK) - -/* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open()) - * Danger will robinson... APPEND doesn't have any effect on OpenSSH servers */ -#define LIBSSH2_FXF_READ 0x00000001 -#define LIBSSH2_FXF_WRITE 0x00000002 -#define LIBSSH2_FXF_APPEND 0x00000004 -#define LIBSSH2_FXF_CREAT 0x00000008 -#define LIBSSH2_FXF_TRUNC 0x00000010 -#define LIBSSH2_FXF_EXCL 0x00000020 - -/* SFTP Status Codes (returned by libssh2_sftp_last_error() ) */ -#define LIBSSH2_FX_OK 0 -#define LIBSSH2_FX_EOF 1 -#define LIBSSH2_FX_NO_SUCH_FILE 2 -#define LIBSSH2_FX_PERMISSION_DENIED 3 -#define LIBSSH2_FX_FAILURE 4 -#define LIBSSH2_FX_BAD_MESSAGE 5 -#define LIBSSH2_FX_NO_CONNECTION 6 -#define LIBSSH2_FX_CONNECTION_LOST 7 -#define LIBSSH2_FX_OP_UNSUPPORTED 8 -#define LIBSSH2_FX_INVALID_HANDLE 9 -#define LIBSSH2_FX_NO_SUCH_PATH 10 -#define LIBSSH2_FX_FILE_ALREADY_EXISTS 11 -#define LIBSSH2_FX_WRITE_PROTECT 12 -#define LIBSSH2_FX_NO_MEDIA 13 -#define LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM 14 -#define LIBSSH2_FX_QUOTA_EXCEEDED 15 -#define LIBSSH2_FX_UNKNOWN_PRINCIPLE 16 /* Initial mis-spelling */ -#define LIBSSH2_FX_UNKNOWN_PRINCIPAL 16 -#define LIBSSH2_FX_LOCK_CONFlICT 17 /* Initial mis-spelling */ -#define LIBSSH2_FX_LOCK_CONFLICT 17 -#define LIBSSH2_FX_DIR_NOT_EMPTY 18 -#define LIBSSH2_FX_NOT_A_DIRECTORY 19 -#define LIBSSH2_FX_INVALID_FILENAME 20 -#define LIBSSH2_FX_LINK_LOOP 21 - -/* Returned by any function that would block during a read/write opperation */ -#define LIBSSH2SFTP_EAGAIN LIBSSH2_ERROR_EAGAIN - -/* SFTP API */ -LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session); -LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp); -LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp); -LIBSSH2_API LIBSSH2_CHANNEL *libssh2_sftp_get_channel(LIBSSH2_SFTP *sftp); - -/* File / Directory Ops */ -LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, - const char *filename, - unsigned int filename_len, - unsigned long flags, - long mode, int open_type); -#define libssh2_sftp_open(sftp, filename, flags, mode) \ - libssh2_sftp_open_ex((sftp), (filename), strlen(filename), (flags), \ - (mode), LIBSSH2_SFTP_OPENFILE) -#define libssh2_sftp_opendir(sftp, path) \ - libssh2_sftp_open_ex((sftp), (path), strlen(path), 0, 0, \ - LIBSSH2_SFTP_OPENDIR) - -LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, - char *buffer, size_t buffer_maxlen); - -LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, \ - char *buffer, size_t buffer_maxlen, - char *longentry, - size_t longentry_maxlen, - LIBSSH2_SFTP_ATTRIBUTES *attrs); -#define libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs) \ - libssh2_sftp_readdir_ex((handle), (buffer), (buffer_maxlen), NULL, 0, \ - (attrs)) - -LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, - const char *buffer, size_t count); - -LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle); -#define libssh2_sftp_close(handle) libssh2_sftp_close_handle(handle) -#define libssh2_sftp_closedir(handle) libssh2_sftp_close_handle(handle) - -LIBSSH2_API void libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset); -LIBSSH2_API void libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE *handle, - libssh2_uint64_t offset); -#define libssh2_sftp_rewind(handle) libssh2_sftp_seek64((handle), 0) - -LIBSSH2_API size_t libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle); -LIBSSH2_API libssh2_uint64_t libssh2_sftp_tell64(LIBSSH2_SFTP_HANDLE *handle); - -LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, - LIBSSH2_SFTP_ATTRIBUTES *attrs, - int setstat); -#define libssh2_sftp_fstat(handle, attrs) \ - libssh2_sftp_fstat_ex((handle), (attrs), 0) -#define libssh2_sftp_fsetstat(handle, attrs) \ - libssh2_sftp_fstat_ex((handle), (attrs), 1) - -/* Miscellaneous Ops */ -LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, - const char *source_filename, - unsigned int srouce_filename_len, - const char *dest_filename, - unsigned int dest_filename_len, - long flags); -#define libssh2_sftp_rename(sftp, sourcefile, destfile) \ - libssh2_sftp_rename_ex((sftp), (sourcefile), strlen(sourcefile), \ - (destfile), strlen(destfile), \ - LIBSSH2_SFTP_RENAME_OVERWRITE | \ - LIBSSH2_SFTP_RENAME_ATOMIC | \ - LIBSSH2_SFTP_RENAME_NATIVE) - -LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, - const char *filename, - unsigned int filename_len); -#define libssh2_sftp_unlink(sftp, filename) \ - libssh2_sftp_unlink_ex((sftp), (filename), strlen(filename)) - -LIBSSH2_API int libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, - LIBSSH2_SFTP_STATVFS *st); - -LIBSSH2_API int libssh2_sftp_statvfs(LIBSSH2_SFTP *sftp, - const char *path, - size_t path_len, - LIBSSH2_SFTP_STATVFS *st); - -LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, - const char *path, - unsigned int path_len, long mode); -#define libssh2_sftp_mkdir(sftp, path, mode) \ - libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode)) - -LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, - const char *path, - unsigned int path_len); -#define libssh2_sftp_rmdir(sftp, path) \ - libssh2_sftp_rmdir_ex((sftp), (path), strlen(path)) - -LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, - const char *path, - unsigned int path_len, - int stat_type, - LIBSSH2_SFTP_ATTRIBUTES *attrs); -#define libssh2_sftp_stat(sftp, path, attrs) \ - libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_STAT, \ - (attrs)) -#define libssh2_sftp_lstat(sftp, path, attrs) \ - libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_LSTAT, \ - (attrs)) -#define libssh2_sftp_setstat(sftp, path, attrs) \ - libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_SETSTAT, \ - (attrs)) - -LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, - const char *path, - unsigned int path_len, - char *target, - unsigned int target_len, int link_type); -#define libssh2_sftp_symlink(sftp, orig, linkpath) \ - libssh2_sftp_symlink_ex((sftp), (orig), strlen(orig), (linkpath), \ - strlen(linkpath), LIBSSH2_SFTP_SYMLINK) -#define libssh2_sftp_readlink(sftp, path, target, maxlen) \ - libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \ - LIBSSH2_SFTP_READLINK) -#define libssh2_sftp_realpath(sftp, path, target, maxlen) \ - libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \ - LIBSSH2_SFTP_REALPATH) - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* LIBSSH2_SFTP_H */ diff --git a/vendor/libssh2-1.4.2/src/agent.c b/vendor/libssh2-1.4.2/src/agent.c deleted file mode 100644 index 1c65149..0000000 --- a/vendor/libssh2-1.4.2/src/agent.c +++ /dev/null @@ -1,793 +0,0 @@ -/* - * Copyright (c) 2009 by Daiki Ueno - * Copyright (C) 2010 by Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" -#include "misc.h" -#include -#ifdef HAVE_SYS_UN_H -#include -#else -/* Use the existence of sys/un.h as a test if Unix domain socket is - supported. winsock*.h define PF_UNIX/AF_UNIX but do not actually - support them. */ -#undef PF_UNIX -#endif -#include "userauth.h" -#include "session.h" - -/* Requests from client to agent for protocol 1 key operations */ -#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1 -#define SSH_AGENTC_RSA_CHALLENGE 3 -#define SSH_AGENTC_ADD_RSA_IDENTITY 7 -#define SSH_AGENTC_REMOVE_RSA_IDENTITY 8 -#define SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES 9 -#define SSH_AGENTC_ADD_RSA_ID_CONSTRAINED 24 - -/* Requests from client to agent for protocol 2 key operations */ -#define SSH2_AGENTC_REQUEST_IDENTITIES 11 -#define SSH2_AGENTC_SIGN_REQUEST 13 -#define SSH2_AGENTC_ADD_IDENTITY 17 -#define SSH2_AGENTC_REMOVE_IDENTITY 18 -#define SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19 -#define SSH2_AGENTC_ADD_ID_CONSTRAINED 25 - -/* Key-type independent requests from client to agent */ -#define SSH_AGENTC_ADD_SMARTCARD_KEY 20 -#define SSH_AGENTC_REMOVE_SMARTCARD_KEY 21 -#define SSH_AGENTC_LOCK 22 -#define SSH_AGENTC_UNLOCK 23 -#define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26 - -/* Generic replies from agent to client */ -#define SSH_AGENT_FAILURE 5 -#define SSH_AGENT_SUCCESS 6 - -/* Replies from agent to client for protocol 1 key operations */ -#define SSH_AGENT_RSA_IDENTITIES_ANSWER 2 -#define SSH_AGENT_RSA_RESPONSE 4 - -/* Replies from agent to client for protocol 2 key operations */ -#define SSH2_AGENT_IDENTITIES_ANSWER 12 -#define SSH2_AGENT_SIGN_RESPONSE 14 - -/* Key constraint identifiers */ -#define SSH_AGENT_CONSTRAIN_LIFETIME 1 -#define SSH_AGENT_CONSTRAIN_CONFIRM 2 - -/* non-blocking mode on agent connection is not yet implemented, but - for future use. */ -typedef enum { - agent_NB_state_init = 0, - agent_NB_state_request_created, - agent_NB_state_request_length_sent, - agent_NB_state_request_sent, - agent_NB_state_response_length_received, - agent_NB_state_response_received -} agent_nonblocking_states; - -typedef struct agent_transaction_ctx { - unsigned char *request; - size_t request_len; - unsigned char *response; - size_t response_len; - agent_nonblocking_states state; -} *agent_transaction_ctx_t; - -typedef int (*agent_connect_func)(LIBSSH2_AGENT *agent); -typedef int (*agent_transact_func)(LIBSSH2_AGENT *agent, - agent_transaction_ctx_t transctx); -typedef int (*agent_disconnect_func)(LIBSSH2_AGENT *agent); - -struct agent_publickey { - struct list_node node; - - /* this is the struct we expose externally */ - struct libssh2_agent_publickey external; -}; - -struct agent_ops { - agent_connect_func connect; - agent_transact_func transact; - agent_disconnect_func disconnect; -}; - -struct _LIBSSH2_AGENT -{ - LIBSSH2_SESSION *session; /* the session this "belongs to" */ - - libssh2_socket_t fd; - - struct agent_ops *ops; - - struct agent_transaction_ctx transctx; - struct agent_publickey *identity; - struct list_head head; /* list of public keys */ -}; - -#ifdef PF_UNIX -static int -agent_connect_unix(LIBSSH2_AGENT *agent) -{ - const char *path; - struct sockaddr_un s_un; - - path = getenv("SSH_AUTH_SOCK"); - if (!path) - return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE, - "no auth sock variable"); - - agent->fd = socket(PF_UNIX, SOCK_STREAM, 0); - if (agent->fd < 0) - return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_SOCKET, - "failed creating socket"); - - s_un.sun_family = AF_UNIX; - strncpy (s_un.sun_path, path, sizeof s_un.sun_path); - if (connect(agent->fd, (struct sockaddr*)(&s_un), sizeof s_un) != 0) { - close (agent->fd); - return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, - "failed connecting with agent"); - } - - return LIBSSH2_ERROR_NONE; -} - -static int -agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) -{ - unsigned char buf[4]; - int rc; - - /* Send the length of the request */ - if (transctx->state == agent_NB_state_request_created) { - _libssh2_htonu32(buf, transctx->request_len); - rc = LIBSSH2_SEND_FD(agent->session, agent->fd, buf, sizeof buf, 0); - if (rc == -EAGAIN) - return LIBSSH2_ERROR_EAGAIN; - else if (rc < 0) - return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND, - "agent send failed"); - transctx->state = agent_NB_state_request_length_sent; - } - - /* Send the request body */ - if (transctx->state == agent_NB_state_request_length_sent) { - rc = LIBSSH2_SEND_FD(agent->session, agent->fd, transctx->request, - transctx->request_len, 0); - if (rc == -EAGAIN) - return LIBSSH2_ERROR_EAGAIN; - else if (rc < 0) - return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND, - "agent send failed"); - transctx->state = agent_NB_state_request_sent; - } - - /* Receive the length of a response */ - if (transctx->state == agent_NB_state_request_sent) { - rc = LIBSSH2_RECV_FD(agent->session, agent->fd, buf, sizeof buf, 0); - if (rc < 0) { - if (rc == -EAGAIN) - return LIBSSH2_ERROR_EAGAIN; - return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_RECV, - "agent recv failed"); - } - transctx->response_len = _libssh2_ntohu32(buf); - transctx->response = LIBSSH2_ALLOC(agent->session, - transctx->response_len); - if (!transctx->response) - return LIBSSH2_ERROR_ALLOC; - - transctx->state = agent_NB_state_response_length_received; - } - - /* Receive the response body */ - if (transctx->state == agent_NB_state_response_length_received) { - rc = LIBSSH2_RECV_FD(agent->session, agent->fd, transctx->response, - transctx->response_len, 0); - if (rc < 0) { - if (rc == -EAGAIN) - return LIBSSH2_ERROR_EAGAIN; - return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND, - "agent recv failed"); - } - transctx->state = agent_NB_state_response_received; - } - - return 0; -} - -static int -agent_disconnect_unix(LIBSSH2_AGENT *agent) -{ - int ret; - ret = close(agent->fd); - - if(ret == -1) - return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_DISCONNECT, - "failed closing the agent socket"); - return LIBSSH2_ERROR_NONE; -} - -struct agent_ops agent_ops_unix = { - agent_connect_unix, - agent_transact_unix, - agent_disconnect_unix -}; -#endif /* PF_UNIX */ - -#ifdef WIN32 -/* Code to talk to Pageant was taken from PuTTY. - * - * Portions copyright Robert de Bath, Joris van Rantwijk, Delian - * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas - * Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, - * Markus Kuhn, Colin Watson, and CORE SDI S.A. - */ -#define PAGEANT_COPYDATA_ID 0x804e50ba /* random goop */ -#define PAGEANT_MAX_MSGLEN 8192 - -static int -agent_connect_pageant(LIBSSH2_AGENT *agent) -{ - HWND hwnd; - hwnd = FindWindow("Pageant", "Pageant"); - if (!hwnd) - return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, - "failed connecting agent"); - agent->fd = 0; /* Mark as the connection has been established */ - return LIBSSH2_ERROR_NONE; -} - -static int -agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) -{ - HWND hwnd; - char mapname[23]; - HANDLE filemap; - unsigned char *p; - unsigned char *p2; - int id; - COPYDATASTRUCT cds; - - if (!transctx || 4 + transctx->request_len > PAGEANT_MAX_MSGLEN) - return _libssh2_error(agent->session, LIBSSH2_ERROR_INVAL, - "illegal input"); - - hwnd = FindWindow("Pageant", "Pageant"); - if (!hwnd) - return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, - "found no pageant"); - - sprintf(mapname, "PageantRequest%08x", (unsigned)GetCurrentThreadId()); - filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, - 0, PAGEANT_MAX_MSGLEN, mapname); - - if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) - return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, - "failed setting up pageant filemap"); - - p2 = p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0); - _libssh2_store_str(&p2, (const char *)transctx->request, - transctx->request_len); - - cds.dwData = PAGEANT_COPYDATA_ID; - cds.cbData = 1 + strlen(mapname); - cds.lpData = mapname; - - id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds); - if (id > 0) { - transctx->response_len = _libssh2_ntohu32(p); - if (transctx->response_len > PAGEANT_MAX_MSGLEN) { - UnmapViewOfFile(p); - CloseHandle(filemap); - return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, - "agent setup fail"); - } - transctx->response = LIBSSH2_ALLOC(agent->session, - transctx->response_len); - if (!transctx->response) { - UnmapViewOfFile(p); - CloseHandle(filemap); - return _libssh2_error(agent->session, LIBSSH2_ERROR_ALLOC, - "agent malloc"); - } - memcpy(transctx->response, p + 4, transctx->response_len); - } - - UnmapViewOfFile(p); - CloseHandle(filemap); - return 0; -} - -static int -agent_disconnect_pageant(LIBSSH2_AGENT *agent) -{ - agent->fd = LIBSSH2_INVALID_SOCKET; - return 0; -} - -struct agent_ops agent_ops_pageant = { - agent_connect_pageant, - agent_transact_pageant, - agent_disconnect_pageant -}; -#endif /* WIN32 */ - -static struct { - const char *name; - struct agent_ops *ops; -} supported_backends[] = { -#ifdef WIN32 - {"Pageant", &agent_ops_pageant}, -#endif /* WIN32 */ -#ifdef PF_UNIX - {"Unix", &agent_ops_unix}, -#endif /* PF_UNIX */ - {NULL, NULL} -}; - -static int -agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, - const unsigned char *data, size_t data_len, void **abstract) -{ - LIBSSH2_AGENT *agent = (LIBSSH2_AGENT *) (*abstract); - agent_transaction_ctx_t transctx = &agent->transctx; - struct agent_publickey *identity = agent->identity; - ssize_t len = 1 + 4 + identity->external.blob_len + 4 + data_len + 4; - ssize_t method_len; - unsigned char *s; - int rc; - - /* Create a request to sign the data */ - if (transctx->state == agent_NB_state_init) { - s = transctx->request = LIBSSH2_ALLOC(session, len); - if (!transctx->request) - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "out of memory"); - - *s++ = SSH2_AGENTC_SIGN_REQUEST; - /* key blob */ - _libssh2_store_str(&s, (const char *)identity->external.blob, - identity->external.blob_len); - /* data */ - _libssh2_store_str(&s, (const char *)data, data_len); - - /* flags */ - _libssh2_store_u32(&s, 0); - - transctx->request_len = s - transctx->request; - transctx->state = agent_NB_state_request_created; - } - - /* Make sure to be re-called as a result of EAGAIN. */ - if (*transctx->request != SSH2_AGENTC_SIGN_REQUEST) - return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, - "illegal request"); - - if (!agent->ops) - /* if no agent has been connected, bail out */ - return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, - "agent not connected"); - - rc = agent->ops->transact(agent, transctx); - if (rc) { - goto error; - } - LIBSSH2_FREE(session, transctx->request); - transctx->request = NULL; - - len = transctx->response_len; - s = transctx->response; - len--; - if (len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - if (*s != SSH2_AGENT_SIGN_RESPONSE) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - s++; - - /* Skip the entire length of the signature */ - len -= 4; - if (len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - s += 4; - - /* Skip signing method */ - len -= 4; - if (len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - method_len = _libssh2_ntohu32(s); - s += 4; - len -= method_len; - if (len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - s += method_len; - - /* Read the signature */ - len -= 4; - if (len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - *sig_len = _libssh2_ntohu32(s); - s += 4; - len -= *sig_len; - if (len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - - *sig = LIBSSH2_ALLOC(session, *sig_len); - if (!*sig) { - rc = LIBSSH2_ERROR_ALLOC; - goto error; - } - memcpy(*sig, s, *sig_len); - - error: - LIBSSH2_FREE(session, transctx->request); - transctx->request = NULL; - - LIBSSH2_FREE(session, transctx->response); - transctx->response = NULL; - - return _libssh2_error(session, rc, "agent sign failure"); -} - -static int -agent_list_identities(LIBSSH2_AGENT *agent) -{ - agent_transaction_ctx_t transctx = &agent->transctx; - ssize_t len, num_identities; - unsigned char *s; - int rc; - unsigned char c = SSH2_AGENTC_REQUEST_IDENTITIES; - - /* Create a request to list identities */ - if (transctx->state == agent_NB_state_init) { - transctx->request = &c; - transctx->request_len = 1; - transctx->state = agent_NB_state_request_created; - } - - /* Make sure to be re-called as a result of EAGAIN. */ - if (*transctx->request != SSH2_AGENTC_REQUEST_IDENTITIES) - return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE, - "illegal agent request"); - - if (!agent->ops) - /* if no agent has been connected, bail out */ - return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE, - "agent not connected"); - - rc = agent->ops->transact(agent, transctx); - if (rc) { - goto error; - } - transctx->request = NULL; - - len = transctx->response_len; - s = transctx->response; - len--; - if (len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - if (*s != SSH2_AGENT_IDENTITIES_ANSWER) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - s++; - - /* Read the length of identities */ - len -= 4; - if (len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - num_identities = _libssh2_ntohu32(s); - s += 4; - - while (num_identities--) { - struct agent_publickey *identity; - ssize_t comment_len; - - identity = LIBSSH2_ALLOC(agent->session, sizeof *identity); - if (!identity) { - rc = LIBSSH2_ERROR_ALLOC; - goto error; - } - - /* Read the length of the blob */ - len -= 4; - if (len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - identity->external.blob_len = _libssh2_ntohu32(s); - s += 4; - - /* Read the blob */ - len -= identity->external.blob_len; - if (len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - identity->external.blob = LIBSSH2_ALLOC(agent->session, - identity->external.blob_len); - if (!identity->external.blob) { - rc = LIBSSH2_ERROR_ALLOC; - goto error; - } - memcpy(identity->external.blob, s, identity->external.blob_len); - s += identity->external.blob_len; - - /* Read the length of the comment */ - len -= 4; - if (len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - comment_len = _libssh2_ntohu32(s); - s += 4; - - /* Read the comment */ - len -= comment_len; - if (len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - identity->external.comment = LIBSSH2_ALLOC(agent->session, - comment_len + 1); - if (!identity->external.comment) { - rc = LIBSSH2_ERROR_ALLOC; - goto error; - } - identity->external.comment[comment_len] = '\0'; - memcpy(identity->external.comment, s, comment_len); - s += comment_len; - - _libssh2_list_add(&agent->head, &identity->node); - } - error: - LIBSSH2_FREE(agent->session, transctx->response); - transctx->response = NULL; - - return _libssh2_error(agent->session, rc, - "agent list id failed"); -} - -static void -agent_free_identities(LIBSSH2_AGENT *agent) { - struct agent_publickey *node; - struct agent_publickey *next; - - for (node = _libssh2_list_first(&agent->head); node; node = next) { - next = _libssh2_list_next(&node->node); - LIBSSH2_FREE(agent->session, node->external.blob); - LIBSSH2_FREE(agent->session, node->external.comment); - LIBSSH2_FREE(agent->session, node); - } - _libssh2_list_init(&agent->head); -} - -#define AGENT_PUBLICKEY_MAGIC 0x3bdefed2 -/* - * agent_publickey_to_external() - * - * Copies data from the internal to the external representation struct. - * - */ -static struct libssh2_agent_publickey * -agent_publickey_to_external(struct agent_publickey *node) -{ - struct libssh2_agent_publickey *ext = &node->external; - - ext->magic = AGENT_PUBLICKEY_MAGIC; - ext->node = node; - - return ext; -} - -/* - * libssh2_agent_init - * - * Init an ssh-agent handle. Returns the pointer to the handle. - * - */ -LIBSSH2_API LIBSSH2_AGENT * -libssh2_agent_init(LIBSSH2_SESSION *session) -{ - LIBSSH2_AGENT *agent; - - agent = LIBSSH2_ALLOC(session, sizeof *agent); - if (!agent) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate space for agent connection"); - return NULL; - } - memset(agent, 0, sizeof *agent); - agent->session = session; - _libssh2_list_init(&agent->head); - - return agent; -} - -/* - * libssh2_agent_connect() - * - * Connect to an ssh-agent. - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int -libssh2_agent_connect(LIBSSH2_AGENT *agent) -{ - int i, rc = -1; - for (i = 0; supported_backends[i].name; i++) { - agent->ops = supported_backends[i].ops; - rc = agent->ops->connect(agent); - if (!rc) - return 0; - } - return rc; -} - -/* - * libssh2_agent_list_identities() - * - * Request ssh-agent to list identities. - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int -libssh2_agent_list_identities(LIBSSH2_AGENT *agent) -{ - memset(&agent->transctx, 0, sizeof agent->transctx); - /* Abondon the last fetched identities */ - agent_free_identities(agent); - return agent_list_identities(agent); -} - -/* - * libssh2_agent_get_identity() - * - * Traverse the internal list of public keys. Pass NULL to 'prev' to get - * the first one. Or pass a poiner to the previously returned one to get the - * next. - * - * Returns: - * 0 if a fine public key was stored in 'store' - * 1 if end of public keys - * [negative] on errors - */ -LIBSSH2_API int -libssh2_agent_get_identity(LIBSSH2_AGENT *agent, - struct libssh2_agent_publickey **ext, - struct libssh2_agent_publickey *oprev) -{ - struct agent_publickey *node; - if (oprev && oprev->node) { - /* we have a starting point */ - struct agent_publickey *prev = oprev->node; - - /* get the next node in the list */ - node = _libssh2_list_next(&prev->node); - } - else - node = _libssh2_list_first(&agent->head); - - if (!node) - /* no (more) node */ - return 1; - - *ext = agent_publickey_to_external(node); - - return 0; -} - -/* - * libssh2_agent_userauth() - * - * Do publickey user authentication with the help of ssh-agent. - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int -libssh2_agent_userauth(LIBSSH2_AGENT *agent, - const char *username, - struct libssh2_agent_publickey *identity) -{ - void *abstract = agent; - int rc; - - if (agent->session->userauth_pblc_state == libssh2_NB_state_idle) { - memset(&agent->transctx, 0, sizeof agent->transctx); - agent->identity = identity->node; - } - - BLOCK_ADJUST(rc, agent->session, - _libssh2_userauth_publickey(agent->session, username, - strlen(username), - identity->blob, - identity->blob_len, - agent_sign, - &abstract)); - return rc; -} - -/* - * libssh2_agent_disconnect() - * - * Close a connection to an ssh-agent. - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int -libssh2_agent_disconnect(LIBSSH2_AGENT *agent) -{ - if (agent->ops && agent->fd != LIBSSH2_INVALID_SOCKET) - return agent->ops->disconnect(agent); - return 0; -} - -/* - * libssh2_agent_free() - * - * Free an ssh-agent handle. This function also frees the internal - * collection of public keys. - */ -LIBSSH2_API void -libssh2_agent_free(LIBSSH2_AGENT *agent) { - /* Allow connection freeing when the socket has lost its connection */ - if (agent->fd != LIBSSH2_INVALID_SOCKET) { - libssh2_agent_disconnect(agent); - } - agent_free_identities(agent); - LIBSSH2_FREE(agent->session, agent); -} diff --git a/vendor/libssh2-1.4.2/src/channel.c b/vendor/libssh2-1.4.2/src/channel.c deleted file mode 100644 index 63e5d5b..0000000 --- a/vendor/libssh2-1.4.2/src/channel.c +++ /dev/null @@ -1,2570 +0,0 @@ -/* Copyright (c) 2004-2007 Sara Golemon - * Copyright (c) 2005 Mikhail Gusarov - * Copyright (c) 2008-2011 by Daniel Stenberg - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#ifdef HAVE_INTTYPES_H -#include -#endif -#include - -#include "channel.h" -#include "transport.h" -#include "packet.h" -#include "session.h" - -/* - * _libssh2_channel_nextid - * - * Determine the next channel ID we can use at our end - */ -uint32_t -_libssh2_channel_nextid(LIBSSH2_SESSION * session) -{ - uint32_t id = session->next_channel; - LIBSSH2_CHANNEL *channel; - - channel = _libssh2_list_first(&session->channels); - - while (channel) { - if (channel->local.id > id) { - id = channel->local.id; - } - channel = _libssh2_list_next(&channel->node); - } - - /* This is a shortcut to avoid waiting for close packets on channels we've - * forgotten about, This *could* be a problem if we request and close 4 - * billion or so channels in too rapid succession for the remote end to - * respond, but the worst case scenario is that some data meant for - * another channel Gets picked up by the new one.... Pretty unlikely all - * told... - */ - session->next_channel = id + 1; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Allocated new channel ID#%lu", - id); - return id; -} - -/* - * _libssh2_channel_locate - * - * Locate a channel pointer by number - */ -LIBSSH2_CHANNEL * -_libssh2_channel_locate(LIBSSH2_SESSION *session, uint32_t channel_id) -{ - LIBSSH2_CHANNEL *channel; - LIBSSH2_LISTENER *l; - - for(channel = _libssh2_list_first(&session->channels); - channel; - channel = _libssh2_list_next(&channel->node)) { - if (channel->local.id == channel_id) - return channel; - } - - /* We didn't find the channel in the session, let's then check its - listeners since each listener may have its own set of pending channels - */ - for(l = _libssh2_list_first(&session->listeners); l; - l = _libssh2_list_next(&l->node)) { - for(channel = _libssh2_list_first(&l->queue); - channel; - channel = _libssh2_list_next(&channel->node)) { - if (channel->local.id == channel_id) - return channel; - } - } - - return NULL; -} - -/* - * _libssh2_channel_open - * - * Establish a generic session channel - */ -LIBSSH2_CHANNEL * -_libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type, - uint32_t channel_type_len, - uint32_t window_size, - uint32_t packet_size, - const unsigned char *message, - size_t message_len) -{ - static const unsigned char reply_codes[3] = { - SSH_MSG_CHANNEL_OPEN_CONFIRMATION, - SSH_MSG_CHANNEL_OPEN_FAILURE, - 0 - }; - unsigned char *s; - int rc; - - if (session->open_state == libssh2_NB_state_idle) { - session->open_channel = NULL; - session->open_packet = NULL; - session->open_data = NULL; - /* 17 = packet_type(1) + channel_type_len(4) + sender_channel(4) + - * window_size(4) + packet_size(4) */ - session->open_packet_len = channel_type_len + 17; - session->open_local_channel = _libssh2_channel_nextid(session); - - /* Zero the whole thing out */ - memset(&session->open_packet_requirev_state, 0, - sizeof(session->open_packet_requirev_state)); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Opening Channel - win %d pack %d", window_size, - packet_size); - session->open_channel = - LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL)); - if (!session->open_channel) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate space for channel data"); - return NULL; - } - memset(session->open_channel, 0, sizeof(LIBSSH2_CHANNEL)); - - session->open_channel->channel_type_len = channel_type_len; - session->open_channel->channel_type = - LIBSSH2_ALLOC(session, channel_type_len); - if (!session->open_channel->channel_type) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Failed allocating memory for channel type name"); - LIBSSH2_FREE(session, session->open_channel); - session->open_channel = NULL; - return NULL; - } - memcpy(session->open_channel->channel_type, channel_type, - channel_type_len); - - /* REMEMBER: local as in locally sourced */ - session->open_channel->local.id = session->open_local_channel; - session->open_channel->remote.window_size = window_size; - session->open_channel->remote.window_size_initial = window_size; - session->open_channel->remote.packet_size = packet_size; - session->open_channel->session = session; - - _libssh2_list_add(&session->channels, - &session->open_channel->node); - - s = session->open_packet = - LIBSSH2_ALLOC(session, session->open_packet_len); - if (!session->open_packet) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate temporary space for packet"); - goto channel_error; - } - *(s++) = SSH_MSG_CHANNEL_OPEN; - _libssh2_store_str(&s, channel_type, channel_type_len); - _libssh2_store_u32(&s, session->open_local_channel); - _libssh2_store_u32(&s, window_size); - _libssh2_store_u32(&s, packet_size); - - /* Do not copy the message */ - - session->open_state = libssh2_NB_state_created; - } - - if (session->open_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, - session->open_packet, - session->open_packet_len, - message, message_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending channel-open request"); - return NULL; - } - else if (rc) { - _libssh2_error(session, rc, - "Unable to send channel-open request"); - goto channel_error; - } - - session->open_state = libssh2_NB_state_sent; - } - - if (session->open_state == libssh2_NB_state_sent) { - rc = _libssh2_packet_requirev(session, reply_codes, - &session->open_data, - &session->open_data_len, 1, - session->open_packet + 5 + - channel_type_len, 4, - &session->open_packet_requirev_state); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); - return NULL; - } else if (rc) { - goto channel_error; - } - - if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_CONFIRMATION) { - session->open_channel->remote.id = - _libssh2_ntohu32(session->open_data + 5); - session->open_channel->local.window_size = - _libssh2_ntohu32(session->open_data + 9); - session->open_channel->local.window_size_initial = - _libssh2_ntohu32(session->open_data + 9); - session->open_channel->local.packet_size = - _libssh2_ntohu32(session->open_data + 13); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Connection Established - ID: %lu/%lu win: %lu/%lu" - " pack: %lu/%lu", - session->open_channel->local.id, - session->open_channel->remote.id, - session->open_channel->local.window_size, - session->open_channel->remote.window_size, - session->open_channel->local.packet_size, - session->open_channel->remote.packet_size); - LIBSSH2_FREE(session, session->open_packet); - session->open_packet = NULL; - LIBSSH2_FREE(session, session->open_data); - session->open_data = NULL; - - session->open_state = libssh2_NB_state_idle; - return session->open_channel; - } - - if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_FAILURE) { - _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, - "Channel open failure"); - } - } - - channel_error: - - if (session->open_data) { - LIBSSH2_FREE(session, session->open_data); - session->open_data = NULL; - } - if (session->open_packet) { - LIBSSH2_FREE(session, session->open_packet); - session->open_packet = NULL; - } - if (session->open_channel) { - unsigned char channel_id[4]; - LIBSSH2_FREE(session, session->open_channel->channel_type); - - _libssh2_list_remove(&session->open_channel->node); - - /* Clear out packets meant for this channel */ - _libssh2_htonu32(channel_id, session->open_channel->local.id); - while ((_libssh2_packet_ask(session, SSH_MSG_CHANNEL_DATA, - &session->open_data, - &session->open_data_len, 1, - channel_id, 4) >= 0) - || - (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA, - &session->open_data, - &session->open_data_len, 1, - channel_id, 4) >= 0)) { - LIBSSH2_FREE(session, session->open_data); - session->open_data = NULL; - } - - LIBSSH2_FREE(session, session->open_channel); - session->open_channel = NULL; - } - - session->open_state = libssh2_NB_state_idle; - return NULL; -} - -/* - * libssh2_channel_open_ex - * - * Establish a generic session channel - */ -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *type, - unsigned int type_len, - unsigned int window_size, unsigned int packet_size, - const char *msg, unsigned int msg_len) -{ - LIBSSH2_CHANNEL *ptr; - - if(!session) - return NULL; - - BLOCK_ADJUST_ERRNO(ptr, session, - _libssh2_channel_open(session, type, type_len, - window_size, packet_size, - (unsigned char *)msg, - msg_len)); - return ptr; -} - -/* - * libssh2_channel_direct_tcpip_ex - * - * Tunnel TCP/IP connect through the SSH session to direct host/port - */ -static LIBSSH2_CHANNEL * -channel_direct_tcpip(LIBSSH2_SESSION * session, const char *host, - int port, const char *shost, int sport) -{ - LIBSSH2_CHANNEL *channel; - unsigned char *s; - - if (session->direct_state == libssh2_NB_state_idle) { - session->direct_host_len = strlen(host); - session->direct_shost_len = strlen(shost); - /* host_len(4) + port(4) + shost_len(4) + sport(4) */ - session->direct_message_len = - session->direct_host_len + session->direct_shost_len + 16; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Requesting direct-tcpip session to from %s:%d to %s:%d", - shost, sport, host, port); - - s = session->direct_message = - LIBSSH2_ALLOC(session, session->direct_message_len); - if (!session->direct_message) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for direct-tcpip connection"); - return NULL; - } - _libssh2_store_str(&s, host, session->direct_host_len); - _libssh2_store_u32(&s, port); - _libssh2_store_str(&s, shost, session->direct_shost_len); - _libssh2_store_u32(&s, sport); - } - - channel = - _libssh2_channel_open(session, "direct-tcpip", - sizeof("direct-tcpip") - 1, - LIBSSH2_CHANNEL_WINDOW_DEFAULT, - LIBSSH2_CHANNEL_PACKET_DEFAULT, - session->direct_message, - session->direct_message_len); - - if (!channel && - libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) { - /* The error code is still set to LIBSSH2_ERROR_EAGAIN, set our state - to created to avoid re-creating the package on next invoke */ - session->direct_state = libssh2_NB_state_created; - return NULL; - } - /* by default we set (keep?) idle state... */ - session->direct_state = libssh2_NB_state_idle; - - LIBSSH2_FREE(session, session->direct_message); - session->direct_message = NULL; - - return channel; -} - -/* - * libssh2_channel_direct_tcpip_ex - * - * Tunnel TCP/IP connect through the SSH session to direct host/port - */ -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, - int port, const char *shost, int sport) -{ - LIBSSH2_CHANNEL *ptr; - - if(!session) - return NULL; - - BLOCK_ADJUST_ERRNO(ptr, session, - channel_direct_tcpip(session, host, port, shost, sport)); - return ptr; -} - -/* - * channel_forward_listen - * - * Bind a port on the remote host and listen for connections - */ -static LIBSSH2_LISTENER * -channel_forward_listen(LIBSSH2_SESSION * session, const char *host, - int port, int *bound_port, int queue_maxsize) -{ - unsigned char *s; - static const unsigned char reply_codes[3] = - { SSH_MSG_REQUEST_SUCCESS, SSH_MSG_REQUEST_FAILURE, 0 }; - int rc; - - if(!host) - host = "0.0.0.0"; - - if (session->fwdLstn_state == libssh2_NB_state_idle) { - session->fwdLstn_host_len = strlen(host); - /* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4) - + port(4) */ - session->fwdLstn_packet_len = - session->fwdLstn_host_len + (sizeof("tcpip-forward") - 1) + 14; - - /* Zero the whole thing out */ - memset(&session->fwdLstn_packet_requirev_state, 0, - sizeof(session->fwdLstn_packet_requirev_state)); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Requesting tcpip-forward session for %s:%d", host, - port); - - s = session->fwdLstn_packet = - LIBSSH2_ALLOC(session, session->fwdLstn_packet_len); - if (!session->fwdLstn_packet) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memeory for setenv packet"); - return NULL; - } - - *(s++) = SSH_MSG_GLOBAL_REQUEST; - _libssh2_store_str(&s, "tcpip-forward", sizeof("tcpip-forward") - 1); - *(s++) = 0x01; /* want_reply */ - - _libssh2_store_str(&s, host, session->fwdLstn_host_len); - _libssh2_store_u32(&s, port); - - session->fwdLstn_state = libssh2_NB_state_created; - } - - if (session->fwdLstn_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, - session->fwdLstn_packet, - session->fwdLstn_packet_len, - NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block sending global-request packet for " - "forward listen request"); - return NULL; - } - else if (rc) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send global-request packet for forward " - "listen request"); - LIBSSH2_FREE(session, session->fwdLstn_packet); - session->fwdLstn_packet = NULL; - session->fwdLstn_state = libssh2_NB_state_idle; - return NULL; - } - LIBSSH2_FREE(session, session->fwdLstn_packet); - session->fwdLstn_packet = NULL; - - session->fwdLstn_state = libssh2_NB_state_sent; - } - - if (session->fwdLstn_state == libssh2_NB_state_sent) { - unsigned char *data; - size_t data_len; - rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, - 0, NULL, 0, - &session->fwdLstn_packet_requirev_state); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); - return NULL; - } else if (rc) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Unknown"); - session->fwdLstn_state = libssh2_NB_state_idle; - return NULL; - } - - if (data[0] == SSH_MSG_REQUEST_SUCCESS) { - LIBSSH2_LISTENER *listener; - - listener = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_LISTENER)); - if (!listener) - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for listener queue"); - else { - memset(listener, 0, sizeof(LIBSSH2_LISTENER)); - listener->host = - LIBSSH2_ALLOC(session, session->fwdLstn_host_len + 1); - if (!listener->host) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for listener queue"); - LIBSSH2_FREE(session, listener); - listener = NULL; - } - else { - listener->session = session; - memcpy(listener->host, host ? host : "0.0.0.0", - session->fwdLstn_host_len); - listener->host[session->fwdLstn_host_len] = 0; - if (data_len >= 5 && !port) { - listener->port = _libssh2_ntohu32(data + 1); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Dynamic tcpip-forward port allocated: %d", - listener->port); - } - else - listener->port = port; - - listener->queue_size = 0; - listener->queue_maxsize = queue_maxsize; - - /* append this to the parent's list of listeners */ - _libssh2_list_add(&session->listeners, &listener->node); - - if (bound_port) { - *bound_port = listener->port; - } - } - } - - LIBSSH2_FREE(session, data); - session->fwdLstn_state = libssh2_NB_state_idle; - return listener; - } - else if (data[0] == SSH_MSG_REQUEST_FAILURE) { - LIBSSH2_FREE(session, data); - _libssh2_error(session, LIBSSH2_ERROR_REQUEST_DENIED, - "Unable to complete request for forward-listen"); - session->fwdLstn_state = libssh2_NB_state_idle; - return NULL; - } - } - - session->fwdLstn_state = libssh2_NB_state_idle; - - return NULL; -} - -/* - * libssh2_channel_forward_listen_ex - * - * Bind a port on the remote host and listen for connections - */ -LIBSSH2_API LIBSSH2_LISTENER * -libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, const char *host, - int port, int *bound_port, int queue_maxsize) -{ - LIBSSH2_LISTENER *ptr; - - if(!session) - return NULL; - - BLOCK_ADJUST_ERRNO(ptr, session, - channel_forward_listen(session, host, port, bound_port, - queue_maxsize)); - return ptr; -} - -/* - * _libssh2_channel_forward_cancel - * - * Stop listening on a remote port and free the listener - * Toss out any pending (un-accept()ed) connections - * - * Return 0 on success, LIBSSH2_ERROR_EAGAIN if would block, -1 on error - */ -int _libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener) -{ - LIBSSH2_SESSION *session = listener->session; - LIBSSH2_CHANNEL *queued; - unsigned char *packet, *s; - size_t host_len = strlen(listener->host); - /* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4) + - port(4) */ - size_t packet_len = - host_len + 14 + sizeof("cancel-tcpip-forward") - 1; - int rc; - - if (listener->chanFwdCncl_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Cancelling tcpip-forward session for %s:%d", - listener->host, listener->port); - - s = packet = LIBSSH2_ALLOC(session, packet_len); - if (!packet) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memeory for setenv packet"); - return LIBSSH2_ERROR_ALLOC; - } - - *(s++) = SSH_MSG_GLOBAL_REQUEST; - _libssh2_store_str(&s, "cancel-tcpip-forward", - sizeof("cancel-tcpip-forward") - 1); - *(s++) = 0x00; /* want_reply */ - - _libssh2_store_str(&s, listener->host, host_len); - _libssh2_store_u32(&s, listener->port); - - listener->chanFwdCncl_state = libssh2_NB_state_created; - } else { - packet = listener->chanFwdCncl_data; - } - - if (listener->chanFwdCncl_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, packet, packet_len, NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending forward request"); - listener->chanFwdCncl_data = packet; - return rc; - } - else if (rc) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send global-request packet for forward " - "listen request"); - LIBSSH2_FREE(session, packet); - listener->chanFwdCncl_state = libssh2_NB_state_idle; - return LIBSSH2_ERROR_SOCKET_SEND; - } - LIBSSH2_FREE(session, packet); - - listener->chanFwdCncl_state = libssh2_NB_state_sent; - } - - queued = _libssh2_list_first(&listener->queue); - while (queued) { - LIBSSH2_CHANNEL *next = _libssh2_list_next(&queued->node); - - rc = _libssh2_channel_free(queued); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - queued = next; - } - LIBSSH2_FREE(session, listener->host); - - /* remove this entry from the parent's list of listeners */ - _libssh2_list_remove(&listener->node); - - LIBSSH2_FREE(session, listener); - - listener->chanFwdCncl_state = libssh2_NB_state_idle; - - return 0; -} - -/* - * libssh2_channel_forward_cancel - * - * Stop listening on a remote port and free the listener - * Toss out any pending (un-accept()ed) connections - * - * Return 0 on success, LIBSSH2_ERROR_EAGAIN if would block, -1 on error - */ -LIBSSH2_API int -libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener) -{ - int rc; - - if(!listener) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, listener->session, - _libssh2_channel_forward_cancel(listener)); - return rc; -} - -/* - * channel_forward_accept - * - * Accept a connection - */ -static LIBSSH2_CHANNEL * -channel_forward_accept(LIBSSH2_LISTENER *listener) -{ - int rc; - - do { - rc = _libssh2_transport_read(listener->session); - } while (rc > 0); - - if (_libssh2_list_first(&listener->queue)) { - LIBSSH2_CHANNEL *channel = _libssh2_list_first(&listener->queue); - - /* detach channel from listener's queue */ - _libssh2_list_remove(&channel->node); - - listener->queue_size--; - - /* add channel to session's channel list */ - _libssh2_list_add(&channel->session->channels, &channel->node); - - return channel; - } - - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(listener->session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting for packet"); - } - else - _libssh2_error(listener->session, LIBSSH2_ERROR_CHANNEL_UNKNOWN, - "Channel not found"); - return NULL; -} - -/* - * libssh2_channel_forward_accept - * - * Accept a connection - */ -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener) -{ - LIBSSH2_CHANNEL *ptr; - - if(!listener) - return NULL; - - BLOCK_ADJUST_ERRNO(ptr, listener->session, - channel_forward_accept(listener)); - return ptr; - -} - -/* - * channel_setenv - * - * Set an environment variable prior to requesting a shell/program/subsystem - */ -static int channel_setenv(LIBSSH2_CHANNEL *channel, - const char *varname, unsigned int varname_len, - const char *value, unsigned int value_len) -{ - LIBSSH2_SESSION *session = channel->session; - unsigned char *s, *data; - static const unsigned char reply_codes[3] = - { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }; - size_t data_len; - int rc; - - if (channel->setenv_state == libssh2_NB_state_idle) { - /* 21 = packet_type(1) + channel_id(4) + request_len(4) + - * request(3)"env" + want_reply(1) + varname_len(4) + value_len(4) */ - channel->setenv_packet_len = varname_len + value_len + 21; - - /* Zero the whole thing out */ - memset(&channel->setenv_packet_requirev_state, 0, - sizeof(channel->setenv_packet_requirev_state)); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Setting remote environment variable: %s=%s on " - "channel %lu/%lu", - varname, value, channel->local.id, channel->remote.id); - - s = channel->setenv_packet = - LIBSSH2_ALLOC(session, channel->setenv_packet_len); - if (!channel->setenv_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memeory " - "for setenv packet"); - } - - *(s++) = SSH_MSG_CHANNEL_REQUEST; - _libssh2_store_u32(&s, channel->remote.id); - _libssh2_store_str(&s, "env", sizeof("env") - 1); - *(s++) = 0x01; - _libssh2_store_str(&s, varname, varname_len); - _libssh2_store_str(&s, value, value_len); - - channel->setenv_state = libssh2_NB_state_created; - } - - if (channel->setenv_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, - channel->setenv_packet, - channel->setenv_packet_len, - NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending setenv request"); - return rc; - } else if (rc) { - LIBSSH2_FREE(session, channel->setenv_packet); - channel->setenv_packet = NULL; - channel->setenv_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send channel-request packet for " - "setenv request"); - } - LIBSSH2_FREE(session, channel->setenv_packet); - channel->setenv_packet = NULL; - - _libssh2_htonu32(channel->setenv_local_channel, channel->local.id); - - channel->setenv_state = libssh2_NB_state_sent; - } - - if (channel->setenv_state == libssh2_NB_state_sent) { - rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, - 1, channel->setenv_local_channel, 4, - &channel-> - setenv_packet_requirev_state); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - if (rc) { - channel->setenv_state = libssh2_NB_state_idle; - return rc; - } - - if (data[0] == SSH_MSG_CHANNEL_SUCCESS) { - LIBSSH2_FREE(session, data); - channel->setenv_state = libssh2_NB_state_idle; - return 0; - } - - LIBSSH2_FREE(session, data); - } - - channel->setenv_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, - "Unable to complete request for channel-setenv"); -} - -/* - * libssh2_channel_setenv_ex - * - * Set an environment variable prior to requesting a shell/program/subsystem - */ -LIBSSH2_API int -libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, - const char *varname, unsigned int varname_len, - const char *value, unsigned int value_len) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - channel_setenv(channel, varname, varname_len, - value, value_len)); - return rc; -} - -/* - * channel_request_pty - * Duh... Request a PTY - */ -static int channel_request_pty(LIBSSH2_CHANNEL *channel, - const char *term, unsigned int term_len, - const char *modes, unsigned int modes_len, - int width, int height, - int width_px, int height_px) -{ - LIBSSH2_SESSION *session = channel->session; - unsigned char *s; - static const unsigned char reply_codes[3] = - { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }; - int rc; - - if (channel->reqPTY_state == libssh2_NB_state_idle) { - /* 41 = packet_type(1) + channel(4) + pty_req_len(4) + "pty_req"(7) + - * want_reply(1) + term_len(4) + width(4) + height(4) + width_px(4) + - * height_px(4) + modes_len(4) */ - if(term_len + modes_len > 256) { - return _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "term + mode lengths too large"); - } - - channel->reqPTY_packet_len = term_len + modes_len + 41; - - /* Zero the whole thing out */ - memset(&channel->reqPTY_packet_requirev_state, 0, - sizeof(channel->reqPTY_packet_requirev_state)); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Allocating tty on channel %lu/%lu", channel->local.id, - channel->remote.id); - - s = channel->reqPTY_packet; - - *(s++) = SSH_MSG_CHANNEL_REQUEST; - _libssh2_store_u32(&s, channel->remote.id); - _libssh2_store_str(&s, (char *)"pty-req", sizeof("pty-req") - 1); - - *(s++) = 0x01; - - _libssh2_store_str(&s, term, term_len); - _libssh2_store_u32(&s, width); - _libssh2_store_u32(&s, height); - _libssh2_store_u32(&s, width_px); - _libssh2_store_u32(&s, height_px); - _libssh2_store_str(&s, modes, modes_len); - - channel->reqPTY_state = libssh2_NB_state_created; - } - - if (channel->reqPTY_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, channel->reqPTY_packet, - channel->reqPTY_packet_len, - NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending pty request"); - return rc; - } else if (rc) { - channel->reqPTY_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Unable to send pty-request packet"); - } - _libssh2_htonu32(channel->reqPTY_local_channel, channel->local.id); - - channel->reqPTY_state = libssh2_NB_state_sent; - } - - if (channel->reqPTY_state == libssh2_NB_state_sent) { - unsigned char *data; - size_t data_len; - unsigned char code; - rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, - 1, channel->reqPTY_local_channel, 4, - &channel->reqPTY_packet_requirev_state); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - channel->reqPTY_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Failed to require the PTY package"); - } - - code = data[0]; - - LIBSSH2_FREE(session, data); - channel->reqPTY_state = libssh2_NB_state_idle; - - if (code == SSH_MSG_CHANNEL_SUCCESS) - return 0; - } - - return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, - "Unable to complete request for channel request-pty"); -} - -/* - * libssh2_channel_request_pty_ex - * Duh... Request a PTY - */ -LIBSSH2_API int -libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, const char *term, - unsigned int term_len, const char *modes, - unsigned int modes_len, int width, int height, - int width_px, int height_px) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - channel_request_pty(channel, term, term_len, modes, - modes_len, width, height, - width_px, height_px)); - return rc; -} - -static int -channel_request_pty_size(LIBSSH2_CHANNEL * channel, int width, - int height, int width_px, int height_px) -{ - LIBSSH2_SESSION *session = channel->session; - unsigned char *s; - int rc; - int retcode = LIBSSH2_ERROR_PROTO; - - if (channel->reqPTY_state == libssh2_NB_state_idle) { - channel->reqPTY_packet_len = 39; - - /* Zero the whole thing out */ - memset(&channel->reqPTY_packet_requirev_state, 0, - sizeof(channel->reqPTY_packet_requirev_state)); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "changing tty size on channel %lu/%lu", - channel->local.id, - channel->remote.id); - - s = channel->reqPTY_packet; - - *(s++) = SSH_MSG_CHANNEL_REQUEST; - _libssh2_store_u32(&s, channel->remote.id); - _libssh2_store_str(&s, (char *)"window-change", - sizeof("window-change") - 1); - *(s++) = 0x00; /* Don't reply */ - _libssh2_store_u32(&s, width); - _libssh2_store_u32(&s, height); - _libssh2_store_u32(&s, width_px); - _libssh2_store_u32(&s, height_px); - - channel->reqPTY_state = libssh2_NB_state_created; - } - - if (channel->reqPTY_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, channel->reqPTY_packet, - channel->reqPTY_packet_len, - NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending window-change request"); - return rc; - } else if (rc) { - channel->reqPTY_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Unable to send window-change packet"); - } - _libssh2_htonu32(channel->reqPTY_local_channel, channel->local.id); - retcode = LIBSSH2_ERROR_NONE; - } - - channel->reqPTY_state = libssh2_NB_state_idle; - return retcode; -} - -LIBSSH2_API int -libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL *channel, int width, - int height, int width_px, int height_px) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - channel_request_pty_size(channel, width, height, width_px, - height_px)); - return rc; -} - -/* Keep this an even number */ -#define LIBSSH2_X11_RANDOM_COOKIE_LEN 32 - -/* - * channel_x11_req - * Request X11 forwarding - */ -static int -channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection, - const char *auth_proto, const char *auth_cookie, - int screen_number) -{ - LIBSSH2_SESSION *session = channel->session; - unsigned char *s; - static const unsigned char reply_codes[3] = - { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }; - size_t proto_len = - auth_proto ? strlen(auth_proto) : (sizeof("MIT-MAGIC-COOKIE-1") - 1); - size_t cookie_len = - auth_cookie ? strlen(auth_cookie) : LIBSSH2_X11_RANDOM_COOKIE_LEN; - int rc; - - if (channel->reqX11_state == libssh2_NB_state_idle) { - /* 30 = packet_type(1) + channel(4) + x11_req_len(4) + "x11-req"(7) + - * want_reply(1) + single_cnx(1) + proto_len(4) + cookie_len(4) + - * screen_num(4) */ - channel->reqX11_packet_len = proto_len + cookie_len + 30; - - /* Zero the whole thing out */ - memset(&channel->reqX11_packet_requirev_state, 0, - sizeof(channel->reqX11_packet_requirev_state)); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Requesting x11-req for channel %lu/%lu: single=%d " - "proto=%s cookie=%s screen=%d", - channel->local.id, channel->remote.id, - single_connection, - auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", - auth_cookie ? auth_cookie : "", screen_number); - - s = channel->reqX11_packet = - LIBSSH2_ALLOC(session, channel->reqX11_packet_len); - if (!channel->reqX11_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for pty-request"); - } - - *(s++) = SSH_MSG_CHANNEL_REQUEST; - _libssh2_store_u32(&s, channel->remote.id); - _libssh2_store_str(&s, "x11-req", sizeof("x11-req") - 1); - - *(s++) = 0x01; /* want_reply */ - *(s++) = single_connection ? 0x01 : 0x00; - - _libssh2_store_str(&s, auth_proto?auth_proto:"MIT-MAGIC-COOKIE-1", - proto_len); - - _libssh2_store_u32(&s, cookie_len); - if (auth_cookie) { - memcpy(s, auth_cookie, cookie_len); - } else { - int i; - /* note: the extra +1 below is necessary since the sprintf() - loop will always write 3 bytes so the last one will write - the trailing zero at the LIBSSH2_X11_RANDOM_COOKIE_LEN/2 - border */ - unsigned char buffer[(LIBSSH2_X11_RANDOM_COOKIE_LEN / 2) +1]; - - _libssh2_random(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); - for(i = 0; i < (LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); i++) { - sprintf((char *)&s[i*2], "%02X", buffer[i]); - } - } - s += cookie_len; - - _libssh2_store_u32(&s, screen_number); - channel->reqX11_state = libssh2_NB_state_created; - } - - if (channel->reqX11_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, channel->reqX11_packet, - channel->reqX11_packet_len, - NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending X11-req packet"); - return rc; - } - if (rc) { - LIBSSH2_FREE(session, channel->reqX11_packet); - channel->reqX11_packet = NULL; - channel->reqX11_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Unable to send x11-req packet"); - } - LIBSSH2_FREE(session, channel->reqX11_packet); - channel->reqX11_packet = NULL; - - _libssh2_htonu32(channel->reqX11_local_channel, channel->local.id); - - channel->reqX11_state = libssh2_NB_state_sent; - } - - if (channel->reqX11_state == libssh2_NB_state_sent) { - size_t data_len; - unsigned char *data; - unsigned char code; - - rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, - 1, channel->reqX11_local_channel, 4, - &channel->reqX11_packet_requirev_state); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - channel->reqX11_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "waiting for x11-req response packet"); - } - - code = data[0]; - LIBSSH2_FREE(session, data); - channel->reqX11_state = libssh2_NB_state_idle; - - if (code == SSH_MSG_CHANNEL_SUCCESS) - return 0; - } - - return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, - "Unable to complete request for channel x11-req"); -} - -/* - * libssh2_channel_x11_req_ex - * Request X11 forwarding - */ -LIBSSH2_API int -libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, - const char *auth_proto, const char *auth_cookie, - int screen_number) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - channel_x11_req(channel, single_connection, auth_proto, - auth_cookie, screen_number)); - return rc; -} - - -/* - * _libssh2_channel_process_startup - * - * Primitive for libssh2_channel_(shell|exec|subsystem) - */ -int -_libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, - const char *request, size_t request_len, - const char *message, size_t message_len) -{ - LIBSSH2_SESSION *session = channel->session; - unsigned char *s; - static const unsigned char reply_codes[3] = - { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }; - int rc; - - if (channel->process_state == libssh2_NB_state_idle) { - /* 10 = packet_type(1) + channel(4) + request_len(4) + want_reply(1) */ - channel->process_packet_len = request_len + 10; - - /* Zero the whole thing out */ - memset(&channel->process_packet_requirev_state, 0, - sizeof(channel->process_packet_requirev_state)); - - if (message) - channel->process_packet_len += + 4; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "starting request(%s) on channel %lu/%lu, message=%s", - request, channel->local.id, channel->remote.id, - message?message:""); - s = channel->process_packet = - LIBSSH2_ALLOC(session, channel->process_packet_len); - if (!channel->process_packet) - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory " - "for channel-process request"); - - *(s++) = SSH_MSG_CHANNEL_REQUEST; - _libssh2_store_u32(&s, channel->remote.id); - _libssh2_store_str(&s, request, request_len); - *(s++) = 0x01; - - if (message) - _libssh2_store_u32(&s, message_len); - - channel->process_state = libssh2_NB_state_created; - } - - if (channel->process_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, - channel->process_packet, - channel->process_packet_len, - (unsigned char *)message, message_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending channel request"); - return rc; - } - else if (rc) { - LIBSSH2_FREE(session, channel->process_packet); - channel->process_packet = NULL; - channel->process_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Unable to send channel request"); - } - LIBSSH2_FREE(session, channel->process_packet); - channel->process_packet = NULL; - - _libssh2_htonu32(channel->process_local_channel, channel->local.id); - - channel->process_state = libssh2_NB_state_sent; - } - - if (channel->process_state == libssh2_NB_state_sent) { - unsigned char *data; - size_t data_len; - unsigned char code; - rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, - 1, channel->process_local_channel, 4, - &channel->process_packet_requirev_state); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - channel->process_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Failed waiting for channel success"); - } - - code = data[0]; - LIBSSH2_FREE(session, data); - channel->process_state = libssh2_NB_state_idle; - - if (code == SSH_MSG_CHANNEL_SUCCESS) - return 0; - } - - return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, - "Unable to complete request for " - "channel-process-startup"); -} - -/* - * libssh2_channel_process_startup - * - * Primitive for libssh2_channel_(shell|exec|subsystem) - */ -LIBSSH2_API int -libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, - const char *req, unsigned int req_len, - const char *msg, unsigned int msg_len) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_process_startup(channel, req, req_len, - msg, msg_len)); - return rc; -} - - -/* - * libssh2_channel_set_blocking - * - * Set a channel's BEHAVIOR blocking on or off. The socket will remain non- - * blocking. - */ -LIBSSH2_API void -libssh2_channel_set_blocking(LIBSSH2_CHANNEL * channel, int blocking) -{ - if(channel) - (void) _libssh2_session_set_blocking(channel->session, blocking); -} - -/* - * _libssh2_channel_flush - * - * Flush data from one (or all) stream - * Returns number of bytes flushed, or negative on failure - */ -int -_libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid) -{ - if (channel->flush_state == libssh2_NB_state_idle) { - LIBSSH2_PACKET *packet = - _libssh2_list_first(&channel->session->packets); - channel->flush_refund_bytes = 0; - channel->flush_flush_bytes = 0; - - while (packet) { - LIBSSH2_PACKET *next = _libssh2_list_next(&packet->node); - unsigned char packet_type = packet->data[0]; - - if (((packet_type == SSH_MSG_CHANNEL_DATA) - || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)) - && (_libssh2_ntohu32(packet->data + 1) == channel->local.id)) { - /* It's our channel at least */ - long packet_stream_id = - (packet_type == SSH_MSG_CHANNEL_DATA) ? 0 : - _libssh2_ntohu32(packet->data + 5); - if ((streamid == LIBSSH2_CHANNEL_FLUSH_ALL) - || ((packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA) - && ((streamid == LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA) - || (streamid == packet_stream_id))) - || ((packet_type == SSH_MSG_CHANNEL_DATA) - && (streamid == 0))) { - int bytes_to_flush = packet->data_len - packet->data_head; - - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, - "Flushing %d bytes of data from stream " - "%lu on channel %lu/%lu", - bytes_to_flush, packet_stream_id, - channel->local.id, channel->remote.id); - - /* It's one of the streams we wanted to flush */ - channel->flush_refund_bytes += packet->data_len - 13; - channel->flush_flush_bytes += bytes_to_flush; - - LIBSSH2_FREE(channel->session, packet->data); - - /* remove this packet from the parent's list */ - _libssh2_list_remove(&packet->node); - LIBSSH2_FREE(channel->session, packet); - } - } - packet = next; - } - - channel->flush_state = libssh2_NB_state_created; - } - - if (channel->flush_refund_bytes) { - int rc; - - rc = _libssh2_channel_receive_window_adjust(channel, - channel->flush_refund_bytes, - 1, NULL); - if (rc == LIBSSH2_ERROR_EAGAIN) - return rc; - } - - channel->flush_state = libssh2_NB_state_idle; - - return channel->flush_flush_bytes; -} - -/* - * libssh2_channel_flush_ex - * - * Flush data from one (or all) stream - * Returns number of bytes flushed, or negative on failure - */ -LIBSSH2_API int -libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int stream) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_flush(channel, stream)); - return rc; -} - -/* - * libssh2_channel_get_exit_status - * - * Return the channel's program exit status. Note that the actual protocol - * provides the full 32bit this function returns. We cannot abuse it to - * return error values in case of errors so we return a zero if channel is - * NULL. - */ -LIBSSH2_API int -libssh2_channel_get_exit_status(LIBSSH2_CHANNEL *channel) -{ - if(!channel) - return 0; - - return channel->exit_status; -} - -/* - * libssh2_channel_get_exit_signal - * - * Get exit signal (without leading "SIG"), error message, and language - * tag into newly allocated buffers of indicated length. Caller can - * use NULL pointers to indicate that the value should not be set. The - * *_len variables are set if they are non-NULL even if the - * corresponding string parameter is NULL. Returns LIBSSH2_ERROR_NONE - * on success, or an API error code. - */ -LIBSSH2_API int -libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL *channel, - char **exitsignal, - size_t *exitsignal_len, - char **errmsg, - size_t *errmsg_len, - char **langtag, - size_t *langtag_len) -{ - LIBSSH2_SESSION *session = channel->session; - size_t namelen = 0; - - if (channel) { - if (channel->exit_signal) { - namelen = strlen(channel->exit_signal); - if (exitsignal) { - *exitsignal = LIBSSH2_ALLOC(session, namelen + 1); - if (!*exitsignal) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for signal name"); - } - memcpy(*exitsignal, channel->exit_signal, namelen); - (*exitsignal)[namelen] = '\0'; - } - if (exitsignal_len) - *exitsignal_len = namelen; - } else { - if (exitsignal) - *exitsignal = NULL; - if (exitsignal_len) - *exitsignal_len = 0; - } - - /* TODO: set error message and language tag */ - - if (errmsg) - *errmsg = NULL; - - if (errmsg_len) - *errmsg_len = 0; - - if (langtag) - *langtag = NULL; - - if (langtag_len) - *langtag_len = 0; - } - - return LIBSSH2_ERROR_NONE; -} - -/* - * _libssh2_channel_receive_window_adjust - * - * Adjust the receive window for a channel by adjustment bytes. If the amount - * to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the - * adjustment amount will be queued for a later packet. - * - * Calls _libssh2_error() ! - */ -int -_libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel, - uint32_t adjustment, - unsigned char force, - unsigned int *store) -{ - int rc; - - if (channel->adjust_state == libssh2_NB_state_idle) { - if (!force - && (adjustment + channel->adjust_queue < - LIBSSH2_CHANNEL_MINADJUST)) { - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, - "Queueing %lu bytes for receive window adjustment " - "for channel %lu/%lu", - adjustment, channel->local.id, channel->remote.id); - channel->adjust_queue += adjustment; - if(store) - *store = channel->remote.window_size; - return 0; - } - - if (!adjustment && !channel->adjust_queue) { - if(store) - *store = channel->remote.window_size; - return 0; - } - - adjustment += channel->adjust_queue; - channel->adjust_queue = 0; - - /* Adjust the window based on the block we just freed */ - channel->adjust_adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST; - _libssh2_htonu32(&channel->adjust_adjust[1], channel->remote.id); - _libssh2_htonu32(&channel->adjust_adjust[5], adjustment); - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, - "Adjusting window %lu bytes for data on " - "channel %lu/%lu", - adjustment, channel->local.id, channel->remote.id); - - channel->adjust_state = libssh2_NB_state_created; - } - - rc = _libssh2_transport_send(channel->session, channel->adjust_adjust, 9, - NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(channel->session, rc, - "Would block sending window adjust"); - return rc; - } - else if (rc) { - channel->adjust_queue = adjustment; - return _libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send transfer-window adjustment " - "packet, deferring"); - } - else { - channel->remote.window_size += adjustment; - } - - channel->adjust_state = libssh2_NB_state_idle; - - if(store) - *store = channel->remote.window_size; - return 0; -} - -/* - * libssh2_channel_receive_window_adjust - * - * DEPRECATED - * - * Adjust the receive window for a channel by adjustment bytes. If the amount - * to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the - * adjustment amount will be queued for a later packet. - * - * Returns the new size of the receive window (as understood by remote end). - * Note that it might return EAGAIN too which is highly stupid. - * - */ -LIBSSH2_API unsigned long -libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, - unsigned long adj, - unsigned char force) -{ - unsigned int window; - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_receive_window_adjust(channel, adj, - force, &window)); - - /* stupid - but this is how it was made to work before and this is just - kept for backwards compatibility */ - return rc?(unsigned long)rc:window; -} - -/* - * libssh2_channel_receive_window_adjust2 - * - * Adjust the receive window for a channel by adjustment bytes. If the amount - * to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the - * adjustment amount will be queued for a later packet. - * - * Stores the new size of the receive window in the data 'window' points to. - * - * Returns the "normal" error code: 0 for success, negative for failure. - */ -LIBSSH2_API int -libssh2_channel_receive_window_adjust2(LIBSSH2_CHANNEL *channel, - unsigned long adj, - unsigned char force, - unsigned int *window) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_receive_window_adjust(channel, adj, force, - window)); - return rc; -} - -int -_libssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode) -{ - if (channel->extData2_state == libssh2_NB_state_idle) { - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, - "Setting channel %lu/%lu handle_extended_data" - " mode to %d", - channel->local.id, channel->remote.id, ignore_mode); - channel->remote.extended_data_ignore_mode = ignore_mode; - - channel->extData2_state = libssh2_NB_state_created; - } - - if (channel->extData2_state == libssh2_NB_state_idle) { - if (ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) { - int rc = - _libssh2_channel_flush(channel, - LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA); - if(LIBSSH2_ERROR_EAGAIN == rc) - return rc; - } - } - - channel->extData2_state = libssh2_NB_state_idle; - return 0; -} - -/* - * libssh2_channel_handle_extended_data2() - * - */ -LIBSSH2_API int -libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, - int mode) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, _libssh2_channel_extended_data(channel, - mode)); - return rc; -} - -/* - * libssh2_channel_handle_extended_data - * - * DEPRECATED DO NOTE USE! - * - * How should extended data look to the calling app? Keep it in separate - * channels[_read() _read_stdder()]? (NORMAL) Merge the extended data to the - * standard data? [everything via _read()]? (MERGE) Ignore it entirely [toss - * out packets as they come in]? (IGNORE) - */ -LIBSSH2_API void -libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, - int ignore_mode) -{ - (void)libssh2_channel_handle_extended_data2(channel, ignore_mode); -} - - - -/* - * _libssh2_channel_read - * - * Read data from a channel - * - * It is important to not return 0 until the currently read channel is - * complete. If we read stuff from the wire but it was no payload data to fill - * in the buffer with, we MUST make sure to return LIBSSH2_ERROR_EAGAIN. - * - * The receive window must be maintained (enlarged) by the user of this - * function. - */ -ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, - char *buf, size_t buflen) -{ - LIBSSH2_SESSION *session = channel->session; - int rc; - int bytes_read = 0; - int bytes_want; - int unlink_packet; - LIBSSH2_PACKET *read_packet; - LIBSSH2_PACKET *read_next; - - if (channel->read_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "channel_read() wants %d bytes from channel %lu/%lu " - "stream #%d", - (int) buflen, channel->local.id, channel->remote.id, - stream_id); - channel->read_state = libssh2_NB_state_created; - } - - rc = 1; /* set to >0 to let the while loop start */ - - /* Process all pending incoming packets in all states in order to "even - out" the network readings. Tests prove that this way produces faster - transfers. */ - while (rc > 0) - rc = _libssh2_transport_read(session); - - if ((rc < 0) && (rc != LIBSSH2_ERROR_EAGAIN)) - return _libssh2_error(session, rc, "transport read"); - - read_packet = _libssh2_list_first(&session->packets); - while (read_packet && (bytes_read < (int) buflen)) { - /* previously this loop condition also checked for - !channel->remote.close but we cannot let it do this: - - We may have a series of packets to read that are still pending even - if a close has been received. Acknowledging the close too early - makes us flush buffers prematurely and loose data. - */ - - LIBSSH2_PACKET *readpkt = read_packet; - - /* In case packet gets destroyed during this iteration */ - read_next = _libssh2_list_next(&readpkt->node); - - channel->read_local_id = - _libssh2_ntohu32(readpkt->data + 1); - - /* - * Either we asked for a specific extended data stream - * (and data was available), - * or the standard stream (and data was available), - * or the standard stream with extended_data_merge - * enabled and data was available - */ - if ((stream_id - && (readpkt->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) - && (channel->local.id == channel->read_local_id) - && (stream_id == (int) _libssh2_ntohu32(readpkt->data + 5))) - || (!stream_id && (readpkt->data[0] == SSH_MSG_CHANNEL_DATA) - && (channel->local.id == channel->read_local_id)) - || (!stream_id - && (readpkt->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) - && (channel->local.id == channel->read_local_id) - && (channel->remote.extended_data_ignore_mode == - LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) { - - /* figure out much more data we want to read */ - bytes_want = buflen - bytes_read; - unlink_packet = FALSE; - - if (bytes_want >= (int) (readpkt->data_len - readpkt->data_head)) { - /* we want more than this node keeps, so adjust the number and - delete this node after the copy */ - bytes_want = readpkt->data_len - readpkt->data_head; - unlink_packet = TRUE; - } - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "channel_read() got %d of data from %lu/%lu/%d%s", - bytes_want, channel->local.id, - channel->remote.id, stream_id, - unlink_packet?" [ul]":""); - - /* copy data from this struct to the target buffer */ - memcpy(&buf[bytes_read], - &readpkt->data[readpkt->data_head], bytes_want); - - /* advance pointer and counter */ - readpkt->data_head += bytes_want; - bytes_read += bytes_want; - - /* if drained, remove from list */ - if (unlink_packet) { - /* detach readpkt from session->packets list */ - _libssh2_list_remove(&readpkt->node); - - LIBSSH2_FREE(session, readpkt->data); - LIBSSH2_FREE(session, readpkt); - } - } - - /* check the next struct in the chain */ - read_packet = read_next; - } - - if (!bytes_read) { - channel->read_state = libssh2_NB_state_idle; - - /* If the channel is already at EOF or even closed, we need to signal - that back. We may have gotten that info while draining the incoming - transport layer until EAGAIN so we must not be fooled by that - return code. */ - if(channel->remote.eof || channel->remote.close) - return 0; - else if(rc != LIBSSH2_ERROR_EAGAIN) - return 0; - - /* if the transport layer said EAGAIN then we say so as well */ - return _libssh2_error(session, rc, "would block"); - } - else - /* make sure we remain in the created state to focus on emptying the - data we already have in the packet brigade before we try to read - more off the network again */ - channel->read_state = libssh2_NB_state_created; - - return bytes_read; -} - -/* - * libssh2_channel_read_ex - * - * Read data from a channel (blocking or non-blocking depending on set state) - * - * When this is done non-blocking, it is important to not return 0 until the - * currently read channel is complete. If we read stuff from the wire but it - * was no payload data to fill in the buffer with, we MUST make sure to return - * LIBSSH2_ERROR_EAGAIN. - * - * This function will first make sure there's a receive window enough to - * receive a full buffer's wort of contents. An application may choose to - * adjust the receive window more to increase transfer performance. - */ -LIBSSH2_API ssize_t -libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, - size_t buflen) -{ - int rc; - unsigned long recv_window; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - recv_window = libssh2_channel_window_read_ex(channel, NULL, NULL); - - if(buflen > recv_window) { - BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_receive_window_adjust(channel, buflen, - 1, NULL)); - } - - BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_read(channel, stream_id, buf, buflen)); - return rc; -} - -/* - * _libssh2_channel_packet_data_len - * - * Return the size of the data block of the current packet, or 0 if there - * isn't a packet. - */ -size_t -_libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id) -{ - LIBSSH2_SESSION *session = channel->session; - LIBSSH2_PACKET *read_packet; - uint32_t read_local_id; - - read_packet = _libssh2_list_first(&session->packets); - if (read_packet == NULL) - return 0; - - while (read_packet) { - read_local_id = _libssh2_ntohu32(read_packet->data + 1); - - /* - * Either we asked for a specific extended data stream - * (and data was available), - * or the standard stream (and data was available), - * or the standard stream with extended_data_merge - * enabled and data was available - */ - if ((stream_id - && (read_packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) - && (channel->local.id == read_local_id) - && (stream_id == (int) _libssh2_ntohu32(read_packet->data + 5))) - || - (!stream_id - && (read_packet->data[0] == SSH_MSG_CHANNEL_DATA) - && (channel->local.id == read_local_id)) - || - (!stream_id - && (read_packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) - && (channel->local.id == read_local_id) - && (channel->remote.extended_data_ignore_mode - == LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) - { - return (read_packet->data_len - read_packet->data_head); - } - read_packet = _libssh2_list_next(&read_packet->node); - } - - return 0; -} - -/* - * _libssh2_channel_write - * - * Send data to a channel. Note that if this returns EAGAIN, the caller must - * call this function again with the SAME input arguments. - * - * Returns: number of bytes sent, or if it returns a negative number, that is - * the error code! - */ -ssize_t -_libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, - const unsigned char *buf, size_t buflen) -{ - int rc = 0; - LIBSSH2_SESSION *session = channel->session; - ssize_t wrote = 0; /* counter for this specific this call */ - - /* In theory we could split larger buffers into several smaller packets - * but it turns out to be really hard and nasty to do while still offering - * the API/prototype. - * - * Instead we only deal with the first 32K in this call and for the parent - * function to call it again with the remainder! 32K is a conservative - * limit based on the text in RFC4253 section 6.1. - */ - if(buflen > 32700) - buflen = 32700; - - if (channel->write_state == libssh2_NB_state_idle) { - unsigned char *s = channel->write_packet; - - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, - "Writing %d bytes on channel %lu/%lu, stream #%d", - (int) buflen, channel->local.id, channel->remote.id, - stream_id); - - if (channel->local.close) - return _libssh2_error(channel->session, - LIBSSH2_ERROR_CHANNEL_CLOSED, - "We've already closed this channel"); - else if (channel->local.eof) - return _libssh2_error(channel->session, - LIBSSH2_ERROR_CHANNEL_EOF_SENT, - "EOF has already been received, " - "data might be ignored"); - - /* drain the incoming flow first, mostly to make sure we get all - * pending window adjust packets */ - do - rc = _libssh2_transport_read(session); - while (rc > 0); - - if((rc < 0) && (rc != LIBSSH2_ERROR_EAGAIN)) - return rc; - - if(channel->local.window_size <= 0) - /* there's no room for data so we stop */ - return (rc==LIBSSH2_ERROR_EAGAIN?rc:0); - - channel->write_bufwrite = buflen; - - *(s++) = stream_id ? SSH_MSG_CHANNEL_EXTENDED_DATA : - SSH_MSG_CHANNEL_DATA; - _libssh2_store_u32(&s, channel->remote.id); - if (stream_id) - _libssh2_store_u32(&s, stream_id); - - /* Don't exceed the remote end's limits */ - /* REMEMBER local means local as the SOURCE of the data */ - if (channel->write_bufwrite > channel->local.window_size) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Splitting write block due to %lu byte " - "window_size on %lu/%lu/%d", - channel->local.window_size, channel->local.id, - channel->remote.id, stream_id); - channel->write_bufwrite = channel->local.window_size; - } - if (channel->write_bufwrite > channel->local.packet_size) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Splitting write block due to %lu byte " - "packet_size on %lu/%lu/%d", - channel->local.packet_size, channel->local.id, - channel->remote.id, stream_id); - channel->write_bufwrite = channel->local.packet_size; - } - /* store the size here only, the buffer is passed in as-is to - _libssh2_transport_send() */ - _libssh2_store_u32(&s, channel->write_bufwrite); - channel->write_packet_len = s - channel->write_packet; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Sending %d bytes on channel %lu/%lu, stream_id=%d", - (int) channel->write_bufwrite, channel->local.id, - channel->remote.id, stream_id); - - channel->write_state = libssh2_NB_state_created; - } - - if (channel->write_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, channel->write_packet, - channel->write_packet_len, - buf, channel->write_bufwrite); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, rc, - "Unable to send channel data"); - } - else if (rc) { - channel->write_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Unable to send channel data"); - } - /* Shrink local window size */ - channel->local.window_size -= channel->write_bufwrite; - - wrote += channel->write_bufwrite; - - /* Since _libssh2_transport_write() succeeded, we must return - now to allow the caller to provide the next chunk of data. - - We cannot move on to send the next piece of data that may - already have been provided in this same function call, as we - risk getting EAGAIN for that and we can't return information - both about sent data as well as EAGAIN. So, by returning short - now, the caller will call this function again with new data to - send */ - - channel->write_state = libssh2_NB_state_idle; - - return wrote; - } - - return LIBSSH2_ERROR_INVAL; /* reaching this point is really bad */ -} - -/* - * libssh2_channel_write_ex - * - * Send data to a channel - */ -LIBSSH2_API ssize_t -libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id, - const char *buf, size_t buflen) -{ - ssize_t rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_write(channel, stream_id, - (unsigned char *)buf, buflen)); - return rc; -} - -/* - * channel_send_eof - * - * Send EOF on channel - */ -static int channel_send_eof(LIBSSH2_CHANNEL *channel) -{ - LIBSSH2_SESSION *session = channel->session; - unsigned char packet[5]; /* packet_type(1) + channelno(4) */ - int rc; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Sending EOF on channel %lu/%lu", - channel->local.id, channel->remote.id); - packet[0] = SSH_MSG_CHANNEL_EOF; - _libssh2_htonu32(packet + 1, channel->remote.id); - rc = _libssh2_transport_send(session, packet, 5, NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending EOF"); - return rc; - } - else if (rc) { - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send EOF on channel"); - } - channel->local.eof = 1; - - return 0; -} - -/* - * libssh2_channel_send_eof - * - * Send EOF on channel - */ -LIBSSH2_API int -libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, channel_send_eof(channel)); - return rc; -} - -/* - * libssh2_channel_eof - * - * Read channel's eof status - */ -LIBSSH2_API int -libssh2_channel_eof(LIBSSH2_CHANNEL * channel) -{ - LIBSSH2_SESSION *session; - LIBSSH2_PACKET *packet; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - session = channel->session; - packet = _libssh2_list_first(&session->packets); - - while (packet) { - if (((packet->data[0] == SSH_MSG_CHANNEL_DATA) - || (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)) - && (channel->local.id == _libssh2_ntohu32(packet->data + 1))) { - /* There's data waiting to be read yet, mask the EOF status */ - return 0; - } - packet = _libssh2_list_next(&packet->node); - } - - return channel->remote.eof; -} - -/* - * channel_wait_eof - * - * Awaiting channel EOF - */ -static int channel_wait_eof(LIBSSH2_CHANNEL *channel) -{ - LIBSSH2_SESSION *session = channel->session; - int rc; - - if (channel->wait_eof_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Awaiting close of channel %lu/%lu", channel->local.id, - channel->remote.id); - - channel->wait_eof_state = libssh2_NB_state_created; - } - - /* - * While channel is not eof, read more packets from the network. - * Either the EOF will be set or network timeout will occur. - */ - do { - if (channel->remote.eof) { - break; - } - rc = _libssh2_transport_read(session); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if (rc < 0) { - channel->wait_eof_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "_libssh2_transport_read() bailed out!"); - } - } while (1); - - channel->wait_eof_state = libssh2_NB_state_idle; - - return 0; -} - -/* - * libssh2_channel_wait_eof - * - * Awaiting channel EOF - */ -LIBSSH2_API int -libssh2_channel_wait_eof(LIBSSH2_CHANNEL *channel) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, channel_wait_eof(channel)); - return rc; -} - -int _libssh2_channel_close(LIBSSH2_CHANNEL * channel) -{ - LIBSSH2_SESSION *session = channel->session; - int rc = 0; - int retcode; - - if (channel->local.close) { - /* Already closed, act like we sent another close, - * even though we didn't... shhhhhh */ - channel->close_state = libssh2_NB_state_idle; - return 0; - } - - if (!channel->local.eof) - if ((retcode = channel_send_eof(channel))) - return retcode; - - /* ignore if we have received a remote eof or not, as it is now too - late for us to wait for it. Continue closing! */ - - if (channel->close_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Closing channel %lu/%lu", - channel->local.id, channel->remote.id); - - channel->close_packet[0] = SSH_MSG_CHANNEL_CLOSE; - _libssh2_htonu32(channel->close_packet + 1, channel->remote.id); - - channel->close_state = libssh2_NB_state_created; - } - - if (channel->close_state == libssh2_NB_state_created) { - retcode = _libssh2_transport_send(session, channel->close_packet, 5, - NULL, 0); - if (retcode == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending close-channel"); - return retcode; - } else if (retcode) { - channel->close_state = libssh2_NB_state_idle; - return _libssh2_error(session, retcode, - "Unable to send close-channel request"); - } - - channel->close_state = libssh2_NB_state_sent; - } - - if (channel->close_state == libssh2_NB_state_sent) { - /* We must wait for the remote SSH_MSG_CHANNEL_CLOSE message */ - - while (!channel->remote.close && !rc && - (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED)) - rc = _libssh2_transport_read(session); - } - - if(rc != LIBSSH2_ERROR_EAGAIN) { - /* set the local close state first when we're perfectly confirmed to not - do any more EAGAINs */ - channel->local.close = 1; - - /* We call the callback last in this function to make it keep the local - data as long as EAGAIN is returned. */ - if (channel->close_cb) { - LIBSSH2_CHANNEL_CLOSE(session, channel); - } - - channel->close_state = libssh2_NB_state_idle; - } - - /* return 0 or an error */ - return rc>=0?0:rc; -} - -/* - * libssh2_channel_close - * - * Close a channel - */ -LIBSSH2_API int -libssh2_channel_close(LIBSSH2_CHANNEL *channel) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, _libssh2_channel_close(channel) ); - return rc; -} - -/* - * channel_wait_closed - * - * Awaiting channel close after EOF - */ -static int channel_wait_closed(LIBSSH2_CHANNEL *channel) -{ - LIBSSH2_SESSION *session = channel->session; - int rc; - - if (!libssh2_channel_eof(channel)) { - return _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "libssh2_channel_wait_closed() invoked when " - "channel is not in EOF state"); - } - - if (channel->wait_closed_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Awaiting close of channel %lu/%lu", channel->local.id, - channel->remote.id); - - channel->wait_closed_state = libssh2_NB_state_created; - } - - /* - * While channel is not closed, read more packets from the network. - * Either the channel will be closed or network timeout will occur. - */ - if (!channel->remote.close) { - do { - rc = _libssh2_transport_read(session); - if (channel->remote.close) - /* it is now closed, move on! */ - break; - } while (rc > 0); - if(rc < 0) - return rc; - } - - channel->wait_closed_state = libssh2_NB_state_idle; - - return 0; -} - -/* - * libssh2_channel_wait_closed - * - * Awaiting channel close after EOF - */ -LIBSSH2_API int -libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, channel_wait_closed(channel)); - return rc; -} - -/* - * _libssh2_channel_free - * - * Make sure a channel is closed, then remove the channel from the session - * and free its resource(s) - * - * Returns 0 on success, negative on failure - */ -int _libssh2_channel_free(LIBSSH2_CHANNEL *channel) -{ - LIBSSH2_SESSION *session = channel->session; - unsigned char channel_id[4]; - unsigned char *data; - size_t data_len; - int rc; - - assert(session); - - if (channel->free_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Freeing channel %lu/%lu resources", channel->local.id, - channel->remote.id); - - channel->free_state = libssh2_NB_state_created; - } - - /* Allow channel freeing even when the socket has lost its connection */ - if (!channel->local.close - && (session->socket_state == LIBSSH2_SOCKET_CONNECTED)) { - rc = _libssh2_channel_close(channel); - - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - - /* ignore all other errors as they otherwise risk blocking the channel - free from happening */ - } - - channel->free_state = libssh2_NB_state_idle; - - if (channel->exit_signal) { - LIBSSH2_FREE(session, channel->exit_signal); - } - - /* - * channel->remote.close *might* not be set yet, Well... - * We've sent the close packet, what more do you want? - * Just let packet_add ignore it when it finally arrives - */ - - /* Clear out packets meant for this channel */ - _libssh2_htonu32(channel_id, channel->local.id); - while ((_libssh2_packet_ask(session, SSH_MSG_CHANNEL_DATA, &data, - &data_len, 1, channel_id, 4) >= 0) - || - (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, - &data_len, 1, channel_id, 4) >= 0)) { - LIBSSH2_FREE(session, data); - } - - /* free "channel_type" */ - if (channel->channel_type) { - LIBSSH2_FREE(session, channel->channel_type); - } - - /* Unlink from channel list */ - _libssh2_list_remove(&channel->node); - - /* - * Make sure all memory used in the state variables are free - */ - if (channel->setenv_packet) { - LIBSSH2_FREE(session, channel->setenv_packet); - } - if (channel->reqX11_packet) { - LIBSSH2_FREE(session, channel->reqX11_packet); - } - if (channel->process_packet) { - LIBSSH2_FREE(session, channel->process_packet); - } - - LIBSSH2_FREE(session, channel); - - return 0; -} - -/* - * libssh2_channel_free - * - * Make sure a channel is closed, then remove the channel from the session - * and free its resource(s) - * - * Returns 0 on success, negative on failure - */ -LIBSSH2_API int -libssh2_channel_free(LIBSSH2_CHANNEL *channel) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, _libssh2_channel_free(channel)); - return rc; -} -/* - * libssh2_channel_window_read_ex - * - * Check the status of the read window. Returns the number of bytes which the - * remote end may send without overflowing the window limit read_avail (if - * passed) will be populated with the number of bytes actually available to be - * read window_size_initial (if passed) will be populated with the - * window_size_initial as defined by the channel_open request - */ -LIBSSH2_API unsigned long -libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, - unsigned long *read_avail, - unsigned long *window_size_initial) -{ - if(!channel) - return 0; /* no channel, no window! */ - - if (window_size_initial) { - *window_size_initial = channel->remote.window_size_initial; - } - - if (read_avail) { - size_t bytes_queued = 0; - LIBSSH2_PACKET *packet = - _libssh2_list_first(&channel->session->packets); - - while (packet) { - unsigned char packet_type = packet->data[0]; - - if (((packet_type == SSH_MSG_CHANNEL_DATA) - || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)) - && (_libssh2_ntohu32(packet->data + 1) == channel->local.id)) { - bytes_queued += packet->data_len - packet->data_head; - } - - packet = _libssh2_list_next(&packet->node); - } - - *read_avail = bytes_queued; - } - - return channel->remote.window_size; -} - -/* - * libssh2_channel_window_write_ex - * - * Check the status of the write window Returns the number of bytes which may - * be safely writen on the channel without blocking window_size_initial (if - * passed) will be populated with the size of the initial window as defined by - * the channel_open request - */ -LIBSSH2_API unsigned long -libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, - unsigned long *window_size_initial) -{ - if(!channel) - return 0; /* no channel, no window! */ - - if (window_size_initial) { - /* For locally initiated channels this is very often 0, so it's not - * *that* useful as information goes */ - *window_size_initial = channel->local.window_size_initial; - } - - return channel->local.window_size; -} diff --git a/vendor/libssh2-1.4.2/src/channel.h b/vendor/libssh2-1.4.2/src/channel.h deleted file mode 100644 index dc0ee37..0000000 --- a/vendor/libssh2-1.4.2/src/channel.h +++ /dev/null @@ -1,141 +0,0 @@ -#ifndef __LIBSSH2_CHANNEL_H -#define __LIBSSH2_CHANNEL_H -/* Copyright (c) 2008-2010 by Daniel Stenberg - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -/* - * _libssh2_channel_receive_window_adjust - * - * Adjust the receive window for a channel by adjustment bytes. If the amount - * to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the - * adjustment amount will be queued for a later packet. - * - * Always non-blocking. - */ -int _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel, - uint32_t adjustment, - unsigned char force, - unsigned int *store); - -/* - * _libssh2_channel_flush - * - * Flush data from one (or all) stream - * Returns number of bytes flushed, or negative on failure - */ -int _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid); - -/* - * _libssh2_channel_free - * - * Make sure a channel is closed, then remove the channel from the session - * and free its resource(s) - * - * Returns 0 on success, negative on failure - */ -int _libssh2_channel_free(LIBSSH2_CHANNEL *channel); - -int -_libssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode); - -/* - * _libssh2_channel_write - * - * Send data to a channel - */ -ssize_t -_libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, - const unsigned char *buf, size_t buflen); - -/* - * _libssh2_channel_open - * - * Establish a generic session channel - */ -LIBSSH2_CHANNEL * -_libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type, - uint32_t channel_type_len, - uint32_t window_size, - uint32_t packet_size, - const unsigned char *message, size_t message_len); - - -/* - * _libssh2_channel_process_startup - * - * Primitive for libssh2_channel_(shell|exec|subsystem) - */ -int -_libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, - const char *request, size_t request_len, - const char *message, size_t message_len); - -/* - * _libssh2_channel_read - * - * Read data from a channel - * - * It is important to not return 0 until the currently read channel is - * complete. If we read stuff from the wire but it was no payload data to fill - * in the buffer with, we MUST make sure to return PACKET_EAGAIN. - */ -ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, - char *buf, size_t buflen); - -uint32_t _libssh2_channel_nextid(LIBSSH2_SESSION * session); - -LIBSSH2_CHANNEL *_libssh2_channel_locate(LIBSSH2_SESSION * session, - uint32_t channel_id); - -size_t _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, - int stream_id); - -int _libssh2_channel_close(LIBSSH2_CHANNEL * channel); - -/* - * _libssh2_channel_forward_cancel - * - * Stop listening on a remote port and free the listener - * Toss out any pending (un-accept()ed) connections - * - * Return 0 on success, LIBSSH2_ERROR_EAGAIN if would block, -1 on error - */ -int _libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener); - -#endif /* __LIBSSH2_CHANNEL_H */ - diff --git a/vendor/libssh2-1.4.2/src/comp.c b/vendor/libssh2-1.4.2/src/comp.c deleted file mode 100644 index 0296f62..0000000 --- a/vendor/libssh2-1.4.2/src/comp.c +++ /dev/null @@ -1,390 +0,0 @@ -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2010, Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" -#ifdef LIBSSH2_HAVE_ZLIB -# include -#endif - -#include "comp.h" - -/* ******** - * none * - ******** */ - -/* - * comp_method_none_comp - * - * Minimalist compression: Absolutely none - */ -static int -comp_method_none_comp(LIBSSH2_SESSION *session, - unsigned char *dest, - size_t *dest_len, - const unsigned char *src, - size_t src_len, - void **abstract) -{ - (void) session; - (void) abstract; - (void) dest; - (void) dest_len; - (void) src; - (void) src_len; - - return 0; -} - -/* - * comp_method_none_decomp - * - * Minimalist decompression: Absolutely none - */ -static int -comp_method_none_decomp(LIBSSH2_SESSION * session, - unsigned char **dest, - size_t *dest_len, - size_t payload_limit, - const unsigned char *src, - size_t src_len, void **abstract) -{ - (void) session; - (void) payload_limit; - (void) abstract; - *dest = (unsigned char *) src; - *dest_len = src_len; - return 0; -} - - - -static const LIBSSH2_COMP_METHOD comp_method_none = { - "none", - 0, /* not really compressing */ - NULL, - comp_method_none_comp, - comp_method_none_decomp, - NULL -}; - -#ifdef LIBSSH2_HAVE_ZLIB -/* ******** - * zlib * - ******** */ - -/* Memory management wrappers - * Yes, I realize we're doing a callback to a callback, - * Deal... - */ - -static voidpf -comp_method_zlib_alloc(voidpf opaque, uInt items, uInt size) -{ - LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque; - - return (voidpf) LIBSSH2_ALLOC(session, items * size); -} - -static void -comp_method_zlib_free(voidpf opaque, voidpf address) -{ - LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque; - - LIBSSH2_FREE(session, address); -} - - - -/* libssh2_comp_method_zlib_init - * All your bandwidth are belong to us (so save some) - */ -static int -comp_method_zlib_init(LIBSSH2_SESSION * session, int compr, - void **abstract) -{ - z_stream *strm; - int status; - - strm = LIBSSH2_ALLOC(session, sizeof(z_stream)); - if (!strm) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "zlib compression/decompression"); - } - memset(strm, 0, sizeof(z_stream)); - - strm->opaque = (voidpf) session; - strm->zalloc = (alloc_func) comp_method_zlib_alloc; - strm->zfree = (free_func) comp_method_zlib_free; - if (compr) { - /* deflate */ - status = deflateInit(strm, Z_DEFAULT_COMPRESSION); - } else { - /* inflate */ - status = inflateInit(strm); - } - - if (status != Z_OK) { - LIBSSH2_FREE(session, strm); - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "unhandled zlib error %d", status); - return LIBSSH2_ERROR_COMPRESS; - } - *abstract = strm; - - return LIBSSH2_ERROR_NONE; -} - -/* - * libssh2_comp_method_zlib_comp - * - * Compresses source to destination. Without allocation. - */ -static int -comp_method_zlib_comp(LIBSSH2_SESSION *session, - unsigned char *dest, - - /* dest_len is a pointer to allow this function to - update it with the final actual size used */ - size_t *dest_len, - const unsigned char *src, - size_t src_len, - void **abstract) -{ - z_stream *strm = *abstract; - int out_maxlen = *dest_len; - int status; - - strm->next_in = (unsigned char *) src; - strm->avail_in = src_len; - strm->next_out = dest; - strm->avail_out = out_maxlen; - - status = deflate(strm, Z_PARTIAL_FLUSH); - - if (status != Z_OK) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "unhandled zlib compression error %d", status); - return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, - "compression failure"); - } - - *dest_len = out_maxlen - strm->avail_out; - return 0; -} - -/* - * libssh2_comp_method_zlib_decomp - * - * Decompresses source to destination. Allocates the output memory. - */ -static int -comp_method_zlib_decomp(LIBSSH2_SESSION * session, - unsigned char **dest, - size_t *dest_len, - size_t payload_limit, - const unsigned char *src, - size_t src_len, void **abstract) -{ - z_stream *strm = *abstract; - /* A short-term alloc of a full data chunk is better than a series of - reallocs */ - char *out; - int out_maxlen = 8 * src_len; - int limiter = 0; - - /* If strm is null, then we have not yet been initialized. */ - if (strm == NULL) - return _libssh2_error(session, LIBSSH2_ERROR_COMPRESS, - "decompression unitilized");; - - /* In practice they never come smaller than this */ - if (out_maxlen < 25) - out_maxlen = 25; - - if (out_maxlen > (int) payload_limit) - out_maxlen = payload_limit; - - strm->next_in = (unsigned char *) src; - strm->avail_in = src_len; - strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, out_maxlen); - out = (char *) strm->next_out; - strm->avail_out = out_maxlen; - if (!strm->next_out) - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate decompression buffer"); - while (strm->avail_in) { - int status; - - status = inflate(strm, Z_PARTIAL_FLUSH); - - if (status != Z_OK) { - LIBSSH2_FREE(session, out); - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "unhandled zlib error %d", status); - return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, - "decompression failure"); - } - if (strm->avail_in) { - size_t out_ofs = out_maxlen - strm->avail_out; - char *newout; - - out_maxlen += 8 * strm->avail_in; - - if ((out_maxlen > (int) payload_limit) && limiter++) { - LIBSSH2_FREE(session, out); - return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, - "Excessive growth in decompression phase"); - } - - newout = LIBSSH2_REALLOC(session, out, out_maxlen); - if (!newout) { - LIBSSH2_FREE(session, out); - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to expand decompression buffer"); - } - out = newout; - strm->next_out = (unsigned char *) out + out_ofs; - strm->avail_out += 8 * strm->avail_in; - } else - while (!strm->avail_out) { - /* Done with input, might be a byte or two in internal buffer - * during compress. Or potentially many bytes if it's a - * decompress - */ - int grow_size = 2048; - char *newout; - - if (out_maxlen >= (int) payload_limit) { - LIBSSH2_FREE(session, out); - return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, - "Excessive growth in decompression " - "phase"); - } - - if (grow_size > (int) (payload_limit - out_maxlen)) { - grow_size = payload_limit - out_maxlen; - } - - out_maxlen += grow_size; - strm->avail_out = grow_size; - - newout = LIBSSH2_REALLOC(session, out, out_maxlen); - if (!newout) { - LIBSSH2_FREE(session, out); - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to expand final " - "decompress buffer"); - } - out = newout; - strm->next_out = (unsigned char *) out + out_maxlen - - grow_size; - - status = inflate(strm, Z_PARTIAL_FLUSH); - - if (status != Z_OK) { - LIBSSH2_FREE(session, out); - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "unhandled zlib error %d", status); - return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, - "decompression failure"); - } - } - } - - *dest = (unsigned char *) out; - *dest_len = out_maxlen - strm->avail_out; - - return 0; -} - - -/* libssh2_comp_method_zlib_dtor - * All done, no more compression for you - */ -static int -comp_method_zlib_dtor(LIBSSH2_SESSION *session, int compr, void **abstract) -{ - z_stream *strm = *abstract; - - if (strm) { - if (compr) - deflateEnd(strm); - else - inflateEnd(strm); - LIBSSH2_FREE(session, strm); - } - - *abstract = NULL; - return 0; -} - -static const LIBSSH2_COMP_METHOD comp_method_zlib = { - "zlib", - 1, /* yes, this compresses */ - comp_method_zlib_init, - comp_method_zlib_comp, - comp_method_zlib_decomp, - comp_method_zlib_dtor, -}; -#endif /* LIBSSH2_HAVE_ZLIB */ - -/* If compression is enabled by the API, then this array is used which then - may allow compression if zlib is available at build time */ -static const LIBSSH2_COMP_METHOD *comp_methods[] = { -#ifdef LIBSSH2_HAVE_ZLIB - &comp_method_zlib, -#endif /* LIBSSH2_HAVE_ZLIB */ - &comp_method_none, - NULL -}; - -/* If compression is disabled by the API, then this array is used */ -static const LIBSSH2_COMP_METHOD *no_comp_methods[] = { - &comp_method_none, - NULL -}; - -const LIBSSH2_COMP_METHOD ** -_libssh2_comp_methods(LIBSSH2_SESSION *session) -{ - if(session->flag.compress) - return comp_methods; - else - return no_comp_methods; -} diff --git a/vendor/libssh2-1.4.2/src/comp.h b/vendor/libssh2-1.4.2/src/comp.h deleted file mode 100644 index 8edc150..0000000 --- a/vendor/libssh2-1.4.2/src/comp.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __LIBSSH2_COMP_H -#define __LIBSSH2_COMP_H - -/* Copyright (C) 2009-2010 by Daniel Stenberg - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - */ - -#include "libssh2_priv.h" - -const LIBSSH2_COMP_METHOD **_libssh2_comp_methods(LIBSSH2_SESSION *session); - -#endif /* __LIBSSH2_COMP_H */ diff --git a/vendor/libssh2-1.4.2/src/crypt.c b/vendor/libssh2-1.4.2/src/crypt.c deleted file mode 100644 index 93d99c4..0000000 --- a/vendor/libssh2-1.4.2/src/crypt.c +++ /dev/null @@ -1,334 +0,0 @@ -/* Copyright (c) 2009, 2010 Simon Josefsson - * Copyright (c) 2004-2007, Sara Golemon - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" - -#ifdef LIBSSH2_CRYPT_NONE - -/* crypt_none_crypt - * Minimalist cipher: VERY secure *wink* - */ -static int -crypt_none_crypt(LIBSSH2_SESSION * session, unsigned char *buf, - void **abstract) -{ - /* Do nothing to the data! */ - return 0; -} - -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_none = { - "none", - 8, /* blocksize (SSH2 defines minimum blocksize as 8) */ - 0, /* iv_len */ - 0, /* secret_len */ - 0, /* flags */ - NULL, - crypt_none_crypt, - NULL -}; -#endif /* LIBSSH2_CRYPT_NONE */ - -struct crypt_ctx -{ - int encrypt; - _libssh2_cipher_type(algo); - _libssh2_cipher_ctx h; -}; - -static int -crypt_init(LIBSSH2_SESSION * session, - const LIBSSH2_CRYPT_METHOD * method, - unsigned char *iv, int *free_iv, - unsigned char *secret, int *free_secret, - int encrypt, void **abstract) -{ - struct crypt_ctx *ctx = LIBSSH2_ALLOC(session, - sizeof(struct crypt_ctx)); - if (!ctx) - return LIBSSH2_ERROR_ALLOC; - - ctx->encrypt = encrypt; - ctx->algo = method->algo; - if (_libssh2_cipher_init(&ctx->h, ctx->algo, iv, secret, encrypt)) { - LIBSSH2_FREE(session, ctx); - return -1; - } - *abstract = ctx; - *free_iv = 1; - *free_secret = 1; - return 0; -} - -static int -crypt_encrypt(LIBSSH2_SESSION * session, unsigned char *block, - void **abstract) -{ - struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract; - (void) session; - return _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block); -} - -static int -crypt_dtor(LIBSSH2_SESSION * session, void **abstract) -{ - struct crypt_ctx **cctx = (struct crypt_ctx **) abstract; - if (cctx && *cctx) { - _libssh2_cipher_dtor(&(*cctx)->h); - LIBSSH2_FREE(session, *cctx); - *abstract = NULL; - } - return 0; -} - -#if LIBSSH2_AES_CTR -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_ctr = { - "aes128-ctr", - 16, /* blocksize */ - 16, /* initial value length */ - 16, /* secret length -- 16*8 == 128bit */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_aes128ctr -}; - -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_ctr = { - "aes192-ctr", - 16, /* blocksize */ - 16, /* initial value length */ - 24, /* secret length -- 24*8 == 192bit */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_aes192ctr -}; - -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_ctr = { - "aes256-ctr", - 16, /* blocksize */ - 16, /* initial value length */ - 32, /* secret length -- 32*8 == 256bit */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_aes256ctr -}; -#endif - -#if LIBSSH2_AES -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = { - "aes128-cbc", - 16, /* blocksize */ - 16, /* initial value length */ - 16, /* secret length -- 16*8 == 128bit */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_aes128 -}; - -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = { - "aes192-cbc", - 16, /* blocksize */ - 16, /* initial value length */ - 24, /* secret length -- 24*8 == 192bit */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_aes192 -}; - -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = { - "aes256-cbc", - 16, /* blocksize */ - 16, /* initial value length */ - 32, /* secret length -- 32*8 == 256bit */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_aes256 -}; - -/* rijndael-cbc@lysator.liu.se == aes256-cbc */ -static const LIBSSH2_CRYPT_METHOD - libssh2_crypt_method_rijndael_cbc_lysator_liu_se = { - "rijndael-cbc@lysator.liu.se", - 16, /* blocksize */ - 16, /* initial value length */ - 32, /* secret length -- 32*8 == 256bit */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_aes256 -}; -#endif /* LIBSSH2_AES */ - -#if LIBSSH2_BLOWFISH -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = { - "blowfish-cbc", - 8, /* blocksize */ - 8, /* initial value length */ - 16, /* secret length */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_blowfish -}; -#endif /* LIBSSH2_BLOWFISH */ - -#if LIBSSH2_RC4 -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour = { - "arcfour", - 8, /* blocksize */ - 8, /* initial value length */ - 16, /* secret length */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_arcfour -}; - -static int -crypt_init_arcfour128(LIBSSH2_SESSION * session, - const LIBSSH2_CRYPT_METHOD * method, - unsigned char *iv, int *free_iv, - unsigned char *secret, int *free_secret, - int encrypt, void **abstract) -{ - int rc; - - rc = crypt_init (session, method, iv, free_iv, secret, free_secret, - encrypt, abstract); - if (rc == 0) { - struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract; - unsigned char block[8]; - size_t discard = 1536; - for (; discard; discard -= 8) - _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block); - } - - return rc; -} - -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour128 = { - "arcfour128", - 8, /* blocksize */ - 8, /* initial value length */ - 16, /* secret length */ - 0, /* flags */ - &crypt_init_arcfour128, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_arcfour -}; -#endif /* LIBSSH2_RC4 */ - -#if LIBSSH2_CAST -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = { - "cast128-cbc", - 8, /* blocksize */ - 8, /* initial value length */ - 16, /* secret length */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_cast5 -}; -#endif /* LIBSSH2_CAST */ - -#if LIBSSH2_3DES -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = { - "3des-cbc", - 8, /* blocksize */ - 8, /* initial value length */ - 24, /* secret length */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_3des -}; -#endif - -static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = { -#if LIBSSH2_AES_CTR - &libssh2_crypt_method_aes128_ctr, - &libssh2_crypt_method_aes192_ctr, - &libssh2_crypt_method_aes256_ctr, -#endif /* LIBSSH2_AES */ -#if LIBSSH2_AES - &libssh2_crypt_method_aes256_cbc, - &libssh2_crypt_method_rijndael_cbc_lysator_liu_se, /* == aes256-cbc */ - &libssh2_crypt_method_aes192_cbc, - &libssh2_crypt_method_aes128_cbc, -#endif /* LIBSSH2_AES */ -#if LIBSSH2_BLOWFISH - &libssh2_crypt_method_blowfish_cbc, -#endif /* LIBSSH2_BLOWFISH */ -#if LIBSSH2_RC4 - &libssh2_crypt_method_arcfour128, - &libssh2_crypt_method_arcfour, -#endif /* LIBSSH2_RC4 */ -#if LIBSSH2_CAST - &libssh2_crypt_method_cast128_cbc, -#endif /* LIBSSH2_CAST */ -#if LIBSSH2_3DES - &libssh2_crypt_method_3des_cbc, -#endif /* LIBSSH2_DES */ -#ifdef LIBSSH2_CRYPT_NONE - &libssh2_crypt_method_none, -#endif - NULL -}; - -/* Expose to kex.c */ -const LIBSSH2_CRYPT_METHOD ** -libssh2_crypt_methods(void) -{ - return _libssh2_crypt_methods; -} diff --git a/vendor/libssh2-1.4.2/src/crypto.h b/vendor/libssh2-1.4.2/src/crypto.h deleted file mode 100644 index 8cf34f5..0000000 --- a/vendor/libssh2-1.4.2/src/crypto.h +++ /dev/null @@ -1,118 +0,0 @@ -/* Copyright (C) 2009, 2010 Simon Josefsson - * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. - * Copyright (C) 2010 Daniel Stenberg - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ -#ifndef LIBSSH2_CRYPTO_H -#define LIBSSH2_CRYPTO_H - -#ifdef LIBSSH2_LIBGCRYPT -#include "libgcrypt.h" -#else -#include "openssl.h" -#endif - -int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, unsigned long coefflen); -int _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, - LIBSSH2_SESSION * session, - const char *filename, - unsigned const char *passphrase); -int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, unsigned long m_len); -int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, - libssh2_rsa_ctx * rsactx, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, - size_t *signature_len); - -int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *gdata, - unsigned long glen, - const unsigned char *ydata, - unsigned long ylen, - const unsigned char *x, unsigned long x_len); -int _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, - LIBSSH2_SESSION * session, - const char *filename, - unsigned const char *passphrase); -int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, - const unsigned char *sig, - const unsigned char *m, unsigned long m_len); -int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, - const unsigned char *hash, - unsigned long hash_len, unsigned char *sig); - -int _libssh2_cipher_init(_libssh2_cipher_ctx * h, - _libssh2_cipher_type(algo), - unsigned char *iv, - unsigned char *secret, int encrypt); - -int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, - _libssh2_cipher_type(algo), - int encrypt, unsigned char *block); - -int _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase); - -void _libssh2_init_aes_ctr(void); - -#endif diff --git a/vendor/libssh2-1.4.2/src/global.c b/vendor/libssh2-1.4.2/src/global.c deleted file mode 100644 index dc45e70..0000000 --- a/vendor/libssh2-1.4.2/src/global.c +++ /dev/null @@ -1,78 +0,0 @@ -/* Copyright (c) 2010 Lars Nordin - * Copyright (C) 2010 Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" - -static int _libssh2_initialized = 0; -static int _libssh2_init_flags = 0; - -LIBSSH2_API int -libssh2_init(int flags) -{ - if (_libssh2_initialized == 0 && !(flags & LIBSSH2_INIT_NO_CRYPTO)) { - libssh2_crypto_init(); - _libssh2_init_aes_ctr(); - } - - _libssh2_initialized++; - _libssh2_init_flags |= flags; - - return 0; -} - -LIBSSH2_API void -libssh2_exit(void) -{ - if (_libssh2_initialized == 0) - return; - - _libssh2_initialized--; - - if (!(_libssh2_init_flags & LIBSSH2_INIT_NO_CRYPTO)) { - libssh2_crypto_exit(); - } - - return; -} - -void -_libssh2_init_if_needed(void) -{ - if (_libssh2_initialized == 0) - (void)libssh2_init (0); -} diff --git a/vendor/libssh2-1.4.2/src/hostkey.c b/vendor/libssh2-1.4.2/src/hostkey.c deleted file mode 100644 index 53f7479..0000000 --- a/vendor/libssh2-1.4.2/src/hostkey.c +++ /dev/null @@ -1,485 +0,0 @@ -/* Copyright (c) 2004-2006, Sara Golemon - * Copyright (c) 2009 by Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" -#include "misc.h" - -/* Needed for struct iovec on some platforms */ -#ifdef HAVE_SYS_UIO_H -#include -#endif - -#if LIBSSH2_RSA -/* *********** - * ssh-rsa * - *********** */ - -static int hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, - void **abstract); - -/* - * hostkey_method_ssh_rsa_init - * - * Initialize the server hostkey working area with e/n pair - */ -static int -hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session, - const unsigned char *hostkey_data, - size_t hostkey_data_len, - void **abstract) -{ - libssh2_rsa_ctx *rsactx; - const unsigned char *s, *e, *n; - unsigned long len, e_len, n_len; - - (void) hostkey_data_len; - - if (*abstract) { - hostkey_method_ssh_rsa_dtor(session, abstract); - *abstract = NULL; - } - - s = hostkey_data; - len = _libssh2_ntohu32(s); - s += 4; - - if (len != 7 || strncmp((char *) s, "ssh-rsa", 7) != 0) { - return -1; - } - s += 7; - - e_len = _libssh2_ntohu32(s); - s += 4; - - e = s; - s += e_len; - n_len = _libssh2_ntohu32(s); - s += 4; - n = s; - - if (_libssh2_rsa_new(&rsactx, e, e_len, n, n_len, NULL, 0, - NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0)) - return -1; - - *abstract = rsactx; - - return 0; -} - -/* - * hostkey_method_ssh_rsa_initPEM - * - * Load a Private Key from a PEM file - */ -static int -hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION * session, - const char *privkeyfile, - unsigned const char *passphrase, - void **abstract) -{ - libssh2_rsa_ctx *rsactx; - int ret; - - if (*abstract) { - hostkey_method_ssh_rsa_dtor(session, abstract); - *abstract = NULL; - } - - ret = _libssh2_rsa_new_private(&rsactx, session, privkeyfile, passphrase); - if (ret) { - return -1; - } - - *abstract = rsactx; - - return 0; -} - -/* - * hostkey_method_ssh_rsa_sign - * - * Verify signature created by remote - */ -static int -hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION * session, - const unsigned char *sig, - size_t sig_len, - const unsigned char *m, - size_t m_len, void **abstract) -{ - libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); - (void) session; - - /* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */ - sig += 15; - sig_len -= 15; - return _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len); -} - -/* - * hostkey_method_ssh_rsa_signv - * - * Construct a signature from an array of vectors - */ -static int -hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session, - unsigned char **signature, - size_t *signature_len, - int veccount, - const struct iovec datavec[], - void **abstract) -{ - libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); - int ret; - int i; - unsigned char hash[SHA_DIGEST_LENGTH]; - libssh2_sha1_ctx ctx; - - libssh2_sha1_init(&ctx); - for(i = 0; i < veccount; i++) { - libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len); - } - libssh2_sha1_final(ctx, hash); - - ret = _libssh2_rsa_sha1_sign(session, rsactx, hash, SHA_DIGEST_LENGTH, - signature, signature_len); - if (ret) { - return -1; - } - - return 0; -} - -/* - * hostkey_method_ssh_rsa_dtor - * - * Shutdown the hostkey - */ -static int -hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, void **abstract) -{ - libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); - (void) session; - - _libssh2_rsa_free(rsactx); - - *abstract = NULL; - - return 0; -} - -static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa = { - "ssh-rsa", - MD5_DIGEST_LENGTH, - hostkey_method_ssh_rsa_init, - hostkey_method_ssh_rsa_initPEM, - hostkey_method_ssh_rsa_sig_verify, - hostkey_method_ssh_rsa_signv, - NULL, /* encrypt */ - hostkey_method_ssh_rsa_dtor, -}; -#endif /* LIBSSH2_RSA */ - -#if LIBSSH2_DSA -/* *********** - * ssh-dss * - *********** */ - -static int hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, - void **abstract); - -/* - * hostkey_method_ssh_dss_init - * - * Initialize the server hostkey working area with p/q/g/y set - */ -static int -hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session, - const unsigned char *hostkey_data, - size_t hostkey_data_len, - void **abstract) -{ - libssh2_dsa_ctx *dsactx; - const unsigned char *p, *q, *g, *y, *s; - unsigned long p_len, q_len, g_len, y_len, len; - (void) hostkey_data_len; - - if (*abstract) { - hostkey_method_ssh_dss_dtor(session, abstract); - *abstract = NULL; - } - - s = hostkey_data; - len = _libssh2_ntohu32(s); - s += 4; - if (len != 7 || strncmp((char *) s, "ssh-dss", 7) != 0) { - return -1; - } - s += 7; - - p_len = _libssh2_ntohu32(s); - s += 4; - p = s; - s += p_len; - q_len = _libssh2_ntohu32(s); - s += 4; - q = s; - s += q_len; - g_len = _libssh2_ntohu32(s); - s += 4; - g = s; - s += g_len; - y_len = _libssh2_ntohu32(s); - s += 4; - y = s; - /* s += y_len; */ - - _libssh2_dsa_new(&dsactx, p, p_len, q, q_len, g, g_len, y, y_len, NULL, 0); - - *abstract = dsactx; - - return 0; -} - -/* - * hostkey_method_ssh_dss_initPEM - * - * Load a Private Key from a PEM file - */ -static int -hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION * session, - const char *privkeyfile, - unsigned const char *passphrase, - void **abstract) -{ - libssh2_dsa_ctx *dsactx; - int ret; - - if (*abstract) { - hostkey_method_ssh_dss_dtor(session, abstract); - *abstract = NULL; - } - - ret = _libssh2_dsa_new_private(&dsactx, session, privkeyfile, passphrase); - if (ret) { - return -1; - } - - *abstract = dsactx; - - return 0; -} - -/* - * libssh2_hostkey_method_ssh_dss_sign - * - * Verify signature created by remote - */ -static int -hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION * session, - const unsigned char *sig, - size_t sig_len, - const unsigned char *m, - size_t m_len, void **abstract) -{ - libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract); - - /* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */ - sig += 15; - sig_len -= 15; - if (sig_len != 40) { - return _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Invalid DSS signature length"); - } - return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len); -} - -/* - * hostkey_method_ssh_dss_signv - * - * Construct a signature from an array of vectors - */ -static int -hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session, - unsigned char **signature, - size_t *signature_len, - int veccount, - const struct iovec datavec[], - void **abstract) -{ - libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract); - unsigned char hash[SHA_DIGEST_LENGTH]; - libssh2_sha1_ctx ctx; - int i; - - *signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH); - if (!*signature) { - return -1; - } - - *signature_len = 2 * SHA_DIGEST_LENGTH; - memset(*signature, 0, 2 * SHA_DIGEST_LENGTH); - - libssh2_sha1_init(&ctx); - for(i = 0; i < veccount; i++) { - libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len); - } - libssh2_sha1_final(ctx, hash); - - if (_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH, *signature)) { - LIBSSH2_FREE(session, *signature); - return -1; - } - - return 0; -} - -/* - * libssh2_hostkey_method_ssh_dss_dtor - * - * Shutdown the hostkey method - */ -static int -hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, void **abstract) -{ - libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract); - (void) session; - - _libssh2_dsa_free(dsactx); - - *abstract = NULL; - - return 0; -} - -static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_dss = { - "ssh-dss", - MD5_DIGEST_LENGTH, - hostkey_method_ssh_dss_init, - hostkey_method_ssh_dss_initPEM, - hostkey_method_ssh_dss_sig_verify, - hostkey_method_ssh_dss_signv, - NULL, /* encrypt */ - hostkey_method_ssh_dss_dtor, -}; -#endif /* LIBSSH2_DSA */ - -static const LIBSSH2_HOSTKEY_METHOD *hostkey_methods[] = { -#if LIBSSH2_RSA - &hostkey_method_ssh_rsa, -#endif /* LIBSSH2_RSA */ -#if LIBSSH2_DSA - &hostkey_method_ssh_dss, -#endif /* LIBSSH2_DSA */ - NULL -}; - -const LIBSSH2_HOSTKEY_METHOD ** -libssh2_hostkey_methods(void) -{ - return hostkey_methods; -} - -/* - * libssh2_hostkey_hash - * - * Returns hash signature - * Returned buffer should NOT be freed - * Length of buffer is determined by hash type - * i.e. MD5 == 16, SHA1 == 20 - */ -LIBSSH2_API const char * -libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type) -{ - switch (hash_type) { -#if LIBSSH2_MD5 - case LIBSSH2_HOSTKEY_HASH_MD5: - return (char *) session->server_hostkey_md5; - break; -#endif /* LIBSSH2_MD5 */ - case LIBSSH2_HOSTKEY_HASH_SHA1: - return (char *) session->server_hostkey_sha1; - break; - default: - return NULL; - } -} - -static int hostkey_type(const unsigned char *hostkey, size_t len) -{ - const unsigned char rsa[] = { - 0, 0, 0, 0x07, 's', 's', 'h', '-', 'r', 's', 'a' - }; - const unsigned char dss[] = { - 0, 0, 0, 0x07, 's', 's', 'h', '-', 'd', 's', 's' - }; - - if (len < 11) - return LIBSSH2_HOSTKEY_TYPE_UNKNOWN; - - if (!memcmp(rsa, hostkey, 11)) - return LIBSSH2_HOSTKEY_TYPE_RSA; - - if (!memcmp(dss, hostkey, 11)) - return LIBSSH2_HOSTKEY_TYPE_DSS; - - return LIBSSH2_HOSTKEY_TYPE_UNKNOWN; -} - -/* - * libssh2_session_hostkey() - * - * Returns the server key and length. - * - */ -LIBSSH2_API const char * -libssh2_session_hostkey(LIBSSH2_SESSION *session, size_t *len, int *type) -{ - if(session->server_hostkey_len) { - if(len) - *len = session->server_hostkey_len; - if (type) - *type = hostkey_type(session->server_hostkey, - session->server_hostkey_len); - return (char *) session->server_hostkey; - } - if(len) - *len = 0; - return NULL; -} - diff --git a/vendor/libssh2-1.4.2/src/keepalive.c b/vendor/libssh2-1.4.2/src/keepalive.c deleted file mode 100644 index 260206a..0000000 --- a/vendor/libssh2-1.4.2/src/keepalive.c +++ /dev/null @@ -1,98 +0,0 @@ -/* Copyright (C) 2010 Simon Josefsson - * Author: Simon Josefsson - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - */ - -#include "libssh2_priv.h" -#include "transport.h" /* _libssh2_transport_write */ - -/* Keep-alive stuff. */ - -LIBSSH2_API void -libssh2_keepalive_config (LIBSSH2_SESSION *session, - int want_reply, - unsigned interval) -{ - if (interval == 1) - session->keepalive_interval = 2; - else - session->keepalive_interval = interval; - session->keepalive_want_reply = want_reply ? 1 : 0; -} - -LIBSSH2_API int -libssh2_keepalive_send (LIBSSH2_SESSION *session, - int *seconds_to_next) -{ - time_t now; - - if (!session->keepalive_interval) { - if (seconds_to_next) - *seconds_to_next = 0; - return 0; - } - - now = time (NULL); - - if (session->keepalive_last_sent + session->keepalive_interval <= now) { - /* Format is - "SSH_MSG_GLOBAL_REQUEST || 4-byte len || str || want-reply". */ - unsigned char keepalive_data[] - = "\x50\x00\x00\x00\x15keepalive@libssh2.orgW"; - size_t len = sizeof (keepalive_data) - 1; - int rc; - - keepalive_data[len - 1] = session->keepalive_want_reply; - - rc = _libssh2_transport_send(session, keepalive_data, len, NULL, 0); - /* Silently ignore PACKET_EAGAIN here: if the write buffer is - already full, sending another keepalive is not useful. */ - if (rc && rc != LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send keepalive message"); - return rc; - } - - session->keepalive_last_sent = now; - if (seconds_to_next) - *seconds_to_next = session->keepalive_interval; - } else if (seconds_to_next) { - *seconds_to_next = (int) session->keepalive_last_sent - + session->keepalive_interval - now; - } - - return 0; -} diff --git a/vendor/libssh2-1.4.2/src/kex.c b/vendor/libssh2-1.4.2/src/kex.c deleted file mode 100644 index 0a72cb7..0000000 --- a/vendor/libssh2-1.4.2/src/kex.c +++ /dev/null @@ -1,2008 +0,0 @@ -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2010, Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" - -#include "transport.h" -#include "comp.h" -#include "mac.h" - -/* TODO: Switch this to an inline and handle alloc() failures */ -/* Helper macro called from kex_method_diffie_hellman_group1_sha1_key_exchange */ -#define LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(value, reqlen, version) \ - { \ - libssh2_sha1_ctx hash; \ - unsigned long len = 0; \ - if (!(value)) { \ - value = LIBSSH2_ALLOC(session, reqlen + SHA_DIGEST_LENGTH); \ - } \ - if (value) \ - while (len < (unsigned long)reqlen) { \ - libssh2_sha1_init(&hash); \ - libssh2_sha1_update(hash, exchange_state->k_value, \ - exchange_state->k_value_len); \ - libssh2_sha1_update(hash, exchange_state->h_sig_comp, \ - SHA_DIGEST_LENGTH); \ - if (len > 0) { \ - libssh2_sha1_update(hash, value, len); \ - } else { \ - libssh2_sha1_update(hash, (version), 1); \ - libssh2_sha1_update(hash, session->session_id, \ - session->session_id_len); \ - } \ - libssh2_sha1_final(hash, (value) + len); \ - len += SHA_DIGEST_LENGTH; \ - } \ - } - -/* - * diffie_hellman_sha1 - * - * Diffie Hellman Key Exchange, Group Agnostic - */ -static int diffie_hellman_sha1(LIBSSH2_SESSION *session, - _libssh2_bn *g, - _libssh2_bn *p, - int group_order, - unsigned char packet_type_init, - unsigned char packet_type_reply, - unsigned char *midhash, - unsigned long midhash_len, - kmdhgGPsha1kex_state_t *exchange_state) -{ - int ret = 0; - int rc; - - if (exchange_state->state == libssh2_NB_state_idle) { - /* Setup initial values */ - exchange_state->e_packet = NULL; - exchange_state->s_packet = NULL; - exchange_state->k_value = NULL; - exchange_state->ctx = _libssh2_bn_ctx_new(); - exchange_state->x = _libssh2_bn_init(); /* Random from client */ - exchange_state->e = _libssh2_bn_init(); /* g^x mod p */ - exchange_state->f = _libssh2_bn_init(); /* g^(Random from server) mod p */ - exchange_state->k = _libssh2_bn_init(); /* The shared secret: f^x mod p */ - - /* Zero the whole thing out */ - memset(&exchange_state->req_state, 0, sizeof(packet_require_state_t)); - - /* Generate x and e */ - _libssh2_bn_rand(exchange_state->x, group_order, 0, -1); - _libssh2_bn_mod_exp(exchange_state->e, g, exchange_state->x, p, - exchange_state->ctx); - - /* Send KEX init */ - /* packet_type(1) + String Length(4) + leading 0(1) */ - exchange_state->e_packet_len = - _libssh2_bn_bytes(exchange_state->e) + 6; - if (_libssh2_bn_bits(exchange_state->e) % 8) { - /* Leading 00 not needed */ - exchange_state->e_packet_len--; - } - - exchange_state->e_packet = - LIBSSH2_ALLOC(session, exchange_state->e_packet_len); - if (!exchange_state->e_packet) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Out of memory error"); - goto clean_exit; - } - exchange_state->e_packet[0] = packet_type_init; - _libssh2_htonu32(exchange_state->e_packet + 1, - exchange_state->e_packet_len - 5); - if (_libssh2_bn_bits(exchange_state->e) % 8) { - _libssh2_bn_to_bin(exchange_state->e, - exchange_state->e_packet + 5); - } else { - exchange_state->e_packet[5] = 0; - _libssh2_bn_to_bin(exchange_state->e, - exchange_state->e_packet + 6); - } - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending KEX packet %d", - (int) packet_type_init); - exchange_state->state = libssh2_NB_state_created; - } - - if (exchange_state->state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, exchange_state->e_packet, - exchange_state->e_packet_len, - NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - ret = _libssh2_error(session, rc, - "Unable to send KEX init message"); - goto clean_exit; - } - exchange_state->state = libssh2_NB_state_sent; - } - - if (exchange_state->state == libssh2_NB_state_sent) { - if (session->burn_optimistic_kexinit) { - /* The first KEX packet to come along will be the guess initially - * sent by the server. That guess turned out to be wrong so we - * need to silently ignore it */ - int burn_type; - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Waiting for badly guessed KEX packet (to be ignored)"); - burn_type = - _libssh2_packet_burn(session, &exchange_state->burn_state); - if (burn_type == LIBSSH2_ERROR_EAGAIN) { - return burn_type; - } else if (burn_type <= 0) { - /* Failed to receive a packet */ - ret = burn_type; - goto clean_exit; - } - session->burn_optimistic_kexinit = 0; - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Burnt packet of type: %02x", - (unsigned int) burn_type); - } - - exchange_state->state = libssh2_NB_state_sent1; - } - - if (exchange_state->state == libssh2_NB_state_sent1) { - /* Wait for KEX reply */ - rc = _libssh2_packet_require(session, packet_type_reply, - &exchange_state->s_packet, - &exchange_state->s_packet_len, 0, NULL, - 0, &exchange_state->req_state); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - if (rc) { - ret = _libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, - "Timed out waiting for KEX reply"); - goto clean_exit; - } - - /* Parse KEXDH_REPLY */ - exchange_state->s = exchange_state->s_packet + 1; - - session->server_hostkey_len = _libssh2_ntohu32(exchange_state->s); - exchange_state->s += 4; - session->server_hostkey = - LIBSSH2_ALLOC(session, session->server_hostkey_len); - if (!session->server_hostkey) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for a copy " - "of the host key"); - goto clean_exit; - } - memcpy(session->server_hostkey, exchange_state->s, - session->server_hostkey_len); - exchange_state->s += session->server_hostkey_len; - -#if LIBSSH2_MD5 - { - libssh2_md5_ctx fingerprint_ctx; - - libssh2_md5_init(&fingerprint_ctx); - libssh2_md5_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_md5_final(fingerprint_ctx, session->server_hostkey_md5); - } -#ifdef LIBSSH2DEBUG - { - char fingerprint[50], *fprint = fingerprint; - int i; - for(i = 0; i < 16; i++, fprint += 3) { - snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]); - } - *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's MD5 Fingerprint: %s", fingerprint); - } -#endif /* LIBSSH2DEBUG */ -#endif /* ! LIBSSH2_MD5 */ - - { - libssh2_sha1_ctx fingerprint_ctx; - - libssh2_sha1_init(&fingerprint_ctx); - libssh2_sha1_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_sha1_final(fingerprint_ctx, session->server_hostkey_sha1); - } -#ifdef LIBSSH2DEBUG - { - char fingerprint[64], *fprint = fingerprint; - int i; - - for(i = 0; i < 20; i++, fprint += 3) { - snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]); - } - *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA1 Fingerprint: %s", fingerprint); - } -#endif /* LIBSSH2DEBUG */ - - if (session->hostkey->init(session, session->server_hostkey, - session->server_hostkey_len, - &session->server_hostkey_abstract)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to initialize hostkey importer"); - goto clean_exit; - } - - exchange_state->f_value_len = _libssh2_ntohu32(exchange_state->s); - exchange_state->s += 4; - exchange_state->f_value = exchange_state->s; - exchange_state->s += exchange_state->f_value_len; - _libssh2_bn_from_bin(exchange_state->f, exchange_state->f_value_len, - exchange_state->f_value); - - exchange_state->h_sig_len = _libssh2_ntohu32(exchange_state->s); - exchange_state->s += 4; - exchange_state->h_sig = exchange_state->s; - - /* Compute the shared secret */ - _libssh2_bn_mod_exp(exchange_state->k, exchange_state->f, - exchange_state->x, p, exchange_state->ctx); - exchange_state->k_value_len = _libssh2_bn_bytes(exchange_state->k) + 5; - if (_libssh2_bn_bits(exchange_state->k) % 8) { - /* don't need leading 00 */ - exchange_state->k_value_len--; - } - exchange_state->k_value = - LIBSSH2_ALLOC(session, exchange_state->k_value_len); - if (!exchange_state->k_value) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate buffer for K"); - goto clean_exit; - } - _libssh2_htonu32(exchange_state->k_value, - exchange_state->k_value_len - 4); - if (_libssh2_bn_bits(exchange_state->k) % 8) { - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4); - } else { - exchange_state->k_value[4] = 0; - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5); - } - - libssh2_sha1_init(&exchange_state->exchange_hash); - if (session->local.banner) { - _libssh2_htonu32(exchange_state->h_sig_comp, - strlen((char *) session->local.banner) - 2); - libssh2_sha1_update(exchange_state->exchange_hash, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_state->exchange_hash, - (char *) session->local.banner, - strlen((char *) session->local.banner) - 2); - } else { - _libssh2_htonu32(exchange_state->h_sig_comp, - sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); - libssh2_sha1_update(exchange_state->exchange_hash, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_state->exchange_hash, - LIBSSH2_SSH_DEFAULT_BANNER, - sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); - } - - _libssh2_htonu32(exchange_state->h_sig_comp, - strlen((char *) session->remote.banner)); - libssh2_sha1_update(exchange_state->exchange_hash, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_state->exchange_hash, - session->remote.banner, - strlen((char *) session->remote.banner)); - - _libssh2_htonu32(exchange_state->h_sig_comp, - session->local.kexinit_len); - libssh2_sha1_update(exchange_state->exchange_hash, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_state->exchange_hash, - session->local.kexinit, - session->local.kexinit_len); - - _libssh2_htonu32(exchange_state->h_sig_comp, - session->remote.kexinit_len); - libssh2_sha1_update(exchange_state->exchange_hash, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_state->exchange_hash, - session->remote.kexinit, - session->remote.kexinit_len); - - _libssh2_htonu32(exchange_state->h_sig_comp, - session->server_hostkey_len); - libssh2_sha1_update(exchange_state->exchange_hash, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_state->exchange_hash, - session->server_hostkey, - session->server_hostkey_len); - - if (packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) { - /* diffie-hellman-group-exchange hashes additional fields */ -#ifdef LIBSSH2_DH_GEX_NEW - _libssh2_htonu32(exchange_state->h_sig_comp, - LIBSSH2_DH_GEX_MINGROUP); - _libssh2_htonu32(exchange_state->h_sig_comp + 4, - LIBSSH2_DH_GEX_OPTGROUP); - _libssh2_htonu32(exchange_state->h_sig_comp + 8, - LIBSSH2_DH_GEX_MAXGROUP); - libssh2_sha1_update(exchange_state->exchange_hash, - exchange_state->h_sig_comp, 12); -#else - _libssh2_htonu32(exchange_state->h_sig_comp, - LIBSSH2_DH_GEX_OPTGROUP); - libssh2_sha1_update(exchange_state->exchange_hash, - exchange_state->h_sig_comp, 4); -#endif - } - - if (midhash) { - libssh2_sha1_update(exchange_state->exchange_hash, midhash, - midhash_len); - } - - libssh2_sha1_update(exchange_state->exchange_hash, - exchange_state->e_packet + 1, - exchange_state->e_packet_len - 1); - - _libssh2_htonu32(exchange_state->h_sig_comp, - exchange_state->f_value_len); - libssh2_sha1_update(exchange_state->exchange_hash, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_state->exchange_hash, - exchange_state->f_value, - exchange_state->f_value_len); - - libssh2_sha1_update(exchange_state->exchange_hash, - exchange_state->k_value, - exchange_state->k_value_len); - - libssh2_sha1_final(exchange_state->exchange_hash, - exchange_state->h_sig_comp); - - if (session->hostkey-> - sig_verify(session, exchange_state->h_sig, - exchange_state->h_sig_len, exchange_state->h_sig_comp, - 20, &session->server_hostkey_abstract)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, - "Unable to verify hostkey signature"); - goto clean_exit; - } - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending NEWKEYS message"); - exchange_state->c = SSH_MSG_NEWKEYS; - - exchange_state->state = libssh2_NB_state_sent2; - } - - if (exchange_state->state == libssh2_NB_state_sent2) { - rc = _libssh2_transport_send(session, &exchange_state->c, 1, NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - ret = _libssh2_error(session, rc, "Unable to send NEWKEYS message"); - goto clean_exit; - } - - exchange_state->state = libssh2_NB_state_sent3; - } - - if (exchange_state->state == libssh2_NB_state_sent3) { - rc = _libssh2_packet_require(session, SSH_MSG_NEWKEYS, - &exchange_state->tmp, - &exchange_state->tmp_len, 0, NULL, 0, - &exchange_state->req_state); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - ret = _libssh2_error(session, rc, "Timed out waiting for NEWKEYS"); - goto clean_exit; - } - /* The first key exchange has been performed, - switch to active crypt/comp/mac mode */ - session->state |= LIBSSH2_STATE_NEWKEYS; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message"); - - /* This will actually end up being just packet_type(1) - for this packet type anyway */ - LIBSSH2_FREE(session, exchange_state->tmp); - - if (!session->session_id) { - session->session_id = LIBSSH2_ALLOC(session, SHA_DIGEST_LENGTH); - if (!session->session_id) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate buffer for SHA digest"); - goto clean_exit; - } - memcpy(session->session_id, exchange_state->h_sig_comp, - SHA_DIGEST_LENGTH); - session->session_id_len = SHA_DIGEST_LENGTH; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "session_id calculated"); - } - - /* Cleanup any existing cipher */ - if (session->local.crypt->dtor) { - session->local.crypt->dtor(session, - &session->local.crypt_abstract); - } - - /* Calculate IV/Secret/Key for each direction */ - if (session->local.crypt->init) { - unsigned char *iv = NULL, *secret = NULL; - int free_iv = 0, free_secret = 0; - - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, - session->local.crypt-> - iv_len, "A"); - if (!iv) { - ret = -1; - goto clean_exit; - } - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, - session->local.crypt-> - secret_len, "C"); - if (!secret) { - LIBSSH2_FREE(session, iv); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - if (session->local.crypt-> - init(session, session->local.crypt, iv, &free_iv, secret, - &free_secret, 1, &session->local.crypt_abstract)) { - LIBSSH2_FREE(session, iv); - LIBSSH2_FREE(session, secret); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - - if (free_iv) { - memset(iv, 0, session->local.crypt->iv_len); - LIBSSH2_FREE(session, iv); - } - - if (free_secret) { - memset(secret, 0, session->local.crypt->secret_len); - LIBSSH2_FREE(session, secret); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server IV and Key calculated"); - - if (session->remote.crypt->dtor) { - /* Cleanup any existing cipher */ - session->remote.crypt->dtor(session, - &session->remote.crypt_abstract); - } - - if (session->remote.crypt->init) { - unsigned char *iv = NULL, *secret = NULL; - int free_iv = 0, free_secret = 0; - - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, - session->remote.crypt-> - iv_len, "B"); - if (!iv) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, - session->remote.crypt-> - secret_len, "D"); - if (!secret) { - LIBSSH2_FREE(session, iv); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - if (session->remote.crypt-> - init(session, session->remote.crypt, iv, &free_iv, secret, - &free_secret, 0, &session->remote.crypt_abstract)) { - LIBSSH2_FREE(session, iv); - LIBSSH2_FREE(session, secret); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - - if (free_iv) { - memset(iv, 0, session->remote.crypt->iv_len); - LIBSSH2_FREE(session, iv); - } - - if (free_secret) { - memset(secret, 0, session->remote.crypt->secret_len); - LIBSSH2_FREE(session, secret); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client IV and Key calculated"); - - if (session->local.mac->dtor) { - session->local.mac->dtor(session, &session->local.mac_abstract); - } - - if (session->local.mac->init) { - unsigned char *key = NULL; - int free_key = 0; - - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, - session->local.mac-> - key_len, "E"); - if (!key) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - session->local.mac->init(session, key, &free_key, - &session->local.mac_abstract); - - if (free_key) { - memset(key, 0, session->local.mac->key_len); - LIBSSH2_FREE(session, key); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server HMAC Key calculated"); - - if (session->remote.mac->dtor) { - session->remote.mac->dtor(session, &session->remote.mac_abstract); - } - - if (session->remote.mac->init) { - unsigned char *key = NULL; - int free_key = 0; - - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, - session->remote.mac-> - key_len, "F"); - if (!key) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - session->remote.mac->init(session, key, &free_key, - &session->remote.mac_abstract); - - if (free_key) { - memset(key, 0, session->remote.mac->key_len); - LIBSSH2_FREE(session, key); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client HMAC Key calculated"); - - /* Initialize compression for each direction */ - - /* Cleanup any existing compression */ - if (session->local.comp && session->local.comp->dtor) { - session->local.comp->dtor(session, 1, - &session->local.comp_abstract); - } - - if (session->local.comp && session->local.comp->init) { - if (session->local.comp->init(session, 1, - &session->local.comp_abstract)) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server compression initialized"); - - if (session->remote.comp && session->remote.comp->dtor) { - session->remote.comp->dtor(session, 0, - &session->remote.comp_abstract); - } - - if (session->remote.comp && session->remote.comp->init) { - if (session->remote.comp->init(session, 0, - &session->remote.comp_abstract)) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client compression initialized"); - - } - - clean_exit: - _libssh2_bn_free(exchange_state->x); - exchange_state->x = NULL; - _libssh2_bn_free(exchange_state->e); - exchange_state->e = NULL; - _libssh2_bn_free(exchange_state->f); - exchange_state->f = NULL; - _libssh2_bn_free(exchange_state->k); - exchange_state->k = NULL; - _libssh2_bn_ctx_free(exchange_state->ctx); - exchange_state->ctx = NULL; - - if (exchange_state->e_packet) { - LIBSSH2_FREE(session, exchange_state->e_packet); - exchange_state->e_packet = NULL; - } - - if (exchange_state->s_packet) { - LIBSSH2_FREE(session, exchange_state->s_packet); - exchange_state->s_packet = NULL; - } - - if (exchange_state->k_value) { - LIBSSH2_FREE(session, exchange_state->k_value); - exchange_state->k_value = NULL; - } - - exchange_state->state = libssh2_NB_state_idle; - - return ret; -} - - - -/* kex_method_diffie_hellman_group1_sha1_key_exchange - * Diffie-Hellman Group1 (Actually Group2) Key Exchange using SHA1 - */ -static int -kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *session, - key_exchange_state_low_t - * key_state) -{ - static const unsigned char p_value[128] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, - 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, - 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, - 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, - 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, - 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, - 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, - 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, - 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, - 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, - 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, - 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, - 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, - 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF - }; - - int ret; - - if (key_state->state == libssh2_NB_state_idle) { - /* g == 2 */ - key_state->p = _libssh2_bn_init(); /* SSH2 defined value (p_value) */ - key_state->g = _libssh2_bn_init(); /* SSH2 defined value (2) */ - - /* Initialize P and G */ - _libssh2_bn_set_word(key_state->g, 2); - _libssh2_bn_from_bin(key_state->p, 128, p_value); - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group1 Key Exchange"); - - key_state->state = libssh2_NB_state_created; - } - ret = diffie_hellman_sha1(session, key_state->g, key_state->p, 128, - SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, - NULL, 0, &key_state->exchange_state); - if (ret == LIBSSH2_ERROR_EAGAIN) { - return ret; - } - - _libssh2_bn_free(key_state->p); - key_state->p = NULL; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; - key_state->state = libssh2_NB_state_idle; - - return ret; -} - - - -/* kex_method_diffie_hellman_group14_sha1_key_exchange - * Diffie-Hellman Group14 Key Exchange using SHA1 - */ -static int -kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *session, - key_exchange_state_low_t - * key_state) -{ - static const unsigned char p_value[256] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, - 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, - 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, - 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, - 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, - 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, - 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, - 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, - 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, - 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, - 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, - 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, - 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, - 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, - 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, - 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, - 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, - 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, - 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, - 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, - 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, - 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, - 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, - 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, - 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, - 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, - 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, - 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, - 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, - 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF - }; - int ret; - - if (key_state->state == libssh2_NB_state_idle) { - key_state->p = _libssh2_bn_init(); /* SSH2 defined value (p_value) */ - key_state->g = _libssh2_bn_init(); /* SSH2 defined value (2) */ - - /* g == 2 */ - /* Initialize P and G */ - _libssh2_bn_set_word(key_state->g, 2); - _libssh2_bn_from_bin(key_state->p, 256, p_value); - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group14 Key Exchange"); - - key_state->state = libssh2_NB_state_created; - } - ret = diffie_hellman_sha1(session, key_state->g, key_state->p, - 256, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, - NULL, 0, &key_state->exchange_state); - if (ret == LIBSSH2_ERROR_EAGAIN) { - return ret; - } - - key_state->state = libssh2_NB_state_idle; - _libssh2_bn_free(key_state->p); - key_state->p = NULL; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; - - return ret; -} - - - -/* kex_method_diffie_hellman_group_exchange_sha1_key_exchange - * Diffie-Hellman Group Exchange Key Exchange using SHA1 - * Negotiates random(ish) group for secret derivation - */ -static int -kex_method_diffie_hellman_group_exchange_sha1_key_exchange -(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) -{ - unsigned long p_len, g_len; - int ret = 0; - int rc; - - if (key_state->state == libssh2_NB_state_idle) { - key_state->p = _libssh2_bn_init(); - key_state->g = _libssh2_bn_init(); - /* Ask for a P and G pair */ -#ifdef LIBSSH2_DH_GEX_NEW - key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST; - _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_MINGROUP); - _libssh2_htonu32(key_state->request + 5, LIBSSH2_DH_GEX_OPTGROUP); - _libssh2_htonu32(key_state->request + 9, LIBSSH2_DH_GEX_MAXGROUP); - key_state->request_len = 13; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group-Exchange (New Method)"); -#else - key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD; - _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_OPTGROUP); - key_state->request_len = 5; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group-Exchange (Old Method)"); -#endif - - key_state->state = libssh2_NB_state_created; - } - - if (key_state->state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, key_state->request, - key_state->request_len, NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - ret = _libssh2_error(session, rc, - "Unable to send Group Exchange Request"); - goto dh_gex_clean_exit; - } - - key_state->state = libssh2_NB_state_sent; - } - - if (key_state->state == libssh2_NB_state_sent) { - rc = _libssh2_packet_require(session, SSH_MSG_KEX_DH_GEX_GROUP, - &key_state->data, &key_state->data_len, - 0, NULL, 0, &key_state->req_state); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - ret = _libssh2_error(session, rc, - "Timeout waiting for GEX_GROUP reply"); - goto dh_gex_clean_exit; - } - - key_state->state = libssh2_NB_state_sent1; - } - - if (key_state->state == libssh2_NB_state_sent1) { - unsigned char *s = key_state->data + 1; - p_len = _libssh2_ntohu32(s); - s += 4; - _libssh2_bn_from_bin(key_state->p, p_len, s); - s += p_len; - - g_len = _libssh2_ntohu32(s); - s += 4; - _libssh2_bn_from_bin(key_state->g, g_len, s); - - ret = diffie_hellman_sha1(session, key_state->g, key_state->p, p_len, - SSH_MSG_KEX_DH_GEX_INIT, - SSH_MSG_KEX_DH_GEX_REPLY, - key_state->data + 1, - key_state->data_len - 1, - &key_state->exchange_state); - if (ret == LIBSSH2_ERROR_EAGAIN) { - return ret; - } - - LIBSSH2_FREE(session, key_state->data); - } - - dh_gex_clean_exit: - key_state->state = libssh2_NB_state_idle; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; - _libssh2_bn_free(key_state->p); - key_state->p = NULL; - - return ret; -} - - - -#define LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY 0x0001 -#define LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY 0x0002 - -static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group1_sha1 = { - "diffie-hellman-group1-sha1", - kex_method_diffie_hellman_group1_sha1_key_exchange, - LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, -}; - -static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group14_sha1 = { - "diffie-hellman-group14-sha1", - kex_method_diffie_hellman_group14_sha1_key_exchange, - LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, -}; - -static const LIBSSH2_KEX_METHOD -kex_method_diffie_helman_group_exchange_sha1 = { - "diffie-hellman-group-exchange-sha1", - kex_method_diffie_hellman_group_exchange_sha1_key_exchange, - LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, -}; - -static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = { - &kex_method_diffie_helman_group14_sha1, - &kex_method_diffie_helman_group_exchange_sha1, - &kex_method_diffie_helman_group1_sha1, - NULL -}; - -typedef struct _LIBSSH2_COMMON_METHOD -{ - const char *name; -} LIBSSH2_COMMON_METHOD; - -/* kex_method_strlen - * Calculate the length of a particular method list's resulting string - * Includes SUM(strlen() of each individual method plus 1 (for coma)) - 1 (because the last coma isn't used) - * Another sign of bad coding practices gone mad. Pretend you don't see this. - */ -static size_t -kex_method_strlen(LIBSSH2_COMMON_METHOD ** method) -{ - size_t len = 0; - - if (!method || !*method) { - return 0; - } - - while (*method && (*method)->name) { - len += strlen((*method)->name) + 1; - method++; - } - - return len - 1; -} - - - -/* kex_method_list - * Generate formatted preference list in buf - */ -static size_t -kex_method_list(unsigned char *buf, size_t list_strlen, - LIBSSH2_COMMON_METHOD ** method) -{ - _libssh2_htonu32(buf, list_strlen); - buf += 4; - - if (!method || !*method) { - return 4; - } - - while (*method && (*method)->name) { - int mlen = strlen((*method)->name); - memcpy(buf, (*method)->name, mlen); - buf += mlen; - *(buf++) = ','; - method++; - } - - return list_strlen + 4; -} - - - -#define LIBSSH2_METHOD_PREFS_LEN(prefvar, defaultvar) \ - ((prefvar) ? strlen(prefvar) : \ - kex_method_strlen((LIBSSH2_COMMON_METHOD**)(defaultvar))) - -#define LIBSSH2_METHOD_PREFS_STR(buf, prefvarlen, prefvar, defaultvar) \ - if (prefvar) { \ - _libssh2_htonu32((buf), (prefvarlen)); \ - buf += 4; \ - memcpy((buf), (prefvar), (prefvarlen)); \ - buf += (prefvarlen); \ - } else { \ - buf += kex_method_list((buf), (prefvarlen), \ - (LIBSSH2_COMMON_METHOD**)(defaultvar)); \ - } - -/* kexinit - * Send SSH_MSG_KEXINIT packet - */ -static int kexinit(LIBSSH2_SESSION * session) -{ - /* 62 = packet_type(1) + cookie(16) + first_packet_follows(1) + - reserved(4) + length longs(40) */ - size_t data_len = 62; - size_t kex_len, hostkey_len = 0; - size_t crypt_cs_len, crypt_sc_len; - size_t comp_cs_len, comp_sc_len; - size_t mac_cs_len, mac_sc_len; - size_t lang_cs_len, lang_sc_len; - unsigned char *data, *s; - int rc; - - if (session->kexinit_state == libssh2_NB_state_idle) { - kex_len = - LIBSSH2_METHOD_PREFS_LEN(session->kex_prefs, libssh2_kex_methods); - hostkey_len = - LIBSSH2_METHOD_PREFS_LEN(session->hostkey_prefs, - libssh2_hostkey_methods()); - crypt_cs_len = - LIBSSH2_METHOD_PREFS_LEN(session->local.crypt_prefs, - libssh2_crypt_methods()); - crypt_sc_len = - LIBSSH2_METHOD_PREFS_LEN(session->remote.crypt_prefs, - libssh2_crypt_methods()); - mac_cs_len = - LIBSSH2_METHOD_PREFS_LEN(session->local.mac_prefs, - _libssh2_mac_methods()); - mac_sc_len = - LIBSSH2_METHOD_PREFS_LEN(session->remote.mac_prefs, - _libssh2_mac_methods()); - comp_cs_len = - LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs, - _libssh2_comp_methods(session)); - comp_sc_len = - LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs, - _libssh2_comp_methods(session)); - lang_cs_len = - LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL); - lang_sc_len = - LIBSSH2_METHOD_PREFS_LEN(session->remote.lang_prefs, NULL); - - data_len += kex_len + hostkey_len + crypt_cs_len + crypt_sc_len + - comp_cs_len + comp_sc_len + mac_cs_len + mac_sc_len + - lang_cs_len + lang_sc_len; - - s = data = LIBSSH2_ALLOC(session, data_len); - if (!data) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory"); - } - - *(s++) = SSH_MSG_KEXINIT; - - _libssh2_random(s, 16); - s += 16; - - /* Ennumerating through these lists twice is probably (certainly?) - inefficient from a CPU standpoint, but it saves multiple - malloc/realloc calls */ - LIBSSH2_METHOD_PREFS_STR(s, kex_len, session->kex_prefs, - libssh2_kex_methods); - LIBSSH2_METHOD_PREFS_STR(s, hostkey_len, session->hostkey_prefs, - libssh2_hostkey_methods()); - LIBSSH2_METHOD_PREFS_STR(s, crypt_cs_len, session->local.crypt_prefs, - libssh2_crypt_methods()); - LIBSSH2_METHOD_PREFS_STR(s, crypt_sc_len, session->remote.crypt_prefs, - libssh2_crypt_methods()); - LIBSSH2_METHOD_PREFS_STR(s, mac_cs_len, session->local.mac_prefs, - _libssh2_mac_methods()); - LIBSSH2_METHOD_PREFS_STR(s, mac_sc_len, session->remote.mac_prefs, - _libssh2_mac_methods()); - LIBSSH2_METHOD_PREFS_STR(s, comp_cs_len, session->local.comp_prefs, - _libssh2_comp_methods(session)); - LIBSSH2_METHOD_PREFS_STR(s, comp_sc_len, session->remote.comp_prefs, - _libssh2_comp_methods(session)); - LIBSSH2_METHOD_PREFS_STR(s, lang_cs_len, session->local.lang_prefs, - NULL); - LIBSSH2_METHOD_PREFS_STR(s, lang_sc_len, session->remote.lang_prefs, - NULL); - - /* No optimistic KEX packet follows */ - /* Deal with optimistic packets - * session->flags |= KEXINIT_OPTIMISTIC - * session->flags |= KEXINIT_METHODSMATCH - */ - *(s++) = 0; - - /* Reserved == 0 */ - _libssh2_htonu32(s, 0); - -#ifdef LIBSSH2DEBUG - { - /* Funnily enough, they'll all "appear" to be '\0' terminated */ - unsigned char *p = data + 21; /* type(1) + cookie(16) + len(4) */ - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent KEX: %s", p); - p += kex_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent HOSTKEY: %s", p); - p += hostkey_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent CRYPT_CS: %s", p); - p += crypt_cs_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent CRYPT_SC: %s", p); - p += crypt_sc_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent MAC_CS: %s", p); - p += mac_cs_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent MAC_SC: %s", p); - p += mac_sc_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent COMP_CS: %s", p); - p += comp_cs_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent COMP_SC: %s", p); - p += comp_sc_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent LANG_CS: %s", p); - p += lang_cs_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent LANG_SC: %s", p); - p += lang_sc_len + 4; - } -#endif /* LIBSSH2DEBUG */ - - session->kexinit_state = libssh2_NB_state_created; - } else { - data = session->kexinit_data; - data_len = session->kexinit_data_len; - /* zap the variables to ensure there is NOT a double free later */ - session->kexinit_data = NULL; - session->kexinit_data_len = 0; - } - - rc = _libssh2_transport_send(session, data, data_len, NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - session->kexinit_data = data; - session->kexinit_data_len = data_len; - return rc; - } - else if (rc) { - LIBSSH2_FREE(session, data); - session->kexinit_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Unable to send KEXINIT packet to remote host"); - - } - - if (session->local.kexinit) { - LIBSSH2_FREE(session, session->local.kexinit); - } - - session->local.kexinit = data; - session->local.kexinit_len = data_len; - - session->kexinit_state = libssh2_NB_state_idle; - - return 0; -} - -/* kex_agree_instr - * Kex specific variant of strstr() - * Needle must be preceed by BOL or ',', and followed by ',' or EOL - */ -static unsigned char * -kex_agree_instr(unsigned char *haystack, unsigned long haystack_len, - const unsigned char *needle, unsigned long needle_len) -{ - unsigned char *s; - - /* Haystack too short to bother trying */ - if (haystack_len < needle_len) { - return NULL; - } - - /* Needle at start of haystack */ - if ((strncmp((char *) haystack, (char *) needle, needle_len) == 0) && - (needle_len == haystack_len || haystack[needle_len] == ',')) { - return haystack; - } - - s = haystack; - /* Search until we run out of comas or we run out of haystack, - whichever comes first */ - while ((s = (unsigned char *) strchr((char *) s, ',')) - && ((haystack_len - (s - haystack)) > needle_len)) { - s++; - /* Needle at X position */ - if ((strncmp((char *) s, (char *) needle, needle_len) == 0) && - (((s - haystack) + needle_len) == haystack_len - || s[needle_len] == ',')) { - return s; - } - } - - return NULL; -} - - - -/* kex_get_method_by_name - */ -static const LIBSSH2_COMMON_METHOD * -kex_get_method_by_name(const char *name, size_t name_len, - const LIBSSH2_COMMON_METHOD ** methodlist) -{ - while (*methodlist) { - if ((strlen((*methodlist)->name) == name_len) && - (strncmp((*methodlist)->name, name, name_len) == 0)) { - return *methodlist; - } - methodlist++; - } - return NULL; -} - - - -/* kex_agree_hostkey - * Agree on a Hostkey which works with this kex - */ -static int kex_agree_hostkey(LIBSSH2_SESSION * session, - unsigned long kex_flags, - unsigned char *hostkey, unsigned long hostkey_len) -{ - const LIBSSH2_HOSTKEY_METHOD **hostkeyp = libssh2_hostkey_methods(); - unsigned char *s; - - if (session->hostkey_prefs) { - s = (unsigned char *) session->hostkey_prefs; - - while (s && *s) { - unsigned char *p = (unsigned char *) strchr((char *) s, ','); - size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); - if (kex_agree_instr(hostkey, hostkey_len, s, method_len)) { - const LIBSSH2_HOSTKEY_METHOD *method = - (const LIBSSH2_HOSTKEY_METHOD *) - kex_get_method_by_name((char *) s, method_len, - (const LIBSSH2_COMMON_METHOD **) - hostkeyp); - - if (!method) { - /* Invalid method -- Should never be reached */ - return -1; - } - - /* So far so good, but does it suit our purposes? (Encrypting - vs Signing) */ - if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) == - 0) || (method->encrypt)) { - /* Either this hostkey can do encryption or this kex just - doesn't require it */ - if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY) - == 0) || (method->sig_verify)) { - /* Either this hostkey can do signing or this kex just - doesn't require it */ - session->hostkey = method; - return 0; - } - } - } - - s = p ? p + 1 : NULL; - } - return -1; - } - - while (hostkeyp && (*hostkeyp) && (*hostkeyp)->name) { - s = kex_agree_instr(hostkey, hostkey_len, - (unsigned char *) (*hostkeyp)->name, - strlen((*hostkeyp)->name)); - if (s) { - /* So far so good, but does it suit our purposes? (Encrypting vs - Signing) */ - if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) == 0) || - ((*hostkeyp)->encrypt)) { - /* Either this hostkey can do encryption or this kex just - doesn't require it */ - if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY) == - 0) || ((*hostkeyp)->sig_verify)) { - /* Either this hostkey can do signing or this kex just - doesn't require it */ - session->hostkey = *hostkeyp; - return 0; - } - } - } - hostkeyp++; - } - - return -1; -} - - - -/* kex_agree_kex_hostkey - * Agree on a Key Exchange method and a hostkey encoding type - */ -static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex, - unsigned long kex_len, unsigned char *hostkey, - unsigned long hostkey_len) -{ - const LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods; - unsigned char *s; - - if (session->kex_prefs) { - s = (unsigned char *) session->kex_prefs; - - while (s && *s) { - unsigned char *q, *p = (unsigned char *) strchr((char *) s, ','); - size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); - if ((q = kex_agree_instr(kex, kex_len, s, method_len))) { - const LIBSSH2_KEX_METHOD *method = (const LIBSSH2_KEX_METHOD *) - kex_get_method_by_name((char *) s, method_len, - (const LIBSSH2_COMMON_METHOD **) - kexp); - - if (!method) { - /* Invalid method -- Should never be reached */ - return -1; - } - - /* We've agreed on a key exchange method, - * Can we agree on a hostkey that works with this kex? - */ - if (kex_agree_hostkey(session, method->flags, hostkey, - hostkey_len) == 0) { - session->kex = method; - if (session->burn_optimistic_kexinit && (kex == q)) { - /* Server sent an optimistic packet, - * and client agrees with preference - * cancel burning the first KEX_INIT packet that comes in */ - session->burn_optimistic_kexinit = 0; - } - return 0; - } - } - - s = p ? p + 1 : NULL; - } - return -1; - } - - while (*kexp && (*kexp)->name) { - s = kex_agree_instr(kex, kex_len, - (unsigned char *) (*kexp)->name, - strlen((*kexp)->name)); - if (s) { - /* We've agreed on a key exchange method, - * Can we agree on a hostkey that works with this kex? - */ - if (kex_agree_hostkey(session, (*kexp)->flags, hostkey, - hostkey_len) == 0) { - session->kex = *kexp; - if (session->burn_optimistic_kexinit && (kex == s)) { - /* Server sent an optimistic packet, - * and client agrees with preference - * cancel burning the first KEX_INIT packet that comes in */ - session->burn_optimistic_kexinit = 0; - } - return 0; - } - } - kexp++; - } - return -1; -} - - - -/* kex_agree_crypt - * Agree on a cipher algo - */ -static int kex_agree_crypt(LIBSSH2_SESSION * session, - libssh2_endpoint_data *endpoint, - unsigned char *crypt, - unsigned long crypt_len) -{ - const LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods(); - unsigned char *s; - - (void) session; - - if (endpoint->crypt_prefs) { - s = (unsigned char *) endpoint->crypt_prefs; - - while (s && *s) { - unsigned char *p = (unsigned char *) strchr((char *) s, ','); - size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); - - if (kex_agree_instr(crypt, crypt_len, s, method_len)) { - const LIBSSH2_CRYPT_METHOD *method = - (const LIBSSH2_CRYPT_METHOD *) - kex_get_method_by_name((char *) s, method_len, - (const LIBSSH2_COMMON_METHOD **) - cryptp); - - if (!method) { - /* Invalid method -- Should never be reached */ - return -1; - } - - endpoint->crypt = method; - return 0; - } - - s = p ? p + 1 : NULL; - } - return -1; - } - - while (*cryptp && (*cryptp)->name) { - s = kex_agree_instr(crypt, crypt_len, - (unsigned char *) (*cryptp)->name, - strlen((*cryptp)->name)); - if (s) { - endpoint->crypt = *cryptp; - return 0; - } - cryptp++; - } - - return -1; -} - - - -/* kex_agree_mac - * Agree on a message authentication hash - */ -static int kex_agree_mac(LIBSSH2_SESSION * session, - libssh2_endpoint_data * endpoint, unsigned char *mac, - unsigned long mac_len) -{ - const LIBSSH2_MAC_METHOD **macp = _libssh2_mac_methods(); - unsigned char *s; - (void) session; - - if (endpoint->mac_prefs) { - s = (unsigned char *) endpoint->mac_prefs; - - while (s && *s) { - unsigned char *p = (unsigned char *) strchr((char *) s, ','); - size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); - - if (kex_agree_instr(mac, mac_len, s, method_len)) { - const LIBSSH2_MAC_METHOD *method = (const LIBSSH2_MAC_METHOD *) - kex_get_method_by_name((char *) s, method_len, - (const LIBSSH2_COMMON_METHOD **) - macp); - - if (!method) { - /* Invalid method -- Should never be reached */ - return -1; - } - - endpoint->mac = method; - return 0; - } - - s = p ? p + 1 : NULL; - } - return -1; - } - - while (*macp && (*macp)->name) { - s = kex_agree_instr(mac, mac_len, (unsigned char *) (*macp)->name, - strlen((*macp)->name)); - if (s) { - endpoint->mac = *macp; - return 0; - } - macp++; - } - - return -1; -} - - - -/* kex_agree_comp - * Agree on a compression scheme - */ -static int kex_agree_comp(LIBSSH2_SESSION *session, - libssh2_endpoint_data *endpoint, unsigned char *comp, - unsigned long comp_len) -{ - const LIBSSH2_COMP_METHOD **compp = _libssh2_comp_methods(session); - unsigned char *s; - (void) session; - - if (endpoint->comp_prefs) { - s = (unsigned char *) endpoint->comp_prefs; - - while (s && *s) { - unsigned char *p = (unsigned char *) strchr((char *) s, ','); - size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); - - if (kex_agree_instr(comp, comp_len, s, method_len)) { - const LIBSSH2_COMP_METHOD *method = - (const LIBSSH2_COMP_METHOD *) - kex_get_method_by_name((char *) s, method_len, - (const LIBSSH2_COMMON_METHOD **) - compp); - - if (!method) { - /* Invalid method -- Should never be reached */ - return -1; - } - - endpoint->comp = method; - return 0; - } - - s = p ? p + 1 : NULL; - } - return -1; - } - - while (*compp && (*compp)->name) { - s = kex_agree_instr(comp, comp_len, (unsigned char *) (*compp)->name, - strlen((*compp)->name)); - if (s) { - endpoint->comp = *compp; - return 0; - } - compp++; - } - - return -1; -} - - - -/* TODO: When in server mode we need to turn this logic on its head - * The Client gets to make the final call on "agreed methods" - */ - -/* kex_agree_methods - * Decide which specific method to use of the methods offered by each party - */ -static int kex_agree_methods(LIBSSH2_SESSION * session, unsigned char *data, - unsigned data_len) -{ - unsigned char *kex, *hostkey, *crypt_cs, *crypt_sc, *comp_cs, *comp_sc, - *mac_cs, *mac_sc; - size_t kex_len, hostkey_len, crypt_cs_len, crypt_sc_len, comp_cs_len; - size_t comp_sc_len, mac_cs_len, mac_sc_len; - unsigned char *s = data; - - /* Skip packet_type, we know it already */ - s++; - - /* Skip cookie, don't worry, it's preserved in the kexinit field */ - s += 16; - - /* Locate each string */ - kex_len = _libssh2_ntohu32(s); - kex = s + 4; - s += 4 + kex_len; - hostkey_len = _libssh2_ntohu32(s); - hostkey = s + 4; - s += 4 + hostkey_len; - crypt_cs_len = _libssh2_ntohu32(s); - crypt_cs = s + 4; - s += 4 + crypt_cs_len; - crypt_sc_len = _libssh2_ntohu32(s); - crypt_sc = s + 4; - s += 4 + crypt_sc_len; - mac_cs_len = _libssh2_ntohu32(s); - mac_cs = s + 4; - s += 4 + mac_cs_len; - mac_sc_len = _libssh2_ntohu32(s); - mac_sc = s + 4; - s += 4 + mac_sc_len; - comp_cs_len = _libssh2_ntohu32(s); - comp_cs = s + 4; - s += 4 + comp_cs_len; - comp_sc_len = _libssh2_ntohu32(s); - comp_sc = s + 4; -#if 0 - s += 4 + comp_sc_len; - lang_cs_len = _libssh2_ntohu32(s); - lang_cs = s + 4; - s += 4 + lang_cs_len; - lang_sc_len = _libssh2_ntohu32(s); - lang_sc = s + 4; - s += 4 + lang_sc_len; -#endif - /* If the server sent an optimistic packet, assume that it guessed wrong. - * If the guess is determined to be right (by kex_agree_kex_hostkey) - * This flag will be reset to zero so that it's not ignored */ - session->burn_optimistic_kexinit = *(s++); - /* Next uint32 in packet is all zeros (reserved) */ - - if (data_len < (unsigned) (s - data)) - return -1; /* short packet */ - - if (kex_agree_kex_hostkey(session, kex, kex_len, hostkey, hostkey_len)) { - return -1; - } - - if (kex_agree_crypt(session, &session->local, crypt_cs, crypt_cs_len) - || kex_agree_crypt(session, &session->remote, crypt_sc, crypt_sc_len)) { - return -1; - } - - if (kex_agree_mac(session, &session->local, mac_cs, mac_cs_len) || - kex_agree_mac(session, &session->remote, mac_sc, mac_sc_len)) { - return -1; - } - - if (kex_agree_comp(session, &session->local, comp_cs, comp_cs_len) || - kex_agree_comp(session, &session->remote, comp_sc, comp_sc_len)) { - return -1; - } - -#if 0 - if (libssh2_kex_agree_lang(session, &session->local, lang_cs, lang_cs_len) - || libssh2_kex_agree_lang(session, &session->remote, lang_sc, - lang_sc_len)) { - return -1; - } -#endif - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on KEX method: %s", - session->kex->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on HOSTKEY method: %s", - session->hostkey->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on CRYPT_CS method: %s", - session->local.crypt->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on CRYPT_SC method: %s", - session->remote.crypt->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on MAC_CS method: %s", - session->local.mac->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on MAC_SC method: %s", - session->remote.mac->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on COMP_CS method: %s", - session->local.comp->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on COMP_SC method: %s", - session->remote.comp->name); - - return 0; -} - - - -/* _libssh2_kex_exchange - * Exchange keys - * Returns 0 on success, non-zero on failure - * - * Returns some errors without _libssh2_error() - */ -int -_libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, - key_exchange_state_t * key_state) -{ - int rc = 0; - int retcode; - - session->state |= LIBSSH2_STATE_KEX_ACTIVE; - - if (key_state->state == libssh2_NB_state_idle) { - /* Prevent loop in packet_add() */ - session->state |= LIBSSH2_STATE_EXCHANGING_KEYS; - - if (reexchange) { - session->kex = NULL; - - if (session->hostkey && session->hostkey->dtor) { - session->hostkey->dtor(session, - &session->server_hostkey_abstract); - } - session->hostkey = NULL; - } - - key_state->state = libssh2_NB_state_created; - } - - if (!session->kex || !session->hostkey) { - if (key_state->state == libssh2_NB_state_created) { - /* Preserve in case of failure */ - key_state->oldlocal = session->local.kexinit; - key_state->oldlocal_len = session->local.kexinit_len; - - session->local.kexinit = NULL; - - key_state->state = libssh2_NB_state_sent; - } - - if (key_state->state == libssh2_NB_state_sent) { - retcode = kexinit(session); - if (retcode == LIBSSH2_ERROR_EAGAIN) { - session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; - return retcode; - } else if (retcode) { - session->local.kexinit = key_state->oldlocal; - session->local.kexinit_len = key_state->oldlocal_len; - key_state->state = libssh2_NB_state_idle; - session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; - session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS; - return -1; - } - - key_state->state = libssh2_NB_state_sent1; - } - - if (key_state->state == libssh2_NB_state_sent1) { - retcode = - _libssh2_packet_require(session, SSH_MSG_KEXINIT, - &key_state->data, - &key_state->data_len, 0, NULL, 0, - &key_state->req_state); - if (retcode == LIBSSH2_ERROR_EAGAIN) { - session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; - return retcode; - } - else if (retcode) { - if (session->local.kexinit) { - LIBSSH2_FREE(session, session->local.kexinit); - } - session->local.kexinit = key_state->oldlocal; - session->local.kexinit_len = key_state->oldlocal_len; - key_state->state = libssh2_NB_state_idle; - session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; - session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS; - return -1; - } - - if (session->remote.kexinit) { - LIBSSH2_FREE(session, session->remote.kexinit); - } - session->remote.kexinit = key_state->data; - session->remote.kexinit_len = key_state->data_len; - - if (kex_agree_methods(session, key_state->data, - key_state->data_len)) - rc = LIBSSH2_ERROR_KEX_FAILURE; - - key_state->state = libssh2_NB_state_sent2; - } - } else { - key_state->state = libssh2_NB_state_sent2; - } - - if (rc == 0) { - if (key_state->state == libssh2_NB_state_sent2) { - retcode = session->kex->exchange_keys(session, - &key_state->key_state_low); - if (retcode == LIBSSH2_ERROR_EAGAIN) { - session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; - return retcode; - } else if (retcode) { - rc = _libssh2_error(session, LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE, - "Unrecoverable error exchanging keys"); - } - } - } - - /* Done with kexinit buffers */ - if (session->local.kexinit) { - LIBSSH2_FREE(session, session->local.kexinit); - session->local.kexinit = NULL; - } - if (session->remote.kexinit) { - LIBSSH2_FREE(session, session->remote.kexinit); - session->remote.kexinit = NULL; - } - - session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; - session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS; - - key_state->state = libssh2_NB_state_idle; - - return rc; -} - - - -/* libssh2_session_method_pref - * Set preferred method - */ -LIBSSH2_API int -libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, - const char *prefs) -{ - char **prefvar, *s, *newprefs; - int prefs_len = strlen(prefs); - const LIBSSH2_COMMON_METHOD **mlist; - - switch (method_type) { - case LIBSSH2_METHOD_KEX: - prefvar = &session->kex_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods; - break; - - case LIBSSH2_METHOD_HOSTKEY: - prefvar = &session->hostkey_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods(); - break; - - case LIBSSH2_METHOD_CRYPT_CS: - prefvar = &session->local.crypt_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods(); - break; - - case LIBSSH2_METHOD_CRYPT_SC: - prefvar = &session->remote.crypt_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods(); - break; - - case LIBSSH2_METHOD_MAC_CS: - prefvar = &session->local.mac_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods(); - break; - - case LIBSSH2_METHOD_MAC_SC: - prefvar = &session->remote.mac_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods(); - break; - - case LIBSSH2_METHOD_COMP_CS: - prefvar = &session->local.comp_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) - _libssh2_comp_methods(session); - break; - - case LIBSSH2_METHOD_COMP_SC: - prefvar = &session->remote.comp_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) - _libssh2_comp_methods(session); - break; - - case LIBSSH2_METHOD_LANG_CS: - prefvar = &session->local.lang_prefs; - mlist = NULL; - break; - - case LIBSSH2_METHOD_LANG_SC: - prefvar = &session->remote.lang_prefs; - mlist = NULL; - break; - - default: - return _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "Invalid parameter specified for method_type"); - } - - s = newprefs = LIBSSH2_ALLOC(session, prefs_len + 1); - if (!newprefs) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Error allocated space for method preferences"); - } - memcpy(s, prefs, prefs_len + 1); - - while (s && *s) { - char *p = strchr(s, ','); - int method_len = p ? (p - s) : (int) strlen(s); - - if (!kex_get_method_by_name(s, method_len, mlist)) { - /* Strip out unsupported method */ - if (p) { - memcpy(s, p + 1, strlen(s) - method_len); - } else { - if (s > newprefs) { - *(--s) = '\0'; - } else { - *s = '\0'; - } - } - } - - s = p ? (p + 1) : NULL; - } - - if (strlen(newprefs) == 0) { - LIBSSH2_FREE(session, newprefs); - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "The requested method(s) are not currently " - "supported"); - } - - if (*prefvar) { - LIBSSH2_FREE(session, *prefvar); - } - *prefvar = newprefs; - - return 0; -} - -/* - * libssh2_session_supported_algs() - * returns a number of returned algorithms (a positive number) on success, - * a negative number on failure - */ - -LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session, - int method_type, - const char*** algs) -{ - unsigned int i; - unsigned int j; - unsigned int ialg; - const LIBSSH2_COMMON_METHOD **mlist; - - /* to prevent coredumps due to dereferencing of NULL */ - if (NULL == algs) - return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, - "algs must not be NULL"); - - switch (method_type) { - case LIBSSH2_METHOD_KEX: - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods; - break; - - case LIBSSH2_METHOD_HOSTKEY: - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods(); - break; - - case LIBSSH2_METHOD_CRYPT_CS: - case LIBSSH2_METHOD_CRYPT_SC: - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods(); - break; - - case LIBSSH2_METHOD_MAC_CS: - case LIBSSH2_METHOD_MAC_SC: - mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods(); - break; - - case LIBSSH2_METHOD_COMP_CS: - case LIBSSH2_METHOD_COMP_SC: - mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_comp_methods(session); - break; - - default: - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unknown method type"); - } /* switch */ - - /* weird situation */ - if (NULL==mlist) - return _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "No algorithm found"); - - /* - mlist is looped through twice. The first time to find the number od - supported algorithms (needed to allocate the proper size of array) and - the second time to actually copy the pointers. Typically this function - will not be called often (typically at the beginning of a session) and - the number of algorithms (i.e. niumber of iterations in one loop) will - not be high (typically it will not exceed 20) for quite a long time. - - So double looping really shouldn't be an issue and it is definitely a - better solution than reallocation several times. - */ - - /* count the number of supported algorithms */ - for ( i=0, ialg=0; NULL!=mlist[i]; i++) { - /* do not count fields with NULL name */ - if (mlist[i]->name) - ialg++; - } - - /* weird situation, no algorithm found */ - if (0==ialg) - return _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "No algorithm found"); - - /* allocate buffer */ - *algs = (const char**) LIBSSH2_ALLOC(session, ialg*sizeof(const char*)); - if ( NULL==*algs ) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Memory allocation failed"); - } - /* Past this point *algs must be deallocated in case of an error!! */ - - /* copy non-NULL pointers only */ - for ( i=0, j=0; NULL!=mlist[i] && jname ){ - /* maybe a weird situation but if it occurs, do not include NULL - pointers */ - continue; - } - - /* note that [] has higher priority than * (dereferencing) */ - (*algs)[j++] = mlist[i]->name; - } - - /* correct number of pointers copied? (test the code above) */ - if ( j!=ialg ) { - /* deallocate buffer */ - LIBSSH2_FREE(session, (void *)*algs); - *algs = NULL; - - return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, - "Internal error"); - } - - return ialg; -} diff --git a/vendor/libssh2-1.4.2/src/knownhost.c b/vendor/libssh2-1.4.2/src/knownhost.c deleted file mode 100644 index c58dfbb..0000000 --- a/vendor/libssh2-1.4.2/src/knownhost.c +++ /dev/null @@ -1,1146 +0,0 @@ -/* - * Copyright (c) 2009-2011 by Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" -#include "misc.h" - -struct known_host { - struct list_node node; - char *name; /* points to the name or the hash (allocated) */ - size_t name_len; /* needed for hashed data */ - int port; /* if non-zero, a specific port this key is for on this - host */ - int typemask; /* plain, sha1, custom, ... */ - char *salt; /* points to binary salt (allocated) */ - size_t salt_len; /* size of salt */ - char *key; /* the (allocated) associated key. This is kept base64 - encoded in memory. */ - char *comment; /* the (allocated) optional comment text, may be NULL */ - - /* this is the struct we expose externally */ - struct libssh2_knownhost external; -}; - -struct _LIBSSH2_KNOWNHOSTS -{ - LIBSSH2_SESSION *session; /* the session this "belongs to" */ - struct list_head head; -}; - -static void free_host(LIBSSH2_SESSION *session, struct known_host *entry) -{ - if(entry) { - if(entry->comment) - LIBSSH2_FREE(session, entry->comment); - if(entry->key) - LIBSSH2_FREE(session, entry->key); - if(entry->salt) - LIBSSH2_FREE(session, entry->salt); - if(entry->name) - LIBSSH2_FREE(session, entry->name); - LIBSSH2_FREE(session, entry); - } -} - -/* - * libssh2_knownhost_init - * - * Init a collection of known hosts. Returns the pointer to a collection. - * - */ -LIBSSH2_API LIBSSH2_KNOWNHOSTS * -libssh2_knownhost_init(LIBSSH2_SESSION *session) -{ - LIBSSH2_KNOWNHOSTS *knh = - LIBSSH2_ALLOC(session, sizeof(struct _LIBSSH2_KNOWNHOSTS)); - - if(!knh) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for known-hosts " - "collection"); - return NULL; - } - - knh->session = session; - - _libssh2_list_init(&knh->head); - - return knh; -} - -#define KNOWNHOST_MAGIC 0xdeadcafe -/* - * knownhost_to_external() - * - * Copies data from the internal to the external representation struct. - * - */ -static struct libssh2_knownhost *knownhost_to_external(struct known_host *node) -{ - struct libssh2_knownhost *ext = &node->external; - - ext->magic = KNOWNHOST_MAGIC; - ext->node = node; - ext->name = ((node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) == - LIBSSH2_KNOWNHOST_TYPE_PLAIN)? node->name:NULL; - ext->key = node->key; - ext->typemask = node->typemask; - - return ext; -} - -static int -knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, const char *salt, - const char *key, size_t keylen, - const char *comment, size_t commentlen, - int typemask, struct libssh2_knownhost **store) -{ - struct known_host *entry; - size_t hostlen = strlen(host); - int rc; - char *ptr; - unsigned int ptrlen; - - /* make sure we have a key type set */ - if(!(typemask & LIBSSH2_KNOWNHOST_KEY_MASK)) - return _libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL, - "No key type set"); - - if(!(entry = LIBSSH2_ALLOC(hosts->session, sizeof(struct known_host)))) - return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for known host " - "entry"); - - memset(entry, 0, sizeof(struct known_host)); - - entry->typemask = typemask; - - switch(entry->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) { - case LIBSSH2_KNOWNHOST_TYPE_PLAIN: - case LIBSSH2_KNOWNHOST_TYPE_CUSTOM: - entry->name = LIBSSH2_ALLOC(hosts->session, hostlen+1); - if(!entry->name) { - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for host name"); - goto error; - } - memcpy(entry->name, host, hostlen+1); - break; - case LIBSSH2_KNOWNHOST_TYPE_SHA1: - rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen, - host, hostlen); - if(rc) - goto error; - entry->name = ptr; - entry->name_len = ptrlen; - - rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen, - salt, strlen(salt)); - if(rc) - goto error; - entry->salt = ptr; - entry->salt_len = ptrlen; - break; - default: - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unknown host name type"); - goto error; - } - - if(typemask & LIBSSH2_KNOWNHOST_KEYENC_BASE64) { - /* the provided key is base64 encoded already */ - if(!keylen) - keylen = strlen(key); - entry->key = LIBSSH2_ALLOC(hosts->session, keylen+1); - if(!entry->key) { - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for key"); - goto error; - } - memcpy(entry->key, key, keylen+1); - entry->key[keylen]=0; /* force a terminating zero trailer */ - } - else { - /* key is raw, we base64 encode it and store it as such */ - size_t nlen = _libssh2_base64_encode(hosts->session, key, keylen, - &ptr); - if(!nlen) { - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "base64-encoded key"); - goto error; - } - - entry->key = ptr; - } - - if (comment) { - entry->comment = LIBSSH2_ALLOC(hosts->session, commentlen+1); - if(!entry->comment) { - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for comment"); - goto error; - } - memcpy(entry->comment, comment, commentlen+1); - entry->comment[commentlen]=0; /* force a terminating zero trailer */ - } - else { - entry->comment = NULL; - } - - /* add this new host to the big list of known hosts */ - _libssh2_list_add(&hosts->head, &entry->node); - - if(store) - *store = knownhost_to_external(entry); - - return LIBSSH2_ERROR_NONE; - error: - free_host(hosts->session, entry); - return rc; -} - -/* - * libssh2_knownhost_add - * - * Add a host and its associated key to the collection of known hosts. - * - * The 'type' argument specifies on what format the given host and keys are: - * - * plain - ascii "hostname.domain.tld" - * sha1 - SHA1( ) base64-encoded! - * custom - another hash - * - * If 'sha1' is selected as type, the salt must be provided to the salt - * argument. This too base64 encoded. - * - * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If - * a custom type is used, salt is ignored and you must provide the host - * pre-hashed when checking for it in the libssh2_knownhost_check() function. - * - * The keylen parameter may be omitted (zero) if the key is provided as a - * NULL-terminated base64-encoded string. - */ - -LIBSSH2_API int -libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, const char *salt, - const char *key, size_t keylen, - int typemask, struct libssh2_knownhost **store) -{ - return knownhost_add(hosts, host, salt, key, keylen, NULL, 0, typemask, - store); -} - - -/* - * libssh2_knownhost_addc - * - * Add a host and its associated key to the collection of known hosts. - * - * Takes a comment argument that may be NULL. A NULL comment indicates - * there is no comment and the entry will end directly after the key - * when written out to a file. An empty string "" comment will indicate an - * empty comment which will cause a single space to be written after the key. - * - * The 'type' argument specifies on what format the given host and keys are: - * - * plain - ascii "hostname.domain.tld" - * sha1 - SHA1( ) base64-encoded! - * custom - another hash - * - * If 'sha1' is selected as type, the salt must be provided to the salt - * argument. This too base64 encoded. - * - * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If - * a custom type is used, salt is ignored and you must provide the host - * pre-hashed when checking for it in the libssh2_knownhost_check() function. - * - * The keylen parameter may be omitted (zero) if the key is provided as a - * NULL-terminated base64-encoded string. - */ - -LIBSSH2_API int -libssh2_knownhost_addc(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, const char *salt, - const char *key, size_t keylen, - const char *comment, size_t commentlen, - int typemask, struct libssh2_knownhost **store) -{ - return knownhost_add(hosts, host, salt, key, keylen, comment, commentlen, - typemask, store); -} - -/* - * knownhost_check - * - * Check a host and its associated key against the collection of known hosts. - * - * The typemask is the type/format of the given host name and key - * - * plain - ascii "hostname.domain.tld" - * sha1 - NOT SUPPORTED AS INPUT - * custom - prehashed base64 encoded. Note that this cannot use any salts. - * - * Returns: - * - * LIBSSH2_KNOWNHOST_CHECK_FAILURE - * LIBSSH2_KNOWNHOST_CHECK_NOTFOUND - * LIBSSH2_KNOWNHOST_CHECK_MATCH - * LIBSSH2_KNOWNHOST_CHECK_MISMATCH - */ -static int -knownhost_check(LIBSSH2_KNOWNHOSTS *hosts, - const char *hostp, int port, - const char *key, size_t keylen, - int typemask, - struct libssh2_knownhost **ext) -{ - struct known_host *node; - struct known_host *badkey = NULL; - int type = typemask & LIBSSH2_KNOWNHOST_TYPE_MASK; - char *keyalloc = NULL; - int rc = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND; - char hostbuff[270]; /* most host names can't be longer than like 256 */ - const char *host; - int numcheck; /* number of host combos to check */ - int match = 0; - - if(type == LIBSSH2_KNOWNHOST_TYPE_SHA1) - /* we can't work with a sha1 as given input */ - return LIBSSH2_KNOWNHOST_CHECK_MISMATCH; - - if(!(typemask & LIBSSH2_KNOWNHOST_KEYENC_BASE64)) { - /* we got a raw key input, convert it to base64 for the checks below */ - size_t nlen = _libssh2_base64_encode(hosts->session, key, keylen, - &keyalloc); - if(!nlen) { - _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for base64-encoded " - "key"); - return LIBSSH2_KNOWNHOST_CHECK_FAILURE; - } - - /* make the key point to this */ - key = keyalloc; - } - - /* if a port number is given, check for a '[host]:port' first before the - plain 'host' */ - if(port >= 0) { - snprintf(hostbuff, sizeof(hostbuff), "[%s]:%d", hostp, port); - host = hostbuff; - numcheck = 2; /* check both combos, start with this */ - } - else { - host = hostp; - numcheck = 1; /* only check this host version */ - } - - do { - node = _libssh2_list_first(&hosts->head); - while (node) { - switch(node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) { - case LIBSSH2_KNOWNHOST_TYPE_PLAIN: - if(type == LIBSSH2_KNOWNHOST_TYPE_PLAIN) - match = !strcmp(host, node->name); - break; - case LIBSSH2_KNOWNHOST_TYPE_CUSTOM: - if(type == LIBSSH2_KNOWNHOST_TYPE_CUSTOM) - match = !strcmp(host, node->name); - break; - case LIBSSH2_KNOWNHOST_TYPE_SHA1: - if(type == LIBSSH2_KNOWNHOST_TYPE_PLAIN) { - /* when we have the sha1 version stored, we can use a - plain input to produce a hash to compare with the - stored hash. - */ - libssh2_hmac_ctx ctx; - unsigned char hash[SHA_DIGEST_LENGTH]; - - if(SHA_DIGEST_LENGTH != node->name_len) { - /* the name hash length must be the sha1 size or - we can't match it */ - break; - } - libssh2_hmac_sha1_init(&ctx, node->salt, node->salt_len); - libssh2_hmac_update(ctx, (unsigned char *)host, - strlen(host)); - libssh2_hmac_final(ctx, hash); - libssh2_hmac_cleanup(&ctx); - - if(!memcmp(hash, node->name, SHA_DIGEST_LENGTH)) - /* this is a node we're interested in */ - match = 1; - } - break; - default: /* unsupported type */ - break; - } - if(match) { - /* host name match, now compare the keys */ - if(!strcmp(key, node->key)) { - /* they match! */ - if (ext) - *ext = knownhost_to_external(node); - badkey = NULL; - rc = LIBSSH2_KNOWNHOST_CHECK_MATCH; - break; - } - else { - /* remember the first node that had a host match but a - failed key match since we continue our search from - here */ - if(!badkey) - badkey = node; - match = 0; /* don't count this as a match anymore */ - } - } - node= _libssh2_list_next(&node->node); - } - host = hostp; - } while(!match && --numcheck); - - if(badkey) { - /* key mismatch */ - if (ext) - *ext = knownhost_to_external(badkey); - rc = LIBSSH2_KNOWNHOST_CHECK_MISMATCH; - } - - if(keyalloc) - LIBSSH2_FREE(hosts->session, keyalloc); - - return rc; -} - -/* - * libssh2_knownhost_check - * - * Check a host and its associated key against the collection of known hosts. - * - * The typemask is the type/format of the given host name and key - * - * plain - ascii "hostname.domain.tld" - * sha1 - NOT SUPPORTED AS INPUT - * custom - prehashed base64 encoded. Note that this cannot use any salts. - * - * Returns: - * - * LIBSSH2_KNOWNHOST_CHECK_FAILURE - * LIBSSH2_KNOWNHOST_CHECK_NOTFOUND - * LIBSSH2_KNOWNHOST_CHECK_MATCH - * LIBSSH2_KNOWNHOST_CHECK_MISMATCH - */ -LIBSSH2_API int -libssh2_knownhost_check(LIBSSH2_KNOWNHOSTS *hosts, - const char *hostp, const char *key, size_t keylen, - int typemask, - struct libssh2_knownhost **ext) -{ - return knownhost_check(hosts, hostp, -1, key, keylen, - typemask, ext); -} - -/* - * libssh2_knownhost_checkp - * - * Check a host+port and its associated key against the collection of known - * hosts. - * - * Note that if 'port' is specified as greater than zero, the check function - * will be able to check for a dedicated key for this particular host+port - * combo, and if 'port' is negative it only checks for the generic host key. - * - * The typemask is the type/format of the given host name and key - * - * plain - ascii "hostname.domain.tld" - * sha1 - NOT SUPPORTED AS INPUT - * custom - prehashed base64 encoded. Note that this cannot use any salts. - * - * Returns: - * - * LIBSSH2_KNOWNHOST_CHECK_FAILURE - * LIBSSH2_KNOWNHOST_CHECK_NOTFOUND - * LIBSSH2_KNOWNHOST_CHECK_MATCH - * LIBSSH2_KNOWNHOST_CHECK_MISMATCH - */ -LIBSSH2_API int -libssh2_knownhost_checkp(LIBSSH2_KNOWNHOSTS *hosts, - const char *hostp, int port, - const char *key, size_t keylen, - int typemask, - struct libssh2_knownhost **ext) -{ - return knownhost_check(hosts, hostp, port, key, keylen, - typemask, ext); -} - - -/* - * libssh2_knownhost_del - * - * Remove a host from the collection of known hosts. - * - */ -LIBSSH2_API int -libssh2_knownhost_del(LIBSSH2_KNOWNHOSTS *hosts, - struct libssh2_knownhost *entry) -{ - struct known_host *node; - - /* check that this was retrieved the right way or get out */ - if(!entry || (entry->magic != KNOWNHOST_MAGIC)) - return _libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL, - "Invalid host information"); - - /* get the internal node pointer */ - node = entry->node; - - /* unlink from the list of all hosts */ - _libssh2_list_remove(&node->node); - - /* clear the struct now since the memory in which it is allocated is - about to be freed! */ - memset(entry, 0, sizeof(struct libssh2_knownhost)); - - /* free all resources */ - free_host(hosts->session, node); - - return 0; -} - -/* - * libssh2_knownhost_free - * - * Free an entire collection of known hosts. - * - */ -LIBSSH2_API void -libssh2_knownhost_free(LIBSSH2_KNOWNHOSTS *hosts) -{ - struct known_host *node; - struct known_host *next; - - for(node = _libssh2_list_first(&hosts->head); node; node = next) { - next = _libssh2_list_next(&node->node); - free_host(hosts->session, node); - } - LIBSSH2_FREE(hosts->session, hosts); -} - - -/* old style plain text: [name]([,][name])* - - for the sake of simplicity, we add them as separate hosts with the same - key -*/ -static int oldstyle_hostline(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, size_t hostlen, - const char *key, size_t keylen, int key_type, - const char *comment, size_t commentlen) -{ - int rc = 0; - size_t namelen = 0; - const char *name = host + hostlen; - - if(hostlen < 1) - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Failed to parse known_hosts line " - "(no host names)"); - - while(name > host) { - --name; - ++namelen; - - /* when we get the the start or see a comma coming up, add the host - name to the collection */ - if((name == host) || (*(name-1) == ',')) { - - char hostbuf[256]; - - /* make sure we don't overflow the buffer */ - if(namelen >= sizeof(hostbuf)-1) - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Failed to parse known_hosts line " - "(unexpected length)"); - - /* copy host name to the temp buffer and zero terminate */ - memcpy(hostbuf, name, namelen); - hostbuf[namelen]=0; - - rc = knownhost_add(hosts, hostbuf, NULL, key, keylen, - comment, commentlen, - key_type | LIBSSH2_KNOWNHOST_TYPE_PLAIN | - LIBSSH2_KNOWNHOST_KEYENC_BASE64, NULL); - if(rc) - return rc; - - if(name > host) { - namelen = 0; - --name; /* skip comma */ - } - } - } - - return rc; -} - -/* |1|[salt]|[hash] */ -static int hashed_hostline(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, size_t hostlen, - const char *key, size_t keylen, int key_type, - const char *comment, size_t commentlen) -{ - const char *p; - char saltbuf[32]; - char hostbuf[256]; - - const char *salt = &host[3]; /* skip the magic marker */ - hostlen -= 3; /* deduct the marker */ - - /* this is where the salt starts, find the end of it */ - for(p = salt; *p && (*p != '|'); p++) - ; - - if(*p=='|') { - const char *hash = NULL; - size_t saltlen = p - salt; - if(saltlen >= (sizeof(saltbuf)-1)) /* weird length */ - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Failed to parse known_hosts line " - "(unexpectedly long salt)"); - - memcpy(saltbuf, salt, saltlen); - saltbuf[saltlen] = 0; /* zero terminate */ - salt = saltbuf; /* point to the stack based buffer */ - - hash = p+1; /* the host hash is after the separator */ - - /* now make the host point to the hash */ - host = hash; - hostlen -= saltlen+1; /* deduct the salt and separator */ - - /* check that the lengths seem sensible */ - if(hostlen >= sizeof(hostbuf)-1) - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Failed to parse known_hosts line " - "(unexpected length)"); - - memcpy(hostbuf, host, hostlen); - hostbuf[hostlen]=0; - - return knownhost_add(hosts, hostbuf, salt, key, keylen, comment, - commentlen, - key_type | LIBSSH2_KNOWNHOST_TYPE_SHA1 | - LIBSSH2_KNOWNHOST_KEYENC_BASE64, NULL); - } - else - return 0; /* XXX: This should be an error, shouldn't it? */ -} - -/* - * hostline() - * - * Parse a single known_host line pre-split into host and key. - * - * The key part may include an optional comment which will be parsed here - * for ssh-rsa and ssh-dsa keys. Comments in other key types aren't handled. - * - * The function assumes new-lines have already been removed from the arguments. - */ -static int hostline(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, size_t hostlen, - const char *key, size_t keylen) -{ - const char *comment = NULL; - size_t commentlen = 0; - int key_type; - - /* make some checks that the lengths seem sensible */ - if(keylen < 20) - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Failed to parse known_hosts line " - "(key too short)"); - - switch(key[0]) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - key_type = LIBSSH2_KNOWNHOST_KEY_RSA1; - - /* Note that the old-style keys (RSA1) aren't truly base64, but we - * claim it is for now since we can get away with strcmp()ing the - * entire anything anyway! We need to check and fix these to make them - * work properly. - */ - break; - - case 's': /* ssh-dss or ssh-rsa */ - if(!strncmp(key, "ssh-dss", 7)) - key_type = LIBSSH2_KNOWNHOST_KEY_SSHDSS; - else if(!strncmp(key, "ssh-rsa", 7)) - key_type = LIBSSH2_KNOWNHOST_KEY_SSHRSA; - else - /* unknown key type */ - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unknown key type"); - - key += 7; - keylen -= 7; - - /* skip whitespaces */ - while((*key ==' ') || (*key == '\t')) { - key++; - keylen--; - } - - comment = key; - commentlen = keylen; - - /* move over key */ - while(commentlen && *comment && - (*comment != ' ') && (*comment != '\t')) { - comment++; - commentlen--; - } - - /* reduce key by comment length */ - keylen -= commentlen; - - /* Distinguish empty comment (a space) from no comment (no space) */ - if (commentlen == 0) - comment = NULL; - - /* skip whitespaces */ - while(commentlen && *comment && - ((*comment ==' ') || (*comment == '\t'))) { - comment++; - commentlen--; - } - break; - - default: /* unknown key format */ - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unknown key format"); - } - - /* Figure out host format */ - if((hostlen >2) && memcmp(host, "|1|", 3)) { - /* old style plain text: [name]([,][name])* - - for the sake of simplicity, we add them as separate hosts with the - same key - */ - return oldstyle_hostline(hosts, host, hostlen, key, keylen, key_type, - comment, commentlen); - } - else { - /* |1|[salt]|[hash] */ - return hashed_hostline(hosts, host, hostlen, key, keylen, key_type, - comment, commentlen); - } -} - -/* - * libssh2_knownhost_readline() - * - * Pass in a line of a file of 'type'. - * - * LIBSSH2_KNOWNHOST_FILE_OPENSSH is the only supported type. - * - * OpenSSH line format: - * - * - * - * Where the two parts can be created like: - * - * can be either - * or - * - * consists of - * [name] optionally followed by [,name] one or more times - * - * consists of - * |1||hash - * - * can be one of: - * [RSA bits] [e] [n as a decimal number] - * 'ssh-dss' [base64-encoded-key] - * 'ssh-rsa' [base64-encoded-key] - * - */ -LIBSSH2_API int -libssh2_knownhost_readline(LIBSSH2_KNOWNHOSTS *hosts, - const char *line, size_t len, int type) -{ - const char *cp; - const char *hostp; - const char *keyp; - size_t hostlen; - size_t keylen; - int rc; - - if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unsupported type of known-host information " - "store"); - - cp = line; - - /* skip leading whitespaces */ - while(len && ((*cp==' ') || (*cp == '\t'))) { - cp++; - len--; - } - - if(!len || !*cp || (*cp == '#') || (*cp == '\n')) - /* comment or empty line */ - return LIBSSH2_ERROR_NONE; - - /* the host part starts here */ - hostp = cp; - - /* move over the host to the separator */ - while(len && *cp && (*cp!=' ') && (*cp != '\t')) { - cp++; - len--; - } - - hostlen = cp - hostp; - - /* the key starts after the whitespaces */ - while(len && *cp && ((*cp==' ') || (*cp == '\t'))) { - cp++; - len--; - } - - if(!*cp || !len) /* illegal line */ - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Failed to parse known_hosts line"); - - keyp = cp; /* the key starts here */ - keylen = len; - - /* check if the line (key) ends with a newline and if so kill it */ - while(len && *cp && (*cp != '\n')) { - cp++; - len--; - } - - /* zero terminate where the newline is */ - if(*cp == '\n') - keylen--; /* don't include this in the count */ - - /* deal with this one host+key line */ - rc = hostline(hosts, hostp, hostlen, keyp, keylen); - if(rc) - return rc; /* failed */ - - return LIBSSH2_ERROR_NONE; /* success */ -} - -/* - * libssh2_knownhost_readfile - * - * Read hosts+key pairs from a given file. - * - * Returns a negative value for error or number of successfully added hosts. - * - */ - -LIBSSH2_API int -libssh2_knownhost_readfile(LIBSSH2_KNOWNHOSTS *hosts, - const char *filename, int type) -{ - FILE *file; - int num = 0; - char buf[2048]; - - if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unsupported type of known-host information " - "store"); - - file = fopen(filename, "r"); - if(file) { - while(fgets(buf, sizeof(buf), file)) { - if(libssh2_knownhost_readline(hosts, buf, strlen(buf), type)) - break; - num++; - } - fclose(file); - } - else - return _libssh2_error(hosts->session, LIBSSH2_ERROR_FILE, - "Failed to open file"); - - return num; -} - -/* - * knownhost_writeline() - * - * Ask libssh2 to convert a known host to an output line for storage. - * - * Note that this function returns LIBSSH2_ERROR_BUFFER_TOO_SMALL if the given - * output buffer is too small to hold the desired output. The 'outlen' field - * will then contain the size libssh2 wanted to store, which then is the - * smallest sufficient buffer it would require. - * - */ -static int -knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, - struct known_host *node, - char *buf, size_t buflen, - size_t *outlen, int type) -{ - int rc = LIBSSH2_ERROR_NONE; - int tindex; - const char *keytypes[4]={ - "", /* not used */ - "", /* this type has no name in the file */ - " ssh-rsa", - " ssh-dss" - }; - const char *keytype; - size_t nlen; - size_t commentlen = 0; - - /* we only support this single file type for now, bail out on all other - attempts */ - if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unsupported type of known-host information " - "store"); - - tindex = (node->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) >> - LIBSSH2_KNOWNHOST_KEY_SHIFT; - - /* set the string used in the file */ - keytype = keytypes[tindex]; - - /* calculate extra space needed for comment */ - if(node->comment) - commentlen = strlen(node->comment) + 1; - - if((node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) == - LIBSSH2_KNOWNHOST_TYPE_SHA1) { - char *namealloc; - char *saltalloc; - nlen = _libssh2_base64_encode(hosts->session, node->name, - node->name_len, &namealloc); - if(!nlen) - return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "base64-encoded host name"); - - nlen = _libssh2_base64_encode(hosts->session, - node->salt, node->salt_len, - &saltalloc); - if(!nlen) { - free(namealloc); - return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "base64-encoded salt"); - } - - nlen = strlen(saltalloc) + strlen(namealloc) + strlen(keytype) + - strlen(node->key) + commentlen + 7; - /* |1| + | + ' ' + \n + \0 = 7 */ - - if(nlen <= buflen) - if(node->comment) - snprintf(buf, buflen, "|1|%s|%s%s %s %s\n", saltalloc, namealloc, - keytype, node->key, node->comment); - else - snprintf(buf, buflen, "|1|%s|%s%s %s\n", saltalloc, namealloc, - keytype, node->key); - else - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Known-host write buffer too small"); - - free(namealloc); - free(saltalloc); - } - else { - nlen = strlen(node->name) + strlen(keytype) + strlen(node->key) + - commentlen + 3; - /* ' ' + '\n' + \0 = 3 */ - if(nlen <= buflen) - /* these types have the plain name */ - if(node->comment) - snprintf(buf, buflen, "%s%s %s %s\n", node->name, keytype, node->key, - node->comment); - else - snprintf(buf, buflen, "%s%s %s\n", node->name, keytype, node->key); - else - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Known-host write buffer too small"); - } - - /* we report the full length of the data with the trailing zero excluded */ - *outlen = nlen-1; - - return rc; -} - -/* - * libssh2_knownhost_writeline() - * - * Ask libssh2 to convert a known host to an output line for storage. - * - * Note that this function returns LIBSSH2_ERROR_BUFFER_TOO_SMALL if the given - * output buffer is too small to hold the desired output. - */ -LIBSSH2_API int -libssh2_knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, - struct libssh2_knownhost *known, - char *buffer, size_t buflen, - size_t *outlen, /* the amount of written data */ - int type) -{ - struct known_host *node; - - if(known->magic != KNOWNHOST_MAGIC) - return _libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL, - "Invalid host information"); - - node = known->node; - - return knownhost_writeline(hosts, node, buffer, buflen, outlen, type); -} - -/* - * libssh2_knownhost_writefile() - * - * Write hosts+key pairs to the given file. - */ -LIBSSH2_API int -libssh2_knownhost_writefile(LIBSSH2_KNOWNHOSTS *hosts, - const char *filename, int type) -{ - struct known_host *node; - FILE *file; - int rc = LIBSSH2_ERROR_NONE; - char buffer[2048]; - - /* we only support this single file type for now, bail out on all other - attempts */ - if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unsupported type of known-host information " - "store"); - - file = fopen(filename, "w"); - if(!file) - return _libssh2_error(hosts->session, LIBSSH2_ERROR_FILE, - "Failed to open file"); - - for(node = _libssh2_list_first(&hosts->head); - node; - node= _libssh2_list_next(&node->node) ) { - size_t wrote; - size_t nwrote; - rc = knownhost_writeline(hosts, node, buffer, sizeof(buffer), &wrote, - type); - if(rc) - break; - - nwrote = fwrite(buffer, 1, wrote, file); - if(nwrote != wrote) { - /* failed to write the whole thing, bail out */ - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_FILE, - "Write failed"); - break; - } - } - fclose(file); - - return rc; -} - - -/* - * libssh2_knownhost_get() - * - * Traverse the internal list of known hosts. Pass NULL to 'prev' to get - * the first one. - * - * Returns: - * 0 if a fine host was stored in 'store' - * 1 if end of hosts - * [negative] on errors - */ -LIBSSH2_API int -libssh2_knownhost_get(LIBSSH2_KNOWNHOSTS *hosts, - struct libssh2_knownhost **ext, - struct libssh2_knownhost *oprev) -{ - struct known_host *node; - if(oprev && oprev->node) { - /* we have a starting point */ - struct known_host *prev = oprev->node; - - /* get the next node in the list */ - node = _libssh2_list_next(&prev->node); - - } - else - node = _libssh2_list_first(&hosts->head); - - if(!node) - /* no (more) node */ - return 1; - - *ext = knownhost_to_external(node); - - return 0; -} diff --git a/vendor/libssh2-1.4.2/src/libgcrypt.c b/vendor/libssh2-1.4.2/src/libgcrypt.c deleted file mode 100644 index 5c2787b..0000000 --- a/vendor/libssh2-1.4.2/src/libgcrypt.c +++ /dev/null @@ -1,593 +0,0 @@ -/* Copyright (C) 2008, 2009, Simon Josefsson - * Copyright (C) 2006, 2007, The Written Word, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" - -#ifdef LIBSSH2_LIBGCRYPT /* compile only if we build with libgcrypt */ - -#include - -int -_libssh2_rsa_new(libssh2_rsa_ctx ** rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, unsigned long coefflen) -{ - int rc; - (void) e1data; - (void) e1len; - (void) e2data; - (void) e2len; - - if (ddata) { - rc = gcry_sexp_build - (rsa, NULL, - "(private-key(rsa(n%b)(e%b)(d%b)(q%b)(p%b)(u%b)))", - nlen, ndata, elen, edata, dlen, ddata, plen, pdata, - qlen, qdata, coefflen, coeffdata); - } else { - rc = gcry_sexp_build(rsa, NULL, "(public-key(rsa(n%b)(e%b)))", - nlen, ndata, elen, edata); - } - if (rc) { - *rsa = NULL; - return -1; - } - - return 0; -} - -int -_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, unsigned long m_len) -{ - unsigned char hash[SHA_DIGEST_LENGTH]; - gcry_sexp_t s_sig, s_hash; - int rc = -1; - - libssh2_sha1(m, m_len, hash); - - rc = gcry_sexp_build(&s_hash, NULL, - "(data (flags pkcs1) (hash sha1 %b))", - SHA_DIGEST_LENGTH, hash); - if (rc != 0) { - return -1; - } - - rc = gcry_sexp_build(&s_sig, NULL, "(sig-val(rsa(s %b)))", sig_len, sig); - if (rc != 0) { - gcry_sexp_release(s_hash); - return -1; - } - - rc = gcry_pk_verify(s_sig, s_hash, rsa); - gcry_sexp_release(s_sig); - gcry_sexp_release(s_hash); - - return (rc == 0) ? 0 : -1; -} - -int -_libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, - const unsigned char *p, - unsigned long p_len, - const unsigned char *q, - unsigned long q_len, - const unsigned char *g, - unsigned long g_len, - const unsigned char *y, - unsigned long y_len, - const unsigned char *x, unsigned long x_len) -{ - int rc; - - if (x_len) { - rc = gcry_sexp_build - (dsactx, NULL, - "(private-key(dsa(p%b)(q%b)(g%b)(y%b)(x%b)))", - p_len, p, q_len, q, g_len, g, y_len, y, x_len, x); - } else { - rc = gcry_sexp_build(dsactx, NULL, - "(public-key(dsa(p%b)(q%b)(g%b)(y%b)))", - p_len, p, q_len, q, g_len, g, y_len, y); - } - - if (rc) { - *dsactx = NULL; - return -1; - } - - return 0; -} - -int -_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, - LIBSSH2_SESSION * session, - const char *filename, unsigned const char *passphrase) -{ - FILE *fp; - unsigned char *data, *save_data; - unsigned int datalen; - int ret; - unsigned char *n, *e, *d, *p, *q, *e1, *e2, *coeff; - unsigned int nlen, elen, dlen, plen, qlen, e1len, e2len, coefflen; - - (void) passphrase; - - fp = fopen(filename, "r"); - if (!fp) { - return -1; - } - - ret = _libssh2_pem_parse(session, - "-----BEGIN RSA PRIVATE KEY-----", - "-----END RSA PRIVATE KEY-----", - fp, &data, &datalen); - fclose(fp); - if (ret) { - return -1; - } - - save_data = data; - - if (_libssh2_pem_decode_sequence(&data, &datalen)) { - ret = -1; - goto fail; - } -/* First read Version field (should be 0). */ - ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen); - if (ret != 0 || (nlen != 1 && *n != '\0')) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen); - if (ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &e, &elen); - if (ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &d, &dlen); - if (ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen); - if (ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen); - if (ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &e1, &e1len); - if (ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &e2, &e2len); - if (ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &coeff, &coefflen); - if (ret != 0) { - ret = -1; - goto fail; - } - - if (_libssh2_rsa_new(rsa, e, elen, n, nlen, d, dlen, p, plen, - q, qlen, e1, e1len, e2, e2len, coeff, coefflen)) { - ret = -1; - goto fail; - } - - ret = 0; - - fail: - LIBSSH2_FREE(session, save_data); - return ret; -} - -int -_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, - LIBSSH2_SESSION * session, - const char *filename, unsigned const char *passphrase) -{ - FILE *fp; - unsigned char *data, *save_data; - unsigned int datalen; - int ret; - unsigned char *p, *q, *g, *y, *x; - unsigned int plen, qlen, glen, ylen, xlen; - - (void) passphrase; - - fp = fopen(filename, "r"); - if (!fp) { - return -1; - } - - ret = _libssh2_pem_parse(session, - "-----BEGIN DSA PRIVATE KEY-----", - "-----END DSA PRIVATE KEY-----", - fp, &data, &datalen); - fclose(fp); - if (ret) { - return -1; - } - - save_data = data; - - if (_libssh2_pem_decode_sequence(&data, &datalen)) { - ret = -1; - goto fail; - } - -/* First read Version field (should be 0). */ - ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen); - if (ret != 0 || (plen != 1 && *p != '\0')) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen); - if (ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen); - if (ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &g, &glen); - if (ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &y, &ylen); - if (ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &x, &xlen); - if (ret != 0) { - ret = -1; - goto fail; - } - - if (datalen != 0) { - ret = -1; - goto fail; - } - - if (_libssh2_dsa_new(dsa, p, plen, q, qlen, g, glen, y, ylen, x, xlen)) { - ret = -1; - goto fail; - } - - ret = 0; - - fail: - LIBSSH2_FREE(session, save_data); - return ret; -} - -int -_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, - libssh2_dsa_ctx * rsactx, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, size_t *signature_len) -{ - gcry_sexp_t sig_sexp; - gcry_sexp_t data; - int rc; - const char *tmp; - size_t size; - - if (hash_len != SHA_DIGEST_LENGTH) { - return -1; - } - - if (gcry_sexp_build(&data, NULL, - "(data (flags pkcs1) (hash sha1 %b))", - hash_len, hash)) { - return -1; - } - - rc = gcry_pk_sign(&sig_sexp, data, rsactx); - - gcry_sexp_release(data); - - if (rc != 0) { - return -1; - } - - data = gcry_sexp_find_token(sig_sexp, "s", 0); - if (!data) { - return -1; - } - - tmp = gcry_sexp_nth_data(data, 1, &size); - if (!tmp) { - return -1; - } - - if (tmp[0] == '\0') { - tmp++; - size--; - } - - *signature = LIBSSH2_ALLOC(session, size); - memcpy(*signature, tmp, size); - *signature_len = size; - - return rc; -} - -int -_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, - const unsigned char *hash, - unsigned long hash_len, unsigned char *sig) -{ - unsigned char zhash[SHA_DIGEST_LENGTH + 1]; - gcry_sexp_t sig_sexp; - gcry_sexp_t data; - int ret; - const char *tmp; - size_t size; - - if (hash_len != SHA_DIGEST_LENGTH) { - return -1; - } - - memcpy(zhash + 1, hash, hash_len); - zhash[0] = 0; - - if (gcry_sexp_build(&data, NULL, "(data (value %b))", hash_len + 1, zhash)) { - return -1; - } - - ret = gcry_pk_sign(&sig_sexp, data, dsactx); - - gcry_sexp_release(data); - - if (ret != 0) { - return -1; - } - - memset(sig, 0, 40); - -/* Extract R. */ - - data = gcry_sexp_find_token(sig_sexp, "r", 0); - if (!data) - goto err; - - tmp = gcry_sexp_nth_data(data, 1, &size); - if (!tmp) - goto err; - - if (tmp[0] == '\0') { - tmp++; - size--; - } - - if (size < 1 || size > 20) - goto err; - - memcpy(sig + (20 - size), tmp, size); - - gcry_sexp_release(data); - -/* Extract S. */ - - data = gcry_sexp_find_token(sig_sexp, "s", 0); - if (!data) - goto err; - - tmp = gcry_sexp_nth_data(data, 1, &size); - if (!tmp) - goto err; - - if (tmp[0] == '\0') { - tmp++; - size--; - } - - if (size < 1 || size > 20) - goto err; - - memcpy(sig + 20 + (20 - size), tmp, size); - goto out; - - err: - ret = -1; - - out: - if (sig_sexp) { - gcry_sexp_release(sig_sexp); - } - if (data) { - gcry_sexp_release(data); - } - return ret; -} - -int -_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, - const unsigned char *sig, - const unsigned char *m, unsigned long m_len) -{ - unsigned char hash[SHA_DIGEST_LENGTH + 1]; - gcry_sexp_t s_sig, s_hash; - int rc = -1; - - libssh2_sha1(m, m_len, hash + 1); - hash[0] = 0; - - if (gcry_sexp_build(&s_hash, NULL, "(data(flags raw)(value %b))", - SHA_DIGEST_LENGTH + 1, hash)) { - return -1; - } - - if (gcry_sexp_build(&s_sig, NULL, "(sig-val(dsa(r %b)(s %b)))", - 20, sig, 20, sig + 20)) { - gcry_sexp_release(s_hash); - return -1; - } - - rc = gcry_pk_verify(s_sig, s_hash, dsactx); - gcry_sexp_release(s_sig); - gcry_sexp_release(s_hash); - - return (rc == 0) ? 0 : -1; -} - -int -_libssh2_cipher_init(_libssh2_cipher_ctx * h, - _libssh2_cipher_type(algo), - unsigned char *iv, unsigned char *secret, int encrypt) -{ - int ret; - int cipher = _libssh2_gcry_cipher (algo); - int mode = _libssh2_gcry_mode (algo); - int keylen = gcry_cipher_get_algo_keylen(cipher); - - (void) encrypt; - - ret = gcry_cipher_open(h, cipher, mode, 0); - if (ret) { - return -1; - } - - ret = gcry_cipher_setkey(*h, secret, keylen); - if (ret) { - gcry_cipher_close(*h); - return -1; - } - - if (mode != GCRY_CIPHER_MODE_STREAM) { - int blklen = gcry_cipher_get_algo_blklen(cipher); - if (mode == GCRY_CIPHER_MODE_CTR) - ret = gcry_cipher_setctr(*h, iv, blklen); - else - ret = gcry_cipher_setiv(*h, iv, blklen); - if (ret) { - gcry_cipher_close(*h); - return -1; - } - } - - return 0; -} - -int -_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, - _libssh2_cipher_type(algo), - int encrypt, unsigned char *block) -{ - int cipher = _libssh2_gcry_cipher (algo); - size_t blklen = gcry_cipher_get_algo_blklen(cipher); - int ret; - - if (blklen == 1) { -/* Hack for arcfour. */ - blklen = 8; - } - - if (encrypt) { - ret = gcry_cipher_encrypt(*ctx, block, blklen, block, blklen); - } else { - ret = gcry_cipher_decrypt(*ctx, block, blklen, block, blklen); - } - return ret; -} - -int -_libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase) -{ - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to extract public key from private key file: " - "Method unimplemented in libgcrypt backend"); -} - -void _libssh2_init_aes_ctr(void) -{ - /* no implementation */ -} -#endif /* LIBSSH2_LIBGCRYPT */ diff --git a/vendor/libssh2-1.4.2/src/libgcrypt.h b/vendor/libssh2-1.4.2/src/libgcrypt.h deleted file mode 100644 index 04516e5..0000000 --- a/vendor/libssh2-1.4.2/src/libgcrypt.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2008, 2009, 2010 Simon Josefsson - * Copyright (C) 2006, 2007, The Written Word, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include - -#define LIBSSH2_MD5 1 - -#define LIBSSH2_HMAC_RIPEMD 1 - -#define LIBSSH2_AES 1 -#define LIBSSH2_AES_CTR 1 -#define LIBSSH2_BLOWFISH 1 -#define LIBSSH2_RC4 1 -#define LIBSSH2_CAST 1 -#define LIBSSH2_3DES 1 - -#define LIBSSH2_RSA 1 -#define LIBSSH2_DSA 1 - -#define MD5_DIGEST_LENGTH 16 -#define SHA_DIGEST_LENGTH 20 - -#define _libssh2_random(buf, len) \ - (gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1) - -#define libssh2_sha1_ctx gcry_md_hd_t -#define libssh2_sha1_init(ctx) gcry_md_open (ctx, GCRY_MD_SHA1, 0); -#define libssh2_sha1_update(ctx, data, len) gcry_md_write (ctx, data, len) -#define libssh2_sha1_final(ctx, out) \ - memcpy (out, gcry_md_read (ctx, 0), SHA_DIGEST_LENGTH), gcry_md_close (ctx) -#define libssh2_sha1(message, len, out) \ - gcry_md_hash_buffer (GCRY_MD_SHA1, out, message, len) - -#define libssh2_md5_ctx gcry_md_hd_t -#define libssh2_md5_init(ctx) gcry_md_open (ctx, GCRY_MD_MD5, 0); -#define libssh2_md5_update(ctx, data, len) gcry_md_write (ctx, data, len) -#define libssh2_md5_final(ctx, out) \ - memcpy (out, gcry_md_read (ctx, 0), MD5_DIGEST_LENGTH), gcry_md_close (ctx) -#define libssh2_md5(message, len, out) \ - gcry_md_hash_buffer (GCRY_MD_MD5, out, message, len) - -#define libssh2_hmac_ctx gcry_md_hd_t -#define libssh2_hmac_sha1_init(ctx, key, keylen) \ - gcry_md_open (ctx, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC), \ - gcry_md_setkey (*ctx, key, keylen) -#define libssh2_hmac_md5_init(ctx, key, keylen) \ - gcry_md_open (ctx, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC), \ - gcry_md_setkey (*ctx, key, keylen) -#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \ - gcry_md_open (ctx, GCRY_MD_RMD160, GCRY_MD_FLAG_HMAC), \ - gcry_md_setkey (*ctx, key, keylen) -#define libssh2_hmac_update(ctx, data, datalen) \ - gcry_md_write (ctx, data, datalen) -#define libssh2_hmac_final(ctx, data) \ - memcpy (data, gcry_md_read (ctx, 0), \ - gcry_md_get_algo_dlen (gcry_md_get_algo (ctx))) -#define libssh2_hmac_cleanup(ctx) gcry_md_close (*ctx); - -#define libssh2_crypto_init() gcry_control (GCRYCTL_DISABLE_SECMEM) -#define libssh2_crypto_exit() - -#define libssh2_rsa_ctx struct gcry_sexp - -#define _libssh2_rsa_free(rsactx) gcry_sexp_release (rsactx) - -#define libssh2_dsa_ctx struct gcry_sexp - -#define _libssh2_dsa_free(dsactx) gcry_sexp_release (dsactx) - -#define _libssh2_cipher_type(name) int name -#define _libssh2_cipher_ctx gcry_cipher_hd_t - -#define _libssh2_gcry_ciphermode(c,m) ((c << 8) | m) -#define _libssh2_gcry_cipher(c) (c >> 8) -#define _libssh2_gcry_mode(m) (m & 0xFF) - -#define _libssh2_cipher_aes256ctr \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR) -#define _libssh2_cipher_aes192ctr \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR) -#define _libssh2_cipher_aes128ctr \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR) -#define _libssh2_cipher_aes256 \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC) -#define _libssh2_cipher_aes192 \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC) -#define _libssh2_cipher_aes128 \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC) -#define _libssh2_cipher_blowfish \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC) -#define _libssh2_cipher_arcfour \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM) -#define _libssh2_cipher_cast5 \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC) -#define _libssh2_cipher_3des \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC) - - -#define _libssh2_cipher_dtor(ctx) gcry_cipher_close(*(ctx)) - -#define _libssh2_bn struct gcry_mpi -#define _libssh2_bn_ctx int -#define _libssh2_bn_ctx_new() 0 -#define _libssh2_bn_ctx_free(bnctx) ((void)0) -#define _libssh2_bn_init() gcry_mpi_new(0) -#define _libssh2_bn_rand(bn, bits, top, bottom) gcry_mpi_randomize (bn, bits, GCRY_WEAK_RANDOM) -#define _libssh2_bn_mod_exp(r, a, p, m, ctx) gcry_mpi_powm (r, a, p, m) -#define _libssh2_bn_set_word(bn, val) gcry_mpi_set_ui(bn, val) -#define _libssh2_bn_from_bin(bn, len, val) gcry_mpi_scan(&((bn)), GCRYMPI_FMT_USG, val, len, NULL) -#define _libssh2_bn_to_bin(bn, val) gcry_mpi_print (GCRYMPI_FMT_USG, val, _libssh2_bn_bytes(bn), NULL, bn) -#define _libssh2_bn_bytes(bn) (gcry_mpi_get_nbits (bn) / 8 + ((gcry_mpi_get_nbits (bn) % 8 == 0) ? 0 : 1)) -#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits (bn) -#define _libssh2_bn_free(bn) gcry_mpi_release(bn) - diff --git a/vendor/libssh2-1.4.2/src/libssh2_config.h b/vendor/libssh2-1.4.2/src/libssh2_config.h deleted file mode 100644 index 4591f5f..0000000 --- a/vendor/libssh2-1.4.2/src/libssh2_config.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifdef WIN32 - #include "libssh2_config_win.h" -#else - #include "libssh2_config_osx.h" -#endif diff --git a/vendor/libssh2-1.4.2/src/libssh2_config_osx.h b/vendor/libssh2-1.4.2/src/libssh2_config_osx.h deleted file mode 100644 index d8917c2..0000000 --- a/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +++ /dev/null @@ -1,224 +0,0 @@ -/* src/libssh2_config.h. Generated from libssh2_config.h.in by configure. */ -/* src/libssh2_config.h.in. Generated from configure.ac by autoheader. */ - -/* Define if building universal (internal helper macro) */ -/* #undef AC_APPLE_UNIVERSAL_BUILD */ - -/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP - systems. This function is required for `alloca.c' support on those systems. - */ -/* #undef CRAY_STACKSEG_END */ - -/* Define to 1 if using `alloca.c'. */ -/* #undef C_ALLOCA */ - -/* Define to 1 if you have `alloca', as a function or macro. */ -#define HAVE_ALLOCA 1 - -/* Define to 1 if you have and it should be used (not on Ultrix). - */ -#define HAVE_ALLOCA_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ARPA_INET_H 1 - -/* disabled non-blocking sockets */ -/* #undef HAVE_DISABLED_NONBLOCKING */ - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if you have the `EVP_aes_128_ctr' function. */ -/* #undef HAVE_EVP_AES_128_CTR */ - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* use FIONBIO for non-blocking sockets */ -/* #undef HAVE_FIONBIO */ - -/* Define to 1 if you have the `gettimeofday' function. */ -#define HAVE_GETTIMEOFDAY 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* use ioctlsocket() for non-blocking sockets */ -/* #undef HAVE_IOCTLSOCKET */ - -/* use Ioctlsocket() for non-blocking sockets */ -/* #undef HAVE_IOCTLSOCKET_CASE */ - -/* Define if you have the gcrypt library. */ -/* #undef HAVE_LIBGCRYPT */ - -/* Define if you have the ssl library. */ -#define HAVE_LIBSSL 1 - -/* Define if you have the z library. */ -#define HAVE_LIBZ 1 - -/* Define to 1 if the compiler supports the 'long long' data type. */ -#define HAVE_LONGLONG 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_NETINET_IN_H 1 - -/* use O_NONBLOCK for non-blocking sockets */ -#define HAVE_O_NONBLOCK 1 - -/* Define to 1 if you have the `poll' function. */ -/* #undef HAVE_POLL */ - -/* Define to 1 if you have the select function. */ -#define HAVE_SELECT 1 - -/* use SO_NONBLOCK for non-blocking sockets */ -/* #undef HAVE_SO_NONBLOCK */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDIO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strtoll' function. */ -#define HAVE_STRTOLL 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_IOCTL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SELECT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_UIO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_UN_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINDOWS_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINSOCK2_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WS2TCPIP_H */ - -/* to make a symbol visible */ -/* #undef LIBSSH2_API */ - -/* Enable "none" cipher -- NOT RECOMMENDED */ -/* #undef LIBSSH2_CRYPT_NONE */ - -/* Enable newer diffie-hellman-group-exchange-sha1 syntax */ -#define LIBSSH2_DH_GEX_NEW 1 - -/* Compile in zlib support */ -#define LIBSSH2_HAVE_ZLIB 1 - -/* Use libgcrypt */ -/* #undef LIBSSH2_LIBGCRYPT */ - -/* Enable "none" MAC -- NOT RECOMMENDED */ -/* #undef LIBSSH2_MAC_NONE */ - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#define LT_OBJDIR ".libs/" - -/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ -/* #undef NEED_REENTRANT */ - -/* Name of package */ -#define PACKAGE "libssh2" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "libssh2-devel@cool.haxx.se" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "libssh2" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libssh2 -" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "libssh2" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "-" - -/* If using the C implementation of alloca, define if you know the - direction of stack growth for your system; otherwise it will be - automatically deduced at runtime. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown */ -/* #undef STACK_DIRECTION */ - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Version number of package */ -#define VERSION "-" - -/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most - significant byte first (like Motorola and SPARC, unlike Intel). */ -#if defined AC_APPLE_UNIVERSAL_BUILD -# if defined __BIG_ENDIAN__ -# define WORDS_BIGENDIAN 1 -# endif -#else -# ifndef WORDS_BIGENDIAN -/* # undef WORDS_BIGENDIAN */ -# endif -#endif - -/* Number of bits in a file offset, on hosts where this is settable. */ -/* #undef _FILE_OFFSET_BITS */ - -/* Define for large files, on AIX-style hosts. */ -/* #undef _LARGE_FILES */ - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -/* #undef inline */ -#endif diff --git a/vendor/libssh2-1.4.2/src/libssh2_config_win.h b/vendor/libssh2-1.4.2/src/libssh2_config_win.h deleted file mode 100644 index 39e438f..0000000 --- a/vendor/libssh2-1.4.2/src/libssh2_config_win.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef LIBSSH2_CONFIG_H -#define LIBSSH2_CONFIG_H - -#ifndef WIN32 -#define WIN32 -#endif -#ifndef _CRT_SECURE_NO_DEPRECATE -#define _CRT_SECURE_NO_DEPRECATE 1 -#endif /* _CRT_SECURE_NO_DEPRECATE */ -#include -#include -#include - -#ifdef __MINGW32__ -#define HAVE_UNISTD_H -#define HAVE_INTTYPES_H -#define HAVE_SYS_TIME_H -#endif - -#define HAVE_WINSOCK2_H -#define HAVE_IOCTLSOCKET -#define HAVE_SELECT - -#ifdef _MSC_VER -#define snprintf _snprintf -#if _MSC_VER < 1500 -#define vsnprintf _vsnprintf -#endif -#define strdup _strdup -#define strncasecmp _strnicmp -#define strcasecmp _stricmp -#else -#define strncasecmp strnicmp -#define strcasecmp stricmp -#endif /* _MSC_VER */ - -/* Enable newer diffie-hellman-group-exchange-sha1 syntax */ -#define LIBSSH2_DH_GEX_NEW 1 - -#endif /* LIBSSH2_CONFIG_H */ - diff --git a/vendor/libssh2-1.4.2/src/libssh2_priv.h b/vendor/libssh2-1.4.2/src/libssh2_priv.h deleted file mode 100644 index c670a16..0000000 --- a/vendor/libssh2-1.4.2/src/libssh2_priv.h +++ /dev/null @@ -1,1038 +0,0 @@ -/* Copyright (c) 2004-2008, 2010, Sara Golemon - * Copyright (c) 2009-2011 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#ifndef LIBSSH2_PRIV_H -#define LIBSSH2_PRIV_H 1 - -#define LIBSSH2_LIBRARY -#include "libssh2_config.h" - -#ifdef HAVE_WINDOWS_H -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#undef WIN32_LEAN_AND_MEAN -#endif - -#ifdef HAVE_WS2TCPIP_H -#include -#endif - -#include -#include - -/* The following CPP block should really only be in session.c and - packet.c. However, AIX have #define's for 'events' and 'revents' - and we are using those names in libssh2.h, so we need to include - the AIX headers first, to make sure all code is compiled with - consistent names of these fields. While arguable the best would to - change libssh2.h to use other names, that would break backwards - compatibility. For more information, see: - http://www.mail-archive.com/libssh2-devel%40lists.sourceforge.net/msg00003.html - http://www.mail-archive.com/libssh2-devel%40lists.sourceforge.net/msg00224.html -*/ -#ifdef HAVE_POLL -# include -#else -# if defined(HAVE_SELECT) && !defined(WIN32) -# ifdef HAVE_SYS_SELECT_H -# include -# else -# include -# include -# endif -# endif -#endif - -/* Needed for struct iovec on some platforms */ -#ifdef HAVE_SYS_UIO_H -#include -#endif - -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -#ifdef HAVE_SYS_IOCTL_H -# include -#endif -#ifdef HAVE_INTTYPES_H -#include -#endif - -#include "libssh2.h" -#include "libssh2_publickey.h" -#include "libssh2_sftp.h" -#include "misc.h" /* for the linked list stuff */ - -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE 1 -#endif - -/* Provide iovec / writev on WIN32 platform. */ -#ifdef WIN32 - -struct iovec { - size_t iov_len; - void * iov_base; -}; - -#define inline __inline - -static inline int writev(int sock, struct iovec *iov, int nvecs) -{ - DWORD ret; - if (WSASend(sock, (LPWSABUF)iov, nvecs, &ret, 0, NULL, NULL) == 0) { - return ret; - } - return -1; -} - -#endif /* WIN32 */ - -#include "crypto.h" - -#ifdef HAVE_WINSOCK2_H - -#include -#include -#include - -#ifdef _MSC_VER -/* "inline" keyword is valid only with C++ engine! */ -#define inline __inline -#endif - -#endif - -/* RFC4253 section 6.1 Maximum Packet Length says: - * - * "All implementations MUST be able to process packets with - * uncompressed payload length of 32768 bytes or less and - * total packet size of 35000 bytes or less (including length, - * padding length, payload, padding, and MAC.)." - */ -#define MAX_SSH_PACKET_LEN 35000 - -#define LIBSSH2_ALLOC(session, count) \ - session->alloc((count), &(session)->abstract) -#define LIBSSH2_REALLOC(session, ptr, count) \ - ((ptr) ? session->realloc((ptr), (count), &(session)->abstract) : \ - session->alloc((count), &(session)->abstract)) -#define LIBSSH2_FREE(session, ptr) \ - session->free((ptr), &(session)->abstract) -#define LIBSSH2_IGNORE(session, data, datalen) \ - session->ssh_msg_ignore((session), (data), (datalen), &(session)->abstract) -#define LIBSSH2_DEBUG(session, always_display, message, message_len, \ - language, language_len) \ - session->ssh_msg_debug((session), (always_display), (message), \ - (message_len), (language), (language_len), \ - &(session)->abstract) -#define LIBSSH2_DISCONNECT(session, reason, message, message_len, \ - language, language_len) \ - session->ssh_msg_disconnect((session), (reason), (message), \ - (message_len), (language), (language_len), \ - &(session)->abstract) - -#define LIBSSH2_MACERROR(session, data, datalen) \ - session->macerror((session), (data), (datalen), &(session)->abstract) -#define LIBSSH2_X11_OPEN(channel, shost, sport) \ - channel->session->x11(((channel)->session), (channel), \ - (shost), (sport), (&(channel)->session->abstract)) - -#define LIBSSH2_CHANNEL_CLOSE(session, channel) \ - channel->close_cb((session), &(session)->abstract, \ - (channel), &(channel)->abstract) - -#define LIBSSH2_SEND_FD(session, fd, buffer, length, flags) \ - session->send(fd, buffer, length, flags, &session->abstract) -#define LIBSSH2_RECV_FD(session, fd, buffer, length, flags) \ - session->recv(fd, buffer, length, flags, &session->abstract) - -#define LIBSSH2_SEND(session, buffer, length, flags) \ - LIBSSH2_SEND_FD(session, session->socket_fd, buffer, length, flags) -#define LIBSSH2_RECV(session, buffer, length, flags) \ - LIBSSH2_RECV_FD(session, session->socket_fd, buffer, length, flags) - -typedef struct _LIBSSH2_KEX_METHOD LIBSSH2_KEX_METHOD; -typedef struct _LIBSSH2_HOSTKEY_METHOD LIBSSH2_HOSTKEY_METHOD; -typedef struct _LIBSSH2_CRYPT_METHOD LIBSSH2_CRYPT_METHOD; -typedef struct _LIBSSH2_COMP_METHOD LIBSSH2_COMP_METHOD; - -typedef struct _LIBSSH2_PACKET LIBSSH2_PACKET; - -typedef enum -{ - libssh2_NB_state_idle = 0, - libssh2_NB_state_allocated, - libssh2_NB_state_created, - libssh2_NB_state_sent, - libssh2_NB_state_sent1, - libssh2_NB_state_sent2, - libssh2_NB_state_sent3, - libssh2_NB_state_sent4, - libssh2_NB_state_sent5, - libssh2_NB_state_sent6, - libssh2_NB_state_sent7, - libssh2_NB_state_jump1, - libssh2_NB_state_jump2, - libssh2_NB_state_jump3, - libssh2_NB_state_jump4, - libssh2_NB_state_jump5 -} libssh2_nonblocking_states; - -typedef struct packet_require_state_t -{ - libssh2_nonblocking_states state; - time_t start; -} packet_require_state_t; - -typedef struct packet_requirev_state_t -{ - time_t start; -} packet_requirev_state_t; - -typedef struct kmdhgGPsha1kex_state_t -{ - libssh2_nonblocking_states state; - unsigned char *e_packet; - unsigned char *s_packet; - unsigned char *tmp; - unsigned char h_sig_comp[SHA_DIGEST_LENGTH]; - unsigned char c; - size_t e_packet_len; - size_t s_packet_len; - size_t tmp_len; - _libssh2_bn_ctx *ctx; - _libssh2_bn *x; - _libssh2_bn *e; - _libssh2_bn *f; - _libssh2_bn *k; - unsigned char *s; - unsigned char *f_value; - unsigned char *k_value; - unsigned char *h_sig; - size_t f_value_len; - size_t k_value_len; - size_t h_sig_len; - libssh2_sha1_ctx exchange_hash; - packet_require_state_t req_state; - libssh2_nonblocking_states burn_state; -} kmdhgGPsha1kex_state_t; - -typedef struct key_exchange_state_low_t -{ - libssh2_nonblocking_states state; - packet_require_state_t req_state; - kmdhgGPsha1kex_state_t exchange_state; - _libssh2_bn *p; /* SSH2 defined value (p_value) */ - _libssh2_bn *g; /* SSH2 defined value (2) */ - unsigned char request[13]; - unsigned char *data; - size_t request_len; - size_t data_len; -} key_exchange_state_low_t; - -typedef struct key_exchange_state_t -{ - libssh2_nonblocking_states state; - packet_require_state_t req_state; - key_exchange_state_low_t key_state_low; - unsigned char *data; - size_t data_len; - unsigned char *oldlocal; - size_t oldlocal_len; -} key_exchange_state_t; - -#define FwdNotReq "Forward not requested" - -typedef struct packet_queue_listener_state_t -{ - libssh2_nonblocking_states state; - unsigned char packet[17 + (sizeof(FwdNotReq) - 1)]; - unsigned char *host; - unsigned char *shost; - uint32_t sender_channel; - uint32_t initial_window_size; - uint32_t packet_size; - uint32_t port; - uint32_t sport; - uint32_t host_len; - uint32_t shost_len; - LIBSSH2_CHANNEL *channel; -} packet_queue_listener_state_t; - -#define X11FwdUnAvil "X11 Forward Unavailable" - -typedef struct packet_x11_open_state_t -{ - libssh2_nonblocking_states state; - unsigned char packet[17 + (sizeof(X11FwdUnAvil) - 1)]; - unsigned char *shost; - uint32_t sender_channel; - uint32_t initial_window_size; - uint32_t packet_size; - uint32_t sport; - uint32_t shost_len; - LIBSSH2_CHANNEL *channel; -} packet_x11_open_state_t; - -struct _LIBSSH2_PACKET -{ - struct list_node node; /* linked list header */ - - /* the raw unencrypted payload */ - unsigned char *data; - size_t data_len; - - /* Where to start reading data from, - * used for channel data that's been partially consumed */ - size_t data_head; -}; - -typedef struct _libssh2_channel_data -{ - /* Identifier */ - uint32_t id; - - /* Limits and restrictions */ - uint32_t window_size_initial, window_size, packet_size; - - /* Set to 1 when CHANNEL_CLOSE / CHANNEL_EOF sent/received */ - char close, eof, extended_data_ignore_mode; -} libssh2_channel_data; - -struct _LIBSSH2_CHANNEL -{ - struct list_node node; - - unsigned char *channel_type; - unsigned channel_type_len; - - /* channel's program exit status */ - int exit_status; - - /* channel's program exit signal (without the SIG prefix) */ - char *exit_signal; - - libssh2_channel_data local, remote; - /* Amount of bytes to be refunded to receive window (but not yet sent) */ - uint32_t adjust_queue; - - LIBSSH2_SESSION *session; - - void *abstract; - LIBSSH2_CHANNEL_CLOSE_FUNC((*close_cb)); - - /* State variables used in libssh2_channel_setenv_ex() */ - libssh2_nonblocking_states setenv_state; - unsigned char *setenv_packet; - size_t setenv_packet_len; - unsigned char setenv_local_channel[4]; - packet_requirev_state_t setenv_packet_requirev_state; - - /* State variables used in libssh2_channel_request_pty_ex() - libssh2_channel_request_pty_size_ex() */ - libssh2_nonblocking_states reqPTY_state; - unsigned char reqPTY_packet[41 + 256]; - size_t reqPTY_packet_len; - unsigned char reqPTY_local_channel[4]; - packet_requirev_state_t reqPTY_packet_requirev_state; - - /* State variables used in libssh2_channel_x11_req_ex() */ - libssh2_nonblocking_states reqX11_state; - unsigned char *reqX11_packet; - size_t reqX11_packet_len; - unsigned char reqX11_local_channel[4]; - packet_requirev_state_t reqX11_packet_requirev_state; - - /* State variables used in libssh2_channel_process_startup() */ - libssh2_nonblocking_states process_state; - unsigned char *process_packet; - size_t process_packet_len; - unsigned char process_local_channel[4]; - packet_requirev_state_t process_packet_requirev_state; - - /* State variables used in libssh2_channel_flush_ex() */ - libssh2_nonblocking_states flush_state; - size_t flush_refund_bytes; - size_t flush_flush_bytes; - - /* State variables used in libssh2_channel_receive_window_adjust() */ - libssh2_nonblocking_states adjust_state; - unsigned char adjust_adjust[9]; /* packet_type(1) + channel(4) + adjustment(4) */ - - /* State variables used in libssh2_channel_read_ex() */ - libssh2_nonblocking_states read_state; - - uint32_t read_local_id; - - /* State variables used in libssh2_channel_write_ex() */ - libssh2_nonblocking_states write_state; - unsigned char write_packet[13]; - size_t write_packet_len; - size_t write_bufwrite; - - /* State variables used in libssh2_channel_close() */ - libssh2_nonblocking_states close_state; - unsigned char close_packet[5]; - - /* State variables used in libssh2_channel_wait_closedeof() */ - libssh2_nonblocking_states wait_eof_state; - - /* State variables used in libssh2_channel_wait_closed() */ - libssh2_nonblocking_states wait_closed_state; - - /* State variables used in libssh2_channel_free() */ - libssh2_nonblocking_states free_state; - - /* State variables used in libssh2_channel_handle_extended_data2() */ - libssh2_nonblocking_states extData2_state; - -}; - -struct _LIBSSH2_LISTENER -{ - struct list_node node; /* linked list header */ - - LIBSSH2_SESSION *session; - - char *host; - int port; - - /* a list of CHANNELs for this listener */ - struct list_head queue; - - int queue_size; - int queue_maxsize; - - /* State variables used in libssh2_channel_forward_cancel() */ - libssh2_nonblocking_states chanFwdCncl_state; - unsigned char *chanFwdCncl_data; - size_t chanFwdCncl_data_len; -}; - -typedef struct _libssh2_endpoint_data -{ - unsigned char *banner; - - unsigned char *kexinit; - size_t kexinit_len; - - const LIBSSH2_CRYPT_METHOD *crypt; - void *crypt_abstract; - - const struct _LIBSSH2_MAC_METHOD *mac; - uint32_t seqno; - void *mac_abstract; - - const LIBSSH2_COMP_METHOD *comp; - void *comp_abstract; - - /* Method Preferences -- NULL yields "load order" */ - char *crypt_prefs; - char *mac_prefs; - char *comp_prefs; - char *lang_prefs; -} libssh2_endpoint_data; - -#define PACKETBUFSIZE (1024*16) - -struct transportpacket -{ - /* ------------- for incoming data --------------- */ - unsigned char buf[PACKETBUFSIZE]; - unsigned char init[5]; /* first 5 bytes of the incoming data stream, - still encrypted */ - size_t writeidx; /* at what array index we do the next write into - the buffer */ - size_t readidx; /* at what array index we do the next read from - the buffer */ - uint32_t packet_length; /* the most recent packet_length as read from the - network data */ - uint8_t padding_length; /* the most recent padding_length as read from the - network data */ - size_t data_num; /* How much of the total package that has been read - so far. */ - size_t total_num; /* How much a total package is supposed to be, in - number of bytes. A full package is - packet_length + padding_length + 4 + - mac_length. */ - unsigned char *payload; /* this is a pointer to a LIBSSH2_ALLOC() - area to which we write decrypted data */ - unsigned char *wptr; /* write pointer into the payload to where we - are currently writing decrypted data */ - - /* ------------- for outgoing data --------------- */ - unsigned char outbuf[MAX_SSH_PACKET_LEN]; /* area for the outgoing data */ - - int ototal_num; /* size of outbuf in number of bytes */ - const unsigned char *odata; /* original pointer to the data */ - size_t olen; /* original size of the data we stored in - outbuf */ - size_t osent; /* number of bytes already sent */ -}; - -struct _LIBSSH2_PUBLICKEY -{ - LIBSSH2_CHANNEL *channel; - uint32_t version; - - /* State variables used in libssh2_publickey_packet_receive() */ - libssh2_nonblocking_states receive_state; - unsigned char *receive_packet; - size_t receive_packet_len; - - /* State variables used in libssh2_publickey_add_ex() */ - libssh2_nonblocking_states add_state; - unsigned char *add_packet; - unsigned char *add_s; - - /* State variables used in libssh2_publickey_remove_ex() */ - libssh2_nonblocking_states remove_state; - unsigned char *remove_packet; - unsigned char *remove_s; - - /* State variables used in libssh2_publickey_list_fetch() */ - libssh2_nonblocking_states listFetch_state; - unsigned char *listFetch_s; - unsigned char listFetch_buffer[12]; - unsigned char *listFetch_data; - size_t listFetch_data_len; -}; - -#define LIBSSH2_SCP_RESPONSE_BUFLEN 256 - -struct flags { - int sigpipe; /* LIBSSH2_FLAG_SIGPIPE */ - int compress; /* LIBSSH2_FLAG_COMPRESS */ -}; - -struct _LIBSSH2_SESSION -{ - /* Memory management callbacks */ - void *abstract; - LIBSSH2_ALLOC_FUNC((*alloc)); - LIBSSH2_REALLOC_FUNC((*realloc)); - LIBSSH2_FREE_FUNC((*free)); - - /* Other callbacks */ - LIBSSH2_IGNORE_FUNC((*ssh_msg_ignore)); - LIBSSH2_DEBUG_FUNC((*ssh_msg_debug)); - LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect)); - LIBSSH2_MACERROR_FUNC((*macerror)); - LIBSSH2_X11_OPEN_FUNC((*x11)); - LIBSSH2_SEND_FUNC((*send)); - LIBSSH2_RECV_FUNC((*recv)); - - /* Method preferences -- NULL yields "load order" */ - char *kex_prefs; - char *hostkey_prefs; - - int state; - - /* Flag options */ - struct flags flag; - - /* Agreed Key Exchange Method */ - const LIBSSH2_KEX_METHOD *kex; - int burn_optimistic_kexinit:1; - - unsigned char *session_id; - uint32_t session_id_len; - - /* this is set to TRUE if a blocking API behavior is requested */ - int api_block_mode; - - /* Timeout used when blocking API behavior is active */ - long api_timeout; - - /* Server's public key */ - const LIBSSH2_HOSTKEY_METHOD *hostkey; - void *server_hostkey_abstract; - - /* Either set with libssh2_session_hostkey() (for server mode) - * Or read from server in (eg) KEXDH_INIT (for client mode) - */ - unsigned char *server_hostkey; - uint32_t server_hostkey_len; -#if LIBSSH2_MD5 - unsigned char server_hostkey_md5[MD5_DIGEST_LENGTH]; -#endif /* ! LIBSSH2_MD5 */ - unsigned char server_hostkey_sha1[SHA_DIGEST_LENGTH]; - - /* (remote as source of data -- packet_read ) */ - libssh2_endpoint_data remote; - - /* (local as source of data -- packet_write ) */ - libssh2_endpoint_data local; - - /* Inbound Data linked list -- Sometimes the packet that comes in isn't the - packet we're ready for */ - struct list_head packets; - - /* Active connection channels */ - struct list_head channels; - - uint32_t next_channel; - - struct list_head listeners; /* list of LIBSSH2_LISTENER structs */ - - /* Actual I/O socket */ - libssh2_socket_t socket_fd; - int socket_state; - int socket_block_directions; - int socket_prev_blockstate; /* stores the state of the socket blockiness - when libssh2_session_startup() is called */ - - /* Error tracking */ - const char *err_msg; - int err_code; - - /* struct members for packet-level reading */ - struct transportpacket packet; -#ifdef LIBSSH2DEBUG - int showmask; /* what debug/trace messages to display */ - libssh2_trace_handler_func tracehandler; /* callback to display trace messages */ - void* tracehandler_context; /* context for the trace handler */ -#endif - - /* State variables used in libssh2_banner_send() */ - libssh2_nonblocking_states banner_TxRx_state; - char banner_TxRx_banner[256]; - ssize_t banner_TxRx_total_send; - - /* State variables used in libssh2_kexinit() */ - libssh2_nonblocking_states kexinit_state; - unsigned char *kexinit_data; - size_t kexinit_data_len; - - /* State variables used in libssh2_session_startup() */ - libssh2_nonblocking_states startup_state; - unsigned char *startup_data; - size_t startup_data_len; - unsigned char startup_service[sizeof("ssh-userauth") + 5 - 1]; - size_t startup_service_length; - packet_require_state_t startup_req_state; - key_exchange_state_t startup_key_state; - - /* State variables used in libssh2_session_free() */ - libssh2_nonblocking_states free_state; - - /* State variables used in libssh2_session_disconnect_ex() */ - libssh2_nonblocking_states disconnect_state; - unsigned char disconnect_data[256 + 13]; - size_t disconnect_data_len; - - /* State variables used in libssh2_packet_read() */ - libssh2_nonblocking_states readPack_state; - int readPack_encrypted; - - /* State variables used in libssh2_userauth_list() */ - libssh2_nonblocking_states userauth_list_state; - unsigned char *userauth_list_data; - size_t userauth_list_data_len; - packet_requirev_state_t userauth_list_packet_requirev_state; - - /* State variables used in libssh2_userauth_password_ex() */ - libssh2_nonblocking_states userauth_pswd_state; - unsigned char *userauth_pswd_data; - unsigned char userauth_pswd_data0; - size_t userauth_pswd_data_len; - char *userauth_pswd_newpw; - int userauth_pswd_newpw_len; - packet_requirev_state_t userauth_pswd_packet_requirev_state; - - /* State variables used in libssh2_userauth_hostbased_fromfile_ex() */ - libssh2_nonblocking_states userauth_host_state; - unsigned char *userauth_host_data; - size_t userauth_host_data_len; - unsigned char *userauth_host_packet; - size_t userauth_host_packet_len; - unsigned char *userauth_host_method; - size_t userauth_host_method_len; - unsigned char *userauth_host_s; - packet_requirev_state_t userauth_host_packet_requirev_state; - - /* State variables used in libssh2_userauth_publickey_fromfile_ex() */ - libssh2_nonblocking_states userauth_pblc_state; - unsigned char *userauth_pblc_data; - size_t userauth_pblc_data_len; - unsigned char *userauth_pblc_packet; - size_t userauth_pblc_packet_len; - unsigned char *userauth_pblc_method; - size_t userauth_pblc_method_len; - unsigned char *userauth_pblc_s; - unsigned char *userauth_pblc_b; - packet_requirev_state_t userauth_pblc_packet_requirev_state; - - /* State variables used in libssh2_userauth_keyboard_interactive_ex() */ - libssh2_nonblocking_states userauth_kybd_state; - unsigned char *userauth_kybd_data; - size_t userauth_kybd_data_len; - unsigned char *userauth_kybd_packet; - size_t userauth_kybd_packet_len; - unsigned int userauth_kybd_auth_name_len; - char *userauth_kybd_auth_name; - unsigned userauth_kybd_auth_instruction_len; - char *userauth_kybd_auth_instruction; - unsigned int userauth_kybd_num_prompts; - int userauth_kybd_auth_failure; - LIBSSH2_USERAUTH_KBDINT_PROMPT *userauth_kybd_prompts; - LIBSSH2_USERAUTH_KBDINT_RESPONSE *userauth_kybd_responses; - packet_requirev_state_t userauth_kybd_packet_requirev_state; - - /* State variables used in libssh2_channel_open_ex() */ - libssh2_nonblocking_states open_state; - packet_requirev_state_t open_packet_requirev_state; - LIBSSH2_CHANNEL *open_channel; - unsigned char *open_packet; - size_t open_packet_len; - unsigned char *open_data; - size_t open_data_len; - uint32_t open_local_channel; - - /* State variables used in libssh2_channel_direct_tcpip_ex() */ - libssh2_nonblocking_states direct_state; - unsigned char *direct_message; - size_t direct_host_len; - size_t direct_shost_len; - size_t direct_message_len; - - /* State variables used in libssh2_channel_forward_listen_ex() */ - libssh2_nonblocking_states fwdLstn_state; - unsigned char *fwdLstn_packet; - uint32_t fwdLstn_host_len; - uint32_t fwdLstn_packet_len; - packet_requirev_state_t fwdLstn_packet_requirev_state; - - /* State variables used in libssh2_publickey_init() */ - libssh2_nonblocking_states pkeyInit_state; - LIBSSH2_PUBLICKEY *pkeyInit_pkey; - LIBSSH2_CHANNEL *pkeyInit_channel; - unsigned char *pkeyInit_data; - size_t pkeyInit_data_len; - /* 19 = packet_len(4) + version_len(4) + "version"(7) + version_num(4) */ - unsigned char pkeyInit_buffer[19]; - size_t pkeyInit_buffer_sent; /* how much of buffer that has been sent */ - - /* State variables used in libssh2_packet_add() */ - libssh2_nonblocking_states packAdd_state; - LIBSSH2_CHANNEL *packAdd_channelp; /* keeper of the channel during EAGAIN - states */ - packet_queue_listener_state_t packAdd_Qlstn_state; - packet_x11_open_state_t packAdd_x11open_state; - - /* State variables used in fullpacket() */ - libssh2_nonblocking_states fullpacket_state; - int fullpacket_macstate; - size_t fullpacket_payload_len; - int fullpacket_packet_type; - - /* State variables used in libssh2_sftp_init() */ - libssh2_nonblocking_states sftpInit_state; - LIBSSH2_SFTP *sftpInit_sftp; - LIBSSH2_CHANNEL *sftpInit_channel; - unsigned char sftpInit_buffer[9]; /* sftp_header(5){excludes request_id} - + version_id(4) */ - int sftpInit_sent; /* number of bytes from the buffer that have been - sent */ - - /* State variables used in libssh2_scp_recv() */ - libssh2_nonblocking_states scpRecv_state; - unsigned char *scpRecv_command; - size_t scpRecv_command_len; - unsigned char scpRecv_response[LIBSSH2_SCP_RESPONSE_BUFLEN]; - size_t scpRecv_response_len; - long scpRecv_mode; -#if defined(HAVE_LONGLONG) && defined(HAVE_STRTOLL) - /* we have the type and we can parse such numbers */ - long long scpRecv_size; -#define scpsize_strtol strtoll -#else - long scpRecv_size; -#define scpsize_strtol strtol -#endif - long scpRecv_mtime; - long scpRecv_atime; - LIBSSH2_CHANNEL *scpRecv_channel; - - /* State variables used in libssh2_scp_send_ex() */ - libssh2_nonblocking_states scpSend_state; - unsigned char *scpSend_command; - size_t scpSend_command_len; - unsigned char scpSend_response[LIBSSH2_SCP_RESPONSE_BUFLEN]; - size_t scpSend_response_len; - LIBSSH2_CHANNEL *scpSend_channel; - - /* Keepalive variables used by keepalive.c. */ - int keepalive_interval; - int keepalive_want_reply; - time_t keepalive_last_sent; -}; - -/* session.state bits */ -#define LIBSSH2_STATE_EXCHANGING_KEYS 0x00000001 -#define LIBSSH2_STATE_NEWKEYS 0x00000002 -#define LIBSSH2_STATE_AUTHENTICATED 0x00000004 -#define LIBSSH2_STATE_KEX_ACTIVE 0x00000008 - -/* session.flag helpers */ -#ifdef MSG_NOSIGNAL -#define LIBSSH2_SOCKET_SEND_FLAGS(session) \ - (((session)->flag.sigpipe) ? 0 : MSG_NOSIGNAL) -#define LIBSSH2_SOCKET_RECV_FLAGS(session) \ - (((session)->flag.sigpipe) ? 0 : MSG_NOSIGNAL) -#else -/* If MSG_NOSIGNAL isn't defined we're SOL on blocking SIGPIPE */ -#define LIBSSH2_SOCKET_SEND_FLAGS(session) 0 -#define LIBSSH2_SOCKET_RECV_FLAGS(session) 0 -#endif - -/* --------- */ - -/* libssh2 extensible ssh api, ultimately I'd like to allow loading additional - methods via .so/.dll */ - -struct _LIBSSH2_KEX_METHOD -{ - const char *name; - - /* Key exchange, populates session->* and returns 0 on success, non-0 on error */ - int (*exchange_keys) (LIBSSH2_SESSION * session, - key_exchange_state_low_t * key_state); - - long flags; -}; - -struct _LIBSSH2_HOSTKEY_METHOD -{ - const char *name; - unsigned long hash_len; - - int (*init) (LIBSSH2_SESSION * session, const unsigned char *hostkey_data, - size_t hostkey_data_len, void **abstract); - int (*initPEM) (LIBSSH2_SESSION * session, const char *privkeyfile, - unsigned const char *passphrase, void **abstract); - int (*sig_verify) (LIBSSH2_SESSION * session, const unsigned char *sig, - size_t sig_len, const unsigned char *m, - size_t m_len, void **abstract); - int (*signv) (LIBSSH2_SESSION * session, unsigned char **signature, - size_t *signature_len, int veccount, - const struct iovec datavec[], void **abstract); - int (*encrypt) (LIBSSH2_SESSION * session, unsigned char **dst, - size_t *dst_len, const unsigned char *src, - size_t src_len, void **abstract); - int (*dtor) (LIBSSH2_SESSION * session, void **abstract); -}; - -struct _LIBSSH2_CRYPT_METHOD -{ - const char *name; - - int blocksize; - - /* iv and key sizes (-1 for variable length) */ - int iv_len; - int secret_len; - - long flags; - - int (*init) (LIBSSH2_SESSION * session, - const LIBSSH2_CRYPT_METHOD * method, unsigned char *iv, - int *free_iv, unsigned char *secret, int *free_secret, - int encrypt, void **abstract); - int (*crypt) (LIBSSH2_SESSION * session, unsigned char *block, - void **abstract); - int (*dtor) (LIBSSH2_SESSION * session, void **abstract); - - _libssh2_cipher_type(algo); -}; - -struct _LIBSSH2_COMP_METHOD -{ - const char *name; - int compress; /* 1 if it does compress, 0 if it doesn't */ - int (*init) (LIBSSH2_SESSION *session, int compress, void **abstract); - int (*comp) (LIBSSH2_SESSION *session, - unsigned char *dest, - size_t *dest_len, - const unsigned char *src, - size_t src_len, - void **abstract); - int (*decomp) (LIBSSH2_SESSION *session, - unsigned char **dest, - size_t *dest_len, - size_t payload_limit, - const unsigned char *src, - size_t src_len, - void **abstract); - int (*dtor) (LIBSSH2_SESSION * session, int compress, void **abstract); -}; - -#ifdef LIBSSH2DEBUG -void _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, - ...); -#else -#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || defined(__GNUC__) -/* C99 supported and also by older GCC */ -#define _libssh2_debug(x,y,z,...) do {} while (0) -#else -/* no gcc and not C99, do static and hopefully inline */ -static inline void -_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) -{ -} -#endif -#endif - -#define LIBSSH2_SOCKET_UNKNOWN 1 -#define LIBSSH2_SOCKET_CONNECTED 0 -#define LIBSSH2_SOCKET_DISCONNECTED -1 - -/* Initial packet state, prior to MAC check */ -#define LIBSSH2_MAC_UNCONFIRMED 1 -/* When MAC type is "none" (proto initiation phase) all packets are deemed "confirmed" */ -#define LIBSSH2_MAC_CONFIRMED 0 -/* Something very bad is going on */ -#define LIBSSH2_MAC_INVALID -1 - -/* SSH Packet Types -- Defined by internet draft */ -/* Transport Layer */ -#define SSH_MSG_DISCONNECT 1 -#define SSH_MSG_IGNORE 2 -#define SSH_MSG_UNIMPLEMENTED 3 -#define SSH_MSG_DEBUG 4 -#define SSH_MSG_SERVICE_REQUEST 5 -#define SSH_MSG_SERVICE_ACCEPT 6 - -#define SSH_MSG_KEXINIT 20 -#define SSH_MSG_NEWKEYS 21 - -/* diffie-hellman-group1-sha1 */ -#define SSH_MSG_KEXDH_INIT 30 -#define SSH_MSG_KEXDH_REPLY 31 - -/* diffie-hellman-group-exchange-sha1 */ -#define SSH_MSG_KEX_DH_GEX_REQUEST_OLD 30 -#define SSH_MSG_KEX_DH_GEX_REQUEST 34 -#define SSH_MSG_KEX_DH_GEX_GROUP 31 -#define SSH_MSG_KEX_DH_GEX_INIT 32 -#define SSH_MSG_KEX_DH_GEX_REPLY 33 - -/* User Authentication */ -#define SSH_MSG_USERAUTH_REQUEST 50 -#define SSH_MSG_USERAUTH_FAILURE 51 -#define SSH_MSG_USERAUTH_SUCCESS 52 -#define SSH_MSG_USERAUTH_BANNER 53 - -/* "public key" method */ -#define SSH_MSG_USERAUTH_PK_OK 60 -/* "password" method */ -#define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60 -/* "keyboard-interactive" method */ -#define SSH_MSG_USERAUTH_INFO_REQUEST 60 -#define SSH_MSG_USERAUTH_INFO_RESPONSE 61 - -/* Channels */ -#define SSH_MSG_GLOBAL_REQUEST 80 -#define SSH_MSG_REQUEST_SUCCESS 81 -#define SSH_MSG_REQUEST_FAILURE 82 - -#define SSH_MSG_CHANNEL_OPEN 90 -#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 91 -#define SSH_MSG_CHANNEL_OPEN_FAILURE 92 -#define SSH_MSG_CHANNEL_WINDOW_ADJUST 93 -#define SSH_MSG_CHANNEL_DATA 94 -#define SSH_MSG_CHANNEL_EXTENDED_DATA 95 -#define SSH_MSG_CHANNEL_EOF 96 -#define SSH_MSG_CHANNEL_CLOSE 97 -#define SSH_MSG_CHANNEL_REQUEST 98 -#define SSH_MSG_CHANNEL_SUCCESS 99 -#define SSH_MSG_CHANNEL_FAILURE 100 - -/* Error codes returned in SSH_MSG_CHANNEL_OPEN_FAILURE message - (see RFC4254) */ -#define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1 -#define SSH_OPEN_CONNECT_FAILED 2 -#define SSH_OPEN_UNKNOWN_CHANNELTYPE 3 -#define SSH_OPEN_RESOURCE_SHORTAGE 4 - -ssize_t _libssh2_recv(libssh2_socket_t socket, void *buffer, - size_t length, int flags, void **abstract); -ssize_t _libssh2_send(libssh2_socket_t socket, const void *buffer, - size_t length, int flags, void **abstract); - -#define LIBSSH2_READ_TIMEOUT 60 /* generic timeout in seconds used when - waiting for more data to arrive */ - - -int _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, - key_exchange_state_t * state); - -/* Let crypt.c/hostkey.c expose their method structs */ -const LIBSSH2_CRYPT_METHOD **libssh2_crypt_methods(void); -const LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void); - -/* pem.c */ -int _libssh2_pem_parse(LIBSSH2_SESSION * session, - const char *headerbegin, - const char *headerend, - FILE * fp, unsigned char **data, unsigned int *datalen); -int _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen); -int _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen, - unsigned char **i, unsigned int *ilen); - -/* global.c */ -void _libssh2_init_if_needed (void); - - -#define ARRAY_SIZE(a) (sizeof ((a)) / sizeof ((a)[0])) - -/* define to output the libssh2_int64_t type in a *printf() */ -#if defined( __BORLANDC__ ) || defined( _MSC_VER ) || defined( __MINGW32__ ) -#define LIBSSH2_INT64_T_FORMAT "I64" -#else -#define LIBSSH2_INT64_T_FORMAT "ll" -#endif - -#endif /* LIBSSH2_H */ diff --git a/vendor/libssh2-1.4.2/src/mac.c b/vendor/libssh2-1.4.2/src/mac.c deleted file mode 100644 index 76894fc..0000000 --- a/vendor/libssh2-1.4.2/src/mac.c +++ /dev/null @@ -1,314 +0,0 @@ -/* Copyright (c) 2004-2007, Sara Golemon - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" -#include "mac.h" - -#ifdef LIBSSH2_MAC_NONE -/* mac_none_MAC - * Minimalist MAC: No MAC - */ -static int -mac_none_MAC(LIBSSH2_SESSION * session, unsigned char *buf, - uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, void **abstract) -{ - return 0; -} - - - - -static LIBSSH2_MAC_METHOD mac_method_none = { - "none", - 0, - 0, - NULL, - mac_none_MAC, - NULL -}; -#endif /* LIBSSH2_MAC_NONE */ - -/* mac_method_common_init - * Initialize simple mac methods - */ -static int -mac_method_common_init(LIBSSH2_SESSION * session, unsigned char *key, - int *free_key, void **abstract) -{ - *abstract = key; - *free_key = 0; - (void) session; - - return 0; -} - - - -/* mac_method_common_dtor - * Cleanup simple mac methods - */ -static int -mac_method_common_dtor(LIBSSH2_SESSION * session, void **abstract) -{ - if (*abstract) { - LIBSSH2_FREE(session, *abstract); - } - *abstract = NULL; - - return 0; -} - - - -/* mac_method_hmac_sha1_hash - * Calculate hash using full sha1 value - */ -static int -mac_method_hmac_sha1_hash(LIBSSH2_SESSION * session, - unsigned char *buf, uint32_t seqno, - const unsigned char *packet, - uint32_t packet_len, - const unsigned char *addtl, - uint32_t addtl_len, void **abstract) -{ - libssh2_hmac_ctx ctx; - unsigned char seqno_buf[4]; - (void) session; - - _libssh2_htonu32(seqno_buf, seqno); - - libssh2_hmac_sha1_init(&ctx, *abstract, 20); - libssh2_hmac_update(ctx, seqno_buf, 4); - libssh2_hmac_update(ctx, packet, packet_len); - if (addtl && addtl_len) { - libssh2_hmac_update(ctx, addtl, addtl_len); - } - libssh2_hmac_final(ctx, buf); - libssh2_hmac_cleanup(&ctx); - - return 0; -} - - - -static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1 = { - "hmac-sha1", - 20, - 20, - mac_method_common_init, - mac_method_hmac_sha1_hash, - mac_method_common_dtor, -}; - -/* mac_method_hmac_sha1_96_hash - * Calculate hash using first 96 bits of sha1 value - */ -static int -mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION * session, - unsigned char *buf, uint32_t seqno, - const unsigned char *packet, - uint32_t packet_len, - const unsigned char *addtl, - uint32_t addtl_len, void **abstract) -{ - unsigned char temp[SHA_DIGEST_LENGTH]; - - mac_method_hmac_sha1_hash(session, temp, seqno, packet, packet_len, - addtl, addtl_len, abstract); - memcpy(buf, (char *) temp, 96 / 8); - - return 0; -} - - - -static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1_96 = { - "hmac-sha1-96", - 12, - 20, - mac_method_common_init, - mac_method_hmac_sha1_96_hash, - mac_method_common_dtor, -}; - -#if LIBSSH2_MD5 -/* mac_method_hmac_md5_hash - * Calculate hash using full md5 value - */ -static int -mac_method_hmac_md5_hash(LIBSSH2_SESSION * session, unsigned char *buf, - uint32_t seqno, - const unsigned char *packet, - uint32_t packet_len, - const unsigned char *addtl, - uint32_t addtl_len, void **abstract) -{ - libssh2_hmac_ctx ctx; - unsigned char seqno_buf[4]; - (void) session; - - _libssh2_htonu32(seqno_buf, seqno); - - libssh2_hmac_md5_init(&ctx, *abstract, 16); - libssh2_hmac_update(ctx, seqno_buf, 4); - libssh2_hmac_update(ctx, packet, packet_len); - if (addtl && addtl_len) { - libssh2_hmac_update(ctx, addtl, addtl_len); - } - libssh2_hmac_final(ctx, buf); - libssh2_hmac_cleanup(&ctx); - - return 0; -} - - - -static const LIBSSH2_MAC_METHOD mac_method_hmac_md5 = { - "hmac-md5", - 16, - 16, - mac_method_common_init, - mac_method_hmac_md5_hash, - mac_method_common_dtor, -}; - -/* mac_method_hmac_md5_96_hash - * Calculate hash using first 96 bits of md5 value - */ -static int -mac_method_hmac_md5_96_hash(LIBSSH2_SESSION * session, - unsigned char *buf, uint32_t seqno, - const unsigned char *packet, - uint32_t packet_len, - const unsigned char *addtl, - uint32_t addtl_len, void **abstract) -{ - unsigned char temp[MD5_DIGEST_LENGTH]; - mac_method_hmac_md5_hash(session, temp, seqno, packet, packet_len, - addtl, addtl_len, abstract); - memcpy(buf, (char *) temp, 96 / 8); - return 0; -} - - - -static const LIBSSH2_MAC_METHOD mac_method_hmac_md5_96 = { - "hmac-md5-96", - 12, - 16, - mac_method_common_init, - mac_method_hmac_md5_96_hash, - mac_method_common_dtor, -}; -#endif /* LIBSSH2_MD5 */ - -#if LIBSSH2_HMAC_RIPEMD -/* mac_method_hmac_ripemd160_hash - * Calculate hash using ripemd160 value - */ -static int -mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION * session, - unsigned char *buf, uint32_t seqno, - const unsigned char *packet, - uint32_t packet_len, - const unsigned char *addtl, - uint32_t addtl_len, - void **abstract) -{ - libssh2_hmac_ctx ctx; - unsigned char seqno_buf[4]; - (void) session; - - _libssh2_htonu32(seqno_buf, seqno); - - libssh2_hmac_ripemd160_init(&ctx, *abstract, 20); - libssh2_hmac_update(ctx, seqno_buf, 4); - libssh2_hmac_update(ctx, packet, packet_len); - if (addtl && addtl_len) { - libssh2_hmac_update(ctx, addtl, addtl_len); - } - libssh2_hmac_final(ctx, buf); - libssh2_hmac_cleanup(&ctx); - - return 0; -} - - - -static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160 = { - "hmac-ripemd160", - 20, - 20, - mac_method_common_init, - mac_method_hmac_ripemd160_hash, - mac_method_common_dtor, -}; - -static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160_openssh_com = { - "hmac-ripemd160@openssh.com", - 20, - 20, - mac_method_common_init, - mac_method_hmac_ripemd160_hash, - mac_method_common_dtor, -}; -#endif /* LIBSSH2_HMAC_RIPEMD */ - -static const LIBSSH2_MAC_METHOD *mac_methods[] = { - &mac_method_hmac_sha1, - &mac_method_hmac_sha1_96, -#if LIBSSH2_MD5 - &mac_method_hmac_md5, - &mac_method_hmac_md5_96, -#endif -#if LIBSSH2_HMAC_RIPEMD - &mac_method_hmac_ripemd160, - &mac_method_hmac_ripemd160_openssh_com, -#endif /* LIBSSH2_HMAC_RIPEMD */ -#ifdef LIBSSH2_MAC_NONE - &mac_method_none, -#endif /* LIBSSH2_MAC_NONE */ - NULL -}; - -const LIBSSH2_MAC_METHOD ** -_libssh2_mac_methods(void) -{ - return mac_methods; -} diff --git a/vendor/libssh2-1.4.2/src/mac.h b/vendor/libssh2-1.4.2/src/mac.h deleted file mode 100644 index 66d3e61..0000000 --- a/vendor/libssh2-1.4.2/src/mac.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef __LIBSSH2_MAC_H -#define __LIBSSH2_MAC_H - -/* Copyright (C) 2009-2010 by Daniel Stenberg - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - */ - -#include "libssh2_priv.h" - -struct _LIBSSH2_MAC_METHOD -{ - const char *name; - - /* The length of a given MAC packet */ - int mac_len; - - /* integrity key length */ - int key_len; - - /* Message Authentication Code Hashing algo */ - int (*init) (LIBSSH2_SESSION * session, unsigned char *key, int *free_key, - void **abstract); - int (*hash) (LIBSSH2_SESSION * session, unsigned char *buf, - uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, void **abstract); - int (*dtor) (LIBSSH2_SESSION * session, void **abstract); -}; - -typedef struct _LIBSSH2_MAC_METHOD LIBSSH2_MAC_METHOD; - -const LIBSSH2_MAC_METHOD **_libssh2_mac_methods(void); - -#endif /* __LIBSSH2_MAC_H */ diff --git a/vendor/libssh2-1.4.2/src/misc.c b/vendor/libssh2-1.4.2/src/misc.c deleted file mode 100644 index a9f423a..0000000 --- a/vendor/libssh2-1.4.2/src/misc.c +++ /dev/null @@ -1,612 +0,0 @@ -/* Copyright (c) 2004-2007 Sara Golemon - * Copyright (c) 2009-2010 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" -#include "misc.h" - -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#include -#include - -int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char* errmsg) -{ - session->err_msg = errmsg; - session->err_code = errcode; -#ifdef LIBSSH2DEBUG - if((errcode == LIBSSH2_ERROR_EAGAIN) && !session->api_block_mode) - /* if this is EAGAIN and we're in non-blocking mode, don't generate - a debug output for this */ - return errcode; - _libssh2_debug(session, LIBSSH2_TRACE_ERROR, "%d - %s", session->err_code, - session->err_msg); -#endif - - return errcode; -} - -#ifdef WIN32 -static int wsa2errno(void) -{ - switch (WSAGetLastError()) { - case WSAEWOULDBLOCK: - return EAGAIN; - - case WSAENOTSOCK: - return EBADF; - - case WSAEINTR: - return EINTR; - - default: - /* It is most important to ensure errno does not stay at EAGAIN - * when a different error occurs so just set errno to a generic - * error */ - return EIO; - } -} -#endif - -/* _libssh2_recv - * - * Replacement for the standard recv, return -errno on failure. - */ -ssize_t -_libssh2_recv(libssh2_socket_t sock, void *buffer, size_t length, int flags, void **abstract) -{ - ssize_t rc = recv(sock, buffer, length, flags); -#ifdef WIN32 - if (rc < 0 ) - return -wsa2errno(); -#elif defined(__VMS) - if (rc < 0 ){ - if ( errno == EWOULDBLOCK ) - return -EAGAIN; - else - return -errno; - } -#else - if (rc < 0 ){ - /* Sometimes the first recv() function call sets errno to ENOENT on - Solaris and HP-UX */ - if ( errno == ENOENT ) - return -EAGAIN; - else - return -errno; - } -#endif - return rc; -} - -/* _libssh2_send - * - * Replacement for the standard send, return -errno on failure. - */ -ssize_t -_libssh2_send(libssh2_socket_t sock, const void *buffer, size_t length, - int flags, void **abstract) -{ - ssize_t rc = send(sock, buffer, length, flags); -#ifdef WIN32 - if (rc < 0 ) - return -wsa2errno(); -#elif defined(__VMS) - if (rc < 0 ) { - if ( errno == EWOULDBLOCK ) - return -EAGAIN; - else - return -errno; - } -#else - if (rc < 0 ) - return -errno; -#endif - return rc; -} - -/* libssh2_ntohu32 - */ -unsigned int -_libssh2_ntohu32(const unsigned char *buf) -{ - return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; -} - - -/* _libssh2_ntohu64 - */ -libssh2_uint64_t -_libssh2_ntohu64(const unsigned char *buf) -{ - unsigned long msl, lsl; - - msl = ((libssh2_uint64_t)buf[0] << 24) | ((libssh2_uint64_t)buf[1] << 16) - | ((libssh2_uint64_t)buf[2] << 8) | (libssh2_uint64_t)buf[3]; - lsl = ((libssh2_uint64_t)buf[4] << 24) | ((libssh2_uint64_t)buf[5] << 16) - | ((libssh2_uint64_t)buf[6] << 8) | (libssh2_uint64_t)buf[7]; - - return ((libssh2_uint64_t)msl <<32) | lsl; -} - -/* _libssh2_htonu32 - */ -void -_libssh2_htonu32(unsigned char *buf, uint32_t value) -{ - buf[0] = (value >> 24) & 0xFF; - buf[1] = (value >> 16) & 0xFF; - buf[2] = (value >> 8) & 0xFF; - buf[3] = value & 0xFF; -} - -/* _libssh2_store_u32 - */ -void _libssh2_store_u32(unsigned char **buf, uint32_t value) -{ - _libssh2_htonu32(*buf, value); - *buf += sizeof(uint32_t); -} - -/* _libssh2_store_str - */ -void _libssh2_store_str(unsigned char **buf, const char *str, size_t len) -{ - _libssh2_store_u32(buf, (uint32_t)len); - if(len) { - memcpy(*buf, str, len); - *buf += len; - } -} - -/* Base64 Conversion */ - -static const char base64_table[] = -{ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0' -}; - -static const char base64_pad = '='; - -static const short base64_reverse_table[256] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 -}; - -/* libssh2_base64_decode - * - * Decode a base64 chunk and store it into a newly alloc'd buffer - */ -LIBSSH2_API int -libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, - unsigned int *datalen, const char *src, - unsigned int src_len) -{ - unsigned char *s, *d; - short v; - int i = 0, len = 0; - - *data = LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1); - d = (unsigned char *) *data; - if (!d) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for base64 decoding"); - } - - for(s = (unsigned char *) src; ((char *) s) < (src + src_len); s++) { - if ((v = base64_reverse_table[*s]) < 0) - continue; - switch (i % 4) { - case 0: - d[len] = v << 2; - break; - case 1: - d[len++] |= v >> 4; - d[len] = v << 4; - break; - case 2: - d[len++] |= v >> 2; - d[len] = v << 6; - break; - case 3: - d[len++] |= v; - break; - } - i++; - } - if ((i % 4) == 1) { - /* Invalid -- We have a byte which belongs exclusively to a partial - octet */ - LIBSSH2_FREE(session, *data); - return _libssh2_error(session, LIBSSH2_ERROR_INVAL, "Invalid base64"); - } - - *datalen = len; - return 0; -} - -/* ---- Base64 Encoding/Decoding Table --- */ -static const char table64[]= - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -/* - * _libssh2_base64_encode() - * - * Returns the length of the newly created base64 string. The third argument - * is a pointer to an allocated area holding the base64 data. If something - * went wrong, 0 is returned. - * - */ -size_t _libssh2_base64_encode(LIBSSH2_SESSION *session, - const char *inp, size_t insize, char **outptr) -{ - unsigned char ibuf[3]; - unsigned char obuf[4]; - int i; - int inputparts; - char *output; - char *base64data; - const char *indata = inp; - - *outptr = NULL; /* set to NULL in case of failure before we reach the end */ - - if(0 == insize) - insize = strlen(indata); - - base64data = output = LIBSSH2_ALLOC(session, insize*4/3+4); - if(NULL == output) - return 0; - - while(insize > 0) { - for (i = inputparts = 0; i < 3; i++) { - if(insize > 0) { - inputparts++; - ibuf[i] = *indata; - indata++; - insize--; - } - else - ibuf[i] = 0; - } - - obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2); - obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \ - ((ibuf[1] & 0xF0) >> 4)); - obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \ - ((ibuf[2] & 0xC0) >> 6)); - obuf[3] = (unsigned char) (ibuf[2] & 0x3F); - - switch(inputparts) { - case 1: /* only one byte read */ - snprintf(output, 5, "%c%c==", - table64[obuf[0]], - table64[obuf[1]]); - break; - case 2: /* two bytes read */ - snprintf(output, 5, "%c%c%c=", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]]); - break; - default: - snprintf(output, 5, "%c%c%c%c", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]], - table64[obuf[3]] ); - break; - } - output += 4; - } - *output=0; - *outptr = base64data; /* make it return the actual data memory */ - - return strlen(base64data); /* return the length of the new data */ -} -/* ---- End of Base64 Encoding ---- */ - -LIBSSH2_API void -libssh2_free(LIBSSH2_SESSION *session, void *ptr) -{ - LIBSSH2_FREE(session, ptr); -} - -#ifdef LIBSSH2DEBUG -LIBSSH2_API int -libssh2_trace(LIBSSH2_SESSION * session, int bitmask) -{ - session->showmask = bitmask; - return 0; -} - -LIBSSH2_API int -libssh2_trace_sethandler(LIBSSH2_SESSION *session, void* handler_context, - libssh2_trace_handler_func callback) -{ - session->tracehandler = callback; - session->tracehandler_context = handler_context; - return 0; -} - -void -_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) -{ - char buffer[1536]; - int len, msglen, buflen = sizeof(buffer); - va_list vargs; - struct timeval now; - static int firstsec; - static const char *const contexts[] = { - "Unknown", - "Transport", - "Key Ex", - "Userauth", - "Conn", - "SCP", - "SFTP", - "Failure Event", - "Publickey", - "Socket", - }; - const char* contexttext = contexts[0]; - unsigned int contextindex; - - if (!(session->showmask & context)) { - /* no such output asked for */ - return; - } - - /* Find the first matching context string for this message */ - for (contextindex = 0; contextindex < ARRAY_SIZE(contexts); - contextindex++) { - if ((context & (1 << contextindex)) != 0) { - contexttext = contexts[contextindex]; - break; - } - } - - _libssh2_gettimeofday(&now, NULL); - if(!firstsec) { - firstsec = now.tv_sec; - } - now.tv_sec -= firstsec; - - len = snprintf(buffer, buflen, "[libssh2] %d.%06d %s: ", - (int)now.tv_sec, (int)now.tv_usec, contexttext); - - if (len >= buflen) - msglen = buflen - 1; - else { - buflen -= len; - msglen = len; - va_start(vargs, format); - len = vsnprintf(buffer + msglen, buflen, format, vargs); - va_end(vargs); - msglen += len < buflen ? len : buflen - 1; - } - - if (session->tracehandler) - (session->tracehandler)(session, session->tracehandler_context, buffer, - msglen); - else - fprintf(stderr, "%s\n", buffer); -} - -#else -LIBSSH2_API int -libssh2_trace(LIBSSH2_SESSION * session, int bitmask) -{ - (void) session; - (void) bitmask; - return 0; -} - -LIBSSH2_API int -libssh2_trace_sethandler(LIBSSH2_SESSION *session, void* handler_context, - libssh2_trace_handler_func callback) -{ - (void) session; - (void) handler_context; - (void) callback; - return 0; -} -#endif - -/* init the list head */ -void _libssh2_list_init(struct list_head *head) -{ - head->first = head->last = NULL; -} - -/* add a node to the list */ -void _libssh2_list_add(struct list_head *head, - struct list_node *entry) -{ - /* store a pointer to the head */ - entry->head = head; - - /* we add this entry at the "top" so it has no next */ - entry->next = NULL; - - /* make our prev point to what the head thinks is last */ - entry->prev = head->last; - - /* and make head's last be us now */ - head->last = entry; - - /* make sure our 'prev' node points to us next */ - if(entry->prev) - entry->prev->next = entry; - else - head->first = entry; -} - -/* return the "first" node in the list this head points to */ -void *_libssh2_list_first(struct list_head *head) -{ - return head->first; -} - -/* return the next node in the list */ -void *_libssh2_list_next(struct list_node *node) -{ - return node->next; -} - -/* return the prev node in the list */ -void *_libssh2_list_prev(struct list_node *node) -{ - return node->prev; -} - -/* remove this node from the list */ -void _libssh2_list_remove(struct list_node *entry) -{ - if(entry->prev) - entry->prev->next = entry->next; - else - entry->head->first = entry->next; - - if(entry->next) - entry->next->prev = entry->prev; - else - entry->head->last = entry->prev; -} - -#if 0 -/* insert a node before the given 'after' entry */ -void _libssh2_list_insert(struct list_node *after, /* insert before this */ - struct list_node *entry) -{ - /* 'after' is next to 'entry' */ - bentry->next = after; - - /* entry's prev is then made to be the prev after current has */ - entry->prev = after->prev; - - /* the node that is now before 'entry' was previously before 'after' - and must be made to point to 'entry' correctly */ - if(entry->prev) - entry->prev->next = entry; - else - /* there was no node before this, so we make sure we point the head - pointer to this node */ - after->head->first = entry; - - /* after's prev entry points back to entry */ - after->prev = entry; - - /* after's next entry is still the same as before */ - - /* entry's head is the same as after's */ - entry->head = after->head; -} - -#endif - -/* this define is defined in misc.h for the correct platforms */ -#ifdef LIBSSH2_GETTIMEOFDAY_WIN32 -/* - * gettimeofday - * Implementation according to: - * The Open Group Base Specifications Issue 6 - * IEEE Std 1003.1, 2004 Edition - */ - -/* - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Contributed by: - * Danny Smith - */ - -/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */ -#define _W32_FT_OFFSET (116444736000000000) - -int __cdecl _libssh2_gettimeofday(struct timeval *tp, void *tzp) - { - union { - unsigned __int64 ns100; /*time since 1 Jan 1601 in 100ns units */ - FILETIME ft; - } _now; - - if(tp) - { - GetSystemTimeAsFileTime (&_now.ft); - tp->tv_usec=(long)((_now.ns100 / 10) % 1000000 ); - tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000); - } - /* Always return 0 as per Open Group Base Specifications Issue 6. - Do not set errno on error. */ - return 0; -} - - -#endif diff --git a/vendor/libssh2-1.4.2/src/misc.h b/vendor/libssh2-1.4.2/src/misc.h deleted file mode 100644 index 8a8294a..0000000 --- a/vendor/libssh2-1.4.2/src/misc.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef __LIBSSH2_MISC_H -#define __LIBSSH2_MISC_H -/* Copyright (c) 2009-2011 by Daniel Stenberg - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -struct list_head { - struct list_node *last; - struct list_node *first; -}; - -struct list_node { - struct list_node *next; - struct list_node *prev; - struct list_head *head; -}; - -int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char* errmsg); - -void _libssh2_list_init(struct list_head *head); - -/* add a node last in the list */ -void _libssh2_list_add(struct list_head *head, - struct list_node *entry); - -/* return the "first" node in the list this head points to */ -void *_libssh2_list_first(struct list_head *head); - -/* return the next node in the list */ -void *_libssh2_list_next(struct list_node *node); - -/* return the prev node in the list */ -void *_libssh2_list_prev(struct list_node *node); - -/* remove this node from the list */ -void _libssh2_list_remove(struct list_node *entry); - -size_t _libssh2_base64_encode(struct _LIBSSH2_SESSION *session, - const char *inp, size_t insize, char **outptr); - -unsigned int _libssh2_ntohu32(const unsigned char *buf); -libssh2_uint64_t _libssh2_ntohu64(const unsigned char *buf); -void _libssh2_htonu32(unsigned char *buf, uint32_t val); -void _libssh2_store_u32(unsigned char **buf, uint32_t value); -void _libssh2_store_str(unsigned char **buf, const char *str, size_t len); - -#if defined(WIN32) || defined(LIBSSH2_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) -/* provide a private one */ -#undef HAVE_GETTIMEOFDAY -int __cdecl _libssh2_gettimeofday(struct timeval *tp, void *tzp); -#define HAVE_LIBSSH2_GETTIMEOFDAY -#define LIBSSH2_GETTIMEOFDAY_WIN32 /* enable the win32 implementation */ -#else -#ifdef HAVE_GETTIMEOFDAY -#define _libssh2_gettimeofday(x,y) gettimeofday(x,y) -#define HAVE_LIBSSH2_GETTIMEOFDAY -#endif -#endif - -#endif /* _LIBSSH2_MISC_H */ diff --git a/vendor/libssh2-1.4.2/src/openssl.c b/vendor/libssh2-1.4.2/src/openssl.c deleted file mode 100644 index 481982c..0000000 --- a/vendor/libssh2-1.4.2/src/openssl.c +++ /dev/null @@ -1,804 +0,0 @@ -/* Copyright (C) 2009, 2010 Simon Josefsson - * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. - * Copyright (c) 2004-2006, Sara Golemon - * - * Author: Simon Josefsson - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" - -#ifndef LIBSSH2_LIBGCRYPT /* compile only if we build with OpenSSL */ - -#include - -#ifndef EVP_MAX_BLOCK_LENGTH -#define EVP_MAX_BLOCK_LENGTH 32 -#endif - -int -_libssh2_rsa_new(libssh2_rsa_ctx ** rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, unsigned long coefflen) -{ - *rsa = RSA_new(); - - (*rsa)->e = BN_new(); - BN_bin2bn(edata, elen, (*rsa)->e); - - (*rsa)->n = BN_new(); - BN_bin2bn(ndata, nlen, (*rsa)->n); - - if (ddata) { - (*rsa)->d = BN_new(); - BN_bin2bn(ddata, dlen, (*rsa)->d); - - (*rsa)->p = BN_new(); - BN_bin2bn(pdata, plen, (*rsa)->p); - - (*rsa)->q = BN_new(); - BN_bin2bn(qdata, qlen, (*rsa)->q); - - (*rsa)->dmp1 = BN_new(); - BN_bin2bn(e1data, e1len, (*rsa)->dmp1); - - (*rsa)->dmq1 = BN_new(); - BN_bin2bn(e2data, e2len, (*rsa)->dmq1); - - (*rsa)->iqmp = BN_new(); - BN_bin2bn(coeffdata, coefflen, (*rsa)->iqmp); - } - return 0; -} - -int -_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsactx, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, unsigned long m_len) -{ - unsigned char hash[SHA_DIGEST_LENGTH]; - int ret; - - libssh2_sha1(m, m_len, hash); - ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH, - (unsigned char *) sig, sig_len, rsactx); - return (ret == 1) ? 0 : -1; -} - -#if LIBSSH2_DSA -int -_libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, - const unsigned char *p, - unsigned long p_len, - const unsigned char *q, - unsigned long q_len, - const unsigned char *g, - unsigned long g_len, - const unsigned char *y, - unsigned long y_len, - const unsigned char *x, unsigned long x_len) -{ - *dsactx = DSA_new(); - - (*dsactx)->p = BN_new(); - BN_bin2bn(p, p_len, (*dsactx)->p); - - (*dsactx)->q = BN_new(); - BN_bin2bn(q, q_len, (*dsactx)->q); - - (*dsactx)->g = BN_new(); - BN_bin2bn(g, g_len, (*dsactx)->g); - - (*dsactx)->pub_key = BN_new(); - BN_bin2bn(y, y_len, (*dsactx)->pub_key); - - if (x_len) { - (*dsactx)->priv_key = BN_new(); - BN_bin2bn(x, x_len, (*dsactx)->priv_key); - } - - return 0; -} - -int -_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, - const unsigned char *sig, - const unsigned char *m, unsigned long m_len) -{ - unsigned char hash[SHA_DIGEST_LENGTH]; - DSA_SIG dsasig; - int ret; - - dsasig.r = BN_new(); - BN_bin2bn(sig, 20, dsasig.r); - dsasig.s = BN_new(); - BN_bin2bn(sig + 20, 20, dsasig.s); - - libssh2_sha1(m, m_len, hash); - ret = DSA_do_verify(hash, SHA_DIGEST_LENGTH, &dsasig, dsactx); - BN_clear_free(dsasig.s); - BN_clear_free(dsasig.r); - - return (ret == 1) ? 0 : -1; -} -#endif /* LIBSSH_DSA */ - -int -_libssh2_cipher_init(_libssh2_cipher_ctx * h, - _libssh2_cipher_type(algo), - unsigned char *iv, unsigned char *secret, int encrypt) -{ - EVP_CIPHER_CTX_init(h); - EVP_CipherInit(h, algo(), secret, iv, encrypt); - return 0; -} - -int -_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, - _libssh2_cipher_type(algo), - int encrypt, unsigned char *block) -{ - int blocksize = ctx->cipher->block_size; - unsigned char buf[EVP_MAX_BLOCK_LENGTH]; - int ret; - (void) algo; - (void) encrypt; - - if (blocksize == 1) { -/* Hack for arcfour. */ - blocksize = 8; - } - ret = EVP_Cipher(ctx, buf, block, blocksize); - if (ret == 1) { - memcpy(block, buf, blocksize); - } - return ret == 1 ? 0 : 1; -} - -#if LIBSSH2_AES_CTR - -#include -#include - -typedef struct -{ - AES_KEY key; - EVP_CIPHER_CTX *aes_ctx; - unsigned char ctr[AES_BLOCK_SIZE]; -} aes_ctr_ctx; - -static int -aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, - const unsigned char *iv, int enc) /* init key */ -{ - /* - * variable "c" is leaked from this scope, but is later freed - * in aes_ctr_cleanup - */ - aes_ctr_ctx *c = malloc(sizeof(*c)); - const EVP_CIPHER *aes_cipher; - (void) enc; - - if (c == NULL) - return 0; - - switch (ctx->key_len) { - case 16: - aes_cipher = EVP_aes_128_ecb(); - break; - case 24: - aes_cipher = EVP_aes_192_ecb(); - break; - case 32: - aes_cipher = EVP_aes_256_ecb(); - break; - default: - return 0; - } - c->aes_ctx = malloc(sizeof(EVP_CIPHER_CTX)); - if (c->aes_ctx == NULL) - return 0; - - if (EVP_EncryptInit(c->aes_ctx, aes_cipher, key, NULL) != 1) { - return 0; - } - - EVP_CIPHER_CTX_set_padding(c->aes_ctx, 0); - - memcpy(c->ctr, iv, AES_BLOCK_SIZE); - - EVP_CIPHER_CTX_set_app_data(ctx, c); - - return 1; -} - -static int -aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, - const unsigned char *in, - size_t inl) /* encrypt/decrypt data */ -{ - aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx); - unsigned char b1[AES_BLOCK_SIZE]; - size_t i = 0; - int outlen = 0; - - if (inl != 16) /* libssh2 only ever encrypt one block */ - return 0; - - if (c == NULL) { - return 0; - } - -/* - To encrypt a packet P=P1||P2||...||Pn (where P1, P2, ..., Pn are each - blocks of length L), the encryptor first encrypts with - to obtain a block B1. The block B1 is then XORed with P1 to generate - the ciphertext block C1. The counter X is then incremented -*/ - - if (EVP_EncryptUpdate(c->aes_ctx, b1, &outlen, c->ctr, AES_BLOCK_SIZE) != 1) { - return 0; - } - - for (i = 0; i < 16; i++) - *out++ = *in++ ^ b1[i]; - - i = 15; - while (c->ctr[i]++ == 0xFF) { - if (i == 0) - break; - i--; - } - - return 1; -} - -static int -aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) /* cleanup ctx */ -{ - aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx); - - if (c == NULL) { - return 1; - } - - if (c->aes_ctx != NULL) { - _libssh2_cipher_dtor(c->aes_ctx); - free(c->aes_ctx); - } - - free(c); - - return 1; -} - -static const EVP_CIPHER * -make_ctr_evp (size_t keylen, EVP_CIPHER *aes_ctr_cipher) -{ - aes_ctr_cipher->block_size = 16; - aes_ctr_cipher->key_len = keylen; - aes_ctr_cipher->iv_len = 16; - aes_ctr_cipher->init = aes_ctr_init; - aes_ctr_cipher->do_cipher = aes_ctr_do_cipher; - aes_ctr_cipher->cleanup = aes_ctr_cleanup; - - return aes_ctr_cipher; -} - -const EVP_CIPHER * -_libssh2_EVP_aes_128_ctr(void) -{ - static EVP_CIPHER aes_ctr_cipher; - return !aes_ctr_cipher.key_len? - make_ctr_evp (16, &aes_ctr_cipher) : &aes_ctr_cipher; -} - -const EVP_CIPHER * -_libssh2_EVP_aes_192_ctr(void) -{ - static EVP_CIPHER aes_ctr_cipher; - return !aes_ctr_cipher.key_len? - make_ctr_evp (24, &aes_ctr_cipher) : &aes_ctr_cipher; -} - -const EVP_CIPHER * -_libssh2_EVP_aes_256_ctr(void) -{ - static EVP_CIPHER aes_ctr_cipher; - return !aes_ctr_cipher.key_len? - make_ctr_evp (32, &aes_ctr_cipher) : &aes_ctr_cipher; -} - -void _libssh2_init_aes_ctr(void) -{ - _libssh2_EVP_aes_128_ctr(); - _libssh2_EVP_aes_192_ctr(); - _libssh2_EVP_aes_256_ctr(); -} - -#else -void _libssh2_init_aes_ctr(void) {} -#endif /* LIBSSH2_AES_CTR */ - -/* TODO: Optionally call a passphrase callback specified by the - * calling program - */ -static int -passphrase_cb(char *buf, int size, int rwflag, char *passphrase) -{ - int passphrase_len = strlen(passphrase); - (void) rwflag; - - if (passphrase_len > (size - 1)) { - passphrase_len = size - 1; - } - memcpy(buf, passphrase, passphrase_len); - buf[passphrase_len] = '\0'; - - return passphrase_len; -} - -typedef void * (*pem_read_bio_func)(BIO *, void **, pem_password_cb *, - void * u); - -static int -read_private_key_from_file(void ** key_ctx, - pem_read_bio_func read_private_key, - const char * filename, - unsigned const char *passphrase) -{ - BIO * bp; - - *key_ctx = NULL; - - bp = BIO_new_file(filename, "r"); - if (!bp) { - return -1; - } - - *key_ctx = read_private_key(bp, NULL, (pem_password_cb *) passphrase_cb, - (void *) passphrase); - - BIO_free(bp); - return (*key_ctx) ? 0 : -1; -} - -int -_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, - LIBSSH2_SESSION * session, - const char *filename, unsigned const char *passphrase) -{ - pem_read_bio_func read_rsa = - (pem_read_bio_func) &PEM_read_bio_RSAPrivateKey; - (void) session; - - _libssh2_init_if_needed (); - - return read_private_key_from_file((void **) rsa, read_rsa, - filename, passphrase); -} - -#if LIBSSH2_DSA -int -_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, - LIBSSH2_SESSION * session, - const char *filename, unsigned const char *passphrase) -{ - pem_read_bio_func read_dsa = - (pem_read_bio_func) &PEM_read_bio_DSAPrivateKey; - (void) session; - - _libssh2_init_if_needed (); - - return read_private_key_from_file((void **) dsa, read_dsa, - filename, passphrase); -} -#endif /* LIBSSH_DSA */ - -int -_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, - libssh2_rsa_ctx * rsactx, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, size_t *signature_len) -{ - int ret; - unsigned char *sig; - unsigned int sig_len; - - sig_len = RSA_size(rsactx); - sig = LIBSSH2_ALLOC(session, sig_len); - - if (!sig) { - return -1; - } - - ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx); - - if (!ret) { - LIBSSH2_FREE(session, sig); - return -1; - } - - *signature = sig; - *signature_len = sig_len; - - return 0; -} - -#if LIBSSH2_DSA -int -_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, - const unsigned char *hash, - unsigned long hash_len, unsigned char *signature) -{ - DSA_SIG *sig; - int r_len, s_len; - (void) hash_len; - - sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx); - if (!sig) { - return -1; - } - - r_len = BN_num_bytes(sig->r); - if (r_len < 1 || r_len > 20) { - DSA_SIG_free(sig); - return -1; - } - s_len = BN_num_bytes(sig->s); - if (s_len < 1 || s_len > 20) { - DSA_SIG_free(sig); - return -1; - } - - memset(signature, 0, 40); - - BN_bn2bin(sig->r, signature + (20 - r_len)); - BN_bn2bin(sig->s, signature + 20 + (20 - s_len)); - - DSA_SIG_free(sig); - - return 0; -} -#endif /* LIBSSH_DSA */ - -void -libssh2_sha1(const unsigned char *message, unsigned long len, - unsigned char *out) -{ - EVP_MD_CTX ctx; - - EVP_DigestInit(&ctx, EVP_get_digestbyname("sha1")); - EVP_DigestUpdate(&ctx, message, len); - EVP_DigestFinal(&ctx, out, NULL); -} - -void -libssh2_md5(const unsigned char *message, unsigned long len, - unsigned char *out) -{ - EVP_MD_CTX ctx; - - EVP_DigestInit(&ctx, EVP_get_digestbyname("md5")); - EVP_DigestUpdate(&ctx, message, len); - EVP_DigestFinal(&ctx, out, NULL); -} - -static unsigned char * -write_bn(unsigned char *buf, const BIGNUM *bn, int bn_bytes) -{ - unsigned char *p = buf; - - /* Left space for bn size which will be written below. */ - p += 4; - - *p = 0; - BN_bn2bin(bn, p + 1); - if (!(*(p + 1) & 0x80)) { - memmove(p, p + 1, --bn_bytes); - } - _libssh2_htonu32(p - 4, bn_bytes); /* Post write bn size. */ - - return p + bn_bytes; -} - -static unsigned char * -gen_publickey_from_rsa(LIBSSH2_SESSION *session, RSA *rsa, - size_t *key_len) -{ - int e_bytes, n_bytes; - unsigned long len; - unsigned char* key; - unsigned char* p; - - e_bytes = BN_num_bytes(rsa->e) + 1; - n_bytes = BN_num_bytes(rsa->n) + 1; - - /* Key form is "ssh-rsa" + e + n. */ - len = 4 + 7 + 4 + e_bytes + 4 + n_bytes; - - key = LIBSSH2_ALLOC(session, len); - if (key == NULL) { - return NULL; - } - - /* Process key encoding. */ - p = key; - - _libssh2_htonu32(p, 7); /* Key type. */ - p += 4; - memcpy(p, "ssh-rsa", 7); - p += 7; - - p = write_bn(p, rsa->e, e_bytes); - p = write_bn(p, rsa->n, n_bytes); - - *key_len = (size_t)(p - key); - return key; -} - -static unsigned char * -gen_publickey_from_dsa(LIBSSH2_SESSION* session, DSA *dsa, - size_t *key_len) -{ - int p_bytes, q_bytes, g_bytes, k_bytes; - unsigned long len; - unsigned char* key; - unsigned char* p; - - p_bytes = BN_num_bytes(dsa->p) + 1; - q_bytes = BN_num_bytes(dsa->q) + 1; - g_bytes = BN_num_bytes(dsa->g) + 1; - k_bytes = BN_num_bytes(dsa->pub_key) + 1; - - /* Key form is "ssh-dss" + p + q + g + pub_key. */ - len = 4 + 7 + 4 + p_bytes + 4 + q_bytes + 4 + g_bytes + 4 + k_bytes; - - key = LIBSSH2_ALLOC(session, len); - if (key == NULL) { - return NULL; - } - - /* Process key encoding. */ - p = key; - - _libssh2_htonu32(p, 7); /* Key type. */ - p += 4; - memcpy(p, "ssh-dss", 7); - p += 7; - - p = write_bn(p, dsa->p, p_bytes); - p = write_bn(p, dsa->q, q_bytes); - p = write_bn(p, dsa->g, g_bytes); - p = write_bn(p, dsa->pub_key, k_bytes); - - *key_len = (size_t)(p - key); - return key; -} - -static int -gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - EVP_PKEY *pk) -{ - RSA* rsa = NULL; - unsigned char* key; - unsigned char* method_buf = NULL; - size_t key_len; - - _libssh2_debug(session, - LIBSSH2_TRACE_AUTH, - "Computing public key from RSA private key envelop"); - - rsa = EVP_PKEY_get1_RSA(pk); - if (rsa == NULL) { - /* Assume memory allocation error... what else could it be ? */ - goto __alloc_error; - } - - method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-rsa. */ - if (method_buf == NULL) { - goto __alloc_error; - } - - key = gen_publickey_from_rsa(session, rsa, &key_len); - if (key == NULL) { - goto __alloc_error; - } - RSA_free(rsa); - - memcpy(method_buf, "ssh-rsa", 7); - *method = method_buf; - *method_len = 7; - *pubkeydata = key; - *pubkeydata_len = key_len; - return 0; - - __alloc_error: - if (rsa != NULL) { - RSA_free(rsa); - } - if (method_buf != NULL) { - LIBSSH2_FREE(session, method_buf); - } - - return _libssh2_error(session, - LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for private key data"); -} - -static int -gen_publickey_from_dsa_evp(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - EVP_PKEY *pk) -{ - DSA* dsa = NULL; - unsigned char* key; - unsigned char* method_buf = NULL; - size_t key_len; - - _libssh2_debug(session, - LIBSSH2_TRACE_AUTH, - "Computing public key from DSA private key envelop"); - - dsa = EVP_PKEY_get1_DSA(pk); - if (dsa == NULL) { - /* Assume memory allocation error... what else could it be ? */ - goto __alloc_error; - } - - method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-dss. */ - if (method_buf == NULL) { - goto __alloc_error; - } - - key = gen_publickey_from_dsa(session, dsa, &key_len); - if (key == NULL) { - goto __alloc_error; - } - DSA_free(dsa); - - memcpy(method_buf, "ssh-dss", 7); - *method = method_buf; - *method_len = 7; - *pubkeydata = key; - *pubkeydata_len = key_len; - return 0; - - __alloc_error: - if (dsa != NULL) { - DSA_free(dsa); - } - if (method_buf != NULL) { - LIBSSH2_FREE(session, method_buf); - } - - return _libssh2_error(session, - LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for private key data"); -} - -int -_libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase) -{ - int st; - BIO* bp; - EVP_PKEY* pk; - - _libssh2_debug(session, - LIBSSH2_TRACE_AUTH, - "Computing public key from private key file: %s", - privatekey); - - bp = BIO_new_file(privatekey, "r"); - if (bp == NULL) { - return _libssh2_error(session, - LIBSSH2_ERROR_FILE, - "Unable to extract public key from private key " - "file: Unable to open private key file"); - } - if (!EVP_get_cipherbyname("des")) { - /* If this cipher isn't loaded it's a pretty good indication that none - * are. I have *NO DOUBT* that there's a better way to deal with this - * ($#&%#$(%$#( Someone buy me an OpenSSL manual and I'll read up on - * it. - */ - OpenSSL_add_all_ciphers(); - } - BIO_reset(bp); - pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void*)passphrase); - BIO_free(bp); - - if (pk == NULL) { - return _libssh2_error(session, - LIBSSH2_ERROR_FILE, - "Unable to extract public key " - "from private key file: " - "Wrong passphrase or invalid/unrecognized " - "private key file format"); - } - - switch (pk->type) { - case EVP_PKEY_RSA : - st = gen_publickey_from_rsa_evp( - session, method, method_len, pubkeydata, pubkeydata_len, pk); - break; - - case EVP_PKEY_DSA : - st = gen_publickey_from_dsa_evp( - session, method, method_len, pubkeydata, pubkeydata_len, pk); - break; - - default : - st = _libssh2_error(session, - LIBSSH2_ERROR_FILE, - "Unable to extract public key " - "from private key file: " - "Unsupported private key file format"); - break; - } - - EVP_PKEY_free(pk); - return st; -} - -#endif /* !LIBSSH2_LIBGCRYPT */ diff --git a/vendor/libssh2-1.4.2/src/openssl.h b/vendor/libssh2-1.4.2/src/openssl.h deleted file mode 100644 index 6d2aeed..0000000 --- a/vendor/libssh2-1.4.2/src/openssl.h +++ /dev/null @@ -1,178 +0,0 @@ -/* Copyright (C) 2009, 2010 Simon Josefsson - * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. - * - * Author: Simon Josefsson - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include -#include -#ifndef OPENSSL_NO_MD5 -#include -#endif -#include -#include -#include -#include -#include - -#ifdef OPENSSL_NO_RSA -# define LIBSSH2_RSA 0 -#else -# define LIBSSH2_RSA 1 -#endif - -#ifdef OPENSSL_NO_DSA -# define LIBSSH2_DSA 0 -#else -# define LIBSSH2_DSA 1 -#endif - -#ifdef OPENSSL_NO_MD5 -# define LIBSSH2_MD5 0 -#else -# define LIBSSH2_MD5 1 -#endif - -#ifdef OPENSSL_NO_RIPEMD -# define LIBSSH2_HMAC_RIPEMD 0 -#else -# define LIBSSH2_HMAC_RIPEMD 1 -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES) -# define LIBSSH2_AES_CTR 1 -# define LIBSSH2_AES 1 -#else -# define LIBSSH2_AES_CTR 0 -# define LIBSSH2_AES 0 -#endif - -#ifdef OPENSSL_NO_BLOWFISH -# define LIBSSH2_BLOWFISH 0 -#else -# define LIBSSH2_BLOWFISH 1 -#endif - -#ifdef OPENSSL_NO_RC4 -# define LIBSSH2_RC4 0 -#else -# define LIBSSH2_RC4 1 -#endif - -#ifdef OPENSSL_NO_CAST -# define LIBSSH2_CAST 0 -#else -# define LIBSSH2_CAST 1 -#endif - -#ifdef OPENSSL_NO_DES -# define LIBSSH2_3DES 0 -#else -# define LIBSSH2_3DES 1 -#endif - -#define _libssh2_random(buf, len) RAND_bytes ((buf), (len)) - -#define libssh2_sha1_ctx EVP_MD_CTX -#define libssh2_sha1_init(ctx) EVP_DigestInit(ctx, EVP_get_digestbyname("sha1")) -#define libssh2_sha1_update(ctx, data, len) EVP_DigestUpdate(&(ctx), data, len) -#define libssh2_sha1_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) -void libssh2_sha1(const unsigned char *message, unsigned long len, unsigned char *out); - -#define libssh2_md5_ctx EVP_MD_CTX -#define libssh2_md5_init(ctx) EVP_DigestInit(ctx, EVP_get_digestbyname("md5")) -#define libssh2_md5_update(ctx, data, len) EVP_DigestUpdate(&(ctx), data, len) -#define libssh2_md5_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) -void libssh2_md5(const unsigned char *message, unsigned long len, unsigned char *out); - -#define libssh2_hmac_ctx HMAC_CTX -#define libssh2_hmac_sha1_init(ctx, key, keylen) \ - HMAC_Init(ctx, key, keylen, EVP_sha1()) -#define libssh2_hmac_md5_init(ctx, key, keylen) \ - HMAC_Init(ctx, key, keylen, EVP_md5()) -#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \ - HMAC_Init(ctx, key, keylen, EVP_ripemd160()) -#define libssh2_hmac_update(ctx, data, datalen) \ - HMAC_Update(&(ctx), data, datalen) -#define libssh2_hmac_final(ctx, data) HMAC_Final(&(ctx), data, NULL) -#define libssh2_hmac_cleanup(ctx) HMAC_cleanup(ctx) - -#define libssh2_crypto_init() OpenSSL_add_all_algorithms() -#define libssh2_crypto_exit() - -#define libssh2_rsa_ctx RSA - -#define _libssh2_rsa_free(rsactx) RSA_free(rsactx) - -#define libssh2_dsa_ctx DSA - - -#define _libssh2_dsa_free(dsactx) DSA_free(dsactx) - -#define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void) -#define _libssh2_cipher_ctx EVP_CIPHER_CTX - -#define _libssh2_cipher_aes256 EVP_aes_256_cbc -#define _libssh2_cipher_aes192 EVP_aes_192_cbc -#define _libssh2_cipher_aes128 EVP_aes_128_cbc -#define _libssh2_cipher_aes128ctr _libssh2_EVP_aes_128_ctr -#define _libssh2_cipher_aes192ctr _libssh2_EVP_aes_192_ctr -#define _libssh2_cipher_aes256ctr _libssh2_EVP_aes_256_ctr -#define _libssh2_cipher_blowfish EVP_bf_cbc -#define _libssh2_cipher_arcfour EVP_rc4 -#define _libssh2_cipher_cast5 EVP_cast5_cbc -#define _libssh2_cipher_3des EVP_des_ede3_cbc - -#define _libssh2_cipher_dtor(ctx) EVP_CIPHER_CTX_cleanup(ctx) - -#define _libssh2_bn BIGNUM -#define _libssh2_bn_ctx BN_CTX -#define _libssh2_bn_ctx_new() BN_CTX_new() -#define _libssh2_bn_ctx_free(bnctx) BN_CTX_free(bnctx) -#define _libssh2_bn_init() BN_new() -#define _libssh2_bn_rand(bn, bits, top, bottom) BN_rand(bn, bits, top, bottom) -#define _libssh2_bn_mod_exp(r, a, p, m, ctx) BN_mod_exp(r, a, p, m, ctx) -#define _libssh2_bn_set_word(bn, val) BN_set_word(bn, val) -#define _libssh2_bn_from_bin(bn, len, val) BN_bin2bn(val, len, bn) -#define _libssh2_bn_to_bin(bn, val) BN_bn2bin(bn, val) -#define _libssh2_bn_bytes(bn) BN_num_bytes(bn) -#define _libssh2_bn_bits(bn) BN_num_bits(bn) -#define _libssh2_bn_free(bn) BN_clear_free(bn) - -const EVP_CIPHER *_libssh2_EVP_aes_128_ctr(void); -const EVP_CIPHER *_libssh2_EVP_aes_192_ctr(void); -const EVP_CIPHER *_libssh2_EVP_aes_256_ctr(void); - diff --git a/vendor/libssh2-1.4.2/src/packet.c b/vendor/libssh2-1.4.2/src/packet.c deleted file mode 100644 index bfbd56a..0000000 --- a/vendor/libssh2-1.4.2/src/packet.c +++ /dev/null @@ -1,1243 +0,0 @@ -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2005,2006 Mikhail Gusarov - * Copyright (c) 2009-2010 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#ifdef HAVE_INTTYPES_H -#include -#endif - -/* Needed for struct iovec on some platforms */ -#ifdef HAVE_SYS_UIO_H -#include -#endif - -#include - -#include "transport.h" -#include "channel.h" -#include "packet.h" - -/* - * libssh2_packet_queue_listener - * - * Queue a connection request for a listener - */ -static inline int -packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, - unsigned long datalen, - packet_queue_listener_state_t *listen_state) -{ - /* - * Look for a matching listener - */ - /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ - unsigned long packet_len = 17 + (sizeof(FwdNotReq) - 1); - unsigned char *p; - LIBSSH2_LISTENER *listn = _libssh2_list_first(&session->listeners); - char failure_code = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; - int rc; - - (void) datalen; - - if (listen_state->state == libssh2_NB_state_idle) { - unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5; - listen_state->sender_channel = _libssh2_ntohu32(s); - s += 4; - - listen_state->initial_window_size = _libssh2_ntohu32(s); - s += 4; - listen_state->packet_size = _libssh2_ntohu32(s); - s += 4; - - listen_state->host_len = _libssh2_ntohu32(s); - s += 4; - listen_state->host = s; - s += listen_state->host_len; - listen_state->port = _libssh2_ntohu32(s); - s += 4; - - listen_state->shost_len = _libssh2_ntohu32(s); - s += 4; - listen_state->shost = s; - s += listen_state->shost_len; - listen_state->sport = _libssh2_ntohu32(s); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Remote received connection from %s:%ld to %s:%ld", - listen_state->shost, listen_state->sport, - listen_state->host, listen_state->port); - - listen_state->state = libssh2_NB_state_allocated; - } - - if (listen_state->state != libssh2_NB_state_sent) { - while (listn) { - if ((listn->port == (int) listen_state->port) && - (strlen(listn->host) == listen_state->host_len) && - (memcmp (listn->host, listen_state->host, - listen_state->host_len) == 0)) { - /* This is our listener */ - LIBSSH2_CHANNEL *channel = NULL; - listen_state->channel = NULL; - - if (listen_state->state == libssh2_NB_state_allocated) { - if (listn->queue_maxsize && - (listn->queue_maxsize <= listn->queue_size)) { - /* Queue is full */ - failure_code = SSH_OPEN_RESOURCE_SHORTAGE; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Listener queue full, ignoring"); - listen_state->state = libssh2_NB_state_sent; - break; - } - - channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL)); - if (!channel) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate a channel for " - "new connection"); - failure_code = SSH_OPEN_RESOURCE_SHORTAGE; - listen_state->state = libssh2_NB_state_sent; - break; - } - listen_state->channel = channel; - - memset(channel, 0, sizeof(LIBSSH2_CHANNEL)); - - channel->session = session; - channel->channel_type_len = sizeof("forwarded-tcpip") - 1; - channel->channel_type = LIBSSH2_ALLOC(session, - channel-> - channel_type_len + - 1); - if (!channel->channel_type) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate a channel for new" - " connection"); - LIBSSH2_FREE(session, channel); - failure_code = SSH_OPEN_RESOURCE_SHORTAGE; - listen_state->state = libssh2_NB_state_sent; - break; - } - memcpy(channel->channel_type, "forwarded-tcpip", - channel->channel_type_len + 1); - - channel->remote.id = listen_state->sender_channel; - channel->remote.window_size_initial = - LIBSSH2_CHANNEL_WINDOW_DEFAULT; - channel->remote.window_size = - LIBSSH2_CHANNEL_WINDOW_DEFAULT; - channel->remote.packet_size = - LIBSSH2_CHANNEL_PACKET_DEFAULT; - - channel->local.id = _libssh2_channel_nextid(session); - channel->local.window_size_initial = - listen_state->initial_window_size; - channel->local.window_size = - listen_state->initial_window_size; - channel->local.packet_size = listen_state->packet_size; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Connection queued: channel %lu/%lu " - "win %lu/%lu packet %lu/%lu", - channel->local.id, channel->remote.id, - channel->local.window_size, - channel->remote.window_size, - channel->local.packet_size, - channel->remote.packet_size); - - p = listen_state->packet; - *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; - _libssh2_store_u32(&p, channel->remote.id); - _libssh2_store_u32(&p, channel->local.id); - _libssh2_store_u32(&p, - channel->remote.window_size_initial); - _libssh2_store_u32(&p, channel->remote.packet_size); - - listen_state->state = libssh2_NB_state_created; - } - - if (listen_state->state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, listen_state->packet, - 17, NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) - return rc; - else if (rc) { - listen_state->state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Unable to send channel " - "open confirmation"); - } - - /* Link the channel into the end of the queue list */ - _libssh2_list_add(&listn->queue, - &listen_state->channel->node); - listn->queue_size++; - - listen_state->state = libssh2_NB_state_idle; - return 0; - } - } - - listn = _libssh2_list_next(&listn->node); - } - - listen_state->state = libssh2_NB_state_sent; - } - - /* We're not listening to you */ - p = listen_state->packet; - *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; - _libssh2_store_u32(&p, listen_state->sender_channel); - _libssh2_store_u32(&p, failure_code); - _libssh2_store_str(&p, FwdNotReq, sizeof(FwdNotReq) - 1); - _libssh2_htonu32(p, 0); - - rc = _libssh2_transport_send(session, listen_state->packet, - packet_len, NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - listen_state->state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, "Unable to send open failure"); - - } - listen_state->state = libssh2_NB_state_idle; - return 0; -} - -/* - * packet_x11_open - * - * Accept a forwarded X11 connection - */ -static inline int -packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, - unsigned long datalen, - packet_x11_open_state_t *x11open_state) -{ - int failure_code = SSH_OPEN_CONNECT_FAILED; - /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ - unsigned long packet_len = 17 + (sizeof(X11FwdUnAvil) - 1); - unsigned char *p; - LIBSSH2_CHANNEL *channel = x11open_state->channel; - int rc; - - (void) datalen; - - if (x11open_state->state == libssh2_NB_state_idle) { - unsigned char *s = data + (sizeof("x11") - 1) + 5; - x11open_state->sender_channel = _libssh2_ntohu32(s); - s += 4; - x11open_state->initial_window_size = _libssh2_ntohu32(s); - s += 4; - x11open_state->packet_size = _libssh2_ntohu32(s); - s += 4; - x11open_state->shost_len = _libssh2_ntohu32(s); - s += 4; - x11open_state->shost = s; - s += x11open_state->shost_len; - x11open_state->sport = _libssh2_ntohu32(s); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "X11 Connection Received from %s:%ld on channel %lu", - x11open_state->shost, x11open_state->sport, - x11open_state->sender_channel); - - x11open_state->state = libssh2_NB_state_allocated; - } - - if (session->x11) { - if (x11open_state->state == libssh2_NB_state_allocated) { - channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL)); - if (!channel) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "allocate a channel for new connection"); - failure_code = SSH_OPEN_RESOURCE_SHORTAGE; - goto x11_exit; - } - memset(channel, 0, sizeof(LIBSSH2_CHANNEL)); - - channel->session = session; - channel->channel_type_len = sizeof("x11") - 1; - channel->channel_type = LIBSSH2_ALLOC(session, - channel->channel_type_len + - 1); - if (!channel->channel_type) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "allocate a channel for new connection"); - LIBSSH2_FREE(session, channel); - failure_code = SSH_OPEN_RESOURCE_SHORTAGE; - goto x11_exit; - } - memcpy(channel->channel_type, "x11", - channel->channel_type_len + 1); - - channel->remote.id = x11open_state->sender_channel; - channel->remote.window_size_initial = - LIBSSH2_CHANNEL_WINDOW_DEFAULT; - channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT; - channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT; - - channel->local.id = _libssh2_channel_nextid(session); - channel->local.window_size_initial = - x11open_state->initial_window_size; - channel->local.window_size = x11open_state->initial_window_size; - channel->local.packet_size = x11open_state->packet_size; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "X11 Connection established: channel %lu/%lu " - "win %lu/%lu packet %lu/%lu", - channel->local.id, channel->remote.id, - channel->local.window_size, - channel->remote.window_size, - channel->local.packet_size, - channel->remote.packet_size); - p = x11open_state->packet; - *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; - _libssh2_store_u32(&p, channel->remote.id); - _libssh2_store_u32(&p, channel->local.id); - _libssh2_store_u32(&p, channel->remote.window_size_initial); - _libssh2_store_u32(&p, channel->remote.packet_size); - - x11open_state->state = libssh2_NB_state_created; - } - - if (x11open_state->state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, x11open_state->packet, 17, - NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - x11open_state->state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send channel open " - "confirmation"); - } - - /* Link the channel into the session */ - _libssh2_list_add(&session->channels, &channel->node); - - /* - * Pass control to the callback, they may turn right around and - * free the channel, or actually use it - */ - LIBSSH2_X11_OPEN(channel, (char *)x11open_state->shost, - x11open_state->sport); - - x11open_state->state = libssh2_NB_state_idle; - return 0; - } - } - else - failure_code = SSH_OPEN_RESOURCE_SHORTAGE; - /* fall-trough */ - x11_exit: - p = x11open_state->packet; - *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; - _libssh2_store_u32(&p, x11open_state->sender_channel); - _libssh2_store_u32(&p, failure_code); - _libssh2_store_str(&p, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1); - _libssh2_htonu32(p, 0); - - rc = _libssh2_transport_send(session, x11open_state->packet, packet_len, - NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - x11open_state->state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, "Unable to send open failure"); - } - x11open_state->state = libssh2_NB_state_idle; - return 0; -} - -/* - * _libssh2_packet_add - * - * Create a new packet and attach it to the brigade. Called from the transport - * layer when it has received a packet. - * - * The input pointer 'data' is pointing to allocated data that this function - * is asked to deal with so on failure OR success, it must be freed fine. - * - * This function will always be called with 'datalen' greater than zero. - */ -int -_libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, - size_t datalen, int macstate) -{ - int rc = 0; - char *message=NULL; - char *language=NULL; - size_t message_len=0; - size_t language_len=0; - LIBSSH2_CHANNEL *channelp = NULL; - size_t data_head = 0; - unsigned char msg = data[0]; - - switch(session->packAdd_state) { - case libssh2_NB_state_idle: - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Packet type %d received, length=%d", - (int) msg, (int) datalen); - - if ((macstate == LIBSSH2_MAC_INVALID) && - (!session->macerror || - LIBSSH2_MACERROR(session, (char *) data, datalen))) { - /* Bad MAC input, but no callback set or non-zero return from the - callback */ - - LIBSSH2_FREE(session, data); - return _libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC, - "Invalid MAC received"); - } - session->packAdd_state = libssh2_NB_state_allocated; - break; - case libssh2_NB_state_jump1: - goto libssh2_packet_add_jump_point1; - case libssh2_NB_state_jump2: - goto libssh2_packet_add_jump_point2; - case libssh2_NB_state_jump3: - goto libssh2_packet_add_jump_point3; - case libssh2_NB_state_jump4: - goto libssh2_packet_add_jump_point4; - case libssh2_NB_state_jump5: - goto libssh2_packet_add_jump_point5; - default: /* nothing to do */ - break; - } - - if (session->packAdd_state == libssh2_NB_state_allocated) { - /* A couple exceptions to the packet adding rule: */ - switch (msg) { - - /* - byte SSH_MSG_DISCONNECT - uint32 reason code - string description in ISO-10646 UTF-8 encoding [RFC3629] - string language tag [RFC3066] - */ - - case SSH_MSG_DISCONNECT: - if(datalen >= 5) { - size_t reason = _libssh2_ntohu32(data + 1); - - if(datalen >= 9) { - message_len = _libssh2_ntohu32(data + 5); - - if(message_len < datalen-13) { - /* 9 = packet_type(1) + reason(4) + message_len(4) */ - message = (char *) data + 9; - - language_len = _libssh2_ntohu32(data + 9 + message_len); - language = (char *) data + 9 + message_len + 4; - - if(language_len > (datalen-13-message_len)) { - /* bad input, clear info */ - language = message = NULL; - language_len = message_len = 0; - } - } - else - /* bad size, clear it */ - message_len=0; - } - if (session->ssh_msg_disconnect) { - LIBSSH2_DISCONNECT(session, reason, message, - message_len, language, language_len); - } - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Disconnect(%d): %s(%s)", reason, - message, language); - } - - LIBSSH2_FREE(session, data); - session->socket_state = LIBSSH2_SOCKET_DISCONNECTED; - session->packAdd_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT, - "socket disconnect"); - /* - byte SSH_MSG_IGNORE - string data - */ - - case SSH_MSG_IGNORE: - if (datalen >= 2) { - if (session->ssh_msg_ignore) { - LIBSSH2_IGNORE(session, (char *) data + 1, datalen - 1); - } - } else if (session->ssh_msg_ignore) { - LIBSSH2_IGNORE(session, "", 0); - } - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - - /* - byte SSH_MSG_DEBUG - boolean always_display - string message in ISO-10646 UTF-8 encoding [RFC3629] - string language tag [RFC3066] - */ - - case SSH_MSG_DEBUG: - if(datalen >= 2) { - int always_display= data[1]; - - if(datalen >= 6) { - message_len = _libssh2_ntohu32(data + 2); - - if(message_len <= (datalen - 10)) { - /* 6 = packet_type(1) + display(1) + message_len(4) */ - message = (char *) data + 6; - language_len = _libssh2_ntohu32(data + 6 + message_len); - - if(language_len <= (datalen - 10 - message_len)) - language = (char *) data + 10 + message_len; - } - } - - if (session->ssh_msg_debug) { - LIBSSH2_DEBUG(session, always_display, message, - message_len, language, language_len); - } - } - /* - * _libssh2_debug will actually truncate this for us so - * that it's not an inordinate about of data - */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Debug Packet: %s", message); - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - - /* - byte SSH_MSG_GLOBAL_REQUEST - string request name in US-ASCII only - boolean want reply - .... request-specific data follows - */ - - case SSH_MSG_GLOBAL_REQUEST: - if(datalen >= 5) { - uint32_t len =0; - unsigned char want_reply=0; - len = _libssh2_ntohu32(data + 1); - if(datalen >= (6 + len)) { - want_reply = data[5 + len]; - _libssh2_debug(session, - LIBSSH2_TRACE_CONN, - "Received global request type %.*s (wr %X)", - len, data + 5, want_reply); - } - - - if (want_reply) { - unsigned char packet = SSH_MSG_REQUEST_FAILURE; - libssh2_packet_add_jump_point5: - session->packAdd_state = libssh2_NB_state_jump5; - rc = _libssh2_transport_send(session, &packet, 1, NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) - return rc; - } - } - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - - /* - byte SSH_MSG_CHANNEL_EXTENDED_DATA - uint32 recipient channel - uint32 data_type_code - string data - */ - - case SSH_MSG_CHANNEL_EXTENDED_DATA: - /* streamid(4) */ - data_head += 4; - - /* fall-through */ - - /* - byte SSH_MSG_CHANNEL_DATA - uint32 recipient channel - string data - */ - - case SSH_MSG_CHANNEL_DATA: - /* packet_type(1) + channelno(4) + datalen(4) */ - data_head += 9; - - if(datalen >= data_head) - channelp = - _libssh2_channel_locate(session, - _libssh2_ntohu32(data + 1)); - - if (!channelp) { - _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN, - "Packet received for unknown channel"); - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - } -#ifdef LIBSSH2DEBUG - { - uint32_t stream_id = 0; - if (msg == SSH_MSG_CHANNEL_EXTENDED_DATA) - stream_id = _libssh2_ntohu32(data + 5); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "%d bytes packet_add() for %lu/%lu/%lu", - (int) (datalen - data_head), - channelp->local.id, - channelp->remote.id, - stream_id); - } -#endif - if ((channelp->remote.extended_data_ignore_mode == - LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) && - (msg == SSH_MSG_CHANNEL_EXTENDED_DATA)) { - /* Pretend we didn't receive this */ - LIBSSH2_FREE(session, data); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Ignoring extended data and refunding %d bytes", - (int) (datalen - 13)); - session->packAdd_channelp = channelp; - - /* Adjust the window based on the block we just freed */ - libssh2_packet_add_jump_point1: - session->packAdd_state = libssh2_NB_state_jump1; - rc = _libssh2_channel_receive_window_adjust(session-> - packAdd_channelp, - datalen - 13, - 1, NULL); - if (rc == LIBSSH2_ERROR_EAGAIN) - return rc; - - session->packAdd_state = libssh2_NB_state_idle; - return 0; - } - - /* - * REMEMBER! remote means remote as source of data, - * NOT remote window! - */ - if (channelp->remote.packet_size < (datalen - data_head)) { - /* - * Spec says we MAY ignore bytes sent beyond - * packet_size - */ - _libssh2_error(session, - LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, - "Packet contains more data than we offered" - " to receive, truncating"); - datalen = channelp->remote.packet_size + data_head; - } - if (channelp->remote.window_size <= 0) { - /* - * Spec says we MAY ignore bytes sent beyond - * window_size - */ - _libssh2_error(session, - LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, - "The current receive window is full," - " data ignored"); - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - } - /* Reset EOF status */ - channelp->remote.eof = 0; - - if ((datalen - data_head) > channelp->remote.window_size) { - _libssh2_error(session, - LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, - "Remote sent more data than current " - "window allows, truncating"); - datalen = channelp->remote.window_size + data_head; - channelp->remote.window_size = 0; - } - else - /* Now that we've received it, shrink our window */ - channelp->remote.window_size -= datalen - data_head; - - break; - - /* - byte SSH_MSG_CHANNEL_EOF - uint32 recipient channel - */ - - case SSH_MSG_CHANNEL_EOF: - if(datalen >= 5) - channelp = - _libssh2_channel_locate(session, - _libssh2_ntohu32(data + 1)); - if (!channelp) - /* We may have freed already, just quietly ignore this... */ - ; - else { - _libssh2_debug(session, - LIBSSH2_TRACE_CONN, - "EOF received for channel %lu/%lu", - channelp->local.id, - channelp->remote.id); - channelp->remote.eof = 1; - } - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - - /* - byte SSH_MSG_CHANNEL_REQUEST - uint32 recipient channel - string request type in US-ASCII characters only - boolean want reply - .... type-specific data follows - */ - - case SSH_MSG_CHANNEL_REQUEST: - if(datalen >= 9) { - uint32_t channel = _libssh2_ntohu32(data + 1); - uint32_t len = _libssh2_ntohu32(data + 5); - unsigned char want_reply = 1; - - if(len < (datalen - 10)) - want_reply = data[9 + len]; - - _libssh2_debug(session, - LIBSSH2_TRACE_CONN, - "Channel %d received request type %.*s (wr %X)", - channel, len, data + 9, want_reply); - - if (len == sizeof("exit-status") - 1 - && !memcmp("exit-status", data + 9, - sizeof("exit-status") - 1)) { - - /* we've got "exit-status" packet. Set the session value */ - if(datalen >= 20) - channelp = - _libssh2_channel_locate(session, channel); - - if (channelp) { - channelp->exit_status = - _libssh2_ntohu32(data + 9 + sizeof("exit-status")); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Exit status %lu received for " - "channel %lu/%lu", - channelp->exit_status, - channelp->local.id, - channelp->remote.id); - } - - } - else if (len == sizeof("exit-signal") - 1 - && !memcmp("exit-signal", data + 9, - sizeof("exit-signal") - 1)) { - /* command terminated due to signal */ - if(datalen >= 20) - channelp = _libssh2_channel_locate(session, channel); - - if (channelp) { - /* set signal name (without SIG prefix) */ - uint32_t namelen = - _libssh2_ntohu32(data + 9 + sizeof("exit-signal")); - channelp->exit_signal = - LIBSSH2_ALLOC(session, namelen + 1); - if (!channelp->exit_signal) - rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "memory for signal name"); - else { - memcpy(channelp->exit_signal, - data + 13 + sizeof("exit_signal"), namelen); - channelp->exit_signal[namelen] = '\0'; - /* TODO: save error message and language tag */ - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Exit signal %s received for " - "channel %lu/%lu", - channelp->exit_signal, - channelp->local.id, - channelp->remote.id); - } - } - } - - - if (want_reply) { - unsigned char packet[5]; - libssh2_packet_add_jump_point4: - session->packAdd_state = libssh2_NB_state_jump4; - packet[0] = SSH_MSG_CHANNEL_FAILURE; - memcpy(&packet[1], data+1, 4); - rc = _libssh2_transport_send(session, packet, 5, NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) - return rc; - } - } - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return rc; - - /* - byte SSH_MSG_CHANNEL_CLOSE - uint32 recipient channel - */ - - case SSH_MSG_CHANNEL_CLOSE: - if(datalen >= 5) - channelp = - _libssh2_channel_locate(session, - _libssh2_ntohu32(data + 1)); - if (!channelp) { - /* We may have freed already, just quietly ignore this... */ - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - } - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Close received for channel %lu/%lu", - channelp->local.id, - channelp->remote.id); - - channelp->remote.close = 1; - channelp->remote.eof = 1; - - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - - /* - byte SSH_MSG_CHANNEL_OPEN - string "session" - uint32 sender channel - uint32 initial window size - uint32 maximum packet size - */ - - case SSH_MSG_CHANNEL_OPEN: - if(datalen < 17) - ; - else if ((datalen >= (sizeof("forwarded-tcpip") + 4)) && - ((sizeof("forwarded-tcpip") - 1) == - _libssh2_ntohu32(data + 1)) - && - (memcmp(data + 5, "forwarded-tcpip", - sizeof("forwarded-tcpip") - 1) == 0)) { - - /* init the state struct */ - memset(&session->packAdd_Qlstn_state, 0, - sizeof(session->packAdd_Qlstn_state)); - - libssh2_packet_add_jump_point2: - session->packAdd_state = libssh2_NB_state_jump2; - rc = packet_queue_listener(session, data, datalen, - &session->packAdd_Qlstn_state); - } - else if ((datalen >= (sizeof("x11") + 4)) && - ((sizeof("x11") - 1) == _libssh2_ntohu32(data + 1)) && - (memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) { - - /* init the state struct */ - memset(&session->packAdd_x11open_state, 0, - sizeof(session->packAdd_x11open_state)); - - libssh2_packet_add_jump_point3: - session->packAdd_state = libssh2_NB_state_jump3; - rc = packet_x11_open(session, data, datalen, - &session->packAdd_x11open_state); - } - if (rc == LIBSSH2_ERROR_EAGAIN) - return rc; - - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return rc; - - /* - byte SSH_MSG_CHANNEL_WINDOW_ADJUST - uint32 recipient channel - uint32 bytes to add - */ - case SSH_MSG_CHANNEL_WINDOW_ADJUST: - if(datalen < 9) - ; - else { - uint32_t bytestoadd = _libssh2_ntohu32(data + 5); - channelp = - _libssh2_channel_locate(session, - _libssh2_ntohu32(data + 1)); - if(channelp) { - channelp->local.window_size += bytestoadd; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Window adjust for channel %lu/%lu, " - "adding %lu bytes, new window_size=%lu", - channelp->local.id, - channelp->remote.id, - bytestoadd, - channelp->local.window_size); - } - } - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - default: - break; - } - - session->packAdd_state = libssh2_NB_state_sent; - } - - if (session->packAdd_state == libssh2_NB_state_sent) { - LIBSSH2_PACKET *packetp = - LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET)); - if (!packetp) { - _libssh2_debug(session, LIBSSH2_ERROR_ALLOC, - "memory for packet"); - session->packAdd_state = libssh2_NB_state_idle; - return LIBSSH2_ERROR_ALLOC; - } - packetp->data = data; - packetp->data_len = datalen; - packetp->data_head = data_head; - - _libssh2_list_add(&session->packets, &packetp->node); - - session->packAdd_state = libssh2_NB_state_sent1; - } - - if ((msg == SSH_MSG_KEXINIT && - !(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) || - (session->packAdd_state == libssh2_NB_state_sent2)) { - if (session->packAdd_state == libssh2_NB_state_sent1) { - /* - * Remote wants new keys - * Well, it's already in the brigade, - * let's just call back into ourselves - */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Renegotiating Keys"); - - session->packAdd_state = libssh2_NB_state_sent2; - } - - /* - * The KEXINIT message has been added to the queue. The packAdd and - * readPack states need to be reset because _libssh2_kex_exchange - * (eventually) calls upon _libssh2_transport_read to read the rest of - * the key exchange conversation. - */ - session->readPack_state = libssh2_NB_state_idle; - session->packet.total_num = 0; - session->packAdd_state = libssh2_NB_state_idle; - session->fullpacket_state = libssh2_NB_state_idle; - - memset(&session->startup_key_state, 0, sizeof(key_exchange_state_t)); - - /* - * If there was a key reexchange failure, let's just hope we didn't - * send NEWKEYS yet, otherwise remote will drop us like a rock - */ - rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state); - if (rc == LIBSSH2_ERROR_EAGAIN) - return rc; - } - - session->packAdd_state = libssh2_NB_state_idle; - return 0; -} - -/* - * _libssh2_packet_ask - * - * Scan the brigade for a matching packet type, optionally poll the socket for - * a packet first - */ -int -_libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type, - unsigned char **data, size_t *data_len, - int match_ofs, const unsigned char *match_buf, - size_t match_len) -{ - LIBSSH2_PACKET *packet = _libssh2_list_first(&session->packets); - - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Looking for packet of type: %d", (int) packet_type); - - while (packet) { - if (packet->data[0] == packet_type - && (packet->data_len >= (match_ofs + match_len)) - && (!match_buf || - (memcmp(packet->data + match_ofs, match_buf, - match_len) == 0))) { - *data = packet->data; - *data_len = packet->data_len; - - /* unlink struct from session->packets */ - _libssh2_list_remove(&packet->node); - - LIBSSH2_FREE(session, packet); - - return 0; - } - packet = _libssh2_list_next(&packet->node); - } - return -1; -} - -/* - * libssh2_packet_askv - * - * Scan for any of a list of packet types in the brigade, optionally poll the - * socket for a packet first - */ -int -_libssh2_packet_askv(LIBSSH2_SESSION * session, - const unsigned char *packet_types, - unsigned char **data, size_t *data_len, - int match_ofs, - const unsigned char *match_buf, - size_t match_len) -{ - int i, packet_types_len = strlen((char *) packet_types); - - for(i = 0; i < packet_types_len; i++) { - if (0 == _libssh2_packet_ask(session, packet_types[i], data, - data_len, match_ofs, - match_buf, match_len)) { - return 0; - } - } - - return -1; -} - -/* - * _libssh2_packet_require - * - * Loops _libssh2_transport_read() until the packet requested is available - * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout - * - * Returns negative on error - * Returns 0 when it has taken care of the requested packet. - */ -int -_libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type, - unsigned char **data, size_t *data_len, - int match_ofs, - const unsigned char *match_buf, - size_t match_len, - packet_require_state_t *state) -{ - if (state->start == 0) { - if (_libssh2_packet_ask(session, packet_type, data, data_len, - match_ofs, match_buf, - match_len) == 0) { - /* A packet was available in the packet brigade */ - return 0; - } - - state->start = time(NULL); - } - - while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) { - int ret = _libssh2_transport_read(session); - if (ret == LIBSSH2_ERROR_EAGAIN) - return ret; - else if (ret < 0) { - state->start = 0; - /* an error which is not just because of blocking */ - return ret; - } else if (ret == packet_type) { - /* Be lazy, let packet_ask pull it out of the brigade */ - ret = _libssh2_packet_ask(session, packet_type, data, data_len, - match_ofs, match_buf, match_len); - state->start = 0; - return ret; - } else if (ret == 0) { - /* nothing available, wait until data arrives or we time out */ - long left = LIBSSH2_READ_TIMEOUT - (long)(time(NULL) - - state->start); - - if (left <= 0) { - state->start = 0; - return LIBSSH2_ERROR_TIMEOUT; - } - return -1; /* no packet available yet */ - } - } - - /* Only reached if the socket died */ - return LIBSSH2_ERROR_SOCKET_DISCONNECT; -} - -/* - * _libssh2_packet_burn - * - * Loops _libssh2_transport_read() until any packet is available and promptly - * discards it. - * Used during KEX exchange to discard badly guessed KEX_INIT packets - */ -int -_libssh2_packet_burn(LIBSSH2_SESSION * session, - libssh2_nonblocking_states * state) -{ - unsigned char *data; - size_t data_len; - unsigned char all_packets[255]; - int i; - int ret; - - if (*state == libssh2_NB_state_idle) { - for(i = 1; i < 256; i++) { - all_packets[i - 1] = i; - } - - if (_libssh2_packet_askv(session, all_packets, &data, &data_len, 0, - NULL, 0) == 0) { - i = data[0]; - /* A packet was available in the packet brigade, burn it */ - LIBSSH2_FREE(session, data); - return i; - } - - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Blocking until packet becomes available to burn"); - *state = libssh2_NB_state_created; - } - - while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) { - ret = _libssh2_transport_read(session); - if (ret == LIBSSH2_ERROR_EAGAIN) { - return ret; - } else if (ret < 0) { - *state = libssh2_NB_state_idle; - return ret; - } else if (ret == 0) { - /* FIXME: this might busyloop */ - continue; - } - - /* Be lazy, let packet_ask pull it out of the brigade */ - if (0 == - _libssh2_packet_ask(session, ret, &data, &data_len, 0, NULL, 0)) { - /* Smoke 'em if you got 'em */ - LIBSSH2_FREE(session, data); - *state = libssh2_NB_state_idle; - return ret; - } - } - - /* Only reached if the socket died */ - return LIBSSH2_ERROR_SOCKET_DISCONNECT; -} - -/* - * _libssh2_packet_requirev - * - * Loops _libssh2_transport_read() until one of a list of packet types - * requested is available. SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause - * a bailout. packet_types is a null terminated list of packet_type numbers - */ - -int -_libssh2_packet_requirev(LIBSSH2_SESSION *session, - const unsigned char *packet_types, - unsigned char **data, size_t *data_len, - int match_ofs, - const unsigned char *match_buf, size_t match_len, - packet_requirev_state_t * state) -{ - if (_libssh2_packet_askv(session, packet_types, data, data_len, match_ofs, - match_buf, match_len) == 0) { - /* One of the packets listed was available in the packet brigade */ - state->start = 0; - return 0; - } - - if (state->start == 0) { - state->start = time(NULL); - } - - while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) { - int ret = _libssh2_transport_read(session); - if ((ret < 0) && (ret != LIBSSH2_ERROR_EAGAIN)) { - state->start = 0; - return ret; - } - if (ret <= 0) { - long left = LIBSSH2_READ_TIMEOUT - - (long)(time(NULL) - state->start); - - if (left <= 0) { - state->start = 0; - return LIBSSH2_ERROR_TIMEOUT; - } - else if (ret == LIBSSH2_ERROR_EAGAIN) { - return ret; - } - } - - if (strchr((char *) packet_types, ret)) { - /* Be lazy, let packet_ask pull it out of the brigade */ - return _libssh2_packet_askv(session, packet_types, data, - data_len, match_ofs, match_buf, - match_len); - } - } - - /* Only reached if the socket died */ - state->start = 0; - return LIBSSH2_ERROR_SOCKET_DISCONNECT; -} - diff --git a/vendor/libssh2-1.4.2/src/packet.h b/vendor/libssh2-1.4.2/src/packet.h deleted file mode 100644 index d66b15b..0000000 --- a/vendor/libssh2-1.4.2/src/packet.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef LIBSSH2_PACKET_H -#define LIBSSH2_PACKET_H -/* - * Copyright (C) 2010 by Daniel Stenberg - * Author: Daniel Stenberg - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - */ - -int _libssh2_packet_read(LIBSSH2_SESSION * session); - -int _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type, - unsigned char **data, size_t *data_len, - int match_ofs, - const unsigned char *match_buf, - size_t match_len); - -int _libssh2_packet_askv(LIBSSH2_SESSION * session, - const unsigned char *packet_types, - unsigned char **data, size_t *data_len, - int match_ofs, - const unsigned char *match_buf, - size_t match_len); -int _libssh2_packet_require(LIBSSH2_SESSION * session, - unsigned char packet_type, unsigned char **data, - size_t *data_len, int match_ofs, - const unsigned char *match_buf, - size_t match_len, - packet_require_state_t * state); -int _libssh2_packet_requirev(LIBSSH2_SESSION *session, - const unsigned char *packet_types, - unsigned char **data, size_t *data_len, - int match_ofs, - const unsigned char *match_buf, - size_t match_len, - packet_requirev_state_t * state); -int _libssh2_packet_burn(LIBSSH2_SESSION * session, - libssh2_nonblocking_states * state); -int _libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data, - unsigned long data_len); -int _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, - size_t datalen, int macstate); - -#endif /* LIBSSH2_PACKET_H */ diff --git a/vendor/libssh2-1.4.2/src/pem.c b/vendor/libssh2-1.4.2/src/pem.c deleted file mode 100644 index 5749bc8..0000000 --- a/vendor/libssh2-1.4.2/src/pem.c +++ /dev/null @@ -1,213 +0,0 @@ -/* Copyright (C) 2007 The Written Word, Inc. - * Copyright (C) 2008, Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" - -#ifdef LIBSSH2_LIBGCRYPT /* compile only if we build with libgcrypt */ - -static int -readline(char *line, int line_size, FILE * fp) -{ - if (!fgets(line, line_size, fp)) { - return -1; - } - if (*line && line[strlen(line) - 1] == '\n') { - line[strlen(line) - 1] = '\0'; - } - if (*line && line[strlen(line) - 1] == '\r') { - line[strlen(line) - 1] = '\0'; - } - return 0; -} - -#define LINE_SIZE 128 - -int -_libssh2_pem_parse(LIBSSH2_SESSION * session, - const char *headerbegin, - const char *headerend, - FILE * fp, unsigned char **data, unsigned int *datalen) -{ - char line[LINE_SIZE]; - char *b64data = NULL; - unsigned int b64datalen = 0; - int ret; - - do { - if (readline(line, LINE_SIZE, fp)) { - return -1; - } - } - while (strcmp(line, headerbegin) != 0); - - *line = '\0'; - - do { - if (*line) { - char *tmp; - size_t linelen; - - linelen = strlen(line); - tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); - if (!tmp) { - ret = -1; - goto out; - } - memcpy(tmp + b64datalen, line, linelen); - b64data = tmp; - b64datalen += linelen; - } - - if (readline(line, LINE_SIZE, fp)) { - ret = -1; - goto out; - } - } while (strcmp(line, headerend) != 0); - - if (libssh2_base64_decode(session, (char**) data, datalen, - b64data, b64datalen)) { - ret = -1; - goto out; - } - - ret = 0; - out: - if (b64data) { - LIBSSH2_FREE(session, b64data); - } - return ret; -} - -static int -read_asn1_length(const unsigned char *data, - unsigned int datalen, unsigned int *len) -{ - unsigned int lenlen; - int nextpos; - - if (datalen < 1) { - return -1; - } - *len = data[0]; - - if (*len >= 0x80) { - lenlen = *len & 0x7F; - *len = data[1]; - if (1 + lenlen > datalen) { - return -1; - } - if (lenlen > 1) { - *len <<= 8; - *len |= data[2]; - } - } else { - lenlen = 0; - } - - nextpos = 1 + lenlen; - if (lenlen > 2 || 1 + lenlen + *len > datalen) { - return -1; - } - - return nextpos; -} - -int -_libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen) -{ - unsigned int len; - int lenlen; - - if (*datalen < 1) { - return -1; - } - - if ((*data)[0] != '\x30') { - return -1; - } - - (*data)++; - (*datalen)--; - - lenlen = read_asn1_length(*data, *datalen, &len); - if (lenlen < 0 || lenlen + len != *datalen) { - return -1; - } - - *data += lenlen; - *datalen -= lenlen; - - return 0; -} - -int -_libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen, - unsigned char **i, unsigned int *ilen) -{ - unsigned int len; - int lenlen; - - if (*datalen < 1) { - return -1; - } - - if ((*data)[0] != '\x02') { - return -1; - } - - (*data)++; - (*datalen)--; - - lenlen = read_asn1_length(*data, *datalen, &len); - if (lenlen < 0 || lenlen + len > *datalen) { - return -1; - } - - *data += lenlen; - *datalen -= lenlen; - - *i = *data; - *ilen = len; - - *data += len; - *datalen -= len; - - return 0; -} - -#endif /* LIBSSH2_LIBGCRYPT */ diff --git a/vendor/libssh2-1.4.2/src/publickey.c b/vendor/libssh2-1.4.2/src/publickey.c deleted file mode 100644 index ab76ab2..0000000 --- a/vendor/libssh2-1.4.2/src/publickey.c +++ /dev/null @@ -1,1058 +0,0 @@ -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2010 by Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" -#include "libssh2_publickey.h" -#include "channel.h" -#include "session.h" - -#define LIBSSH2_PUBLICKEY_VERSION 2 - -/* Numericised response codes -- Not IETF, just local representation */ -#define LIBSSH2_PUBLICKEY_RESPONSE_STATUS 0 -#define LIBSSH2_PUBLICKEY_RESPONSE_VERSION 1 -#define LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY 2 - -typedef struct _LIBSSH2_PUBLICKEY_CODE_LIST -{ - int code; - const char *name; - int name_len; -} LIBSSH2_PUBLICKEY_CODE_LIST; - -static const LIBSSH2_PUBLICKEY_CODE_LIST publickey_response_codes[] = -{ - {LIBSSH2_PUBLICKEY_RESPONSE_STATUS, "status", sizeof("status") - 1}, - {LIBSSH2_PUBLICKEY_RESPONSE_VERSION, "version", sizeof("version") - 1}, - {LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY, "publickey", - sizeof("publickey") - 1} , - {0, NULL, 0} -}; - -/* PUBLICKEY status codes -- IETF defined */ -#define LIBSSH2_PUBLICKEY_SUCCESS 0 -#define LIBSSH2_PUBLICKEY_ACCESS_DENIED 1 -#define LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED 2 -#define LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED 3 -#define LIBSSH2_PUBLICKEY_KEY_NOT_FOUND 4 -#define LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED 5 -#define LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT 6 -#define LIBSSH2_PUBLICKEY_GENERAL_FAILURE 7 -#define LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED 8 - -#define LIBSSH2_PUBLICKEY_STATUS_CODE_MAX 8 - -static const LIBSSH2_PUBLICKEY_CODE_LIST publickey_status_codes[] = { - {LIBSSH2_PUBLICKEY_SUCCESS, "success", sizeof("success") - 1} , - {LIBSSH2_PUBLICKEY_ACCESS_DENIED, "access denied", - sizeof("access denied") - 1}, - {LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED, "storage exceeded", - sizeof("storage exceeded") - 1} , - {LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED, "version not supported", - sizeof("version not supported") - 1} , - {LIBSSH2_PUBLICKEY_KEY_NOT_FOUND, "key not found", - sizeof("key not found") - 1}, - {LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED, "key not supported", - sizeof("key not supported") - 1}, - {LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT, "key already present", - sizeof("key already present") - 1}, - {LIBSSH2_PUBLICKEY_GENERAL_FAILURE, "general failure", - sizeof("general failure") - 1}, - {LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED, "request not supported", - sizeof("request not supported") - 1}, - {0, NULL, 0} -}; - -/* - * publickey_status_error - * - * Format an error message from a status code - */ -static void -publickey_status_error(const LIBSSH2_PUBLICKEY *pkey, - LIBSSH2_SESSION *session, int status) -{ - const char *msg; - - /* GENERAL_FAILURE got remapped between version 1 and 2 */ - if (status == 6 && pkey && pkey->version == 1) { - status = 7; - } - - if (status < 0 || status > LIBSSH2_PUBLICKEY_STATUS_CODE_MAX) { - msg = "unknown"; - } else { - msg = publickey_status_codes[status].name; - } - - _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, msg); -} - -/* - * publickey_packet_receive - * - * Read a packet from the subsystem - */ -static int -publickey_packet_receive(LIBSSH2_PUBLICKEY * pkey, - unsigned char **data, size_t *data_len) -{ - LIBSSH2_CHANNEL *channel = pkey->channel; - LIBSSH2_SESSION *session = channel->session; - unsigned char buffer[4]; - int rc; - - if (pkey->receive_state == libssh2_NB_state_idle) { - rc = _libssh2_channel_read(channel, 0, (char *) buffer, 4); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc != 4) { - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Invalid response from publickey subsystem"); - } - - pkey->receive_packet_len = _libssh2_ntohu32(buffer); - pkey->receive_packet = - LIBSSH2_ALLOC(session, pkey->receive_packet_len); - if (!pkey->receive_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate publickey response " - "buffer"); - } - - pkey->receive_state = libssh2_NB_state_sent; - } - - if (pkey->receive_state == libssh2_NB_state_sent) { - rc = _libssh2_channel_read(channel, 0, (char *) pkey->receive_packet, - pkey->receive_packet_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc != (int)pkey->receive_packet_len) { - LIBSSH2_FREE(session, pkey->receive_packet); - pkey->receive_packet = NULL; - pkey->receive_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, - "Timeout waiting for publickey subsystem " - "response packet"); - } - - *data = pkey->receive_packet; - *data_len = pkey->receive_packet_len; - } - - pkey->receive_state = libssh2_NB_state_idle; - - return 0; -} - -/* publickey_response_id - * - * Translate a string response name to a numeric code - * Data will be incremented by 4 + response_len on success only - */ -static int -publickey_response_id(unsigned char **pdata, size_t data_len) -{ - size_t response_len; - unsigned char *data = *pdata; - const LIBSSH2_PUBLICKEY_CODE_LIST *codes = publickey_response_codes; - - if (data_len < 4) { - /* Malformed response */ - return -1; - } - response_len = _libssh2_ntohu32(data); - data += 4; - data_len -= 4; - if (data_len < response_len) { - /* Malformed response */ - return -1; - } - - while (codes->name) { - if ((unsigned long)codes->name_len == response_len && - strncmp(codes->name, (char *) data, response_len) == 0) { - *pdata = data + response_len; - return codes->code; - } - codes++; - } - - return -1; -} - -/* publickey_response_success - * - * Generic helper routine to wait for success response and nothing else - */ -static int -publickey_response_success(LIBSSH2_PUBLICKEY * pkey) -{ - LIBSSH2_SESSION *session = pkey->channel->session; - unsigned char *data, *s; - size_t data_len; - int response; - - while (1) { - int rc = publickey_packet_receive(pkey, &data, &data_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, - "Timeout waiting for response from " - "publickey subsystem"); - } - - s = data; - response = publickey_response_id(&s, data_len); - - switch (response) { - case LIBSSH2_PUBLICKEY_RESPONSE_STATUS: - /* Error, or processing complete */ - { - unsigned long status = _libssh2_ntohu32(s); - - LIBSSH2_FREE(session, data); - - if (status == LIBSSH2_PUBLICKEY_SUCCESS) - return 0; - - publickey_status_error(pkey, session, status); - return -1; - } - default: - LIBSSH2_FREE(session, data); - if (response < 0) { - return _libssh2_error(session, - LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Invalid publickey subsystem response"); - } - /* Unknown/Unexpected */ - _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Unexpected publickey subsystem response"); - data = NULL; - } - } - /* never reached, but include `return` to silence compiler warnings */ - return -1; -} - -/* ***************** - * Publickey API * - ***************** */ - -/* - * publickey_init - * - * Startup the publickey subsystem - */ -static LIBSSH2_PUBLICKEY *publickey_init(LIBSSH2_SESSION *session) -{ - int response; - int rc; - - if (session->pkeyInit_state == libssh2_NB_state_idle) { - session->pkeyInit_data = NULL; - session->pkeyInit_pkey = NULL; - session->pkeyInit_channel = NULL; - - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Initializing publickey subsystem"); - - session->pkeyInit_state = libssh2_NB_state_allocated; - } - - if (session->pkeyInit_state == libssh2_NB_state_allocated) { - - session->pkeyInit_channel = - _libssh2_channel_open(session, "session", - sizeof("session") - 1, - LIBSSH2_CHANNEL_WINDOW_DEFAULT, - LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, - 0); - if (!session->pkeyInit_channel) { - if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) - /* The error state is already set, so leave it */ - return NULL; - _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, - "Unable to startup channel"); - goto err_exit; - } - - session->pkeyInit_state = libssh2_NB_state_sent; - } - - if (session->pkeyInit_state == libssh2_NB_state_sent) { - rc = _libssh2_channel_process_startup(session->pkeyInit_channel, - "subsystem", - sizeof("subsystem") - 1, - "publickey", - sizeof("publickey") - 1); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block starting publickey subsystem"); - return NULL; - } else if (rc) { - _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, - "Unable to request publickey subsystem"); - goto err_exit; - } - - session->pkeyInit_state = libssh2_NB_state_sent1; - } - - if (session->pkeyInit_state == libssh2_NB_state_sent1) { - unsigned char *s; - rc = _libssh2_channel_extended_data(session->pkeyInit_channel, - LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block starting publickey subsystem"); - return NULL; - } - - session->pkeyInit_pkey = - LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PUBLICKEY)); - if (!session->pkeyInit_pkey) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate a new publickey structure"); - goto err_exit; - } - memset(session->pkeyInit_pkey, 0, sizeof(LIBSSH2_PUBLICKEY)); - session->pkeyInit_pkey->channel = session->pkeyInit_channel; - session->pkeyInit_pkey->version = 0; - - s = session->pkeyInit_buffer; - _libssh2_htonu32(s, 4 + (sizeof("version") - 1) + 4); - s += 4; - _libssh2_htonu32(s, sizeof("version") - 1); - s += 4; - memcpy(s, "version", sizeof("version") - 1); - s += sizeof("version") - 1; - _libssh2_htonu32(s, LIBSSH2_PUBLICKEY_VERSION); - - session->pkeyInit_buffer_sent = 0; - - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Sending publickey advertising version %d support", - (int) LIBSSH2_PUBLICKEY_VERSION); - - session->pkeyInit_state = libssh2_NB_state_sent2; - } - - if (session->pkeyInit_state == libssh2_NB_state_sent2) { - rc = _libssh2_channel_write(session->pkeyInit_channel, 0, - session->pkeyInit_buffer, - 19 - session->pkeyInit_buffer_sent); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block sending publickey version packet"); - return NULL; - } else if (rc) { - _libssh2_error(session, rc, - "Unable to send publickey version packet"); - goto err_exit; - } - session->pkeyInit_buffer_sent += rc; - if(session->pkeyInit_buffer_sent < 19) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Need to be called again to complete this"); - return NULL; - } - - session->pkeyInit_state = libssh2_NB_state_sent3; - } - - if (session->pkeyInit_state == libssh2_NB_state_sent3) { - while (1) { - unsigned char *s; - rc = publickey_packet_receive(session->pkeyInit_pkey, - &session->pkeyInit_data, - &session->pkeyInit_data_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting for response from " - "publickey subsystem"); - return NULL; - } else if (rc) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, - "Timeout waiting for response from " - "publickey subsystem"); - goto err_exit; - } - - s = session->pkeyInit_data; - if ((response = - publickey_response_id(&s, session->pkeyInit_data_len)) < 0) { - _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Invalid publickey subsystem response code"); - goto err_exit; - } - - switch (response) { - case LIBSSH2_PUBLICKEY_RESPONSE_STATUS: - /* Error */ - { - unsigned long status, descr_len, lang_len; - - status = _libssh2_ntohu32(s); - s += 4; - descr_len = _libssh2_ntohu32(s); - s += 4; - /* description starts here */ - s += descr_len; - lang_len = _libssh2_ntohu32(s); - s += 4; - /* lang starts here */ - s += lang_len; - - if (s > - session->pkeyInit_data + session->pkeyInit_data_len) { - _libssh2_error(session, - LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Malformed publickey subsystem packet"); - goto err_exit; - } - - publickey_status_error(NULL, session, status); - - goto err_exit; - } - - case LIBSSH2_PUBLICKEY_RESPONSE_VERSION: - /* What we want */ - session->pkeyInit_pkey->version = _libssh2_ntohu32(s); - if (session->pkeyInit_pkey->version > - LIBSSH2_PUBLICKEY_VERSION) { - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Truncate remote publickey version from %lu", - session->pkeyInit_pkey->version); - session->pkeyInit_pkey->version = - LIBSSH2_PUBLICKEY_VERSION; - } - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Enabling publickey subsystem version %lu", - session->pkeyInit_pkey->version); - LIBSSH2_FREE(session, session->pkeyInit_data); - session->pkeyInit_data = NULL; - session->pkeyInit_state = libssh2_NB_state_idle; - return session->pkeyInit_pkey; - - default: - /* Unknown/Unexpected */ - _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Unexpected publickey subsystem response, " - "ignoring"); - LIBSSH2_FREE(session, session->pkeyInit_data); - session->pkeyInit_data = NULL; - } - } - } - - /* Never reached except by direct goto */ - err_exit: - session->pkeyInit_state = libssh2_NB_state_sent4; - if (session->pkeyInit_channel) { - rc = _libssh2_channel_close(session->pkeyInit_channel); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block closing channel"); - return NULL; - } - } - if (session->pkeyInit_pkey) { - LIBSSH2_FREE(session, session->pkeyInit_pkey); - session->pkeyInit_pkey = NULL; - } - if (session->pkeyInit_data) { - LIBSSH2_FREE(session, session->pkeyInit_data); - session->pkeyInit_data = NULL; - } - session->pkeyInit_state = libssh2_NB_state_idle; - return NULL; -} - -/* - * libssh2_publickey_init - * - * Startup the publickey subsystem - */ -LIBSSH2_API LIBSSH2_PUBLICKEY * -libssh2_publickey_init(LIBSSH2_SESSION *session) -{ - LIBSSH2_PUBLICKEY *ptr; - - BLOCK_ADJUST_ERRNO(ptr, session, - publickey_init(session)); - return ptr; -} - - - -/* - * libssh2_publickey_add_ex - * - * Add a new public key entry - */ -LIBSSH2_API int -libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, - unsigned long name_len, const unsigned char *blob, - unsigned long blob_len, char overwrite, - unsigned long num_attrs, - const libssh2_publickey_attribute attrs[]) -{ - LIBSSH2_CHANNEL *channel; - LIBSSH2_SESSION *session; - /* 19 = packet_len(4) + add_len(4) + "add"(3) + name_len(4) + {name} - blob_len(4) + {blob} */ - unsigned long i, packet_len = 19 + name_len + blob_len; - unsigned char *comment = NULL; - unsigned long comment_len = 0; - int rc; - - if(!pkey) - return LIBSSH2_ERROR_BAD_USE; - - channel = pkey->channel; - session = channel->session; - - if (pkey->add_state == libssh2_NB_state_idle) { - pkey->add_packet = NULL; - - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, "Adding %s publickey", - name); - - if (pkey->version == 1) { - for(i = 0; i < num_attrs; i++) { - /* Search for a comment attribute */ - if (attrs[i].name_len == (sizeof("comment") - 1) && - strncmp(attrs[i].name, "comment", - sizeof("comment") - 1) == 0) { - comment = (unsigned char *) attrs[i].value; - comment_len = attrs[i].value_len; - break; - } - } - packet_len += 4 + comment_len; - } else { - packet_len += 5; /* overwrite(1) + attribute_count(4) */ - for(i = 0; i < num_attrs; i++) { - packet_len += 9 + attrs[i].name_len + attrs[i].value_len; - /* name_len(4) + value_len(4) + mandatory(1) */ - } - } - - pkey->add_packet = LIBSSH2_ALLOC(session, packet_len); - if (!pkey->add_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "publickey \"add\" packet"); - } - - pkey->add_s = pkey->add_packet; - _libssh2_htonu32(pkey->add_s, packet_len - 4); - pkey->add_s += 4; - _libssh2_htonu32(pkey->add_s, sizeof("add") - 1); - pkey->add_s += 4; - memcpy(pkey->add_s, "add", sizeof("add") - 1); - pkey->add_s += sizeof("add") - 1; - if (pkey->version == 1) { - _libssh2_htonu32(pkey->add_s, comment_len); - pkey->add_s += 4; - if (comment) { - memcpy(pkey->add_s, comment, comment_len); - pkey->add_s += comment_len; - } - - _libssh2_htonu32(pkey->add_s, name_len); - pkey->add_s += 4; - memcpy(pkey->add_s, name, name_len); - pkey->add_s += name_len; - _libssh2_htonu32(pkey->add_s, blob_len); - pkey->add_s += 4; - memcpy(pkey->add_s, blob, blob_len); - pkey->add_s += blob_len; - } else { - /* Version == 2 */ - - _libssh2_htonu32(pkey->add_s, name_len); - pkey->add_s += 4; - memcpy(pkey->add_s, name, name_len); - pkey->add_s += name_len; - _libssh2_htonu32(pkey->add_s, blob_len); - pkey->add_s += 4; - memcpy(pkey->add_s, blob, blob_len); - pkey->add_s += blob_len; - *(pkey->add_s++) = overwrite ? 0x01 : 0; - _libssh2_htonu32(pkey->add_s, num_attrs); - pkey->add_s += 4; - for(i = 0; i < num_attrs; i++) { - _libssh2_htonu32(pkey->add_s, attrs[i].name_len); - pkey->add_s += 4; - memcpy(pkey->add_s, attrs[i].name, attrs[i].name_len); - pkey->add_s += attrs[i].name_len; - _libssh2_htonu32(pkey->add_s, attrs[i].value_len); - pkey->add_s += 4; - memcpy(pkey->add_s, attrs[i].value, attrs[i].value_len); - pkey->add_s += attrs[i].value_len; - *(pkey->add_s++) = attrs[i].mandatory ? 0x01 : 0; - } - } - - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Sending publickey \"add\" packet: " - "type=%s blob_len=%ld num_attrs=%ld", - name, blob_len, num_attrs); - - pkey->add_state = libssh2_NB_state_created; - } - - if (pkey->add_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, pkey->add_packet, - (pkey->add_s - pkey->add_packet)); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if ((pkey->add_s - pkey->add_packet) != rc) { - LIBSSH2_FREE(session, pkey->add_packet); - pkey->add_packet = NULL; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send publickey add packet"); - } - LIBSSH2_FREE(session, pkey->add_packet); - pkey->add_packet = NULL; - - pkey->add_state = libssh2_NB_state_sent; - } - - rc = publickey_response_success(pkey); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - - pkey->add_state = libssh2_NB_state_idle; - - return rc; -} - -/* libssh2_publickey_remove_ex - * Remove an existing publickey so that authentication can no longer be - * performed using it - */ -LIBSSH2_API int -libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY * pkey, - const unsigned char *name, unsigned long name_len, - const unsigned char *blob, unsigned long blob_len) -{ - LIBSSH2_CHANNEL *channel; - LIBSSH2_SESSION *session; - /* 22 = packet_len(4) + remove_len(4) + "remove"(6) + name_len(4) + {name} - + blob_len(4) + {blob} */ - unsigned long packet_len = 22 + name_len + blob_len; - int rc; - - if(!pkey) - return LIBSSH2_ERROR_BAD_USE; - - channel = pkey->channel; - session = channel->session; - - if (pkey->remove_state == libssh2_NB_state_idle) { - pkey->remove_packet = NULL; - - pkey->remove_packet = LIBSSH2_ALLOC(session, packet_len); - if (!pkey->remove_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "publickey \"remove\" packet"); - } - - pkey->remove_s = pkey->remove_packet; - _libssh2_htonu32(pkey->remove_s, packet_len - 4); - pkey->remove_s += 4; - _libssh2_htonu32(pkey->remove_s, sizeof("remove") - 1); - pkey->remove_s += 4; - memcpy(pkey->remove_s, "remove", sizeof("remove") - 1); - pkey->remove_s += sizeof("remove") - 1; - _libssh2_htonu32(pkey->remove_s, name_len); - pkey->remove_s += 4; - memcpy(pkey->remove_s, name, name_len); - pkey->remove_s += name_len; - _libssh2_htonu32(pkey->remove_s, blob_len); - pkey->remove_s += 4; - memcpy(pkey->remove_s, blob, blob_len); - pkey->remove_s += blob_len; - - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Sending publickey \"remove\" packet: " - "type=%s blob_len=%ld", - name, blob_len); - - pkey->remove_state = libssh2_NB_state_created; - } - - if (pkey->remove_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, pkey->remove_packet, - (pkey->remove_s - pkey->remove_packet)); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if ((pkey->remove_s - pkey->remove_packet) != rc) { - LIBSSH2_FREE(session, pkey->remove_packet); - pkey->remove_packet = NULL; - pkey->remove_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send publickey remove packet"); - } - LIBSSH2_FREE(session, pkey->remove_packet); - pkey->remove_packet = NULL; - - pkey->remove_state = libssh2_NB_state_sent; - } - - rc = publickey_response_success(pkey); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - - pkey->remove_state = libssh2_NB_state_idle; - - return rc; -} - -/* libssh2_publickey_list_fetch - * Fetch a list of supported public key from a server - */ -LIBSSH2_API int -libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys, - libssh2_publickey_list ** pkey_list) -{ - LIBSSH2_CHANNEL *channel; - LIBSSH2_SESSION *session; - libssh2_publickey_list *list = NULL; - unsigned long buffer_len = 12, keys = 0, max_keys = 0, i; - /* 12 = packet_len(4) + list_len(4) + "list"(4) */ - int response; - int rc; - - if(!pkey) - return LIBSSH2_ERROR_BAD_USE; - - channel = pkey->channel; - session = channel->session; - - if (pkey->listFetch_state == libssh2_NB_state_idle) { - pkey->listFetch_data = NULL; - - pkey->listFetch_s = pkey->listFetch_buffer; - _libssh2_htonu32(pkey->listFetch_s, buffer_len - 4); - pkey->listFetch_s += 4; - _libssh2_htonu32(pkey->listFetch_s, sizeof("list") - 1); - pkey->listFetch_s += 4; - memcpy(pkey->listFetch_s, "list", sizeof("list") - 1); - pkey->listFetch_s += sizeof("list") - 1; - - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Sending publickey \"list\" packet"); - - pkey->listFetch_state = libssh2_NB_state_created; - } - - if (pkey->listFetch_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, - pkey->listFetch_buffer, - (pkey->listFetch_s - - pkey->listFetch_buffer)); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if ((pkey->listFetch_s - pkey->listFetch_buffer) != rc) { - pkey->listFetch_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send publickey list packet"); - } - - pkey->listFetch_state = libssh2_NB_state_sent; - } - - while (1) { - rc = publickey_packet_receive(pkey, &pkey->listFetch_data, - &pkey->listFetch_data_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, - "Timeout waiting for response from " - "publickey subsystem"); - goto err_exit; - } - - pkey->listFetch_s = pkey->listFetch_data; - if ((response = - publickey_response_id(&pkey->listFetch_s, - pkey->listFetch_data_len)) < 0) { - _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Invalid publickey subsystem response code"); - goto err_exit; - } - - switch (response) { - case LIBSSH2_PUBLICKEY_RESPONSE_STATUS: - /* Error, or processing complete */ - { - unsigned long status, descr_len, lang_len; - - status = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - descr_len = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - /* description starts at pkey->listFetch_s */ - pkey->listFetch_s += descr_len; - lang_len = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - /* lang starts at pkey->listFetch_s */ - pkey->listFetch_s += lang_len; - - if (pkey->listFetch_s > - pkey->listFetch_data + pkey->listFetch_data_len) { - _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Malformed publickey subsystem packet"); - goto err_exit; - } - - if (status == LIBSSH2_PUBLICKEY_SUCCESS) { - LIBSSH2_FREE(session, pkey->listFetch_data); - pkey->listFetch_data = NULL; - *pkey_list = list; - *num_keys = keys; - pkey->listFetch_state = libssh2_NB_state_idle; - return 0; - } - - publickey_status_error(pkey, session, status); - goto err_exit; - } - case LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY: - /* What we want */ - if (keys >= max_keys) { - libssh2_publickey_list *newlist; - /* Grow the key list if necessary */ - max_keys += 8; - newlist = - LIBSSH2_REALLOC(session, list, - (max_keys + - 1) * sizeof(libssh2_publickey_list)); - if (!newlist) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "publickey list"); - goto err_exit; - } - list = newlist; - } - if (pkey->version == 1) { - unsigned long comment_len; - - comment_len = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - if (comment_len) { - list[keys].num_attrs = 1; - list[keys].attrs = - LIBSSH2_ALLOC(session, - sizeof(libssh2_publickey_attribute)); - if (!list[keys].attrs) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "publickey attributes"); - goto err_exit; - } - list[keys].attrs[0].name = "comment"; - list[keys].attrs[0].name_len = sizeof("comment") - 1; - list[keys].attrs[0].value = (char *) pkey->listFetch_s; - list[keys].attrs[0].value_len = comment_len; - list[keys].attrs[0].mandatory = 0; - - pkey->listFetch_s += comment_len; - } else { - list[keys].num_attrs = 0; - list[keys].attrs = NULL; - } - list[keys].name_len = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - list[keys].name = pkey->listFetch_s; - pkey->listFetch_s += list[keys].name_len; - list[keys].blob_len = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - list[keys].blob = pkey->listFetch_s; - pkey->listFetch_s += list[keys].blob_len; - } else { - /* Version == 2 */ - list[keys].name_len = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - list[keys].name = pkey->listFetch_s; - pkey->listFetch_s += list[keys].name_len; - list[keys].blob_len = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - list[keys].blob = pkey->listFetch_s; - pkey->listFetch_s += list[keys].blob_len; - list[keys].num_attrs = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - if (list[keys].num_attrs) { - list[keys].attrs = - LIBSSH2_ALLOC(session, - list[keys].num_attrs * - sizeof(libssh2_publickey_attribute)); - if (!list[keys].attrs) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "publickey attributes"); - goto err_exit; - } - for(i = 0; i < list[keys].num_attrs; i++) { - list[keys].attrs[i].name_len = - _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - list[keys].attrs[i].name = (char *) pkey->listFetch_s; - pkey->listFetch_s += list[keys].attrs[i].name_len; - list[keys].attrs[i].value_len = - _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - list[keys].attrs[i].value = (char *) pkey->listFetch_s; - pkey->listFetch_s += list[keys].attrs[i].value_len; - - /* actually an ignored value */ - list[keys].attrs[i].mandatory = 0; - } - } else { - list[keys].attrs = NULL; - } - } - /* To be FREEd in libssh2_publickey_list_free() */ - list[keys].packet = pkey->listFetch_data; - keys++; - - list[keys].packet = NULL; /* Terminate the list */ - pkey->listFetch_data = NULL; - break; - default: - /* Unknown/Unexpected */ - _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Unexpected publickey subsystem response"); - LIBSSH2_FREE(session, pkey->listFetch_data); - pkey->listFetch_data = NULL; - } - } - - /* Only reached via explicit goto */ - err_exit: - if (pkey->listFetch_data) { - LIBSSH2_FREE(session, pkey->listFetch_data); - pkey->listFetch_data = NULL; - } - if (list) { - libssh2_publickey_list_free(pkey, list); - } - pkey->listFetch_state = libssh2_NB_state_idle; - return -1; -} - -/* libssh2_publickey_list_free - * Free a previously fetched list of public keys - */ -LIBSSH2_API void -libssh2_publickey_list_free(LIBSSH2_PUBLICKEY * pkey, - libssh2_publickey_list * pkey_list) -{ - LIBSSH2_SESSION *session; - libssh2_publickey_list *p = pkey_list; - - if(!pkey || !p) - return; - - session = pkey->channel->session; - - while (p->packet) { - if (p->attrs) { - LIBSSH2_FREE(session, p->attrs); - } - LIBSSH2_FREE(session, p->packet); - p++; - } - - LIBSSH2_FREE(session, pkey_list); -} - -/* libssh2_publickey_shutdown - * Shutdown the publickey subsystem - */ -LIBSSH2_API int -libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey) -{ - LIBSSH2_SESSION *session; - int rc; - - if(!pkey) - return LIBSSH2_ERROR_BAD_USE; - - session = pkey->channel->session; - - /* - * Make sure all memory used in the state variables are free - */ - if (pkey->receive_packet) { - LIBSSH2_FREE(session, pkey->receive_packet); - pkey->receive_packet = NULL; - } - if (pkey->add_packet) { - LIBSSH2_FREE(session, pkey->add_packet); - pkey->add_packet = NULL; - } - if (pkey->remove_packet) { - LIBSSH2_FREE(session, pkey->remove_packet); - pkey->remove_packet = NULL; - } - if (pkey->listFetch_data) { - LIBSSH2_FREE(session, pkey->listFetch_data); - pkey->listFetch_data = NULL; - } - - rc = _libssh2_channel_free(pkey->channel); - if (rc == LIBSSH2_ERROR_EAGAIN) - return rc; - - LIBSSH2_FREE(session, pkey); - return 0; -} diff --git a/vendor/libssh2-1.4.2/src/scp.c b/vendor/libssh2-1.4.2/src/scp.c deleted file mode 100644 index 6401dac..0000000 --- a/vendor/libssh2-1.4.2/src/scp.c +++ /dev/null @@ -1,1085 +0,0 @@ -/* Copyright (c) 2009-2010 by Daniel Stenberg - * Copyright (c) 2004-2008, Sara Golemon - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" -#include -#include - -#include "channel.h" -#include "session.h" - - -/* Max. length of a quoted string after libssh2_shell_quotearg() processing */ -#define _libssh2_shell_quotedsize(s) (3 * strlen(s) + 2) - -/* - This function quotes a string in a way suitable to be used with a - shell, e.g. the file name - one two - becomes - 'one two' - - The resulting output string is crafted in a way that makes it usable - with the two most common shell types: Bourne Shell derived shells - (sh, ksh, ksh93, bash, zsh) and C-Shell derivates (csh, tcsh). - - The following special cases are handled: - o If the string contains an apostrophy itself, the apostrophy - character is written in quotation marks, e.g. "'". - The shell cannot handle the syntax 'doesn\'t', so we close the - current argument word, add the apostrophe in quotation marks "", - and open a new argument word instead (_ indicate the input - string characters): - _____ _ _ - 'doesn' "'" 't' - - Sequences of apostrophes are combined in one pair of quotation marks: - a'''b - becomes - _ ___ _ - 'a'"'''"'b' - - o If the string contains an exclamation mark (!), the C-Shell - interprets it as an event number. Using \! (not within quotation - marks or single quotation marks) is a mechanism understood by - both Bourne Shell and C-Shell. - - If a quotation was already started, the argument word is closed - first: - a!b - - become - _ _ _ - 'a'\!'b' - - The result buffer must be large enough for the expanded result. A - bad case regarding expansion is alternating characters and - apostrophes: - - a'b'c'd' (length 8) gets converted to - 'a'"'"'b'"'"'c'"'"'d'"'" (length 24) - - This is the worst case. - - Maximum length of the result: - 1 + 6 * (length(input) + 1) / 2) + 1 - - => 3 * length(input) + 2 - - Explanation: - o leading apostrophe - o one character / apostrophe pair (two characters) can get - represented as 6 characters: a' -> a'"'"' - o String terminator (+1) - - A result buffer three times the size of the input buffer + 2 - characters should be safe. - - References: - o csh-compatible quotation (special handling for '!' etc.), see - http://www.grymoire.com/Unix/Csh.html#toc-uh-10 - - Return value: - Length of the resulting string (not counting the terminating '\0'), - or 0 in case of errors, e.g. result buffer too small - - Note: this function could possible be used elsewhere within libssh2, but - until then it is kept static and in this source file. -*/ - -static unsigned -shell_quotearg(const char *path, unsigned char *buf, - unsigned bufsize) -{ - const char *src; - unsigned char *dst, *endp; - - /* - * Processing States: - * UQSTRING: unquoted string: ... -- used for quoting exclamation - * marks. This is the initial state - * SQSTRING: single-qouted-string: '... -- any character may follow - * QSTRING: quoted string: "... -- only apostrophes may follow - */ - enum { UQSTRING, SQSTRING, QSTRING } state = UQSTRING; - - endp = &buf[bufsize]; - src = path; - dst = buf; - while (*src && dst < endp - 1) { - - switch (*src) { - /* - * Special handling for apostrophe. - * An apostrophe is always written in quotation marks, e.g. - * ' -> "'". - */ - - case '\'': - switch (state) { - case UQSTRING: /* Unquoted string */ - if (dst+1 >= endp) - return 0; - *dst++ = '"'; - break; - case QSTRING: /* Continue quoted string */ - break; - case SQSTRING: /* Close single quoted string */ - if (dst+2 >= endp) - return 0; - *dst++ = '\''; - *dst++ = '"'; - break; - default: - break; - } - state = QSTRING; - break; - - /* - * Special handling for exclamation marks. CSH interprets - * exclamation marks even when quoted with apostrophes. We convert - * it to the plain string \!, because both Bourne Shell and CSH - * interpret that as a verbatim exclamation mark. - */ - - case '!': - switch (state) { - case UQSTRING: - if (dst+1 >= endp) - return 0; - *dst++ = '\\'; - break; - case QSTRING: - if (dst+2 >= endp) - return 0; - *dst++ = '"'; /* Closing quotation mark */ - *dst++ = '\\'; - break; - case SQSTRING: /* Close single quoted string */ - if (dst+2 >= endp) - return 0; - *dst++ = '\''; - *dst++ = '\\'; - break; - default: - break; - } - state = UQSTRING; - break; - - /* - * Ordinary character: prefer single-quoted string - */ - - default: - switch (state) { - case UQSTRING: - if (dst+1 >= endp) - return 0; - *dst++ = '\''; - break; - case QSTRING: - if (dst+2 >= endp) - return 0; - *dst++ = '"'; /* Closing quotation mark */ - *dst++ = '\''; - break; - case SQSTRING: /* Continue single quoted string */ - break; - default: - break; - } - state = SQSTRING; /* Start single-quoted string */ - break; - } - - if (dst+1 >= endp) - return 0; - *dst++ = *src++; - } - - switch (state) { - case UQSTRING: - break; - case QSTRING: /* Close quoted string */ - if (dst+1 >= endp) - return 0; - *dst++ = '"'; - break; - case SQSTRING: /* Close single quoted string */ - if (dst+1 >= endp) - return 0; - *dst++ = '\''; - break; - default: - break; - } - - if (dst+1 >= endp) - return 0; - *dst = '\0'; - - /* The result cannot be larger than 3 * strlen(path) + 2 */ - /* assert((dst - buf) <= (3 * (src - path) + 2)); */ - - return dst - buf; -} - -/* - * scp_recv - * - * Open a channel and request a remote file via SCP - * - */ -static LIBSSH2_CHANNEL * -scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb) -{ - int cmd_len; - int rc; - int tmp_err_code; - const char *tmp_err_msg; - - if (session->scpRecv_state == libssh2_NB_state_idle) { - session->scpRecv_mode = 0; - session->scpRecv_size = 0; - session->scpRecv_mtime = 0; - session->scpRecv_atime = 0; - - session->scpRecv_command_len = - _libssh2_shell_quotedsize(path) + sizeof("scp -f ") + (sb?1:0); - - session->scpRecv_command = - LIBSSH2_ALLOC(session, session->scpRecv_command_len); - - if (!session->scpRecv_command) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate a command buffer for " - "SCP session"); - return NULL; - } - - snprintf((char *)session->scpRecv_command, - session->scpRecv_command_len, "scp -%sf ", sb?"p":""); - - cmd_len = strlen((char *)session->scpRecv_command); - - (void) shell_quotearg(path, - &session->scpRecv_command[cmd_len], - session->scpRecv_command_len - cmd_len); - - - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "Opening channel for SCP receive"); - - session->scpRecv_state = libssh2_NB_state_created; - } - - if (session->scpRecv_state == libssh2_NB_state_created) { - /* Allocate a channel */ - session->scpRecv_channel = - _libssh2_channel_open(session, "session", - sizeof("session") - 1, - LIBSSH2_CHANNEL_WINDOW_DEFAULT, - LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, - 0); - if (!session->scpRecv_channel) { - if (libssh2_session_last_errno(session) != - LIBSSH2_ERROR_EAGAIN) { - LIBSSH2_FREE(session, session->scpRecv_command); - session->scpRecv_command = NULL; - session->scpRecv_state = libssh2_NB_state_idle; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block starting up channel"); - } - return NULL; - } - - session->scpRecv_state = libssh2_NB_state_sent; - } - - if (session->scpRecv_state == libssh2_NB_state_sent) { - /* Request SCP for the desired file */ - rc = _libssh2_channel_process_startup(session->scpRecv_channel, "exec", - sizeof("exec") - 1, - (char *) session->scpRecv_command, - session->scpRecv_command_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block requesting SCP startup"); - return NULL; - } else if (rc) { - LIBSSH2_FREE(session, session->scpRecv_command); - session->scpRecv_command = NULL; - goto scp_recv_error; - } - LIBSSH2_FREE(session, session->scpRecv_command); - session->scpRecv_command = NULL; - - _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sending initial wakeup"); - /* SCP ACK */ - session->scpRecv_response[0] = '\0'; - - session->scpRecv_state = libssh2_NB_state_sent1; - } - - if (session->scpRecv_state == libssh2_NB_state_sent1) { - rc = _libssh2_channel_write(session->scpRecv_channel, 0, - session->scpRecv_response, 1); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block sending initial wakeup"); - return NULL; - } else if (rc != 1) { - goto scp_recv_error; - } - - /* Parse SCP response */ - session->scpRecv_response_len = 0; - - session->scpRecv_state = libssh2_NB_state_sent2; - } - - if ((session->scpRecv_state == libssh2_NB_state_sent2) - || (session->scpRecv_state == libssh2_NB_state_sent3)) { - while (sb && (session->scpRecv_response_len < - LIBSSH2_SCP_RESPONSE_BUFLEN)) { - unsigned char *s, *p; - - if (session->scpRecv_state == libssh2_NB_state_sent2) { - rc = _libssh2_channel_read(session->scpRecv_channel, 0, - (char *) session-> - scpRecv_response + - session->scpRecv_response_len, 1); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting for SCP response"); - return NULL; - } - else if (rc < 0) { - /* error, give up */ - _libssh2_error(session, rc, "Failed reading SCP response"); - goto scp_recv_error; - } - else if(rc == 0) - goto scp_recv_empty_channel; - - session->scpRecv_response_len++; - - if (session->scpRecv_response[0] != 'T') { - size_t err_len; - char *err_msg; - - /* there can be - 01 for warnings - 02 for errors - - The following string MUST be newline terminated - */ - err_len = - _libssh2_channel_packet_data_len(session-> - scpRecv_channel, 0); - err_msg = LIBSSH2_ALLOC(session, err_len + 1); - if (!err_msg) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Failed to get memory "); - goto scp_recv_error; - } - - /* Read the remote error message */ - (void)_libssh2_channel_read(session->scpRecv_channel, 0, - err_msg, err_len); - /* If it failed for any reason, we ignore it anyway. */ - - /* zero terminate the error */ - err_msg[err_len]=0; - - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "got %02x %s", session->scpRecv_response[0], - err_msg); - - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Failed to recv file"); - - LIBSSH2_FREE(session, err_msg); - goto scp_recv_error; - } - - if ((session->scpRecv_response_len > 1) && - ((session-> - scpRecv_response[session->scpRecv_response_len - 1] < - '0') - || (session-> - scpRecv_response[session->scpRecv_response_len - 1] > - '9')) - && (session-> - scpRecv_response[session->scpRecv_response_len - 1] != - ' ') - && (session-> - scpRecv_response[session->scpRecv_response_len - 1] != - '\r') - && (session-> - scpRecv_response[session->scpRecv_response_len - 1] != - '\n')) { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid data in SCP response"); - goto scp_recv_error; - } - - if ((session->scpRecv_response_len < 9) - || (session-> - scpRecv_response[session->scpRecv_response_len - 1] != - '\n')) { - if (session->scpRecv_response_len == - LIBSSH2_SCP_RESPONSE_BUFLEN) { - /* You had your chance */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Unterminated response from SCP server"); - goto scp_recv_error; - } - /* Way too short to be an SCP response, or not done yet, - short circuit */ - continue; - } - - /* We're guaranteed not to go under response_len == 0 by the - logic above */ - while ((session-> - scpRecv_response[session->scpRecv_response_len - 1] == - '\r') - || (session-> - scpRecv_response[session->scpRecv_response_len - - 1] == '\n')) - session->scpRecv_response_len--; - session->scpRecv_response[session->scpRecv_response_len] = - '\0'; - - if (session->scpRecv_response_len < 8) { - /* EOL came too soon */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, " - "too short" ); - goto scp_recv_error; - } - - s = session->scpRecv_response + 1; - - p = (unsigned char *) strchr((char *) s, ' '); - if (!p || ((p - s) <= 0)) { - /* No spaces or space in the wrong spot */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, " - "malformed mtime"); - goto scp_recv_error; - } - - *(p++) = '\0'; - /* Make sure we don't get fooled by leftover values */ - session->scpRecv_mtime = strtol((char *) s, NULL, 10); - - s = (unsigned char *) strchr((char *) p, ' '); - if (!s || ((s - p) <= 0)) { - /* No spaces or space in the wrong spot */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, malformed mtime.usec"); - goto scp_recv_error; - } - - /* Ignore mtime.usec */ - s++; - p = (unsigned char *) strchr((char *) s, ' '); - if (!p || ((p - s) <= 0)) { - /* No spaces or space in the wrong spot */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, too short or malformed"); - goto scp_recv_error; - } - - *p = '\0'; - /* Make sure we don't get fooled by leftover values */ - session->scpRecv_atime = strtol((char *) s, NULL, 10); - - /* SCP ACK */ - session->scpRecv_response[0] = '\0'; - - session->scpRecv_state = libssh2_NB_state_sent3; - } - - if (session->scpRecv_state == libssh2_NB_state_sent3) { - rc = _libssh2_channel_write(session->scpRecv_channel, 0, - session->scpRecv_response, 1); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting to send SCP ACK"); - return NULL; - } else if (rc != 1) { - goto scp_recv_error; - } - - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "mtime = %ld, atime = %ld", - session->scpRecv_mtime, session->scpRecv_atime); - - /* We *should* check that atime.usec is valid, but why let - that stop use? */ - break; - } - } - - session->scpRecv_state = libssh2_NB_state_sent4; - } - - if (session->scpRecv_state == libssh2_NB_state_sent4) { - session->scpRecv_response_len = 0; - - session->scpRecv_state = libssh2_NB_state_sent5; - } - - if ((session->scpRecv_state == libssh2_NB_state_sent5) - || (session->scpRecv_state == libssh2_NB_state_sent6)) { - while (session->scpRecv_response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) { - char *s, *p, *e = NULL; - - if (session->scpRecv_state == libssh2_NB_state_sent5) { - rc = _libssh2_channel_read(session->scpRecv_channel, 0, - (char *) session-> - scpRecv_response + - session->scpRecv_response_len, 1); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting for SCP response"); - return NULL; - } - else if (rc < 0) { - /* error, bail out*/ - _libssh2_error(session, rc, "Failed reading SCP response"); - goto scp_recv_error; - } - else if(rc == 0) - goto scp_recv_empty_channel; - - session->scpRecv_response_len++; - - if (session->scpRecv_response[0] != 'C') { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server"); - goto scp_recv_error; - } - - if ((session->scpRecv_response_len > 1) && - (session-> - scpRecv_response[session->scpRecv_response_len - 1] != - '\r') - && (session-> - scpRecv_response[session->scpRecv_response_len - 1] != - '\n') - && - (session-> - scpRecv_response[session->scpRecv_response_len - 1] - < 32)) { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid data in SCP response"); - goto scp_recv_error; - } - - if ((session->scpRecv_response_len < 7) - || (session-> - scpRecv_response[session->scpRecv_response_len - 1] != - '\n')) { - if (session->scpRecv_response_len == - LIBSSH2_SCP_RESPONSE_BUFLEN) { - /* You had your chance */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Unterminated response from SCP server"); - goto scp_recv_error; - } - /* Way too short to be an SCP response, or not done yet, - short circuit */ - continue; - } - - /* We're guaranteed not to go under response_len == 0 by the - logic above */ - while ((session-> - scpRecv_response[session->scpRecv_response_len - 1] == - '\r') - || (session-> - scpRecv_response[session->scpRecv_response_len - - 1] == '\n')) { - session->scpRecv_response_len--; - } - session->scpRecv_response[session->scpRecv_response_len] = - '\0'; - - if (session->scpRecv_response_len < 6) { - /* EOL came too soon */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, too short"); - goto scp_recv_error; - } - - s = (char *) session->scpRecv_response + 1; - - p = strchr(s, ' '); - if (!p || ((p - s) <= 0)) { - /* No spaces or space in the wrong spot */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, malformed mode"); - goto scp_recv_error; - } - - *(p++) = '\0'; - /* Make sure we don't get fooled by leftover values */ - - session->scpRecv_mode = strtol(s, &e, 8); - if (e && *e) { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, invalid mode"); - goto scp_recv_error; - } - - s = strchr(p, ' '); - if (!s || ((s - p) <= 0)) { - /* No spaces or space in the wrong spot */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, too short or malformed"); - goto scp_recv_error; - } - - *s = '\0'; - /* Make sure we don't get fooled by leftover values */ - session->scpRecv_size = scpsize_strtol(p, &e, 10); - if (e && *e) { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, invalid size"); - goto scp_recv_error; - } - - /* SCP ACK */ - session->scpRecv_response[0] = '\0'; - - session->scpRecv_state = libssh2_NB_state_sent6; - } - - if (session->scpRecv_state == libssh2_NB_state_sent6) { - rc = _libssh2_channel_write(session->scpRecv_channel, 0, - session->scpRecv_response, 1); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block sending SCP ACK"); - return NULL; - } else if (rc != 1) { - goto scp_recv_error; - } - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "mode = 0%lo size = %ld", session->scpRecv_mode, - session->scpRecv_size); - - /* We *should* check that basename is valid, but why let that - stop us? */ - break; - } - } - - session->scpRecv_state = libssh2_NB_state_sent7; - } - - if (sb) { - memset(sb, 0, sizeof(struct stat)); - - sb->st_mtime = session->scpRecv_mtime; - sb->st_atime = session->scpRecv_atime; - sb->st_size = session->scpRecv_size; - sb->st_mode = session->scpRecv_mode; - } - - session->scpRecv_state = libssh2_NB_state_idle; - return session->scpRecv_channel; - - scp_recv_empty_channel: - /* the code only jumps here as a result of a zero read from channel_read() - so we check EOF status to avoid getting stuck in a loop */ - if(libssh2_channel_eof(session->scpRecv_channel)) - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Unexpected channel close"); - else - return session->scpRecv_channel; - /* fall-through */ - scp_recv_error: - tmp_err_code = session->err_code; - tmp_err_msg = session->err_msg; - while (libssh2_channel_free(session->scpRecv_channel) == - LIBSSH2_ERROR_EAGAIN); - session->err_code = tmp_err_code; - session->err_msg = tmp_err_msg; - session->scpRecv_channel = NULL; - session->scpRecv_state = libssh2_NB_state_idle; - return NULL; -} - -/* - * libssh2_scp_recv - * - * Open a channel and request a remote file via SCP - * - */ -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat * sb) -{ - LIBSSH2_CHANNEL *ptr; - BLOCK_ADJUST_ERRNO(ptr, session, scp_recv(session, path, sb)); - return ptr; -} - -/* - * scp_send() - * - * Send a file using SCP - * - */ -static LIBSSH2_CHANNEL * -scp_send(LIBSSH2_SESSION * session, const char *path, int mode, - libssh2_int64_t size, time_t mtime, time_t atime) -{ - int cmd_len; - int rc; - int tmp_err_code; - const char *tmp_err_msg; - - if (session->scpSend_state == libssh2_NB_state_idle) { - session->scpSend_command_len = - _libssh2_shell_quotedsize(path) + sizeof("scp -t ") + - ((mtime || atime)?1:0); - - session->scpSend_command = - LIBSSH2_ALLOC(session, session->scpSend_command_len); - if (!session->scpSend_command) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate a command buffer for scp session"); - return NULL; - } - - snprintf((char *)session->scpSend_command, session->scpSend_command_len, - "scp -%st ", (mtime || atime)?"p":""); - - cmd_len = strlen((char *)session->scpSend_command); - - (void)shell_quotearg(path, - &session->scpSend_command[cmd_len], - session->scpSend_command_len - cmd_len); - - session->scpSend_command[session->scpSend_command_len - 1] = '\0'; - - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "Opening channel for SCP send"); - /* Allocate a channel */ - - session->scpSend_state = libssh2_NB_state_created; - } - - if (session->scpSend_state == libssh2_NB_state_created) { - session->scpSend_channel = - _libssh2_channel_open(session, "session", sizeof("session") - 1, - LIBSSH2_CHANNEL_WINDOW_DEFAULT, - LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0); - if (!session->scpSend_channel) { - if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) { - /* previous call set libssh2_session_last_error(), pass it - through */ - LIBSSH2_FREE(session, session->scpSend_command); - session->scpSend_command = NULL; - session->scpSend_state = libssh2_NB_state_idle; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block starting up channel"); - } - return NULL; - } - - session->scpSend_state = libssh2_NB_state_sent; - } - - if (session->scpSend_state == libssh2_NB_state_sent) { - /* Request SCP for the desired file */ - rc = _libssh2_channel_process_startup(session->scpSend_channel, "exec", - sizeof("exec") - 1, - (char *) session->scpSend_command, - session->scpSend_command_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block requesting SCP startup"); - return NULL; - } - else if (rc) { - /* previous call set libssh2_session_last_error(), pass it - through */ - LIBSSH2_FREE(session, session->scpSend_command); - session->scpSend_command = NULL; - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Unknown error while getting error string"); - goto scp_send_error; - } - LIBSSH2_FREE(session, session->scpSend_command); - session->scpSend_command = NULL; - - session->scpSend_state = libssh2_NB_state_sent1; - } - - if (session->scpSend_state == libssh2_NB_state_sent1) { - /* Wait for ACK */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - (char *) session->scpSend_response, 1); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting for response from remote"); - return NULL; - } - else if (rc < 0) { - _libssh2_error(session, rc, "SCP failure"); - goto scp_send_error; - } - else if(!rc) - /* remain in the same state */ - goto scp_send_empty_channel; - else if (session->scpSend_response[0] != 0) { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid ACK response from remote"); - goto scp_send_error; - } - if (mtime || atime) { - /* Send mtime and atime to be used for file */ - session->scpSend_response_len = - snprintf((char *) session->scpSend_response, - LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", - (long)mtime, (long)atime); - _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s", - session->scpSend_response); - } - - session->scpSend_state = libssh2_NB_state_sent2; - } - - /* Send mtime and atime to be used for file */ - if (mtime || atime) { - if (session->scpSend_state == libssh2_NB_state_sent2) { - rc = _libssh2_channel_write(session->scpSend_channel, 0, - session->scpSend_response, - session->scpSend_response_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block sending time data for SCP file"); - return NULL; - } else if (rc != (int)session->scpSend_response_len) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send time data for SCP file"); - goto scp_send_error; - } - - session->scpSend_state = libssh2_NB_state_sent3; - } - - if (session->scpSend_state == libssh2_NB_state_sent3) { - /* Wait for ACK */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - (char *) session->scpSend_response, 1); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting for response"); - return NULL; - } - else if (rc < 0) { - _libssh2_error(session, rc, "SCP failure"); - goto scp_send_error; - } - else if(!rc) - /* remain in the same state */ - goto scp_send_empty_channel; - else if (session->scpSend_response[0] != 0) { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid SCP ACK response"); - goto scp_send_error; - } - - session->scpSend_state = libssh2_NB_state_sent4; - } - } else { - if (session->scpSend_state == libssh2_NB_state_sent2) { - session->scpSend_state = libssh2_NB_state_sent4; - } - } - - if (session->scpSend_state == libssh2_NB_state_sent4) { - /* Send mode, size, and basename */ - const char *base = strrchr(path, '/'); - if (base) - base++; - else - base = path; - - session->scpSend_response_len = - snprintf((char *) session->scpSend_response, - LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %" - LIBSSH2_INT64_T_FORMAT "u %s\n", mode, - size, base); - _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s", - session->scpSend_response); - - session->scpSend_state = libssh2_NB_state_sent5; - } - - if (session->scpSend_state == libssh2_NB_state_sent5) { - rc = _libssh2_channel_write(session->scpSend_channel, 0, - session->scpSend_response, - session->scpSend_response_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block send core file data for SCP file"); - return NULL; - } else if (rc != (int)session->scpSend_response_len) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send core file data for SCP file"); - goto scp_send_error; - } - - session->scpSend_state = libssh2_NB_state_sent6; - } - - if (session->scpSend_state == libssh2_NB_state_sent6) { - /* Wait for ACK */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - (char *) session->scpSend_response, 1); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting for response"); - return NULL; - } - else if (rc < 0) { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid ACK response from remote"); - goto scp_send_error; - } - else if (rc == 0) - goto scp_send_empty_channel; - - else if (session->scpSend_response[0] != 0) { - size_t err_len; - char *err_msg; - - err_len = - _libssh2_channel_packet_data_len(session->scpSend_channel, 0); - err_msg = LIBSSH2_ALLOC(session, err_len + 1); - if (!err_msg) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "failed to get memory"); - goto scp_send_error; - } - - /* Read the remote error message */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - err_msg, err_len); - if (rc > 0) { - err_msg[err_len]=0; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "got %02x %s", session->scpSend_response[0], - err_msg); - } - LIBSSH2_FREE(session, err_msg); - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "failed to send file"); - goto scp_send_error; - } - } - - session->scpSend_state = libssh2_NB_state_idle; - return session->scpSend_channel; - - scp_send_empty_channel: - /* the code only jumps here as a result of a zero read from channel_read() - so we check EOF status to avoid getting stuck in a loop */ - if(libssh2_channel_eof(session->scpSend_channel)) { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Unexpected channel close"); - } - else - return session->scpSend_channel; - /* fall-through */ - scp_send_error: - tmp_err_code = session->err_code; - tmp_err_msg = session->err_msg; - while (libssh2_channel_free(session->scpSend_channel) == - LIBSSH2_ERROR_EAGAIN); - session->err_code = tmp_err_code; - session->err_msg = tmp_err_msg; - session->scpSend_channel = NULL; - session->scpSend_state = libssh2_NB_state_idle; - return NULL; -} - -/* - * libssh2_scp_send_ex - * - * Send a file using SCP. Old API. - */ -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, - size_t size, long mtime, long atime) -{ - LIBSSH2_CHANNEL *ptr; - BLOCK_ADJUST_ERRNO(ptr, session, - scp_send(session, path, mode, size, - (time_t)mtime, (time_t)atime)); - return ptr; -} - -/* - * libssh2_scp_send64 - * - * Send a file using SCP - */ -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_scp_send64(LIBSSH2_SESSION *session, const char *path, int mode, - libssh2_int64_t size, time_t mtime, time_t atime) -{ - LIBSSH2_CHANNEL *ptr; - BLOCK_ADJUST_ERRNO(ptr, session, - scp_send(session, path, mode, size, mtime, atime)); - return ptr; -} diff --git a/vendor/libssh2-1.4.2/src/session.c b/vendor/libssh2-1.4.2/src/session.c deleted file mode 100644 index 77ab9bc..0000000 --- a/vendor/libssh2-1.4.2/src/session.c +++ /dev/null @@ -1,1751 +0,0 @@ -/* Copyright (c) 2004-2007 Sara Golemon - * Copyright (c) 2009-2011 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#include - -#ifdef HAVE_GETTIMEOFDAY -#include -#endif -#ifdef HAVE_ALLOCA_H -#include -#endif - -#include "transport.h" -#include "session.h" -#include "channel.h" -#include "mac.h" -#include "misc.h" - -/* libssh2_default_alloc - */ -static -LIBSSH2_ALLOC_FUNC(libssh2_default_alloc) -{ - (void) abstract; - return malloc(count); -} - -/* libssh2_default_free - */ -static -LIBSSH2_FREE_FUNC(libssh2_default_free) -{ - (void) abstract; - free(ptr); -} - -/* libssh2_default_realloc - */ -static -LIBSSH2_REALLOC_FUNC(libssh2_default_realloc) -{ - (void) abstract; - return realloc(ptr, count); -} - -/* - * banner_receive - * - * Wait for a hello from the remote host - * Allocate a buffer and store the banner in session->remote.banner - * Returns: 0 on success, LIBSSH2_ERROR_EAGAIN if read would block, negative - * on failure - */ -static int -banner_receive(LIBSSH2_SESSION * session) -{ - int ret; - int banner_len; - - if (session->banner_TxRx_state == libssh2_NB_state_idle) { - banner_len = 0; - - session->banner_TxRx_state = libssh2_NB_state_created; - } else { - banner_len = session->banner_TxRx_total_send; - } - - while ((banner_len < (int) sizeof(session->banner_TxRx_banner)) && - ((banner_len == 0) - || (session->banner_TxRx_banner[banner_len - 1] != '\n'))) { - char c = '\0'; - - /* no incoming block yet! */ - session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND; - - ret = LIBSSH2_RECV(session, &c, 1, - LIBSSH2_SOCKET_RECV_FLAGS(session)); - if (ret < 0) { - if(session->api_block_mode || (ret != -EAGAIN)) - /* ignore EAGAIN when non-blocking */ - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error recving %d bytes: %d", 1, -ret); - } - else - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Recved %d bytes banner", ret); - - if (ret < 0) { - if (ret == -EAGAIN) { - session->socket_block_directions = - LIBSSH2_SESSION_BLOCK_INBOUND; - session->banner_TxRx_total_send = banner_len; - return LIBSSH2_ERROR_EAGAIN; - } - - /* Some kinda error */ - session->banner_TxRx_state = libssh2_NB_state_idle; - session->banner_TxRx_total_send = 0; - return LIBSSH2_ERROR_SOCKET_RECV; - } - - if (ret == 0) { - session->socket_state = LIBSSH2_SOCKET_DISCONNECTED; - return LIBSSH2_ERROR_SOCKET_DISCONNECT; - } - - if (c == '\0') { - /* NULLs are not allowed in SSH banners */ - session->banner_TxRx_state = libssh2_NB_state_idle; - session->banner_TxRx_total_send = 0; - return LIBSSH2_ERROR_BANNER_RECV; - } - - session->banner_TxRx_banner[banner_len++] = c; - } - - while (banner_len && - ((session->banner_TxRx_banner[banner_len - 1] == '\n') || - (session->banner_TxRx_banner[banner_len - 1] == '\r'))) { - banner_len--; - } - - /* From this point on, we are done here */ - session->banner_TxRx_state = libssh2_NB_state_idle; - session->banner_TxRx_total_send = 0; - - if (!banner_len) - return LIBSSH2_ERROR_BANNER_RECV; - - session->remote.banner = LIBSSH2_ALLOC(session, banner_len + 1); - if (!session->remote.banner) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Error allocating space for remote banner"); - } - memcpy(session->remote.banner, session->banner_TxRx_banner, banner_len); - session->remote.banner[banner_len] = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Received Banner: %s", - session->remote.banner); - return LIBSSH2_ERROR_NONE; -} - -/* - * banner_send - * - * Send the default banner, or the one set via libssh2_setopt_string - * - * Returns LIBSSH2_ERROR_EAGAIN if it would block - and if it does so, you - * should call this function again as soon as it is likely that more data can - * be sent, and this function should then be called with the same argument set - * (same data pointer and same data_len) until zero or failure is returned. - */ -static int -banner_send(LIBSSH2_SESSION * session) -{ - char *banner = (char *) LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF; - int banner_len = sizeof(LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF) - 1; - ssize_t ret; -#ifdef LIBSSH2DEBUG - char banner_dup[256]; -#endif - - if (session->banner_TxRx_state == libssh2_NB_state_idle) { - if (session->local.banner) { - /* setopt_string will have given us our \r\n characters */ - banner_len = strlen((char *) session->local.banner); - banner = (char *) session->local.banner; - } -#ifdef LIBSSH2DEBUG - /* Hack and slash to avoid sending CRLF in debug output */ - if (banner_len < 256) { - memcpy(banner_dup, banner, banner_len - 2); - banner_dup[banner_len - 2] = '\0'; - } else { - memcpy(banner_dup, banner, 255); - banner[255] = '\0'; - } - - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Sending Banner: %s", - banner_dup); -#endif - - session->banner_TxRx_state = libssh2_NB_state_created; - } - - /* no outgoing block yet! */ - session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_OUTBOUND; - - ret = LIBSSH2_SEND(session, - banner + session->banner_TxRx_total_send, - banner_len - session->banner_TxRx_total_send, - LIBSSH2_SOCKET_SEND_FLAGS(session)); - if (ret < 0) - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error sending %d bytes: %d", - banner_len - session->banner_TxRx_total_send, -ret); - else - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Sent %d/%d bytes at %p+%d", ret, - banner_len - session->banner_TxRx_total_send, - banner, session->banner_TxRx_total_send); - - if (ret != (banner_len - session->banner_TxRx_total_send)) { - if (ret >= 0 || ret == -EAGAIN) { - /* the whole packet could not be sent, save the what was */ - session->socket_block_directions = - LIBSSH2_SESSION_BLOCK_OUTBOUND; - if (ret > 0) - session->banner_TxRx_total_send += ret; - return LIBSSH2_ERROR_EAGAIN; - } - session->banner_TxRx_state = libssh2_NB_state_idle; - session->banner_TxRx_total_send = 0; - return LIBSSH2_ERROR_SOCKET_RECV; - } - - /* Set the state back to idle */ - session->banner_TxRx_state = libssh2_NB_state_idle; - session->banner_TxRx_total_send = 0; - - return 0; -} - -/* - * session_nonblock() sets the given socket to either blocking or - * non-blocking mode based on the 'nonblock' boolean argument. This function - * is copied from the libcurl sources with permission. - */ -static int -session_nonblock(libssh2_socket_t sockfd, /* operate on this */ - int nonblock /* TRUE or FALSE */ ) -{ -#undef SETBLOCK -#define SETBLOCK 0 -#ifdef HAVE_O_NONBLOCK - /* most recent unix versions */ - int flags; - - flags = fcntl(sockfd, F_GETFL, 0); - if (nonblock) - return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); - else - return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); -#undef SETBLOCK -#define SETBLOCK 1 -#endif - -#if defined(HAVE_FIONBIO) && (SETBLOCK == 0) - /* older unix versions and VMS*/ - int flags; - - flags = nonblock; - return ioctl(sockfd, FIONBIO, &flags); -#undef SETBLOCK -#define SETBLOCK 2 -#endif - -#if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0) - /* Windows? */ - unsigned long flags; - flags = nonblock; - - return ioctlsocket(sockfd, FIONBIO, &flags); -#undef SETBLOCK -#define SETBLOCK 3 -#endif - -#if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0) - /* presumably for Amiga */ - return IoctlSocket(sockfd, FIONBIO, (long) nonblock); -#undef SETBLOCK -#define SETBLOCK 4 -#endif - -#if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0) - /* BeOS */ - long b = nonblock ? 1 : 0; - return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); -#undef SETBLOCK -#define SETBLOCK 5 -#endif - -#ifdef HAVE_DISABLED_NONBLOCKING - return 0; /* returns success */ -#undef SETBLOCK -#define SETBLOCK 6 -#endif - -#if (SETBLOCK == 0) -#error "no non-blocking method was found/used/set" -#endif -} - -/* - * get_socket_nonblocking() - * - * gets the given blocking or non-blocking state of the socket. - */ -static int -get_socket_nonblocking(int sockfd) -{ /* operate on this */ -#undef GETBLOCK -#define GETBLOCK 0 -#ifdef HAVE_O_NONBLOCK - /* most recent unix versions */ - int flags; - - if ((flags = fcntl(sockfd, F_GETFL, 0)) == -1) { - /* Assume blocking on error */ - return 1; - } - return (flags & O_NONBLOCK); -#undef GETBLOCK -#define GETBLOCK 1 -#endif - -#if defined(WSAEWOULDBLOCK) && (GETBLOCK == 0) - /* Windows? */ - unsigned int option_value; - socklen_t option_len = sizeof(option_value); - - if (getsockopt - (sockfd, SOL_SOCKET, SO_ERROR, (void *) &option_value, &option_len)) { - /* Assume blocking on error */ - return 1; - } - return (int) option_value; -#undef GETBLOCK -#define GETBLOCK 2 -#endif - -#if defined(HAVE_SO_NONBLOCK) && (GETBLOCK == 0) - /* BeOS */ - long b; - if (getsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b))) { - /* Assume blocking on error */ - return 1; - } - return (int) b; -#undef GETBLOCK -#define GETBLOCK 5 -#endif - -#if defined(SO_STATE) && defined( __VMS ) && (GETBLOCK == 0) - - /* VMS TCP/IP Services */ - - size_t sockstat = 0; - int callstat = 0; - size_t size = sizeof( int ); - - callstat = getsockopt(sockfd, SOL_SOCKET, SO_STATE, - (char *)&sockstat, &size); - if ( callstat == -1 ) return(0); - if ( (sockstat&SS_NBIO) )return(1); - return(0); - -#undef GETBLOCK -#define GETBLOCK 6 -#endif - -#ifdef HAVE_DISABLED_NONBLOCKING - return 1; /* returns blocking */ -#undef GETBLOCK -#define GETBLOCK 7 -#endif - -#if (GETBLOCK == 0) -#error "no non-blocking method was found/used/get" -#endif -} - -/* libssh2_session_banner_set - * Set the local banner to use in the server handshake. - */ -LIBSSH2_API int -libssh2_session_banner_set(LIBSSH2_SESSION * session, const char *banner) -{ - size_t banner_len = banner ? strlen(banner) : 0; - - if (session->local.banner) { - LIBSSH2_FREE(session, session->local.banner); - session->local.banner = NULL; - } - - if (!banner_len) - return 0; - - session->local.banner = LIBSSH2_ALLOC(session, banner_len + 3); - if (!session->local.banner) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for local banner"); - } - - memcpy(session->local.banner, banner, banner_len); - - /* first zero terminate like this so that the debug output is nice */ - session->local.banner[banner_len] = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Setting local Banner: %s", - session->local.banner); - session->local.banner[banner_len++] = '\r'; - session->local.banner[banner_len++] = '\n'; - session->local.banner[banner_len] = '\0'; - - return 0; -} - -/* libssh2_banner_set - * Set the local banner. DEPRECATED VERSION - */ -LIBSSH2_API int -libssh2_banner_set(LIBSSH2_SESSION * session, const char *banner) -{ - return libssh2_session_banner_set(session, banner); -} - -/* - * libssh2_session_init_ex - * - * Allocate and initialize a libssh2 session structure. Allows for malloc - * callbacks in case the calling program has its own memory manager It's - * allowable (but unadvisable) to define some but not all of the malloc - * callbacks An additional pointer value may be optionally passed to be sent - * to the callbacks (so they know who's asking) - */ -LIBSSH2_API LIBSSH2_SESSION * -libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), - LIBSSH2_FREE_FUNC((*my_free)), - LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract) -{ - LIBSSH2_ALLOC_FUNC((*local_alloc)) = libssh2_default_alloc; - LIBSSH2_FREE_FUNC((*local_free)) = libssh2_default_free; - LIBSSH2_REALLOC_FUNC((*local_realloc)) = libssh2_default_realloc; - LIBSSH2_SESSION *session; - - if (my_alloc) { - local_alloc = my_alloc; - } - if (my_free) { - local_free = my_free; - } - if (my_realloc) { - local_realloc = my_realloc; - } - - session = local_alloc(sizeof(LIBSSH2_SESSION), &abstract); - if (session) { - memset(session, 0, sizeof(LIBSSH2_SESSION)); - session->alloc = local_alloc; - session->free = local_free; - session->realloc = local_realloc; - session->send = _libssh2_send; - session->recv = _libssh2_recv; - session->abstract = abstract; - session->api_timeout = 0; /* timeout-free API by default */ - session->api_block_mode = 1; /* blocking API by default */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "New session resource allocated"); - _libssh2_init_if_needed (); - } - return session; -} - -/* - * libssh2_session_callback_set - * - * Set (or reset) a callback function - * Returns the prior address - * - * FIXME: this function relies on that we can typecast function pointers - * to void pointers, which isn't allowed in ISO C! - */ -LIBSSH2_API void * -libssh2_session_callback_set(LIBSSH2_SESSION * session, - int cbtype, void *callback) -{ - void *oldcb; - - switch (cbtype) { - case LIBSSH2_CALLBACK_IGNORE: - oldcb = session->ssh_msg_ignore; - session->ssh_msg_ignore = callback; - return oldcb; - - case LIBSSH2_CALLBACK_DEBUG: - oldcb = session->ssh_msg_debug; - session->ssh_msg_debug = callback; - return oldcb; - - case LIBSSH2_CALLBACK_DISCONNECT: - oldcb = session->ssh_msg_disconnect; - session->ssh_msg_disconnect = callback; - return oldcb; - - case LIBSSH2_CALLBACK_MACERROR: - oldcb = session->macerror; - session->macerror = callback; - return oldcb; - - case LIBSSH2_CALLBACK_X11: - oldcb = session->x11; - session->x11 = callback; - return oldcb; - - case LIBSSH2_CALLBACK_SEND: - oldcb = session->send; - session->send = callback; - return oldcb; - - case LIBSSH2_CALLBACK_RECV: - oldcb = session->recv; - session->recv = callback; - return oldcb; - } - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Setting Callback %d", cbtype); - - return NULL; -} - -/* - * _libssh2_wait_socket() - * - * Utility function that waits for action on the socket. Returns 0 when ready - * to run again or error on timeout. - */ -int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time) -{ - int rc; - int seconds_to_next; - int dir; - int has_timeout; - long ms_to_next = 0; - long elapsed_ms; - - /* since libssh2 often sets EAGAIN internally before this function is - called, we can decrease some amount of confusion in user programs by - resetting the error code in this function to reduce the risk of EAGAIN - being stored as error when a blocking function has returned */ - session->err_code = LIBSSH2_ERROR_NONE; - - rc = libssh2_keepalive_send (session, &seconds_to_next); - if (rc < 0) - return rc; - - ms_to_next = seconds_to_next * 1000; - - /* figure out what to wait for */ - dir = libssh2_session_block_directions(session); - - if(!dir) { - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Nothing to wait for in wait_socket"); - /* To avoid that we hang below just because there's nothing set to - wait for, we timeout on 1 second to also avoid busy-looping - during this condition */ - ms_to_next = 1000; - } - - if (session->api_timeout > 0 && - (seconds_to_next == 0 || - seconds_to_next > session->api_timeout)) { - time_t now = time (NULL); - elapsed_ms = (long)(1000*difftime(start_time, now)); - if (elapsed_ms > session->api_timeout) { - session->err_code = LIBSSH2_ERROR_TIMEOUT; - return LIBSSH2_ERROR_TIMEOUT; - } - ms_to_next = (session->api_timeout - elapsed_ms); - has_timeout = 1; - } - else if (ms_to_next > 0) { - has_timeout = 1; - } - else - has_timeout = 0; - -#ifdef HAVE_POLL - { - struct pollfd sockets[1]; - - sockets[0].fd = session->socket_fd; - sockets[0].events = 0; - sockets[0].revents = 0; - - if(dir & LIBSSH2_SESSION_BLOCK_INBOUND) - sockets[0].events |= POLLIN; - - if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) - sockets[0].events |= POLLOUT; - - rc = poll(sockets, 1, has_timeout?ms_to_next: -1); - } -#else - { - fd_set rfd; - fd_set wfd; - fd_set *writefd = NULL; - fd_set *readfd = NULL; - struct timeval tv; - - tv.tv_sec = ms_to_next / 1000; - tv.tv_usec = (ms_to_next - tv.tv_sec*1000) * 1000; - - if(dir & LIBSSH2_SESSION_BLOCK_INBOUND) { - FD_ZERO(&rfd); - FD_SET(session->socket_fd, &rfd); - readfd = &rfd; - } - - if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) { - FD_ZERO(&wfd); - FD_SET(session->socket_fd, &wfd); - writefd = &wfd; - } - - rc = select(session->socket_fd + 1, readfd, writefd, NULL, - has_timeout ? &tv : NULL); - } -#endif - if(rc <= 0) { - /* timeout (or error), bail out with a timeout error */ - session->err_code = LIBSSH2_ERROR_TIMEOUT; - return LIBSSH2_ERROR_TIMEOUT; - } - - return 0; /* ready to try again */ -} - -static int -session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock) -{ - int rc; - - if (session->startup_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "session_startup for socket %d", sock); - if (LIBSSH2_INVALID_SOCKET == sock) { - /* Did we forget something? */ - return _libssh2_error(session, LIBSSH2_ERROR_BAD_SOCKET, - "Bad socket provided"); - } - session->socket_fd = sock; - - session->socket_prev_blockstate = - !get_socket_nonblocking(session->socket_fd); - - if (session->socket_prev_blockstate) { - /* If in blocking state chang to non-blocking */ - session_nonblock(session->socket_fd, 1); - } - - session->startup_state = libssh2_NB_state_created; - } - - if (session->startup_state == libssh2_NB_state_created) { - rc = banner_send(session); - if (rc) { - return _libssh2_error(session, rc, - "Failed sending banner"); - } - session->startup_state = libssh2_NB_state_sent; - session->banner_TxRx_state = libssh2_NB_state_idle; - } - - if (session->startup_state == libssh2_NB_state_sent) { - do { - rc = banner_receive(session); - if (rc) - return _libssh2_error(session, rc, - "Failed getting banner"); - } while(strncmp("SSH-", (char *)session->remote.banner, 4)); - - session->startup_state = libssh2_NB_state_sent1; - } - - if (session->startup_state == libssh2_NB_state_sent1) { - rc = _libssh2_kex_exchange(session, 0, &session->startup_key_state); - if (rc) - return _libssh2_error(session, rc, - "Unable to exchange encryption keys"); - - session->startup_state = libssh2_NB_state_sent2; - } - - if (session->startup_state == libssh2_NB_state_sent2) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Requesting userauth service"); - - /* Request the userauth service */ - session->startup_service[0] = SSH_MSG_SERVICE_REQUEST; - _libssh2_htonu32(session->startup_service + 1, - sizeof("ssh-userauth") - 1); - memcpy(session->startup_service + 5, "ssh-userauth", - sizeof("ssh-userauth") - 1); - - session->startup_state = libssh2_NB_state_sent3; - } - - if (session->startup_state == libssh2_NB_state_sent3) { - rc = _libssh2_transport_send(session, session->startup_service, - sizeof("ssh-userauth") + 5 - 1, - NULL, 0); - if (rc) { - return _libssh2_error(session, rc, - "Unable to ask for ssh-userauth service"); - } - - session->startup_state = libssh2_NB_state_sent4; - } - - if (session->startup_state == libssh2_NB_state_sent4) { - rc = _libssh2_packet_require(session, SSH_MSG_SERVICE_ACCEPT, - &session->startup_data, - &session->startup_data_len, 0, NULL, 0, - &session->startup_req_state); - if (rc) - return rc; - - session->startup_service_length = - _libssh2_ntohu32(session->startup_data + 1); - - if ((session->startup_service_length != (sizeof("ssh-userauth") - 1)) - || strncmp("ssh-userauth", (char *) session->startup_data + 5, - session->startup_service_length)) { - LIBSSH2_FREE(session, session->startup_data); - session->startup_data = NULL; - return _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Invalid response received from server"); - } - LIBSSH2_FREE(session, session->startup_data); - session->startup_data = NULL; - - session->startup_state = libssh2_NB_state_idle; - - return 0; - } - - /* just for safety return some error */ - return LIBSSH2_ERROR_INVAL; -} - -/* - * libssh2_session_handshake() - * - * session: LIBSSH2_SESSION struct allocated and owned by the calling program - * sock: *must* be populated with an opened and connected socket. - * - * Returns: 0 on success, or non-zero on failure - */ -LIBSSH2_API int -libssh2_session_handshake(LIBSSH2_SESSION *session, libssh2_socket_t sock) -{ - int rc; - - BLOCK_ADJUST(rc, session, session_startup(session, sock) ); - - return rc; -} - -/* - * libssh2_session_startup() - * - * DEPRECATED. Use libssh2_session_handshake() instead! This function is not - * portable enough. - * - * session: LIBSSH2_SESSION struct allocated and owned by the calling program - * sock: *must* be populated with an opened and connected socket. - * - * Returns: 0 on success, or non-zero on failure - */ -LIBSSH2_API int -libssh2_session_startup(LIBSSH2_SESSION *session, int sock) -{ - return libssh2_session_handshake(session, (libssh2_socket_t) sock); -} - -/* - * libssh2_session_free - * - * Frees the memory allocated to the session - * Also closes and frees any channels attached to this session - */ -static int -session_free(LIBSSH2_SESSION *session) -{ - int rc; - LIBSSH2_PACKET *pkg; - LIBSSH2_CHANNEL *ch; - LIBSSH2_LISTENER *l; - int packets_left = 0; - - if (session->free_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Freeing session resource", - session->remote.banner); - - session->state = libssh2_NB_state_created; - } - - if (session->free_state == libssh2_NB_state_created) { - while ((ch = _libssh2_list_first(&session->channels))) { - - rc = _libssh2_channel_free(ch); - if (rc == LIBSSH2_ERROR_EAGAIN) - return rc; - } - - session->state = libssh2_NB_state_sent; - } - - if (session->state == libssh2_NB_state_sent) { - while ((l = _libssh2_list_first(&session->listeners))) { - rc = _libssh2_channel_forward_cancel(l); - if (rc == LIBSSH2_ERROR_EAGAIN) - return rc; - } - - session->state = libssh2_NB_state_sent1; - } - - if (session->state & LIBSSH2_STATE_NEWKEYS) { - /* hostkey */ - if (session->hostkey && session->hostkey->dtor) { - session->hostkey->dtor(session, &session->server_hostkey_abstract); - } - - /* Client to Server */ - /* crypt */ - if (session->local.crypt && session->local.crypt->dtor) { - session->local.crypt->dtor(session, - &session->local.crypt_abstract); - } - /* comp */ - if (session->local.comp && session->local.comp->dtor) { - session->local.comp->dtor(session, 1, - &session->local.comp_abstract); - } - /* mac */ - if (session->local.mac && session->local.mac->dtor) { - session->local.mac->dtor(session, &session->local.mac_abstract); - } - - /* Server to Client */ - /* crypt */ - if (session->remote.crypt && session->remote.crypt->dtor) { - session->remote.crypt->dtor(session, - &session->remote.crypt_abstract); - } - /* comp */ - if (session->remote.comp && session->remote.comp->dtor) { - session->remote.comp->dtor(session, 0, - &session->remote.comp_abstract); - } - /* mac */ - if (session->remote.mac && session->remote.mac->dtor) { - session->remote.mac->dtor(session, &session->remote.mac_abstract); - } - - /* session_id */ - if (session->session_id) { - LIBSSH2_FREE(session, session->session_id); - } - } - - /* Free banner(s) */ - if (session->remote.banner) { - LIBSSH2_FREE(session, session->remote.banner); - } - if (session->local.banner) { - LIBSSH2_FREE(session, session->local.banner); - } - - /* Free preference(s) */ - if (session->kex_prefs) { - LIBSSH2_FREE(session, session->kex_prefs); - } - if (session->hostkey_prefs) { - LIBSSH2_FREE(session, session->hostkey_prefs); - } - - if (session->local.kexinit) { - LIBSSH2_FREE(session, session->local.kexinit); - } - if (session->local.crypt_prefs) { - LIBSSH2_FREE(session, session->local.crypt_prefs); - } - if (session->local.mac_prefs) { - LIBSSH2_FREE(session, session->local.mac_prefs); - } - if (session->local.comp_prefs) { - LIBSSH2_FREE(session, session->local.comp_prefs); - } - if (session->local.lang_prefs) { - LIBSSH2_FREE(session, session->local.lang_prefs); - } - - if (session->remote.kexinit) { - LIBSSH2_FREE(session, session->remote.kexinit); - } - if (session->remote.crypt_prefs) { - LIBSSH2_FREE(session, session->remote.crypt_prefs); - } - if (session->remote.mac_prefs) { - LIBSSH2_FREE(session, session->remote.mac_prefs); - } - if (session->remote.comp_prefs) { - LIBSSH2_FREE(session, session->remote.comp_prefs); - } - if (session->remote.lang_prefs) { - LIBSSH2_FREE(session, session->remote.lang_prefs); - } - - /* - * Make sure all memory used in the state variables are free - */ - if (session->kexinit_data) { - LIBSSH2_FREE(session, session->kexinit_data); - } - if (session->startup_data) { - LIBSSH2_FREE(session, session->startup_data); - } - if (session->userauth_list_data) { - LIBSSH2_FREE(session, session->userauth_list_data); - } - if (session->userauth_pswd_data) { - LIBSSH2_FREE(session, session->userauth_pswd_data); - } - if (session->userauth_pswd_newpw) { - LIBSSH2_FREE(session, session->userauth_pswd_newpw); - } - if (session->userauth_host_packet) { - LIBSSH2_FREE(session, session->userauth_host_packet); - } - if (session->userauth_host_method) { - LIBSSH2_FREE(session, session->userauth_host_method); - } - if (session->userauth_host_data) { - LIBSSH2_FREE(session, session->userauth_host_data); - } - if (session->userauth_pblc_data) { - LIBSSH2_FREE(session, session->userauth_pblc_data); - } - if (session->userauth_pblc_packet) { - LIBSSH2_FREE(session, session->userauth_pblc_packet); - } - if (session->userauth_pblc_method) { - LIBSSH2_FREE(session, session->userauth_pblc_method); - } - if (session->userauth_kybd_data) { - LIBSSH2_FREE(session, session->userauth_kybd_data); - } - if (session->userauth_kybd_packet) { - LIBSSH2_FREE(session, session->userauth_kybd_packet); - } - if (session->userauth_kybd_auth_instruction) { - LIBSSH2_FREE(session, session->userauth_kybd_auth_instruction); - } - if (session->open_packet) { - LIBSSH2_FREE(session, session->open_packet); - } - if (session->open_data) { - LIBSSH2_FREE(session, session->open_data); - } - if (session->direct_message) { - LIBSSH2_FREE(session, session->direct_message); - } - if (session->fwdLstn_packet) { - LIBSSH2_FREE(session, session->fwdLstn_packet); - } - if (session->pkeyInit_data) { - LIBSSH2_FREE(session, session->pkeyInit_data); - } - if (session->scpRecv_command) { - LIBSSH2_FREE(session, session->scpRecv_command); - } - if (session->scpSend_command) { - LIBSSH2_FREE(session, session->scpSend_command); - } - - /* Cleanup all remaining packets */ - while ((pkg = _libssh2_list_first(&session->packets))) { - packets_left++; - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "packet left with id %d", pkg->data[0]); - /* unlink the node */ - _libssh2_list_remove(&pkg->node); - - /* free */ - LIBSSH2_FREE(session, pkg->data); - LIBSSH2_FREE(session, pkg); - } - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Extra packets left %d", packets_left); - - if(session->socket_prev_blockstate) - /* if the socket was previously blocking, put it back so */ - session_nonblock(session->socket_fd, 0); - - if (session->server_hostkey) { - LIBSSH2_FREE(session, session->server_hostkey); - } - - LIBSSH2_FREE(session, session); - - return 0; -} - -/* - * libssh2_session_free - * - * Frees the memory allocated to the session - * Also closes and frees any channels attached to this session - */ -LIBSSH2_API int -libssh2_session_free(LIBSSH2_SESSION * session) -{ - int rc; - - BLOCK_ADJUST(rc, session, session_free(session) ); - - return rc; -} - -/* - * libssh2_session_disconnect_ex - */ -static int -session_disconnect(LIBSSH2_SESSION *session, int reason, - const char *description, - const char *lang) -{ - unsigned char *s; - unsigned long descr_len = 0, lang_len = 0; - int rc; - - if (session->disconnect_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Disconnecting: reason=%d, desc=%s, lang=%s", reason, - description, lang); - if (description) - descr_len = strlen(description); - - if (lang) - lang_len = strlen(lang); - - if(descr_len > 256) - return _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "too long description"); - - /* 13 = packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */ - session->disconnect_data_len = descr_len + lang_len + 13; - - s = session->disconnect_data; - - *(s++) = SSH_MSG_DISCONNECT; - _libssh2_store_u32(&s, reason); - _libssh2_store_str(&s, description, descr_len); - /* store length only, lang is sent separately */ - _libssh2_store_u32(&s, lang_len); - - session->disconnect_state = libssh2_NB_state_created; - } - - rc = _libssh2_transport_send(session, session->disconnect_data, - session->disconnect_data_len, - (unsigned char *)lang, lang_len); - if (rc == LIBSSH2_ERROR_EAGAIN) - return rc; - - session->disconnect_state = libssh2_NB_state_idle; - - return 0; -} - -/* - * libssh2_session_disconnect_ex - */ -LIBSSH2_API int -libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, - const char *desc, const char *lang) -{ - int rc; - - BLOCK_ADJUST(rc, session, - session_disconnect(session, reason, desc, lang)); - - return rc; -} - -/* libssh2_session_methods - * - * Return the currently active methods for method_type - * - * NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string - * regardless of actual negotiation Strings should NOT be freed - */ -LIBSSH2_API const char * -libssh2_session_methods(LIBSSH2_SESSION * session, int method_type) -{ - /* All methods have char *name as their first element */ - const LIBSSH2_KEX_METHOD *method = NULL; - - switch (method_type) { - case LIBSSH2_METHOD_KEX: - method = session->kex; - break; - - case LIBSSH2_METHOD_HOSTKEY: - method = (LIBSSH2_KEX_METHOD *) session->hostkey; - break; - - case LIBSSH2_METHOD_CRYPT_CS: - method = (LIBSSH2_KEX_METHOD *) session->local.crypt; - break; - - case LIBSSH2_METHOD_CRYPT_SC: - method = (LIBSSH2_KEX_METHOD *) session->remote.crypt; - break; - - case LIBSSH2_METHOD_MAC_CS: - method = (LIBSSH2_KEX_METHOD *) session->local.mac; - break; - - case LIBSSH2_METHOD_MAC_SC: - method = (LIBSSH2_KEX_METHOD *) session->remote.mac; - break; - - case LIBSSH2_METHOD_COMP_CS: - method = (LIBSSH2_KEX_METHOD *) session->local.comp; - break; - - case LIBSSH2_METHOD_COMP_SC: - method = (LIBSSH2_KEX_METHOD *) session->remote.comp; - break; - - case LIBSSH2_METHOD_LANG_CS: - return ""; - - case LIBSSH2_METHOD_LANG_SC: - return ""; - - default: - _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "Invalid parameter specified for method_type"); - return NULL; - } - - if (!method) { - _libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, - "No method negotiated"); - return NULL; - } - - return method->name; -} - -/* libssh2_session_abstract - * Retrieve a pointer to the abstract property - */ -LIBSSH2_API void ** -libssh2_session_abstract(LIBSSH2_SESSION * session) -{ - return &session->abstract; -} - -/* libssh2_session_last_error - * - * Returns error code and populates an error string into errmsg If want_buf is - * non-zero then the string placed into errmsg must be freed by the calling - * program. Otherwise it is assumed to be owned by libssh2 - */ -LIBSSH2_API int -libssh2_session_last_error(LIBSSH2_SESSION * session, char **errmsg, - int *errmsg_len, int want_buf) -{ - size_t msglen = 0; - - /* No error to report */ - if (!session->err_code) { - if (errmsg) { - if (want_buf) { - *errmsg = LIBSSH2_ALLOC(session, 1); - if (*errmsg) { - **errmsg = 0; - } - } else { - *errmsg = (char *) ""; - } - } - if (errmsg_len) { - *errmsg_len = 0; - } - return 0; - } - - if (errmsg) { - const char *error = session->err_msg ? session->err_msg : ""; - - msglen = strlen(error); - - if (want_buf) { - /* Make a copy so the calling program can own it */ - *errmsg = LIBSSH2_ALLOC(session, msglen + 1); - if (*errmsg) { - memcpy(*errmsg, error, msglen); - (*errmsg)[msglen] = 0; - } - } - else - *errmsg = (char *)error; - } - - if (errmsg_len) { - *errmsg_len = msglen; - } - - return session->err_code; -} - -/* libssh2_session_last_errno - * - * Returns error code - */ -LIBSSH2_API int -libssh2_session_last_errno(LIBSSH2_SESSION * session) -{ - return session->err_code; -} - -/* libssh2_session_flag - * - * Set/Get session flags - * - * Return error code. - */ -LIBSSH2_API int -libssh2_session_flag(LIBSSH2_SESSION * session, int flag, int value) -{ - switch(flag) { - case LIBSSH2_FLAG_SIGPIPE: - session->flag.sigpipe = value; - break; - case LIBSSH2_FLAG_COMPRESS: - session->flag.compress = value; - break; - default: - /* unknown flag */ - return LIBSSH2_ERROR_INVAL; - } - - return LIBSSH2_ERROR_NONE; -} - -/* _libssh2_session_set_blocking - * - * Set a session's blocking mode on or off, return the previous status when - * this function is called. Note this function does not alter the state of the - * actual socket involved. - */ -int -_libssh2_session_set_blocking(LIBSSH2_SESSION *session, int blocking) -{ - int bl = session->api_block_mode; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Setting blocking mode %s", blocking?"ON":"OFF"); - session->api_block_mode = blocking; - - return bl; -} - -/* libssh2_session_set_blocking - * - * Set a channel's blocking mode on or off, similar to a socket's - * fcntl(fd, F_SETFL, O_NONBLOCK); type command - */ -LIBSSH2_API void -libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking) -{ - (void) _libssh2_session_set_blocking(session, blocking); -} - -/* libssh2_session_get_blocking - * - * Returns a session's blocking mode on or off - */ -LIBSSH2_API int -libssh2_session_get_blocking(LIBSSH2_SESSION * session) -{ - return session->api_block_mode; -} - - -/* libssh2_session_set_timeout - * - * Set a session's timeout (in msec) for blocking mode, - * or 0 to disable timeouts. - */ -LIBSSH2_API void -libssh2_session_set_timeout(LIBSSH2_SESSION * session, long timeout) -{ - session->api_timeout = timeout; -} - -/* libssh2_session_get_timeout - * - * Returns a session's timeout, or 0 if disabled - */ -LIBSSH2_API long -libssh2_session_get_timeout(LIBSSH2_SESSION * session) -{ - return session->api_timeout; -} - -/* - * libssh2_poll_channel_read - * - * Returns 0 if no data is waiting on channel, - * non-0 if data is available - */ -LIBSSH2_API int -libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended) -{ - LIBSSH2_SESSION *session; - LIBSSH2_PACKET *packet; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - session = channel->session; - packet = _libssh2_list_first(&session->packets); - - while (packet) { - if ( channel->local.id == _libssh2_ntohu32(packet->data + 1)) { - if ( extended == 1 && - (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA - || packet->data[0] == SSH_MSG_CHANNEL_DATA )) { - return 1; - } else if ( extended == 0 && - packet->data[0] == SSH_MSG_CHANNEL_DATA) { - return 1; - } - /* else - no data of any type is ready to be read */ - } - packet = _libssh2_list_next(&packet->node); - } - - return 0; -} - -/* - * poll_channel_write - * - * Returns 0 if writing to channel would block, - * non-0 if data can be written without blocking - */ -static inline int -poll_channel_write(LIBSSH2_CHANNEL * channel) -{ - return channel->local.window_size ? 1 : 0; -} - -/* poll_listener_queued - * - * Returns 0 if no connections are waiting to be accepted - * non-0 if one or more connections are available - */ -static inline int -poll_listener_queued(LIBSSH2_LISTENER * listener) -{ - return _libssh2_list_first(&listener->queue) ? 1 : 0; -} - -/* - * libssh2_poll - * - * Poll sockets, channels, and listeners for activity - */ -LIBSSH2_API int -libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout) -{ - long timeout_remaining; - unsigned int i, active_fds; -#ifdef HAVE_POLL - LIBSSH2_SESSION *session = NULL; -#ifdef HAVE_ALLOCA - struct pollfd *sockets = alloca(sizeof(struct pollfd) * nfds); -#else - struct pollfd sockets[256]; - - if (nfds > 256) - /* systems without alloca use a fixed-size array, this can be fixed if - we really want to, at least if the compiler is a C99 capable one */ - return -1; -#endif - /* Setup sockets for polling */ - for(i = 0; i < nfds; i++) { - fds[i].revents = 0; - switch (fds[i].type) { - case LIBSSH2_POLLFD_SOCKET: - sockets[i].fd = fds[i].fd.socket; - sockets[i].events = fds[i].events; - sockets[i].revents = 0; - break; - - case LIBSSH2_POLLFD_CHANNEL: - sockets[i].fd = fds[i].fd.channel->session->socket_fd; - sockets[i].events = POLLIN; - sockets[i].revents = 0; - if (!session) - session = fds[i].fd.channel->session; - break; - - case LIBSSH2_POLLFD_LISTENER: - sockets[i].fd = fds[i].fd.listener->session->socket_fd; - sockets[i].events = POLLIN; - sockets[i].revents = 0; - if (!session) - session = fds[i].fd.listener->session; - break; - - default: - if (session) - _libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, - "Invalid descriptor passed to libssh2_poll()"); - return -1; - } - } -#elif defined(HAVE_SELECT) - LIBSSH2_SESSION *session = NULL; - libssh2_socket_t maxfd = 0; - fd_set rfds, wfds; - struct timeval tv; - - FD_ZERO(&rfds); - FD_ZERO(&wfds); - for(i = 0; i < nfds; i++) { - fds[i].revents = 0; - switch (fds[i].type) { - case LIBSSH2_POLLFD_SOCKET: - if (fds[i].events & LIBSSH2_POLLFD_POLLIN) { - FD_SET(fds[i].fd.socket, &rfds); - if (fds[i].fd.socket > maxfd) - maxfd = fds[i].fd.socket; - } - if (fds[i].events & LIBSSH2_POLLFD_POLLOUT) { - FD_SET(fds[i].fd.socket, &wfds); - if (fds[i].fd.socket > maxfd) - maxfd = fds[i].fd.socket; - } - break; - - case LIBSSH2_POLLFD_CHANNEL: - FD_SET(fds[i].fd.channel->session->socket_fd, &rfds); - if (fds[i].fd.channel->session->socket_fd > maxfd) - maxfd = fds[i].fd.channel->session->socket_fd; - if (!session) - session = fds[i].fd.channel->session; - break; - - case LIBSSH2_POLLFD_LISTENER: - FD_SET(fds[i].fd.listener->session->socket_fd, &rfds); - if (fds[i].fd.listener->session->socket_fd > maxfd) - maxfd = fds[i].fd.listener->session->socket_fd; - if (!session) - session = fds[i].fd.listener->session; - break; - - default: - if (session) - _libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, - "Invalid descriptor passed to libssh2_poll()"); - return -1; - } - } -#else - /* No select() or poll() - * no sockets sturcture to setup - */ - - timeout = 0; -#endif /* HAVE_POLL or HAVE_SELECT */ - - timeout_remaining = timeout; - do { -#if defined(HAVE_POLL) || defined(HAVE_SELECT) - int sysret; -#endif - - active_fds = 0; - - for(i = 0; i < nfds; i++) { - if (fds[i].events != fds[i].revents) { - switch (fds[i].type) { - case LIBSSH2_POLLFD_CHANNEL: - if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && - /* Want to be ready for read */ - ((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { - /* Not yet known to be ready for read */ - fds[i].revents |= - libssh2_poll_channel_read(fds[i].fd.channel, - 0) ? - LIBSSH2_POLLFD_POLLIN : 0; - } - if ((fds[i].events & LIBSSH2_POLLFD_POLLEXT) && - /* Want to be ready for extended read */ - ((fds[i].revents & LIBSSH2_POLLFD_POLLEXT) == 0)) { - /* Not yet known to be ready for extended read */ - fds[i].revents |= - libssh2_poll_channel_read(fds[i].fd.channel, - 1) ? - LIBSSH2_POLLFD_POLLEXT : 0; - } - if ((fds[i].events & LIBSSH2_POLLFD_POLLOUT) && - /* Want to be ready for write */ - ((fds[i].revents & LIBSSH2_POLLFD_POLLOUT) == 0)) { - /* Not yet known to be ready for write */ - fds[i].revents |= - poll_channel_write(fds[i].fd. channel) ? - LIBSSH2_POLLFD_POLLOUT : 0; - } - if (fds[i].fd.channel->remote.close - || fds[i].fd.channel->local.close) { - fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED; - } - if (fds[i].fd.channel->session->socket_state == - LIBSSH2_SOCKET_DISCONNECTED) { - fds[i].revents |= - LIBSSH2_POLLFD_CHANNEL_CLOSED | - LIBSSH2_POLLFD_SESSION_CLOSED; - } - break; - - case LIBSSH2_POLLFD_LISTENER: - if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && - /* Want a connection */ - ((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { - /* No connections known of yet */ - fds[i].revents |= - poll_listener_queued(fds[i].fd. listener) ? - LIBSSH2_POLLFD_POLLIN : 0; - } - if (fds[i].fd.listener->session->socket_state == - LIBSSH2_SOCKET_DISCONNECTED) { - fds[i].revents |= - LIBSSH2_POLLFD_LISTENER_CLOSED | - LIBSSH2_POLLFD_SESSION_CLOSED; - } - break; - } - } - if (fds[i].revents) { - active_fds++; - } - } - - if (active_fds) { - /* Don't block on the sockets if we have channels/listeners which - are ready */ - timeout_remaining = 0; - } -#ifdef HAVE_POLL - -#ifdef HAVE_LIBSSH2_GETTIMEOFDAY - { - struct timeval tv_begin, tv_end; - - _libssh2_gettimeofday((struct timeval *) &tv_begin, NULL); - sysret = poll(sockets, nfds, timeout_remaining); - _libssh2_gettimeofday((struct timeval *) &tv_end, NULL); - timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000; - timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000; - } -#else - /* If the platform doesn't support gettimeofday, - * then just make the call non-blocking and walk away - */ - sysret = poll(sockets, nfds, timeout_remaining); - timeout_remaining = 0; -#endif /* HAVE_GETTIMEOFDAY */ - - if (sysret > 0) { - for(i = 0; i < nfds; i++) { - switch (fds[i].type) { - case LIBSSH2_POLLFD_SOCKET: - fds[i].revents = sockets[i].revents; - sockets[i].revents = 0; /* In case we loop again, be nice */ - if (fds[i].revents) { - active_fds++; - } - break; - case LIBSSH2_POLLFD_CHANNEL: - if (sockets[i].events & POLLIN) { - /* Spin session until no data available */ - while (_libssh2_transport_read(fds[i].fd.channel->session) - > 0); - } - if (sockets[i].revents & POLLHUP) { - fds[i].revents |= - LIBSSH2_POLLFD_CHANNEL_CLOSED | - LIBSSH2_POLLFD_SESSION_CLOSED; - } - sockets[i].revents = 0; - break; - case LIBSSH2_POLLFD_LISTENER: - if (sockets[i].events & POLLIN) { - /* Spin session until no data available */ - while (_libssh2_transport_read(fds[i].fd.listener->session) - > 0); - } - if (sockets[i].revents & POLLHUP) { - fds[i].revents |= - LIBSSH2_POLLFD_LISTENER_CLOSED | - LIBSSH2_POLLFD_SESSION_CLOSED; - } - sockets[i].revents = 0; - break; - } - } - } -#elif defined(HAVE_SELECT) - tv.tv_sec = timeout_remaining / 1000; - tv.tv_usec = (timeout_remaining % 1000) * 1000; -#ifdef HAVE_LIBSSH2_GETTIMEOFDAY - { - struct timeval tv_begin, tv_end; - - _libssh2_gettimeofday((struct timeval *) &tv_begin, NULL); - sysret = select(maxfd+1, &rfds, &wfds, NULL, &tv); - _libssh2_gettimeofday((struct timeval *) &tv_end, NULL); - - timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000; - timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000; - } -#else - /* If the platform doesn't support gettimeofday, - * then just make the call non-blocking and walk away - */ - sysret = select(maxfd+1, &rfds, &wfds, NULL, &tv); - timeout_remaining = 0; -#endif - - if (sysret > 0) { - for(i = 0; i < nfds; i++) { - switch (fds[i].type) { - case LIBSSH2_POLLFD_SOCKET: - if (FD_ISSET(fds[i].fd.socket, &rfds)) { - fds[i].revents |= LIBSSH2_POLLFD_POLLIN; - } - if (FD_ISSET(fds[i].fd.socket, &wfds)) { - fds[i].revents |= LIBSSH2_POLLFD_POLLOUT; - } - if (fds[i].revents) { - active_fds++; - } - break; - - case LIBSSH2_POLLFD_CHANNEL: - if (FD_ISSET(fds[i].fd.channel->session->socket_fd, &rfds)) { - /* Spin session until no data available */ - while (_libssh2_transport_read(fds[i].fd.channel->session) - > 0); - } - break; - - case LIBSSH2_POLLFD_LISTENER: - if (FD_ISSET - (fds[i].fd.listener->session->socket_fd, &rfds)) { - /* Spin session until no data available */ - while (_libssh2_transport_read(fds[i].fd.listener->session) - > 0); - } - break; - } - } - } -#endif /* else no select() or poll() -- timeout (and by extension - * timeout_remaining) will be equal to 0 */ - } while ((timeout_remaining > 0) && !active_fds); - - return active_fds; -} - -/* - * libssh2_session_block_directions - * - * Get blocked direction when a function returns LIBSSH2_ERROR_EAGAIN - * Returns LIBSSH2_SOCKET_BLOCK_INBOUND if recv() blocked - * or LIBSSH2_SOCKET_BLOCK_OUTBOUND if send() blocked - */ -LIBSSH2_API int -libssh2_session_block_directions(LIBSSH2_SESSION *session) -{ - return session->socket_block_directions; -} - -/* libssh2_session_banner_get - * Get the remote banner (server ID string) - */ - -LIBSSH2_API const char * -libssh2_session_banner_get(LIBSSH2_SESSION *session) -{ - /* to avoid a coredump when session is NULL */ - if (NULL == session) - return NULL; - - if (NULL==session->remote.banner) - return NULL; - - return (const char *) session->remote.banner; -} diff --git a/vendor/libssh2-1.4.2/src/session.h b/vendor/libssh2-1.4.2/src/session.h deleted file mode 100644 index aff4f2c..0000000 --- a/vendor/libssh2-1.4.2/src/session.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef LIBSSH2_SESSION_H -#define LIBSSH2_SESSION_H -/* Copyright (c) 2004-2007 Sara Golemon - * Copyright (c) 2009-2010 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -/* Conveniance-macros to allow code like this; - - int rc = BLOCK_ADJUST(rc, session, session_startup(session, sock) ); - - int rc = BLOCK_ADJUST_ERRNO(ptr, session, session_startup(session, sock) ); - - The point of course being to make sure that while in non-blocking mode - these always return no matter what the return code is, but in blocking mode - it blocks if EAGAIN is the reason for the return from the underlying - function. - -*/ -#define BLOCK_ADJUST(rc,sess,x) \ - do { \ - time_t entry_time = time (NULL); \ - do { \ - rc = x; \ - /* the order of the check below is important to properly deal with \ - the case when the 'sess' is freed */ \ - if((rc != LIBSSH2_ERROR_EAGAIN) || !sess->api_block_mode) \ - break; \ - rc = _libssh2_wait_socket(sess, entry_time); \ - } while(!rc); \ - } while(0) - -/* - * For functions that returns a pointer, we need to check if the API is - * non-blocking and return immediately. If the pointer is non-NULL we return - * immediately. If the API is blocking and we get a NULL we check the errno - * and *only* if that is EAGAIN we loop and wait for socket action. - */ -#define BLOCK_ADJUST_ERRNO(ptr,sess,x) \ - do { \ - time_t entry_time = time (NULL); \ - int rc; \ - do { \ - ptr = x; \ - if(!sess->api_block_mode || \ - (ptr != NULL) || \ - (libssh2_session_last_errno(sess) != LIBSSH2_ERROR_EAGAIN) ) \ - break; \ - rc = _libssh2_wait_socket(sess, entry_time); \ - } while(!rc); \ - } while(0) - - -int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t entry_time); - -/* this is the lib-internal set blocking function */ -int _libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking); - -#endif /* LIBSSH2_SESSION_H */ diff --git a/vendor/libssh2-1.4.2/src/sftp.c b/vendor/libssh2-1.4.2/src/sftp.c deleted file mode 100644 index ec9d033..0000000 --- a/vendor/libssh2-1.4.2/src/sftp.c +++ /dev/null @@ -1,3278 +0,0 @@ -/* Copyright (c) 2004-2008, Sara Golemon - * Copyright (c) 2007 Eli Fant - * Copyright (c) 2009-2012 by Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include - -#include "libssh2_priv.h" -#include "libssh2_sftp.h" -#include "channel.h" -#include "session.h" -#include "sftp.h" - -/* Note: Version 6 was documented at the time of writing - * However it was marked as "DO NOT IMPLEMENT" due to pending changes - * - * This release of libssh2 implements Version 5 with automatic downgrade - * based on server's declaration - */ - -/* SFTP packet types */ -#define SSH_FXP_INIT 1 -#define SSH_FXP_VERSION 2 -#define SSH_FXP_OPEN 3 -#define SSH_FXP_CLOSE 4 -#define SSH_FXP_READ 5 -#define SSH_FXP_WRITE 6 -#define SSH_FXP_LSTAT 7 -#define SSH_FXP_FSTAT 8 -#define SSH_FXP_SETSTAT 9 -#define SSH_FXP_FSETSTAT 10 -#define SSH_FXP_OPENDIR 11 -#define SSH_FXP_READDIR 12 -#define SSH_FXP_REMOVE 13 -#define SSH_FXP_MKDIR 14 -#define SSH_FXP_RMDIR 15 -#define SSH_FXP_REALPATH 16 -#define SSH_FXP_STAT 17 -#define SSH_FXP_RENAME 18 -#define SSH_FXP_READLINK 19 -#define SSH_FXP_SYMLINK 20 -#define SSH_FXP_STATUS 101 -#define SSH_FXP_HANDLE 102 -#define SSH_FXP_DATA 103 -#define SSH_FXP_NAME 104 -#define SSH_FXP_ATTRS 105 -#define SSH_FXP_EXTENDED 200 -#define SSH_FXP_EXTENDED_REPLY 201 - -/* S_IFREG */ -#define LIBSSH2_SFTP_ATTR_PFILETYPE_FILE 0100000 -/* S_IFDIR */ -#define LIBSSH2_SFTP_ATTR_PFILETYPE_DIR 0040000 - -#define SSH_FXE_STATVFS_ST_RDONLY 0x00000001 -#define SSH_FXE_STATVFS_ST_NOSUID 0x00000002 - -/* This is the maximum packet length to accept, as larger than this indicate - some kind of server problem. */ -#define LIBSSH2_SFTP_PACKET_MAXLEN 80000 - -static int sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle); -static int sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type, - uint32_t request_id, unsigned char **data, - size_t *data_len); -static void sftp_packet_flush(LIBSSH2_SFTP *sftp); - -/* sftp_attrsize - * Size that attr with this flagset will occupy when turned into a bin struct - */ -static int sftp_attrsize(unsigned long flags) -{ - return (4 + /* flags(4) */ - ((flags & LIBSSH2_SFTP_ATTR_SIZE) ? 8 : 0) + - ((flags & LIBSSH2_SFTP_ATTR_UIDGID) ? 8 : 0) + - ((flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) ? 4 : 0) + - ((flags & LIBSSH2_SFTP_ATTR_ACMODTIME) ? 8 : 0)); - /* atime + mtime as u32 */ -} - -/* _libssh2_store_u64 - */ -static void _libssh2_store_u64(unsigned char **ptr, libssh2_uint64_t value) -{ - uint32_t msl = (uint32_t)(value >> 32); - unsigned char *buf = *ptr; - - buf[0] = (unsigned char)((msl >> 24) & 0xFF); - buf[1] = (unsigned char)((msl >> 16) & 0xFF); - buf[2] = (unsigned char)((msl >> 8) & 0xFF); - buf[3] = (unsigned char)( msl & 0xFF); - - buf[4] = (unsigned char)((value >> 24) & 0xFF); - buf[5] = (unsigned char)((value >> 16) & 0xFF); - buf[6] = (unsigned char)((value >> 8) & 0xFF); - buf[7] = (unsigned char)( value & 0xFF); - - *ptr += 8; -} - -/* - * Search list of zombied FXP_READ request IDs. - * - * Returns NULL if ID not in list. - */ -static struct sftp_zombie_requests * -find_zombie_request(LIBSSH2_SFTP *sftp, uint32_t request_id) -{ - struct sftp_zombie_requests *zombie = - _libssh2_list_first(&sftp->zombie_requests); - - while(zombie) { - if(zombie->request_id == request_id) - break; - else - zombie = _libssh2_list_next(&zombie->node); - } - - return zombie; -} - -static void -remove_zombie_request(LIBSSH2_SFTP *sftp, uint32_t request_id) -{ - LIBSSH2_SESSION *session = sftp->channel->session; - - struct sftp_zombie_requests *zombie = find_zombie_request(sftp, - request_id); - if(zombie) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Removing request ID %ld from the list of zombie requests", - request_id); - - _libssh2_list_remove(&zombie->node); - LIBSSH2_FREE(session, zombie); - } -} - -static int -add_zombie_request(LIBSSH2_SFTP *sftp, uint32_t request_id) -{ - LIBSSH2_SESSION *session = sftp->channel->session; - - struct sftp_zombie_requests *zombie; - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Marking request ID %ld as a zombie request", request_id); - - zombie = LIBSSH2_ALLOC(sftp->channel->session, - sizeof(struct sftp_zombie_requests)); - if (!zombie) - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "malloc fail for zombie request ID"); - else { - zombie->request_id = request_id; - _libssh2_list_add(&sftp->zombie_requests, &zombie->node); - return LIBSSH2_ERROR_NONE; - } -} - -/* - * sftp_packet_add - * - * Add a packet to the SFTP packet brigade - */ -static int -sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data, - size_t data_len) -{ - LIBSSH2_SESSION *session = sftp->channel->session; - LIBSSH2_SFTP_PACKET *packet; - uint32_t request_id; - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Received packet %d (len %d)", - (int) data[0], data_len); - - /* - * Experience shows that if we mess up EAGAIN handling somewhere or - * otherwise get out of sync with the channel, this is where we first get - * a wrong byte and if so we need to bail out at once to aid tracking the - * problem better. - */ - - switch(data[0]) { - case SSH_FXP_INIT: - case SSH_FXP_VERSION: - case SSH_FXP_OPEN: - case SSH_FXP_CLOSE: - case SSH_FXP_READ: - case SSH_FXP_WRITE: - case SSH_FXP_LSTAT: - case SSH_FXP_FSTAT: - case SSH_FXP_SETSTAT: - case SSH_FXP_FSETSTAT: - case SSH_FXP_OPENDIR: - case SSH_FXP_READDIR: - case SSH_FXP_REMOVE: - case SSH_FXP_MKDIR: - case SSH_FXP_RMDIR: - case SSH_FXP_REALPATH: - case SSH_FXP_STAT: - case SSH_FXP_RENAME: - case SSH_FXP_READLINK: - case SSH_FXP_SYMLINK: - case SSH_FXP_STATUS: - case SSH_FXP_HANDLE: - case SSH_FXP_DATA: - case SSH_FXP_NAME: - case SSH_FXP_ATTRS: - case SSH_FXP_EXTENDED: - case SSH_FXP_EXTENDED_REPLY: - break; - default: - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Out of sync with the world"); - } - - request_id = _libssh2_ntohu32(&data[1]); - - /* Don't add the packet if it answers a request we've given up on. */ - if((data[0] == SSH_FXP_STATUS || data[0] == SSH_FXP_DATA) - && find_zombie_request(sftp, request_id)) { - - /* If we get here, the file ended before the response arrived. We - are no longer interested in the request so we discard it */ - - LIBSSH2_FREE(session, data); - - remove_zombie_request(sftp, request_id); - return LIBSSH2_ERROR_NONE; - } - - packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP_PACKET)); - if (!packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate datablock for SFTP packet"); - } - - packet->data = data; - packet->data_len = data_len; - packet->request_id = request_id; - - _libssh2_list_add(&sftp->packets, &packet->node); - - return LIBSSH2_ERROR_NONE; -} - -/* - * sftp_packet_read - * - * Frame an SFTP packet off the channel - */ -static int -sftp_packet_read(LIBSSH2_SFTP *sftp) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - unsigned char *packet = NULL; - ssize_t rc; - unsigned long recv_window; - int packet_type; - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "recv packet"); - - switch(sftp->packet_state) { - case libssh2_NB_state_sent: /* EAGAIN from window adjusting */ - sftp->packet_state = libssh2_NB_state_idle; - - packet = sftp->partial_packet; - goto window_adjust; - - case libssh2_NB_state_sent1: /* EAGAIN from channel read */ - sftp->packet_state = libssh2_NB_state_idle; - - packet = sftp->partial_packet; - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "partial read cont, len: %lu", sftp->partial_len); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "partial read cont, already recvd: %lu", - sftp->partial_received); - /* fall-through */ - default: - if(!packet) { - /* only do this if there's not already a packet buffer allocated - to use */ - - /* each packet starts with a 32 bit length field */ - rc = _libssh2_channel_read(channel, 0, - (char *)&sftp->partial_size[ - sftp->partial_size_len], - 4 - sftp->partial_size_len); - if (rc == LIBSSH2_ERROR_EAGAIN) - return rc; - else if (rc < 0) - return _libssh2_error(session, rc, "channel read"); - - sftp->partial_size_len += rc; - - if(4 != sftp->partial_size_len) - /* we got a short read for the length part */ - return LIBSSH2_ERROR_EAGAIN; - - sftp->partial_len = _libssh2_ntohu32(sftp->partial_size); - /* make sure we don't proceed if the packet size is unreasonably - large */ - if (sftp->partial_len > LIBSSH2_SFTP_PACKET_MAXLEN) - return _libssh2_error(session, - LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, - "SFTP packet too large"); - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Data begin - Packet Length: %lu", - sftp->partial_len); - packet = LIBSSH2_ALLOC(session, sftp->partial_len); - if (!packet) - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate SFTP packet"); - sftp->partial_size_len = 0; - sftp->partial_received = 0; /* how much of the packet already - received */ - sftp->partial_packet = packet; - - window_adjust: - recv_window = libssh2_channel_window_read_ex(channel, NULL, NULL); - - if(sftp->partial_len > recv_window) { - /* ask for twice the data amount we need at once */ - rc = _libssh2_channel_receive_window_adjust(channel, - sftp->partial_len*2, - 1, NULL); - /* store the state so that we continue with the correct - operation at next invoke */ - sftp->packet_state = (rc == LIBSSH2_ERROR_EAGAIN)? - libssh2_NB_state_sent: - libssh2_NB_state_idle; - - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - } - } - - /* Read as much of the packet as we can */ - while (sftp->partial_len > sftp->partial_received) { - rc = _libssh2_channel_read(channel, 0, - (char *)&packet[sftp->partial_received], - sftp->partial_len - - sftp->partial_received); - - if (rc == LIBSSH2_ERROR_EAGAIN) { - /* - * We received EAGAIN, save what we have and return EAGAIN to - * the caller. Set 'partial_packet' so that this function - * knows how to continue on the next invoke. - */ - sftp->packet_state = libssh2_NB_state_sent1; - return rc; - } - else if (rc < 0) { - LIBSSH2_FREE(session, packet); - sftp->partial_packet = NULL; - return _libssh2_error(session, rc, - "Error waiting for SFTP packet"); - } - sftp->partial_received += rc; - } - - sftp->partial_packet = NULL; - - /* sftp_packet_add takes ownership of the packet and might free it - so we take a copy of the packet type before we call it. */ - packet_type = packet[0]; - rc = sftp_packet_add(sftp, packet, sftp->partial_len); - if (rc) { - LIBSSH2_FREE(session, packet); - return rc; - } - else { - return packet_type; - } - } - /* WON'T REACH */ -} -/* - * sftp_packetlist_flush - * - * Remove all pending packets in the packet_list and the corresponding one(s) - * in the SFTP packet brigade. - */ -static void sftp_packetlist_flush(LIBSSH2_SFTP_HANDLE *handle) -{ - struct sftp_pipeline_chunk *chunk; - LIBSSH2_SFTP *sftp = handle->sftp; - LIBSSH2_SESSION *session = sftp->channel->session; - - /* remove pending packets, if any */ - chunk = _libssh2_list_first(&handle->packet_list); - while(chunk) { - unsigned char *data; - size_t data_len; - int rc; - struct sftp_pipeline_chunk *next = _libssh2_list_next(&chunk->node); - - rc = sftp_packet_ask(sftp, SSH_FXP_STATUS, - chunk->request_id, &data, &data_len); - if(rc) - rc = sftp_packet_ask(sftp, SSH_FXP_DATA, - chunk->request_id, &data, &data_len); - - if(!rc) - /* we found a packet, free it */ - LIBSSH2_FREE(session, data); - else if(chunk->sent) - /* there was no incoming packet for this request, mark this - request as a zombie if it ever sent the request */ - add_zombie_request(sftp, chunk->request_id); - - _libssh2_list_remove(&chunk->node); - LIBSSH2_FREE(session, chunk); - chunk = next; - } -} - - -/* - * sftp_packet_ask() - * - * Checks if there's a matching SFTP packet available. - */ -static int -sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type, - uint32_t request_id, unsigned char **data, - size_t *data_len) -{ - LIBSSH2_SESSION *session = sftp->channel->session; - LIBSSH2_SFTP_PACKET *packet = _libssh2_list_first(&sftp->packets); - - if(!packet) - return -1; - - /* Special consideration when getting VERSION packet */ - - while (packet) { - if((packet->data[0] == packet_type) && - ((packet_type == SSH_FXP_VERSION) || - (packet->request_id == request_id))) { - - /* Match! Fetch the data */ - *data = packet->data; - *data_len = packet->data_len; - - /* unlink and free this struct */ - _libssh2_list_remove(&packet->node); - LIBSSH2_FREE(session, packet); - - return 0; - } - /* check next struct in the list */ - packet = _libssh2_list_next(&packet->node); - } - return -1; -} - -/* sftp_packet_require - * A la libssh2_packet_require - */ -static int -sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_type, - uint32_t request_id, unsigned char **data, - size_t *data_len) -{ - LIBSSH2_SESSION *session = sftp->channel->session; - int rc; - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Requiring packet %d id %ld", - (int) packet_type, request_id); - - if (sftp_packet_ask(sftp, packet_type, request_id, data, data_len) == 0) { - /* The right packet was available in the packet brigade */ - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Got %d", - (int) packet_type); - return LIBSSH2_ERROR_NONE; - } - - while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) { - rc = sftp_packet_read(sftp); - if (rc < 0) - return rc; - - /* data was read, check the queue again */ - if (!sftp_packet_ask(sftp, packet_type, request_id, data, data_len)) { - /* The right packet was available in the packet brigade */ - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Got %d", - (int) packet_type); - return LIBSSH2_ERROR_NONE; - } - } - - /* Only reached if the socket died */ - return LIBSSH2_ERROR_SOCKET_DISCONNECT; -} - -/* sftp_packet_requirev - * Require one of N possible reponses - */ -static int -sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses, - const unsigned char *valid_responses, - uint32_t request_id, unsigned char **data, - size_t *data_len) -{ - int i; - int rc; - - /* If no timeout is active, start a new one */ - if (sftp->requirev_start == 0) - sftp->requirev_start = time(NULL); - - while (sftp->channel->session->socket_state == LIBSSH2_SOCKET_CONNECTED) { - for(i = 0; i < num_valid_responses; i++) { - if (sftp_packet_ask(sftp, valid_responses[i], request_id, - data, data_len) == 0) { - /* - * Set to zero before all returns to say - * the timeout is not active - */ - sftp->requirev_start = 0; - return LIBSSH2_ERROR_NONE; - } - } - - rc = sftp_packet_read(sftp); - if ((rc < 0) && (rc != LIBSSH2_ERROR_EAGAIN)) { - sftp->requirev_start = 0; - return rc; - } else if (rc <= 0) { - /* prevent busy-looping */ - long left = - LIBSSH2_READ_TIMEOUT - (long)(time(NULL) - sftp->requirev_start); - - if (left <= 0) { - sftp->requirev_start = 0; - return LIBSSH2_ERROR_TIMEOUT; - } - else if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - } - } - - sftp->requirev_start = 0; - - /* Only reached if the socket died */ - return LIBSSH2_ERROR_SOCKET_DISCONNECT; -} - -/* sftp_attr2bin - * Populate attributes into an SFTP block - */ -static ssize_t -sftp_attr2bin(unsigned char *p, const LIBSSH2_SFTP_ATTRIBUTES * attrs) -{ - unsigned char *s = p; - uint32_t flag_mask = - LIBSSH2_SFTP_ATTR_SIZE | LIBSSH2_SFTP_ATTR_UIDGID | - LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME; - - /* TODO: When we add SFTP4+ functionality flag_mask can get additional - bits */ - - if (!attrs) { - _libssh2_htonu32(s, 0); - return 4; - } - - _libssh2_store_u32(&s, attrs->flags & flag_mask); - - if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) { - _libssh2_store_u64(&s, attrs->filesize); - } - - if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) { - _libssh2_store_u32(&s, attrs->uid); - _libssh2_store_u32(&s, attrs->gid); - } - - if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { - _libssh2_store_u32(&s, attrs->permissions); - } - - if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) { - _libssh2_store_u32(&s, attrs->atime); - _libssh2_store_u32(&s, attrs->mtime); - } - - return (s - p); -} - -/* sftp_bin2attr - */ -static int -sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES * attrs, const unsigned char *p) -{ - const unsigned char *s = p; - - memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); - attrs->flags = _libssh2_ntohu32(s); - s += 4; - - if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) { - attrs->filesize = _libssh2_ntohu64(s); - s += 8; - } - - if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) { - attrs->uid = _libssh2_ntohu32(s); - s += 4; - attrs->gid = _libssh2_ntohu32(s); - s += 4; - } - - if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { - attrs->permissions = _libssh2_ntohu32(s); - s += 4; - } - - if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) { - attrs->atime = _libssh2_ntohu32(s); - s += 4; - attrs->mtime = _libssh2_ntohu32(s); - s += 4; - } - - return (s - p); -} - -/* ************ - * SFTP API * - ************ */ - -LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor); - -/* libssh2_sftp_dtor - * Shutdown an SFTP stream when the channel closes - */ -LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor) -{ - LIBSSH2_SFTP *sftp = (LIBSSH2_SFTP *) (*channel_abstract); - - (void) session_abstract; - (void) channel; - - /* Free the partial packet storage for sftp_packet_read */ - if (sftp->partial_packet) { - LIBSSH2_FREE(session, sftp->partial_packet); - } - - /* Free the packet storage for _libssh2_sftp_packet_readdir */ - if (sftp->readdir_packet) { - LIBSSH2_FREE(session, sftp->readdir_packet); - } - - LIBSSH2_FREE(session, sftp); -} - -/* - * sftp_init - * - * Startup an SFTP session - */ -static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) -{ - unsigned char *data, *s; - size_t data_len; - ssize_t rc; - LIBSSH2_SFTP *sftp_handle; - - if (session->sftpInit_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Initializing SFTP subsystem"); - - /* - * The 'sftpInit_sftp' and 'sftpInit_channel' struct fields within the - * session struct are only to be used during the setup phase. As soon - * as the SFTP session is created they are cleared and can thus be - * re-used again to allow any amount of SFTP handles per sessions. - * - * Note that you MUST NOT try to call libssh2_sftp_init() again to get - * another handle until the previous call has finished and either - * succesffully made a handle or failed and returned error (not - * including *EAGAIN). - */ - - assert(session->sftpInit_sftp == NULL); - session->sftpInit_sftp = NULL; - session->sftpInit_state = libssh2_NB_state_created; - } - - sftp_handle = session->sftpInit_sftp; - - if (session->sftpInit_state == libssh2_NB_state_created) { - session->sftpInit_channel = - _libssh2_channel_open(session, "session", sizeof("session") - 1, - LIBSSH2_CHANNEL_WINDOW_DEFAULT, - LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0); - if (!session->sftpInit_channel) { - if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block starting up channel"); - } - else { - _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, - "Unable to startup channel"); - session->sftpInit_state = libssh2_NB_state_idle; - } - return NULL; - } - - session->sftpInit_state = libssh2_NB_state_sent; - } - - if (session->sftpInit_state == libssh2_NB_state_sent) { - int ret = _libssh2_channel_process_startup(session->sftpInit_channel, - "subsystem", - sizeof("subsystem") - 1, "sftp", - strlen("sftp")); - if (ret == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block to request SFTP subsystem"); - return NULL; - } else if (ret) { - _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, - "Unable to request SFTP subsystem"); - goto sftp_init_error; - } - - session->sftpInit_state = libssh2_NB_state_sent1; - } - - if (session->sftpInit_state == libssh2_NB_state_sent1) { - rc = _libssh2_channel_extended_data(session->sftpInit_channel, - LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block requesting handle extended data"); - return NULL; - } - - sftp_handle = - session->sftpInit_sftp = - LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP)); - if (!sftp_handle) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate a new SFTP structure"); - goto sftp_init_error; - } - memset(sftp_handle, 0, sizeof(LIBSSH2_SFTP)); - sftp_handle->channel = session->sftpInit_channel; - sftp_handle->request_id = 0; - - _libssh2_htonu32(session->sftpInit_buffer, 5); - session->sftpInit_buffer[4] = SSH_FXP_INIT; - _libssh2_htonu32(session->sftpInit_buffer + 5, LIBSSH2_SFTP_VERSION); - session->sftpInit_sent = 0; /* nothing's sent yet */ - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Sending FXP_INIT packet advertising version %d support", - (int) LIBSSH2_SFTP_VERSION); - - session->sftpInit_state = libssh2_NB_state_sent2; - } - - if (session->sftpInit_state == libssh2_NB_state_sent2) { - /* sent off what's left of the init buffer to send */ - rc = _libssh2_channel_write(session->sftpInit_channel, 0, - session->sftpInit_buffer + - session->sftpInit_sent, - 9 - session->sftpInit_sent); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block sending SSH_FXP_INIT"); - return NULL; - } - else if(rc < 0) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send SSH_FXP_INIT"); - goto sftp_init_error; - } - else { - /* add up the number of bytes sent */ - session->sftpInit_sent += rc; - - if(session->sftpInit_sent == 9) - /* move on */ - session->sftpInit_state = libssh2_NB_state_sent3; - - /* if less than 9, we remain in this state to send more later on */ - } - } - - rc = sftp_packet_require(sftp_handle, SSH_FXP_VERSION, - 0, &data, &data_len); - if (rc == LIBSSH2_ERROR_EAGAIN) - return NULL; - else if (rc) { - _libssh2_error(session, rc, - "Timeout waiting for response from SFTP subsystem"); - goto sftp_init_error; - } - if (data_len < 5) { - _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Invalid SSH_FXP_VERSION response"); - goto sftp_init_error; - } - - s = data + 1; - sftp_handle->version = _libssh2_ntohu32(s); - s += 4; - if (sftp_handle->version > LIBSSH2_SFTP_VERSION) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Truncating remote SFTP version from %lu", - sftp_handle->version); - sftp_handle->version = LIBSSH2_SFTP_VERSION; - } - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Enabling SFTP version %lu compatability", - sftp_handle->version); - while (s < (data + data_len)) { - size_t extname_len, extdata_len; - - extname_len = _libssh2_ntohu32(s); - s += 4; - /* the extension name starts here */ - s += extname_len; - - extdata_len = _libssh2_ntohu32(s); - s += 4; - - /* TODO: Actually process extensions */ - s += extdata_len; - - } - LIBSSH2_FREE(session, data); - - /* Make sure that when the channel gets closed, the SFTP service is shut - down too */ - sftp_handle->channel->abstract = sftp_handle; - sftp_handle->channel->close_cb = libssh2_sftp_dtor; - - session->sftpInit_state = libssh2_NB_state_idle; - - /* clear the sftp and channel pointers in this session struct now */ - session->sftpInit_sftp = NULL; - session->sftpInit_channel = NULL; - - _libssh2_list_init(&sftp_handle->sftp_handles); - - return sftp_handle; - - sftp_init_error: - while (_libssh2_channel_free(session->sftpInit_channel) == - LIBSSH2_ERROR_EAGAIN); - session->sftpInit_channel = NULL; - if (session->sftpInit_sftp) { - LIBSSH2_FREE(session, session->sftpInit_sftp); - session->sftpInit_sftp = NULL; - } - session->sftpInit_state = libssh2_NB_state_idle; - return NULL; -} - -/* - * libssh2_sftp_init - * - * Startup an SFTP session - */ -LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session) -{ - LIBSSH2_SFTP *ptr; - - if(!session) - return NULL; - - if(!(session->state & LIBSSH2_STATE_AUTHENTICATED)) { - _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "session not authenticated yet"); - return NULL; - } - - BLOCK_ADJUST_ERRNO(ptr, session, sftp_init(session)); - return ptr; -} - -/* - * sftp_shutdown - * - * Shutsdown the SFTP subsystem - */ -static int -sftp_shutdown(LIBSSH2_SFTP *sftp) -{ - int rc; - LIBSSH2_SESSION *session = sftp->channel->session; - /* - * Make sure all memory used in the state variables are free - */ - if (sftp->partial_packet) { - LIBSSH2_FREE(session, sftp->partial_packet); - sftp->partial_packet = NULL; - } - if (sftp->open_packet) { - LIBSSH2_FREE(session, sftp->open_packet); - sftp->open_packet = NULL; - } - if (sftp->readdir_packet) { - LIBSSH2_FREE(session, sftp->readdir_packet); - sftp->readdir_packet = NULL; - } - if (sftp->fstat_packet) { - LIBSSH2_FREE(session, sftp->fstat_packet); - sftp->fstat_packet = NULL; - } - if (sftp->unlink_packet) { - LIBSSH2_FREE(session, sftp->unlink_packet); - sftp->unlink_packet = NULL; - } - if (sftp->rename_packet) { - LIBSSH2_FREE(session, sftp->rename_packet); - sftp->rename_packet = NULL; - } - if (sftp->fstatvfs_packet) { - LIBSSH2_FREE(session, sftp->fstatvfs_packet); - sftp->fstatvfs_packet = NULL; - } - if (sftp->statvfs_packet) { - LIBSSH2_FREE(session, sftp->statvfs_packet); - sftp->statvfs_packet = NULL; - } - if (sftp->mkdir_packet) { - LIBSSH2_FREE(session, sftp->mkdir_packet); - sftp->mkdir_packet = NULL; - } - if (sftp->rmdir_packet) { - LIBSSH2_FREE(session, sftp->rmdir_packet); - sftp->rmdir_packet = NULL; - } - if (sftp->stat_packet) { - LIBSSH2_FREE(session, sftp->stat_packet); - sftp->stat_packet = NULL; - } - if (sftp->symlink_packet) { - LIBSSH2_FREE(session, sftp->symlink_packet); - sftp->symlink_packet = NULL; - } - - sftp_packet_flush(sftp); - - /* TODO: We should consider walking over the sftp_handles list and kill - * any remaining sftp handles ... */ - - rc = _libssh2_channel_free(sftp->channel); - - return rc; -} - -/* libssh2_sftp_shutdown - * Shutsdown the SFTP subsystem - */ -LIBSSH2_API int -libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp) -{ - int rc; - if(!sftp) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, sftp_shutdown(sftp)); - return rc; -} - -/* ******************************* - * SFTP File and Directory Ops * - ******************************* */ - -/* sftp_open - */ -static LIBSSH2_SFTP_HANDLE * -sftp_open(LIBSSH2_SFTP *sftp, const char *filename, - size_t filename_len, uint32_t flags, long mode, - int open_type) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - LIBSSH2_SFTP_HANDLE *fp; - LIBSSH2_SFTP_ATTRIBUTES attrs = { - LIBSSH2_SFTP_ATTR_PERMISSIONS, 0, 0, 0, 0, 0, 0 - }; - unsigned char *s; - ssize_t rc; - int open_file = (open_type == LIBSSH2_SFTP_OPENFILE)?1:0; - - if (sftp->open_state == libssh2_NB_state_idle) { - /* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) + - flags(4) */ - sftp->open_packet_len = filename_len + 13 + - (open_file? (4 + sftp_attrsize(LIBSSH2_SFTP_ATTR_PERMISSIONS)) : 0); - - /* surprise! this starts out with nothing sent */ - sftp->open_packet_sent = 0; - s = sftp->open_packet = LIBSSH2_ALLOC(session, sftp->open_packet_len); - if (!sftp->open_packet) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_OPEN or " - "FXP_OPENDIR packet"); - return NULL; - } - /* Filetype in SFTP 3 and earlier */ - attrs.permissions = mode | - (open_file ? LIBSSH2_SFTP_ATTR_PFILETYPE_FILE : - LIBSSH2_SFTP_ATTR_PFILETYPE_DIR); - - _libssh2_store_u32(&s, sftp->open_packet_len - 4); - *(s++) = open_file? SSH_FXP_OPEN : SSH_FXP_OPENDIR; - sftp->open_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->open_request_id); - _libssh2_store_str(&s, filename, filename_len); - - if (open_file) { - _libssh2_store_u32(&s, flags); - s += sftp_attr2bin(s, &attrs); - } - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Sending %s open request", - open_file? "file" : "directory"); - - sftp->open_state = libssh2_NB_state_created; - } - - if (sftp->open_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->open_packet+ - sftp->open_packet_sent, - sftp->open_packet_len - - sftp->open_packet_sent); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block sending FXP_OPEN or FXP_OPENDIR command"); - return NULL; - } - else if(rc < 0) { - _libssh2_error(session, rc, "Unable to send FXP_OPEN*"); - LIBSSH2_FREE(session, sftp->open_packet); - sftp->open_packet = NULL; - sftp->open_state = libssh2_NB_state_idle; - return NULL; - } - - /* bump the sent counter and remain in this state until the whole - data is off */ - sftp->open_packet_sent += rc; - - if(sftp->open_packet_len == sftp->open_packet_sent) { - LIBSSH2_FREE(session, sftp->open_packet); - sftp->open_packet = NULL; - - sftp->open_state = libssh2_NB_state_sent; - } - } - - if (sftp->open_state == libssh2_NB_state_sent) { - size_t data_len; - unsigned char *data; - static const unsigned char fopen_responses[2] = - { SSH_FXP_HANDLE, SSH_FXP_STATUS }; - rc = sftp_packet_requirev(sftp, 2, fopen_responses, - sftp->open_request_id, &data, - &data_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting for status message"); - return NULL; - } - sftp->open_state = libssh2_NB_state_idle; - if (rc) { - _libssh2_error(session, rc, "Timeout waiting for status message"); - return NULL; - } - - /* OPEN can basically get STATUS or HANDLE back, where HANDLE implies - a fine response while STATUS means error. It seems though that at - times we get an SSH_FX_OK back in a STATUS, followed the "real" - HANDLE so we need to properly deal with that. */ - if (data[0] == SSH_FXP_STATUS) { - int badness = 1; - - if(data_len < 9) { - _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Too small FXP_STATUS"); - LIBSSH2_FREE(session, data); - return NULL; - } - - sftp->last_errno = _libssh2_ntohu32(data + 5); - - if(LIBSSH2_FX_OK == sftp->last_errno) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "got HANDLE FXOK!"); - - LIBSSH2_FREE(session, data); - - /* silly situation, but check for a HANDLE */ - rc = sftp_packet_require(sftp, SSH_FXP_HANDLE, - sftp->open_request_id, &data, - &data_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - /* go back to sent state and wait for something else */ - sftp->open_state = libssh2_NB_state_sent; - return NULL; - } - else if(!rc) - /* we got the handle so this is not a bad situation */ - badness = 0; - } - - if(badness) { - _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Failed opening remote file"); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "got FXP_STATUS %d", - sftp->last_errno); - LIBSSH2_FREE(session, data); - return NULL; - } - } - - if(data_len < 10) { - _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Too small FXP_HANDLE"); - LIBSSH2_FREE(session, data); - return NULL; - } - - fp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP_HANDLE)); - if (!fp) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate new SFTP handle structure"); - LIBSSH2_FREE(session, data); - return NULL; - } - memset(fp, 0, sizeof(LIBSSH2_SFTP_HANDLE)); - fp->handle_type = open_file ? LIBSSH2_SFTP_HANDLE_FILE : - LIBSSH2_SFTP_HANDLE_DIR; - - fp->handle_len = _libssh2_ntohu32(data + 5); - if (fp->handle_len > SFTP_HANDLE_MAXLEN) - /* SFTP doesn't allow handles longer than 256 characters */ - fp->handle_len = SFTP_HANDLE_MAXLEN; - - if(fp->handle_len > (data_len - 9)) - /* do not reach beyond the end of the data we got */ - fp->handle_len = data_len - 9; - - memcpy(fp->handle, data + 9, fp->handle_len); - - LIBSSH2_FREE(session, data); - - /* add this file handle to the list kept in the sftp session */ - _libssh2_list_add(&sftp->sftp_handles, &fp->node); - - fp->sftp = sftp; /* point to the parent struct */ - - fp->u.file.offset = 0; - fp->u.file.offset_sent = 0; - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Open command successful"); - return fp; - } - return NULL; -} - -/* libssh2_sftp_open_ex - */ -LIBSSH2_API LIBSSH2_SFTP_HANDLE * -libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, const char *filename, - unsigned int filename_len, unsigned long flags, long mode, - int open_type) -{ - LIBSSH2_SFTP_HANDLE *hnd; - - if(!sftp) - return NULL; - - BLOCK_ADJUST_ERRNO(hnd, sftp->channel->session, - sftp_open(sftp, filename, filename_len, flags, mode, - open_type)); - return hnd; -} - -/* - * sftp_read - * - * Read from an SFTP file handle - * - */ -static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, - size_t buffer_size) -{ - LIBSSH2_SFTP *sftp = handle->sftp; - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t count = 0; - struct sftp_pipeline_chunk *chunk; - struct sftp_pipeline_chunk *next; - ssize_t rc; - struct _libssh2_sftp_handle_file_data *filep = - &handle->u.file; - - /* This function can be interrupted in three different places where it - might need to wait for data from the network. It returns EAGAIN to - allow non-blocking clients to do other work but these client are - expected to call this function again (possibly many times) to finish - the operation. - - The tricky part is that if we previously aborted a sftp_read due to - EAGAIN, we must continue at the same spot to continue the previously - interrupted operation. This is done using a state machine to record - what phase of execution we were at. The state is stored in - sftp->read_state. - - libssh2_NB_state_idle: The first phase is where we prepare multiple - FXP_READ packets to do optimistic read-ahead. We send off as many as - possible in the second phase without waiting for a response to each - one; this is the key to fast reads. But we may have to adjust the - channel window size to do this which may interrupt this function while - waiting. The state machine saves the phase as libssh2_NB_state_idle so - it returns here on the next call. - - libssh2_NB_state_sent: The second phase is where we send the FXP_READ - packets. Writing them to the channel can be interrupted with EAGAIN - but the state machine ensures we skip the first phase on the next call - and resume sending. - - libssh2_NB_state_sent2: In the third phase (indicated by ) we read the - data from the responses that have arrived so far. Reading can be - interrupted with EAGAIN but the state machine ensures we skip the first - and second phases on the next call and resume sending. - */ - - switch (sftp->read_state) { - case libssh2_NB_state_idle: - - /* Some data may already have been read from the server in the - previous call but didn't fit in the buffer at the time. If so, we - return that now as we can't risk being interrupted later with data - partially written to the buffer. */ - if(filep->data_left) { - size_t copy = MIN(buffer_size, filep->data_left); - - memcpy(buffer, &filep->data[ filep->data_len - filep->data_left], - copy); - - filep->data_left -= copy; - filep->offset += copy; - - if(!filep->data_left) { - LIBSSH2_FREE(session, filep->data); - filep->data = NULL; - } - - return copy; - } - - /* We allow a number of bytes being requested at any given time - without having been acked - until we reach EOF. */ - if(!filep->eof) { - /* Number of bytes asked for that haven't been acked yet */ - size_t already = (filep->offset_sent - filep->offset); - - size_t max_read_ahead = buffer_size*4; - unsigned long recv_window; - - if(max_read_ahead > LIBSSH2_CHANNEL_WINDOW_DEFAULT*4) - max_read_ahead = LIBSSH2_CHANNEL_WINDOW_DEFAULT*4; - - /* if the buffer_size passed in now is smaller than what has - already been sent, we risk getting count become a very large - number */ - if(max_read_ahead > already) - count = max_read_ahead - already; - - /* 'count' is how much more data to ask for, and 'already' is how - much data that already has been asked for but not yet returned. - Specificly, 'count' means how much data that have or will be - asked for by the nodes that are already added to the linked - list. Some of those read requests may not actually have been - sent off successfully yet. - - If 'already' is very large it should be perfectly fine to have - count set to 0 as then we don't have to ask for more data - (right now). - - buffer_size*4 is just picked more or less out of the air. The - idea is that when reading SFTP from a remote server, we send - away multiple read requests guessing that the client will read - more than only this 'buffer_size' amount of memory. So we ask - for maximum buffer_size*4 amount of data so that we can return - them very fast in subsequent calls. - */ - - recv_window = libssh2_channel_window_read_ex(sftp->channel, - NULL, NULL); - if(max_read_ahead > recv_window) { - /* more data will be asked for than what the window currently - allows, expand it! */ - - rc = _libssh2_channel_receive_window_adjust(sftp->channel, - max_read_ahead*8, - 1, NULL); - /* if this returns EAGAIN, we will get back to this function - at next call */ - assert(rc != LIBSSH2_ERROR_EAGAIN || !filep->data_left); - assert(rc != LIBSSH2_ERROR_EAGAIN || !filep->eof); - if (rc) - return rc; - } - } - - while(count > 0) { - unsigned char *s; - uint32_t size = MIN(MAX_SFTP_READ_SIZE, count); - - /* 25 = packet_len(4) + packet_type(1) + request_id(4) + - handle_len(4) + offset(8) + count(4) */ - uint32_t packet_len = (uint32_t)handle->handle_len + 25; - uint32_t request_id; - - chunk = LIBSSH2_ALLOC(session, packet_len + - sizeof(struct sftp_pipeline_chunk)); - if (!chunk) - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "malloc fail for FXP_WRITE"); - - chunk->len = size; - chunk->lefttosend = packet_len; - chunk->sent = 0; - - s = chunk->packet; - - _libssh2_store_u32(&s, packet_len - 4); - *s++ = SSH_FXP_READ; - request_id = sftp->request_id++; - chunk->request_id = request_id; - _libssh2_store_u32(&s, request_id); - _libssh2_store_str(&s, handle->handle, handle->handle_len); - _libssh2_store_u64(&s, filep->offset_sent); - filep->offset_sent += size; /* advance offset at once */ - _libssh2_store_u32(&s, size); - - /* add this new entry LAST in the list */ - _libssh2_list_add(&handle->packet_list, &chunk->node); - count -= size; /* deduct the size we used, as we might have - to create more packets */ - } - - case libssh2_NB_state_sent: - - sftp->read_state = libssh2_NB_state_idle; - - /* move through the READ packets that haven't been sent and send as - many as possible - remember that we don't block */ - chunk = _libssh2_list_first(&handle->packet_list); - - while(chunk) { - if(chunk->lefttosend) { - - rc = _libssh2_channel_write(channel, 0, - &chunk->packet[chunk->sent], - chunk->lefttosend); - if(rc < 0) { - sftp->read_state = libssh2_NB_state_sent; - return rc; - } - - /* remember where to continue sending the next time */ - chunk->lefttosend -= rc; - chunk->sent += rc; - - if(chunk->lefttosend) - /* data left to send, get out of loop */ - break; - } - - /* move on to the next chunk with data to send */ - chunk = _libssh2_list_next(&chunk->node); - } - - case libssh2_NB_state_sent2: - - sftp->read_state = libssh2_NB_state_idle; - - /* - * Count all ACKed packets and act on the contents of them. - */ - chunk = _libssh2_list_first(&handle->packet_list); - - while(chunk) { - unsigned char *data; - size_t data_len; - uint32_t rc32; - static const unsigned char read_responses[2] = { - SSH_FXP_DATA, SSH_FXP_STATUS - }; - - if(chunk->lefttosend) - /* if the chunk still has data left to send, we shouldn't wait - for an ACK for it just yet */ - break; - - rc = sftp_packet_requirev(sftp, 2, read_responses, - chunk->request_id, &data, &data_len); - if (rc < 0) { - sftp->read_state = libssh2_NB_state_sent2; - return rc; - } - - /* - * We get DATA or STATUS back. STATUS can be error, or it is - * FX_EOF when we reach the end of the file. - */ - - switch (data[0]) { - case SSH_FXP_STATUS: - /* remove the chunk we just processed keeping track of the - * next one in case we need it */ - next = _libssh2_list_next(&chunk->node); - _libssh2_list_remove(&chunk->node); - LIBSSH2_FREE(session, chunk); - - /* we must remove all outstanding READ requests, as either we - got an error or we're at end of file */ - sftp_packetlist_flush(handle); - - rc32 = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - - if (rc32 == LIBSSH2_FX_EOF) { - filep->eof = TRUE; - return 0; - } - else { - sftp->last_errno = rc32; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP READ error"); - } - break; - - case SSH_FXP_DATA: - rc32 = _libssh2_ntohu32(data + 5); - if (rc32 > (data_len - 9)) - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol badness"); - - if(rc32 != chunk->len) { - /* a short read does not imply end of file, but we must - adjust the offset_sent since it was advanced with a - full chunk->len before */ - filep->offset_sent -= (chunk->len - rc32); - } - - if(rc32 > buffer_size) { - /* figure out the overlap amount */ - filep->data_left = rc32 - buffer_size; - - /* getting the full packet would overflow the buffer, so - only get the correct amount and keep the remainder */ - rc32 = (uint32_t)buffer_size; - - /* store data to keep for next call */ - filep->data = data; - filep->data_len = data_len; - } - else - filep->data_len = 0; - - /* copy the received data from the received FXP_DATA packet to - the buffer at the correct index */ - memcpy(buffer, data + 9, rc32); - filep->offset += rc32; - - if(filep->data_len == 0) - /* free the allocated data if not stored to keep */ - LIBSSH2_FREE(session, data); - - - /* remove the chunk we just processed keeping track of the - * next one in case we need it */ - next = _libssh2_list_next(&chunk->node); - _libssh2_list_remove(&chunk->node); - LIBSSH2_FREE(session, chunk); - chunk = NULL; - - if(rc32 > 0) { - /* we must return as we wrote some data to the buffer */ - return rc32; - } else { - /* A zero-byte read is not necessarily EOF so we must not - * return 0 (that would signal EOF to the caller) so - * instead we carry on to the next chunk */ - chunk = next; - } - - break; - default: - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol badness: unrecognised " - "read request response"); - } - } - - break; - - default: - assert(!"State machine error; unrecognised read state"); - } - - return 0; -} - -/* libssh2_sftp_read - * Read from an SFTP file handle - */ -LIBSSH2_API ssize_t -libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *hnd, char *buffer, - size_t buffer_maxlen) -{ - ssize_t rc; - if(!hnd) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, hnd->sftp->channel->session, - sftp_read(hnd, buffer, buffer_maxlen)); - return rc; -} - -/* sftp_readdir - * Read from an SFTP directory handle - */ -static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, - size_t buffer_maxlen, char *longentry, - size_t longentry_maxlen, - LIBSSH2_SFTP_ATTRIBUTES *attrs) -{ - LIBSSH2_SFTP *sftp = handle->sftp; - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - uint32_t num_names; - /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */ - uint32_t packet_len = handle->handle_len + 13; - unsigned char *s, *data; - static const unsigned char read_responses[2] = { - SSH_FXP_NAME, SSH_FXP_STATUS }; - ssize_t retcode; - - if (sftp->readdir_state == libssh2_NB_state_idle) { - if (handle->u.dir.names_left) { - /* - * A prior request returned more than one directory entry, - * feed it back from the buffer - */ - LIBSSH2_SFTP_ATTRIBUTES attrs_dummy; - size_t real_longentry_len; - size_t real_filename_len; - size_t filename_len; - size_t longentry_len; - - s = (unsigned char *) handle->u.dir.next_name; - real_filename_len = _libssh2_ntohu32(s); - - s += 4; - - filename_len = real_filename_len; - if (filename_len >= buffer_maxlen) { - filename_len = LIBSSH2_ERROR_BUFFER_TOO_SMALL; - goto end; - } - - memcpy(buffer, s, filename_len); - buffer[filename_len] = '\0'; /* zero terminate */ - s += real_filename_len; - - real_longentry_len = _libssh2_ntohu32(s); - s += 4; - - if (longentry && (longentry_maxlen>1)) { - longentry_len = real_longentry_len; - - if (longentry_len >= longentry_maxlen) { - filename_len = LIBSSH2_ERROR_BUFFER_TOO_SMALL; - goto end; - } - - memcpy(longentry, s, longentry_len); - longentry[longentry_len] = '\0'; /* zero terminate */ - } - s += real_longentry_len; - - if (attrs) - memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); - - s += sftp_bin2attr(attrs ? attrs : &attrs_dummy, s); - - handle->u.dir.next_name = (char *) s; - end: - - if ((--handle->u.dir.names_left) == 0) - LIBSSH2_FREE(session, handle->u.dir.names_packet); - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "libssh2_sftp_readdir_ex() return %d", - filename_len); - return (ssize_t)filename_len; - } - - /* Request another entry(entries?) */ - - s = sftp->readdir_packet = LIBSSH2_ALLOC(session, packet_len); - if (!sftp->readdir_packet) - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "FXP_READDIR packet"); - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = SSH_FXP_READDIR; - sftp->readdir_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->readdir_request_id); - _libssh2_store_str(&s, handle->handle, handle->handle_len); - - sftp->readdir_state = libssh2_NB_state_created; - } - - if (sftp->readdir_state == libssh2_NB_state_created) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Reading entries from directory handle"); - retcode = _libssh2_channel_write(channel, 0, sftp->readdir_packet, - packet_len); - if (retcode == LIBSSH2_ERROR_EAGAIN) { - return retcode; - } - else if ((ssize_t)packet_len != retcode) { - LIBSSH2_FREE(session, sftp->readdir_packet); - sftp->readdir_packet = NULL; - sftp->readdir_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "_libssh2_channel_write() failed"); - } - - LIBSSH2_FREE(session, sftp->readdir_packet); - sftp->readdir_packet = NULL; - - sftp->readdir_state = libssh2_NB_state_sent; - } - - retcode = sftp_packet_requirev(sftp, 2, read_responses, - sftp->readdir_request_id, &data, - &data_len); - if (retcode == LIBSSH2_ERROR_EAGAIN) - return retcode; - else if (retcode) { - sftp->readdir_state = libssh2_NB_state_idle; - return _libssh2_error(session, retcode, - "Timeout waiting for status message"); - } - - if (data[0] == SSH_FXP_STATUS) { - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - if (retcode == LIBSSH2_FX_EOF) { - sftp->readdir_state = libssh2_NB_state_idle; - return 0; - } - else { - sftp->last_errno = retcode; - sftp->readdir_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } - } - - sftp->readdir_state = libssh2_NB_state_idle; - - num_names = _libssh2_ntohu32(data + 5); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%lu entries returned", - num_names); - if (!num_names) { - LIBSSH2_FREE(session, data); - return 0; - } - - handle->u.dir.names_left = num_names; - handle->u.dir.names_packet = data; - handle->u.dir.next_name = (char *) data + 9; - - /* use the name popping mechanism from the start of the function */ - return sftp_readdir(handle, buffer, buffer_maxlen, longentry, - longentry_maxlen, attrs); -} - -/* libssh2_sftp_readdir_ex - * Read from an SFTP directory handle - */ -LIBSSH2_API int -libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *hnd, char *buffer, - size_t buffer_maxlen, char *longentry, - size_t longentry_maxlen, - LIBSSH2_SFTP_ATTRIBUTES *attrs) -{ - int rc; - if(!hnd) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, hnd->sftp->channel->session, - sftp_readdir(hnd, buffer, buffer_maxlen, longentry, - longentry_maxlen, attrs)); - return rc; -} - -/* - * sftp_write - * - * Write data to an SFTP handle. Returns the number of bytes written, or - * a negative error code. - * - * We recommend sending very large data buffers to this function! - * - * Concept: - * - * - Detect how much of the given buffer that was already sent in a previous - * call by inspecting the linked list of outgoing chunks. Make sure to skip - * passed the data that has already been taken care of. - * - * - Split all (new) outgoing data in chunks no larger than N. - * - * - Each N bytes chunk gets created as a separate SFTP packet. - * - * - Add all created outgoing packets to the linked list. - * - * - Walk through the list and send the chunks that haven't been sent, - * as many as possible until EAGAIN. Some of the chunks may have been put - * in the list in a previous invoke. - * - * - For all the chunks in the list that have been completely sent off, check - * for ACKs. If a chunk has been ACKed, it is removed from the linked - * list and the "acked" counter gets increased with that data amount. - * - * - Return TOTAL bytes acked so far. - * - * Caveats: - * - be careful: we must not return a higher number than what was given! - * - * TODO: - * Introduce an option that disables this sort of "speculative" ahead writing - * as there's a risk that it will do harm to some app. - */ - -static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, - size_t count) -{ - LIBSSH2_SFTP *sftp = handle->sftp; - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - uint32_t retcode; - uint32_t packet_len; - unsigned char *s, *data; - ssize_t rc; - struct sftp_pipeline_chunk *chunk; - struct sftp_pipeline_chunk *next; - size_t acked = 0; - size_t org_count = count; - size_t already; - - switch(sftp->write_state) { - default: - case libssh2_NB_state_idle: - - /* Number of bytes sent off that haven't been acked and therefor we - will get passed in here again. - - Also, add up the number of bytes that actually already have been - acked but we haven't been able to return as such yet, so we will - get that data as well passed in here again. - */ - already = (handle->u.file.offset_sent - handle->u.file.offset)+ - handle->u.file.acked; - - if(count >= already) { - /* skip the part already made into packets */ - buffer += already; - count -= already; - } - else - /* there is more data already fine than what we got in this call */ - count = 0; - - sftp->write_state = libssh2_NB_state_idle; - while(count) { - /* TODO: Possibly this should have some logic to prevent a very - very small fraction to be left but lets ignore that for now */ - uint32_t size = MIN(MAX_SFTP_OUTGOING_SIZE, count); - uint32_t request_id; - - /* 25 = packet_len(4) + packet_type(1) + request_id(4) + - handle_len(4) + offset(8) + count(4) */ - packet_len = handle->handle_len + size + 25; - - chunk = LIBSSH2_ALLOC(session, packet_len + - sizeof(struct sftp_pipeline_chunk)); - if (!chunk) - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "malloc fail for FXP_WRITE"); - - chunk->len = size; - chunk->sent = 0; - chunk->lefttosend = packet_len; - - s = chunk->packet; - _libssh2_store_u32(&s, packet_len - 4); - - *(s++) = SSH_FXP_WRITE; - request_id = sftp->request_id++; - chunk->request_id = request_id; - _libssh2_store_u32(&s, request_id); - _libssh2_store_str(&s, handle->handle, handle->handle_len); - _libssh2_store_u64(&s, handle->u.file.offset_sent); - handle->u.file.offset_sent += size; /* advance offset at once */ - _libssh2_store_str(&s, buffer, size); - - /* add this new entry LAST in the list */ - _libssh2_list_add(&handle->packet_list, &chunk->node); - - buffer += size; - count -= size; /* deduct the size we used, as we might have - to create more packets */ - } - - /* move through the WRITE packets that haven't been sent and send as many - as possible - remember that we don't block */ - chunk = _libssh2_list_first(&handle->packet_list); - - while(chunk) { - if(chunk->lefttosend) { - rc = _libssh2_channel_write(channel, 0, - &chunk->packet[chunk->sent], - chunk->lefttosend); - if(rc < 0) - /* remain in idle state */ - return rc; - - /* remember where to continue sending the next time */ - chunk->lefttosend -= rc; - chunk->sent += rc; - - if(chunk->lefttosend) - /* data left to send, get out of loop */ - break; - } - - /* move on to the next chunk with data to send */ - chunk = _libssh2_list_next(&chunk->node); - } - - /* fall-through */ - case libssh2_NB_state_sent: - - sftp->write_state = libssh2_NB_state_idle; - /* - * Count all ACKed packets - */ - chunk = _libssh2_list_first(&handle->packet_list); - - while(chunk) { - if(chunk->lefttosend) - /* if the chunk still has data left to send, we shouldn't wait - for an ACK for it just yet */ - break; - - else if(acked) - /* if we have sent data that is acked, we must return that - info before we call a function that might return EAGAIN */ - break; - - /* we check the packets in order */ - rc = sftp_packet_require(sftp, SSH_FXP_STATUS, - chunk->request_id, &data, &data_len); - if (rc < 0) { - if (rc == LIBSSH2_ERROR_EAGAIN) - sftp->write_state = libssh2_NB_state_sent; - return rc; - } - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - - sftp->last_errno = retcode; - if (retcode == LIBSSH2_FX_OK) { - acked += chunk->len; /* number of payload data that was acked - here */ - - /* we increase the offset value for all acks */ - handle->u.file.offset += chunk->len; - - next = _libssh2_list_next(&chunk->node); - - _libssh2_list_remove(&chunk->node); /* remove from list */ - LIBSSH2_FREE(session, chunk); /* free memory */ - - chunk = next; - } - else { - /* flush all pending packets from the outgoing list */ - sftp_packetlist_flush(handle); - - /* since we return error now, the applicaton will not get any - outstanding data acked, so we need to rewind the offset to - where the application knows it has reached with acked data */ - handle->u.file.offset -= handle->u.file.acked; - - /* then reset the offset_sent to be the same as the offset */ - handle->u.file.offset_sent = handle->u.file.offset; - - /* clear the acked counter since we can have no pending data to - ack after an error */ - handle->u.file.acked = 0; - - /* the server returned an error for that written chunk, propagate - this back to our parent function */ - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "FXP write failed"); - } - } - break; - } - - /* if there were acked data in a previous call that wasn't returned then, - add that up and try to return it all now. This can happen if the app - first sends a huge buffer of data, and then in a second call it sends a - smaller one. */ - acked += handle->u.file.acked; - - if(acked) { - ssize_t ret = MIN(acked, org_count); - /* we got data acked so return that amount, but no more than what - was asked to get sent! */ - - /* store the remainder. 'ret' is always equal to or less than 'acked' - here */ - handle->u.file.acked = acked - ret; - - return ret; - } - - else - return 0; /* nothing was acked, and no EAGAIN was received! */ -} - -/* libssh2_sftp_write - * Write data to a file handle - */ -LIBSSH2_API ssize_t -libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *hnd, const char *buffer, - size_t count) -{ - ssize_t rc; - if(!hnd) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, hnd->sftp->channel->session, - sftp_write(hnd, buffer, count)); - return rc; - -} - -/* - * sftp_fstat - * - * Get or Set stat on a file - */ -static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle, - LIBSSH2_SFTP_ATTRIBUTES *attrs, int setstat) -{ - LIBSSH2_SFTP *sftp = handle->sftp; - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */ - uint32_t packet_len = - handle->handle_len + 13 + (setstat ? sftp_attrsize(attrs->flags) : 0); - unsigned char *s, *data; - static const unsigned char fstat_responses[2] = - { SSH_FXP_ATTRS, SSH_FXP_STATUS }; - ssize_t rc; - - if (sftp->fstat_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Issuing %s command", - setstat ? "set-stat" : "stat"); - s = sftp->fstat_packet = LIBSSH2_ALLOC(session, packet_len); - if (!sftp->fstat_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "FSTAT/FSETSTAT packet"); - } - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = setstat ? SSH_FXP_FSETSTAT : SSH_FXP_FSTAT; - sftp->fstat_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->fstat_request_id); - _libssh2_store_str(&s, handle->handle, handle->handle_len); - - if (setstat) { - s += sftp_attr2bin(s, attrs); - } - - sftp->fstat_state = libssh2_NB_state_created; - } - - if (sftp->fstat_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->fstat_packet, - packet_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if ((ssize_t)packet_len != rc) { - LIBSSH2_FREE(session, sftp->fstat_packet); - sftp->fstat_packet = NULL; - sftp->fstat_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - (setstat ? "Unable to send FXP_FSETSTAT" - : "Unable to send FXP_FSTAT command")); - } - LIBSSH2_FREE(session, sftp->fstat_packet); - sftp->fstat_packet = NULL; - - sftp->fstat_state = libssh2_NB_state_sent; - } - - rc = sftp_packet_requirev(sftp, 2, fstat_responses, - sftp->fstat_request_id, &data, - &data_len); - if (rc == LIBSSH2_ERROR_EAGAIN) - return rc; - else if (rc) { - sftp->fstat_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Timeout waiting for status message"); - } - - sftp->fstat_state = libssh2_NB_state_idle; - - if (data[0] == SSH_FXP_STATUS) { - uint32_t retcode; - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - if (retcode == LIBSSH2_FX_OK) { - return 0; - } else { - sftp->last_errno = retcode; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } - } - - sftp_bin2attr(attrs, data + 5); - LIBSSH2_FREE(session, data); - - return 0; -} - -/* libssh2_sftp_fstat_ex - * Get or Set stat on a file - */ -LIBSSH2_API int -libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *hnd, - LIBSSH2_SFTP_ATTRIBUTES *attrs, int setstat) -{ - int rc; - if(!hnd || !attrs) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, hnd->sftp->channel->session, - sftp_fstat(hnd, attrs, setstat)); - return rc; -} - - -/* libssh2_sftp_seek64 - * Set the read/write pointer to an arbitrary position within the file - */ -LIBSSH2_API void -libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE *handle, libssh2_uint64_t offset) -{ - if(handle) { - handle->u.file.offset = handle->u.file.offset_sent = offset; - /* discard all pending requests and currently read data */ - sftp_packetlist_flush(handle); - - /* free the left received buffered data */ - if (handle->u.file.data_left) { - LIBSSH2_FREE(handle->sftp->channel->session, handle->u.file.data); - handle->u.file.data_left = handle->u.file.data_len = 0; - handle->u.file.data = NULL; - } - - /* reset EOF to False */ - handle->u.file.eof = FALSE; - } -} - -/* libssh2_sftp_seek - * Set the read/write pointer to an arbitrary position within the file - */ -LIBSSH2_API void -libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset) -{ - libssh2_sftp_seek64(handle, (libssh2_uint64_t)offset); -} - -/* libssh2_sftp_tell - * Return the current read/write pointer's offset - */ -LIBSSH2_API size_t -libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle) -{ - if(!handle) - return 0; /* no handle, no size */ - - /* NOTE: this may very well truncate the size if it is larger than what - size_t can hold, so libssh2_sftp_tell64() is really the function you - should use */ - return (size_t)(handle->u.file.offset); -} - -/* libssh2_sftp_tell64 - * Return the current read/write pointer's offset - */ -LIBSSH2_API libssh2_uint64_t -libssh2_sftp_tell64(LIBSSH2_SFTP_HANDLE *handle) -{ - if(!handle) - return 0; /* no handle, no size */ - - return handle->u.file.offset; -} - -/* - * Flush all remaining incoming SFTP packets and zombies. - */ -static void sftp_packet_flush(LIBSSH2_SFTP *sftp) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - LIBSSH2_SFTP_PACKET *packet = _libssh2_list_first(&sftp->packets); - struct sftp_zombie_requests *zombie = - _libssh2_list_first(&sftp->zombie_requests); - - while(packet) { - LIBSSH2_SFTP_PACKET *next; - - /* check next struct in the list */ - next = _libssh2_list_next(&packet->node); - _libssh2_list_remove(&packet->node); - LIBSSH2_FREE(session, packet->data); - LIBSSH2_FREE(session, packet); - - packet = next; - } - - while(zombie) { - /* figure out the next node */ - struct sftp_zombie_requests *next = _libssh2_list_next(&zombie->node); - /* unlink the current one */ - _libssh2_list_remove(&zombie->node); - /* free the memory */ - LIBSSH2_FREE(session, zombie); - zombie = next; - } - -} - -/* sftp_close_handle - * - * Close a file or directory handle - * Also frees handle resource and unlinks it from the SFTP structure - */ -static int -sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle) -{ - LIBSSH2_SFTP *sftp = handle->sftp; - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - int retcode; - /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */ - uint32_t packet_len = handle->handle_len + 13; - unsigned char *s, *data = NULL; - int rc; - - if (handle->close_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Closing handle"); - s = handle->close_packet = LIBSSH2_ALLOC(session, packet_len); - if (!handle->close_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_CLOSE " - "packet"); - } - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = SSH_FXP_CLOSE; - handle->close_request_id = sftp->request_id++; - _libssh2_store_u32(&s, handle->close_request_id); - _libssh2_store_str(&s, handle->handle, handle->handle_len); - handle->close_state = libssh2_NB_state_created; - } - - if (handle->close_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, handle->close_packet, - packet_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if ((ssize_t)packet_len != rc) { - LIBSSH2_FREE(session, handle->close_packet); - handle->close_packet = NULL; - handle->close_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send FXP_CLOSE command"); - } - LIBSSH2_FREE(session, handle->close_packet); - handle->close_packet = NULL; - - handle->close_state = libssh2_NB_state_sent; - } - - if (handle->close_state == libssh2_NB_state_sent) { - rc = sftp_packet_require(sftp, SSH_FXP_STATUS, - handle->close_request_id, &data, - &data_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - handle->close_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Error waiting for status message"); - } - - handle->close_state = libssh2_NB_state_sent1; - } - - if(!data) - /* if it reaches this point with data unset, something unwanted - happened (like this function is called again when in - libssh2_NB_state_sent1 state) and we just bail out */ - return LIBSSH2_ERROR_INVAL; - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - - if (retcode != LIBSSH2_FX_OK) { - sftp->last_errno = retcode; - handle->close_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } - - /* remove this handle from the parent's list */ - _libssh2_list_remove(&handle->node); - - if ((handle->handle_type == LIBSSH2_SFTP_HANDLE_DIR) - && handle->u.dir.names_left) { - LIBSSH2_FREE(session, handle->u.dir.names_packet); - } - else { - if(handle->u.file.data) - LIBSSH2_FREE(session, handle->u.file.data); - } - - sftp_packetlist_flush(handle); - sftp->read_state = libssh2_NB_state_idle; - - handle->close_state = libssh2_NB_state_idle; - - LIBSSH2_FREE(session, handle); - - return 0; -} - -/* libssh2_sftp_close_handle - * - * Close a file or directory handle - * Also frees handle resource and unlinks it from the SFTP structure - */ -LIBSSH2_API int -libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *hnd) -{ - int rc; - if(!hnd) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, hnd->sftp->channel->session, sftp_close_handle(hnd)); - return rc; -} - -/* sftp_unlink - * Delete a file from the remote server - */ -static int sftp_unlink(LIBSSH2_SFTP *sftp, const char *filename, - size_t filename_len) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - int retcode; - /* 13 = packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) */ - uint32_t packet_len = filename_len + 13; - unsigned char *s, *data; - int rc; - - if (sftp->unlink_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Unlinking %s", filename); - s = sftp->unlink_packet = LIBSSH2_ALLOC(session, packet_len); - if (!sftp->unlink_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_REMOVE " - "packet"); - } - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = SSH_FXP_REMOVE; - sftp->unlink_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->unlink_request_id); - _libssh2_store_str(&s, filename, filename_len); - sftp->unlink_state = libssh2_NB_state_created; - } - - if (sftp->unlink_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->unlink_packet, - packet_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if ((ssize_t)packet_len != rc) { - LIBSSH2_FREE(session, sftp->unlink_packet); - sftp->unlink_packet = NULL; - sftp->unlink_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send FXP_REMOVE command"); - } - LIBSSH2_FREE(session, sftp->unlink_packet); - sftp->unlink_packet = NULL; - - sftp->unlink_state = libssh2_NB_state_sent; - } - - rc = sftp_packet_require(sftp, SSH_FXP_STATUS, - sftp->unlink_request_id, &data, - &data_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if (rc) { - sftp->unlink_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Error waiting for FXP STATUS"); - } - - sftp->unlink_state = libssh2_NB_state_idle; - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - - if (retcode == LIBSSH2_FX_OK) { - return 0; - } else { - sftp->last_errno = retcode; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } -} - -/* libssh2_sftp_unlink_ex - * Delete a file from the remote server - */ -LIBSSH2_API int -libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, const char *filename, - unsigned int filename_len) -{ - int rc; - if(!sftp) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, - sftp_unlink(sftp, filename, filename_len)); - return rc; -} - -/* - * sftp_rename - * - * Rename a file on the remote server - */ -static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename, - unsigned int source_filename_len, - const char *dest_filename, - unsigned int dest_filename_len, long flags) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - int retcode; - uint32_t packet_len = - source_filename_len + dest_filename_len + 17 + (sftp->version >= - 5 ? 4 : 0); - /* packet_len(4) + packet_type(1) + request_id(4) + - source_filename_len(4) + dest_filename_len(4) + flags(4){SFTP5+) */ - unsigned char *data; - ssize_t rc; - - if (sftp->version < 2) { - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Server does not support RENAME"); - } - - if (sftp->rename_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Renaming %s to %s", - source_filename, dest_filename); - sftp->rename_s = sftp->rename_packet = - LIBSSH2_ALLOC(session, packet_len); - if (!sftp->rename_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_RENAME " - "packet"); - } - - _libssh2_store_u32(&sftp->rename_s, packet_len - 4); - *(sftp->rename_s++) = SSH_FXP_RENAME; - sftp->rename_request_id = sftp->request_id++; - _libssh2_store_u32(&sftp->rename_s, sftp->rename_request_id); - _libssh2_store_str(&sftp->rename_s, source_filename, - source_filename_len); - _libssh2_store_str(&sftp->rename_s, dest_filename, dest_filename_len); - - if (sftp->version >= 5) - _libssh2_store_u32(&sftp->rename_s, flags); - - sftp->rename_state = libssh2_NB_state_created; - } - - if (sftp->rename_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->rename_packet, - sftp->rename_s - sftp->rename_packet); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if ((ssize_t)packet_len != rc) { - LIBSSH2_FREE(session, sftp->rename_packet); - sftp->rename_packet = NULL; - sftp->rename_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send FXP_RENAME command"); - } - LIBSSH2_FREE(session, sftp->rename_packet); - sftp->rename_packet = NULL; - - sftp->rename_state = libssh2_NB_state_sent; - } - - rc = sftp_packet_require(sftp, SSH_FXP_STATUS, - sftp->rename_request_id, &data, - &data_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - sftp->rename_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Error waiting for FXP STATUS"); - } - - sftp->rename_state = libssh2_NB_state_idle; - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - - sftp->last_errno = retcode; - - /* now convert the SFTP error code to libssh2 return code or error - message */ - switch (retcode) { - case LIBSSH2_FX_OK: - retcode = LIBSSH2_ERROR_NONE; - break; - - case LIBSSH2_FX_FILE_ALREADY_EXISTS: - retcode = _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "File already exists and " - "SSH_FXP_RENAME_OVERWRITE not specified"); - break; - - case LIBSSH2_FX_OP_UNSUPPORTED: - retcode = _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Operation Not Supported"); - break; - - default: - retcode = _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - break; - } - - return retcode; -} - -/* libssh2_sftp_rename_ex - * Rename a file on the remote server - */ -LIBSSH2_API int -libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, const char *source_filename, - unsigned int source_filename_len, - const char *dest_filename, - unsigned int dest_filename_len, long flags) -{ - int rc; - if(!sftp) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, - sftp_rename(sftp, source_filename, source_filename_len, - dest_filename, dest_filename_len, flags)); - return rc; -} - -/* - * sftp_fstatvfs - * - * Get file system statistics - */ -static int sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) -{ - LIBSSH2_SFTP *sftp = handle->sftp; - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - /* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4) - + handle_len (4) */ - /* 20 = strlen ("fstatvfs@openssh.com") */ - uint32_t packet_len = handle->handle_len + 20 + 17; - unsigned char *packet, *s, *data; - ssize_t rc; - unsigned int flag; - - if (sftp->fstatvfs_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Getting file system statistics"); - s = packet = LIBSSH2_ALLOC(session, packet_len); - if (!packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_EXTENDED " - "packet"); - } - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = SSH_FXP_EXTENDED; - sftp->fstatvfs_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->fstatvfs_request_id); - _libssh2_store_str(&s, "fstatvfs@openssh.com", 20); - _libssh2_store_str(&s, handle->handle, handle->handle_len); - - sftp->fstatvfs_state = libssh2_NB_state_created; - } - else { - packet = sftp->fstatvfs_packet; - } - - if (sftp->fstatvfs_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, packet, packet_len); - if (rc == LIBSSH2_ERROR_EAGAIN || - (0 <= rc && rc < (ssize_t)packet_len)) { - sftp->fstatvfs_packet = packet; - return LIBSSH2_ERROR_EAGAIN; - } - - LIBSSH2_FREE(session, packet); - sftp->fstatvfs_packet = NULL; - - if (rc < 0) { - sftp->fstatvfs_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "_libssh2_channel_write() failed"); - } - sftp->fstatvfs_state = libssh2_NB_state_sent; - } - - rc = sftp_packet_require(sftp, SSH_FXP_EXTENDED_REPLY, - sftp->fstatvfs_request_id, &data, &data_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - sftp->fstatvfs_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Error waiting for FXP EXTENDED REPLY"); - } else if (data_len < 93) { - LIBSSH2_FREE(session, data); - sftp->fstatvfs_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error: short response"); - } - - sftp->fstatvfs_state = libssh2_NB_state_idle; - - st->f_bsize = _libssh2_ntohu64(data + 5); - st->f_frsize = _libssh2_ntohu64(data + 13); - st->f_blocks = _libssh2_ntohu64(data + 21); - st->f_bfree = _libssh2_ntohu64(data + 29); - st->f_bavail = _libssh2_ntohu64(data + 37); - st->f_files = _libssh2_ntohu64(data + 45); - st->f_ffree = _libssh2_ntohu64(data + 53); - st->f_favail = _libssh2_ntohu64(data + 61); - st->f_fsid = _libssh2_ntohu64(data + 69); - flag = _libssh2_ntohu64(data + 77); - st->f_namemax = _libssh2_ntohu64(data + 85); - - st->f_flag = (flag & SSH_FXE_STATVFS_ST_RDONLY) - ? LIBSSH2_SFTP_ST_RDONLY : 0; - st->f_flag |= (flag & SSH_FXE_STATVFS_ST_NOSUID) - ? LIBSSH2_SFTP_ST_NOSUID : 0; - - LIBSSH2_FREE(session, data); - return 0; -} - -/* libssh2_sftp_fstatvfs - * Get filesystem space and inode utilization (requires fstatvfs@openssh.com - * support on the server) - */ -LIBSSH2_API int -libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) -{ - int rc; - if(!handle || !st) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, handle->sftp->channel->session, sftp_fstatvfs(handle, st)); - return rc; -} - -/* - * sftp_statvfs - * - * Get file system statistics - */ -static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len, LIBSSH2_SFTP_STATVFS *st) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - /* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4) - + path_len (4) */ - /* 19 = strlen ("statvfs@openssh.com") */ - uint32_t packet_len = path_len + 19 + 17; - unsigned char *packet, *s, *data; - ssize_t rc; - unsigned int flag; - - if (sftp->statvfs_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Getting file system statistics of %s", path); - s = packet = LIBSSH2_ALLOC(session, packet_len); - if (!packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_EXTENDED " - "packet"); - } - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = SSH_FXP_EXTENDED; - sftp->statvfs_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->statvfs_request_id); - _libssh2_store_str(&s, "statvfs@openssh.com", 19); - _libssh2_store_str(&s, path, path_len); - - sftp->statvfs_state = libssh2_NB_state_created; - } - else { - packet = sftp->statvfs_packet; - } - - if (sftp->statvfs_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, packet, packet_len); - if (rc == LIBSSH2_ERROR_EAGAIN || - (0 <= rc && rc < (ssize_t)packet_len)) { - sftp->statvfs_packet = packet; - return LIBSSH2_ERROR_EAGAIN; - } - - LIBSSH2_FREE(session, packet); - sftp->statvfs_packet = NULL; - - if (rc < 0) { - sftp->statvfs_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "_libssh2_channel_write() failed"); - } - sftp->statvfs_state = libssh2_NB_state_sent; - } - - rc = sftp_packet_require(sftp, SSH_FXP_EXTENDED_REPLY, - sftp->statvfs_request_id, &data, &data_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - sftp->statvfs_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Error waiting for FXP EXTENDED REPLY"); - } else if (data_len < 93) { - LIBSSH2_FREE(session, data); - sftp->fstatvfs_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error: short response"); - } - - sftp->statvfs_state = libssh2_NB_state_idle; - - st->f_bsize = _libssh2_ntohu64(data + 5); - st->f_frsize = _libssh2_ntohu64(data + 13); - st->f_blocks = _libssh2_ntohu64(data + 21); - st->f_bfree = _libssh2_ntohu64(data + 29); - st->f_bavail = _libssh2_ntohu64(data + 37); - st->f_files = _libssh2_ntohu64(data + 45); - st->f_ffree = _libssh2_ntohu64(data + 53); - st->f_favail = _libssh2_ntohu64(data + 61); - st->f_fsid = _libssh2_ntohu64(data + 69); - flag = _libssh2_ntohu64(data + 77); - st->f_namemax = _libssh2_ntohu64(data + 85); - - st->f_flag = (flag & SSH_FXE_STATVFS_ST_RDONLY) - ? LIBSSH2_SFTP_ST_RDONLY : 0; - st->f_flag |= (flag & SSH_FXE_STATVFS_ST_NOSUID) - ? LIBSSH2_SFTP_ST_NOSUID : 0; - - LIBSSH2_FREE(session, data); - return 0; -} - -/* libssh2_sftp_statvfs_ex - * Get filesystem space and inode utilization (requires statvfs@openssh.com - * support on the server) - */ -LIBSSH2_API int -libssh2_sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, - size_t path_len, LIBSSH2_SFTP_STATVFS *st) -{ - int rc; - if(!sftp || !st) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, sftp_statvfs(sftp, path, path_len, - st)); - return rc; -} - - -/* - * sftp_mkdir - * - * Create an SFTP directory - */ -static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len, long mode) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - LIBSSH2_SFTP_ATTRIBUTES attrs = { - LIBSSH2_SFTP_ATTR_PERMISSIONS, 0, 0, 0, 0, 0, 0 - }; - size_t data_len; - int retcode; - /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ - ssize_t packet_len = path_len + 13 + - sftp_attrsize(LIBSSH2_SFTP_ATTR_PERMISSIONS); - unsigned char *packet, *s, *data; - int rc; - - if (sftp->mkdir_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Creating directory %s with mode 0%lo", path, mode); - s = packet = LIBSSH2_ALLOC(session, packet_len); - if (!packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_MKDIR " - "packet"); - } - /* Filetype in SFTP 3 and earlier */ - attrs.permissions = mode | LIBSSH2_SFTP_ATTR_PFILETYPE_DIR; - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = SSH_FXP_MKDIR; - sftp->mkdir_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->mkdir_request_id); - _libssh2_store_str(&s, path, path_len); - - s += sftp_attr2bin(s, &attrs); - - sftp->mkdir_state = libssh2_NB_state_created; - } - else { - packet = sftp->mkdir_packet; - } - - if (sftp->mkdir_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, packet, packet_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - sftp->mkdir_packet = packet; - return rc; - } - if (packet_len != rc) { - LIBSSH2_FREE(session, packet); - sftp->mkdir_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "_libssh2_channel_write() failed"); - } - LIBSSH2_FREE(session, packet); - sftp->mkdir_state = libssh2_NB_state_sent; - sftp->mkdir_packet = NULL; - } - - rc = sftp_packet_require(sftp, SSH_FXP_STATUS, sftp->mkdir_request_id, - &data, &data_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - sftp->mkdir_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Error waiting for FXP STATUS"); - } - - sftp->mkdir_state = libssh2_NB_state_idle; - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - - if (retcode == LIBSSH2_FX_OK) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "OK!"); - return 0; - } else { - sftp->last_errno = retcode; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } -} - -/* - * libssh2_sftp_mkdir_ex - * - * Create an SFTP directory - */ -LIBSSH2_API int -libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len, long mode) -{ - int rc; - if(!sftp) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, - sftp_mkdir(sftp, path, path_len, mode)); - return rc; -} - -/* sftp_rmdir - * Remove a directory - */ -static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - int retcode; - /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ - ssize_t packet_len = path_len + 13; - unsigned char *s, *data; - int rc; - - if (sftp->rmdir_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Removing directory: %s", - path); - s = sftp->rmdir_packet = LIBSSH2_ALLOC(session, packet_len); - if (!sftp->rmdir_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_RMDIR " - "packet"); - } - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = SSH_FXP_RMDIR; - sftp->rmdir_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->rmdir_request_id); - _libssh2_store_str(&s, path, path_len); - - sftp->rmdir_state = libssh2_NB_state_created; - } - - if (sftp->rmdir_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->rmdir_packet, - packet_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (packet_len != rc) { - LIBSSH2_FREE(session, sftp->rmdir_packet); - sftp->rmdir_packet = NULL; - sftp->rmdir_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send FXP_RMDIR command"); - } - LIBSSH2_FREE(session, sftp->rmdir_packet); - sftp->rmdir_packet = NULL; - - sftp->rmdir_state = libssh2_NB_state_sent; - } - - rc = sftp_packet_require(sftp, SSH_FXP_STATUS, - sftp->rmdir_request_id, &data, &data_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (rc) { - sftp->rmdir_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Error waiting for FXP STATUS"); - } - - sftp->rmdir_state = libssh2_NB_state_idle; - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - - if (retcode == LIBSSH2_FX_OK) { - return 0; - } else { - sftp->last_errno = retcode; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } -} - -/* libssh2_sftp_rmdir_ex - * Remove a directory - */ -LIBSSH2_API int -libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len) -{ - int rc; - if(!sftp) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, - sftp_rmdir(sftp, path, path_len)); - return rc; -} - -/* sftp_stat - * Stat a file or symbolic link - */ -static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len, int stat_type, - LIBSSH2_SFTP_ATTRIBUTES * attrs) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ - ssize_t packet_len = - path_len + 13 + - ((stat_type == - LIBSSH2_SFTP_SETSTAT) ? sftp_attrsize(attrs->flags) : 0); - unsigned char *s, *data; - static const unsigned char stat_responses[2] = - { SSH_FXP_ATTRS, SSH_FXP_STATUS }; - int rc; - - if (sftp->stat_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%s %s", - (stat_type == LIBSSH2_SFTP_SETSTAT) ? "Set-statting" : - (stat_type == - LIBSSH2_SFTP_LSTAT ? "LStatting" : "Statting"), path); - s = sftp->stat_packet = LIBSSH2_ALLOC(session, packet_len); - if (!sftp->stat_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_*STAT " - "packet"); - } - - _libssh2_store_u32(&s, packet_len - 4); - - switch (stat_type) { - case LIBSSH2_SFTP_SETSTAT: - *(s++) = SSH_FXP_SETSTAT; - break; - - case LIBSSH2_SFTP_LSTAT: - *(s++) = SSH_FXP_LSTAT; - break; - - case LIBSSH2_SFTP_STAT: - default: - *(s++) = SSH_FXP_STAT; - } - sftp->stat_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->stat_request_id); - _libssh2_store_str(&s, path, path_len); - - if (stat_type == LIBSSH2_SFTP_SETSTAT) - s += sftp_attr2bin(s, attrs); - - sftp->stat_state = libssh2_NB_state_created; - } - - if (sftp->stat_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->stat_packet, packet_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } else if (packet_len != rc) { - LIBSSH2_FREE(session, sftp->stat_packet); - sftp->stat_packet = NULL; - sftp->stat_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send STAT/LSTAT/SETSTAT command"); - } - LIBSSH2_FREE(session, sftp->stat_packet); - sftp->stat_packet = NULL; - - sftp->stat_state = libssh2_NB_state_sent; - } - - rc = sftp_packet_requirev(sftp, 2, stat_responses, - sftp->stat_request_id, &data, &data_len); - if (rc == LIBSSH2_ERROR_EAGAIN) - return rc; - else if (rc) { - sftp->stat_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Timeout waiting for status message"); - } - - sftp->stat_state = libssh2_NB_state_idle; - - if (data[0] == SSH_FXP_STATUS) { - int retcode; - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - if (retcode == LIBSSH2_FX_OK) { - return 0; - } else { - sftp->last_errno = retcode; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } - } - - memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); - sftp_bin2attr(attrs, data + 5); - LIBSSH2_FREE(session, data); - - return 0; -} - -/* libssh2_sftp_stat_ex - * Stat a file or symbolic link - */ -LIBSSH2_API int -libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len, int stat_type, - LIBSSH2_SFTP_ATTRIBUTES *attrs) -{ - int rc; - if(!sftp) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, - sftp_stat(sftp, path, path_len, stat_type, attrs)); - return rc; -} - -/* sftp_symlink - * Read or set a symlink - */ -static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len, char *target, - unsigned int target_len, int link_type) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len, link_len; - /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ - ssize_t packet_len = - path_len + 13 + - ((link_type == LIBSSH2_SFTP_SYMLINK) ? (4 + target_len) : 0); - unsigned char *s, *data; - static const unsigned char link_responses[2] = - { SSH_FXP_NAME, SSH_FXP_STATUS }; - int retcode; - - if ((sftp->version < 3) && (link_type != LIBSSH2_SFTP_REALPATH)) { - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Server does not support SYMLINK or READLINK"); - } - - if (sftp->symlink_state == libssh2_NB_state_idle) { - s = sftp->symlink_packet = LIBSSH2_ALLOC(session, packet_len); - if (!sftp->symlink_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "SYMLINK/READLINK/REALPATH packet"); - } - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%s %s on %s", - (link_type == - LIBSSH2_SFTP_SYMLINK) ? "Creating" : "Reading", - (link_type == - LIBSSH2_SFTP_REALPATH) ? "realpath" : "symlink", path); - - _libssh2_store_u32(&s, packet_len - 4); - - switch (link_type) { - case LIBSSH2_SFTP_REALPATH: - *(s++) = SSH_FXP_REALPATH; - break; - - case LIBSSH2_SFTP_SYMLINK: - *(s++) = SSH_FXP_SYMLINK; - break; - - case LIBSSH2_SFTP_READLINK: - default: - *(s++) = SSH_FXP_READLINK; - } - sftp->symlink_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->symlink_request_id); - _libssh2_store_str(&s, path, path_len); - - if (link_type == LIBSSH2_SFTP_SYMLINK) - _libssh2_store_str(&s, target, target_len); - - sftp->symlink_state = libssh2_NB_state_created; - } - - if (sftp->symlink_state == libssh2_NB_state_created) { - ssize_t rc = _libssh2_channel_write(channel, 0, sftp->symlink_packet, - packet_len); - if (rc == LIBSSH2_ERROR_EAGAIN) - return rc; - else if (packet_len != rc) { - LIBSSH2_FREE(session, sftp->symlink_packet); - sftp->symlink_packet = NULL; - sftp->symlink_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send SYMLINK/READLINK command"); - } - LIBSSH2_FREE(session, sftp->symlink_packet); - sftp->symlink_packet = NULL; - - sftp->symlink_state = libssh2_NB_state_sent; - } - - retcode = sftp_packet_requirev(sftp, 2, link_responses, - sftp->symlink_request_id, &data, - &data_len); - if (retcode == LIBSSH2_ERROR_EAGAIN) - return retcode; - else if (retcode) { - sftp->symlink_state = libssh2_NB_state_idle; - return _libssh2_error(session, retcode, - "Error waiting for status message"); - } - - sftp->symlink_state = libssh2_NB_state_idle; - - if (data[0] == SSH_FXP_STATUS) { - int retcode; - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - if (retcode == LIBSSH2_FX_OK) - return LIBSSH2_ERROR_NONE; - else { - sftp->last_errno = retcode; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } - } - - if (_libssh2_ntohu32(data + 5) < 1) { - LIBSSH2_FREE(session, data); - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Invalid READLINK/REALPATH response, " - "no name entries"); - } - - /* this reads a u32 and stores it into a signed 32bit value */ - link_len = _libssh2_ntohu32(data + 9); - if (link_len < target_len) { - memcpy(target, data + 13, link_len); - target[link_len] = 0; - retcode = (int)link_len; - } - else - retcode = LIBSSH2_ERROR_BUFFER_TOO_SMALL; - LIBSSH2_FREE(session, data); - - return retcode; -} - -/* libssh2_sftp_symlink_ex - * Read or set a symlink - */ -LIBSSH2_API int -libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len, char *target, - unsigned int target_len, int link_type) -{ - int rc; - if(!sftp) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, - sftp_symlink(sftp, path, path_len, target, target_len, - link_type)); - return rc; -} - -/* libssh2_sftp_last_error - * Returns the last error code reported by SFTP - */ -LIBSSH2_API unsigned long -libssh2_sftp_last_error(LIBSSH2_SFTP *sftp) -{ - if(!sftp) - return 0; - - return sftp->last_errno; -} - -/* libssh2_sftp_get_channel - * Return the channel of sftp, then caller can control the channel's behavior. - */ -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_sftp_get_channel(LIBSSH2_SFTP *sftp) -{ - if (!sftp) - return NULL; - - return sftp->channel; -} diff --git a/vendor/libssh2-1.4.2/src/sftp.h b/vendor/libssh2-1.4.2/src/sftp.h deleted file mode 100644 index 55bdb46..0000000 --- a/vendor/libssh2-1.4.2/src/sftp.h +++ /dev/null @@ -1,230 +0,0 @@ -#ifndef _LIBSSH2_SFTP_H -#define _LIBSSH2_SFTP_H -/* - * Copyright (C) 2010 - 2012 by Daniel Stenberg - * Author: Daniel Stenberg - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - */ - -/* - * MAX_SFTP_OUTGOING_SIZE MUST not be larger than 32500 or so. This is the - * amount of data sent in each FXP_WRITE packet - */ -#define MAX_SFTP_OUTGOING_SIZE 30000 - -/* MAX_SFTP_READ_SIZE is how much data is asked for at max in each FXP_READ - * packets. - */ -#define MAX_SFTP_READ_SIZE 2000 - -struct sftp_pipeline_chunk { - struct list_node node; - size_t len; /* WRITE: size of the data to write - READ: how many bytes that was asked for */ - size_t sent; - ssize_t lefttosend; /* if 0, the entire packet has been sent off */ - uint32_t request_id; - unsigned char packet[1]; /* data */ -}; - -struct sftp_zombie_requests { - struct list_node node; - uint32_t request_id; -}; - -#ifndef MIN -#define MIN(x,y) ((x)<(y)?(x):(y)) -#endif - -struct _LIBSSH2_SFTP_PACKET -{ - struct list_node node; /* linked list header */ - uint32_t request_id; - unsigned char *data; - size_t data_len; /* payload size */ -}; - -typedef struct _LIBSSH2_SFTP_PACKET LIBSSH2_SFTP_PACKET; - -#define SFTP_HANDLE_MAXLEN 256 /* according to spec! */ - -struct _LIBSSH2_SFTP_HANDLE -{ - struct list_node node; - - LIBSSH2_SFTP *sftp; - - char handle[SFTP_HANDLE_MAXLEN]; - size_t handle_len; - - enum { - LIBSSH2_SFTP_HANDLE_FILE, - LIBSSH2_SFTP_HANDLE_DIR - } handle_type; - - union _libssh2_sftp_handle_data - { - struct _libssh2_sftp_handle_file_data - { - libssh2_uint64_t offset; - libssh2_uint64_t offset_sent; - size_t acked; /* container for acked data that hasn't been - returned to caller yet, used for sftp_write */ - - /* 'data' is used by sftp_read() and is allocated data that has - been received already from the server but wasn't returned to - the caller yet. It is of size 'data_len' and 'data_left is the - number of bytes not yet returned, counted from the end of the - buffer. */ - unsigned char *data; - size_t data_len; - size_t data_left; - - char eof; /* we have read to the end */ - } file; - struct _libssh2_sftp_handle_dir_data - { - uint32_t names_left; - void *names_packet; - char *next_name; - } dir; - } u; - - /* State variables used in libssh2_sftp_close_handle() */ - libssh2_nonblocking_states close_state; - uint32_t close_request_id; - unsigned char *close_packet; - - /* list of outstanding packets sent to server */ - struct list_head packet_list; - -}; - -struct _LIBSSH2_SFTP -{ - LIBSSH2_CHANNEL *channel; - - uint32_t request_id, version; - - struct list_head packets; - - /* List of FXP_READ responses to ignore because EOF already received. */ - struct list_head zombie_requests; - - /* a list of _LIBSSH2_SFTP_HANDLE structs */ - struct list_head sftp_handles; - - uint32_t last_errno; - - /* Holder for partial packet, use in libssh2_sftp_packet_read() */ - unsigned char partial_size[4]; /* buffer for size field */ - size_t partial_size_len; /* size field length */ - unsigned char *partial_packet; /* The data */ - uint32_t partial_len; /* Desired number of bytes */ - size_t partial_received; /* Bytes received so far */ - - /* Time that libssh2_sftp_packet_requirev() started reading */ - time_t requirev_start; - - /* State variables used in libssh2_sftp_open_ex() */ - libssh2_nonblocking_states open_state; - unsigned char *open_packet; - uint32_t open_packet_len; /* 32 bit on the wire */ - size_t open_packet_sent; - uint32_t open_request_id; - - /* State variable used in sftp_read() */ - libssh2_nonblocking_states read_state; - - /* State variable used in sftp_packet_read() */ - libssh2_nonblocking_states packet_state; - - /* State variable used in sftp_write() */ - libssh2_nonblocking_states write_state; - - /* State variables used in libssh2_sftp_readdir() */ - libssh2_nonblocking_states readdir_state; - unsigned char *readdir_packet; - uint32_t readdir_request_id; - - /* State variables used in libssh2_sftp_fstat_ex() */ - libssh2_nonblocking_states fstat_state; - unsigned char *fstat_packet; - uint32_t fstat_request_id; - - /* State variables used in libssh2_sftp_unlink_ex() */ - libssh2_nonblocking_states unlink_state; - unsigned char *unlink_packet; - uint32_t unlink_request_id; - - /* State variables used in libssh2_sftp_rename_ex() */ - libssh2_nonblocking_states rename_state; - unsigned char *rename_packet; - unsigned char *rename_s; - uint32_t rename_request_id; - - /* State variables used in libssh2_sftp_fstatvfs() */ - libssh2_nonblocking_states fstatvfs_state; - unsigned char *fstatvfs_packet; - uint32_t fstatvfs_request_id; - - /* State variables used in libssh2_sftp_statvfs() */ - libssh2_nonblocking_states statvfs_state; - unsigned char *statvfs_packet; - uint32_t statvfs_request_id; - - /* State variables used in libssh2_sftp_mkdir() */ - libssh2_nonblocking_states mkdir_state; - unsigned char *mkdir_packet; - uint32_t mkdir_request_id; - - /* State variables used in libssh2_sftp_rmdir() */ - libssh2_nonblocking_states rmdir_state; - unsigned char *rmdir_packet; - uint32_t rmdir_request_id; - - /* State variables used in libssh2_sftp_stat() */ - libssh2_nonblocking_states stat_state; - unsigned char *stat_packet; - uint32_t stat_request_id; - - /* State variables used in libssh2_sftp_symlink() */ - libssh2_nonblocking_states symlink_state; - unsigned char *symlink_packet; - uint32_t symlink_request_id; -}; - -#endif diff --git a/vendor/libssh2-1.4.2/src/transport.c b/vendor/libssh2-1.4.2/src/transport.c deleted file mode 100644 index 95b9a3a..0000000 --- a/vendor/libssh2-1.4.2/src/transport.c +++ /dev/null @@ -1,873 +0,0 @@ -/* Copyright (C) 2007 The Written Word, Inc. All rights reserved. - * Copyright (C) 2009-2010 by Daniel Stenberg - * Author: Daniel Stenberg - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file handles reading and writing to the SECSH transport layer. RFC4253. - */ - -#include "libssh2_priv.h" -#include -#include -#include -#ifdef LIBSSH2DEBUG -#include -#endif - -#include - -#include "transport.h" -#include "mac.h" - -#define MAX_BLOCKSIZE 32 /* MUST fit biggest crypto block size we use/get */ -#define MAX_MACSIZE 20 /* MUST fit biggest MAC length we support */ - -#ifdef LIBSSH2DEBUG -#define UNPRINTABLE_CHAR '.' -static void -debugdump(LIBSSH2_SESSION * session, - const char *desc, const unsigned char *ptr, size_t size) -{ - size_t i; - size_t c; - unsigned int width = 0x10; - char buffer[256]; /* Must be enough for width*4 + about 30 or so */ - size_t used; - static const char* hex_chars = "0123456789ABCDEF"; - - if (!(session->showmask & LIBSSH2_TRACE_TRANS)) { - /* not asked for, bail out */ - return; - } - - used = snprintf(buffer, sizeof(buffer), "=> %s (%d bytes)\n", - desc, (int) size); - if (session->tracehandler) - (session->tracehandler)(session, session->tracehandler_context, - buffer, used); - else - fprintf(stderr, "%s", buffer); - - for(i = 0; i < size; i += width) { - - used = snprintf(buffer, sizeof(buffer), "%04lx: ", (long)i); - - /* hex not disabled, show it */ - for(c = 0; c < width; c++) { - if (i + c < size) { - buffer[used++] = hex_chars[(ptr[i+c] >> 4) & 0xF]; - buffer[used++] = hex_chars[ptr[i+c] & 0xF]; - } - else { - buffer[used++] = ' '; - buffer[used++] = ' '; - } - - buffer[used++] = ' '; - if ((width/2) - 1 == c) - buffer[used++] = ' '; - } - - buffer[used++] = ':'; - buffer[used++] = ' '; - - for(c = 0; (c < width) && (i + c < size); c++) { - buffer[used++] = isprint(ptr[i + c]) ? - ptr[i + c] : UNPRINTABLE_CHAR; - } - buffer[used++] = '\n'; - buffer[used] = 0; - - if (session->tracehandler) - (session->tracehandler)(session, session->tracehandler_context, - buffer, used); - else - fprintf(stderr, "%s", buffer); - } -} -#else -#define debugdump(a,x,y,z) -#endif - - -/* decrypt() decrypts 'len' bytes from 'source' to 'dest'. - * - * returns 0 on success and negative on failure - */ - -static int -decrypt(LIBSSH2_SESSION * session, unsigned char *source, - unsigned char *dest, int len) -{ - struct transportpacket *p = &session->packet; - int blocksize = session->remote.crypt->blocksize; - - /* if we get called with a len that isn't an even number of blocksizes - we risk losing those extra bytes */ - assert((len % blocksize) == 0); - - while (len >= blocksize) { - if (session->remote.crypt->crypt(session, source, - &session->remote.crypt_abstract)) { - LIBSSH2_FREE(session, p->payload); - return LIBSSH2_ERROR_DECRYPT; - } - - /* if the crypt() function would write to a given address it - wouldn't have to memcpy() and we could avoid this memcpy() - too */ - memcpy(dest, source, blocksize); - - len -= blocksize; /* less bytes left */ - dest += blocksize; /* advance write pointer */ - source += blocksize; /* advance read pointer */ - } - return LIBSSH2_ERROR_NONE; /* all is fine */ -} - -/* - * fullpacket() gets called when a full packet has been received and properly - * collected. - */ -static int -fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ ) -{ - unsigned char macbuf[MAX_MACSIZE]; - struct transportpacket *p = &session->packet; - int rc; - - if (session->fullpacket_state == libssh2_NB_state_idle) { - session->fullpacket_macstate = LIBSSH2_MAC_CONFIRMED; - session->fullpacket_payload_len = p->packet_length - 1; - - if (encrypted) { - - /* Calculate MAC hash */ - session->remote.mac->hash(session, macbuf, /* store hash here */ - session->remote.seqno, - p->init, 5, - p->payload, - session->fullpacket_payload_len, - &session->remote.mac_abstract); - - /* Compare the calculated hash with the MAC we just read from - * the network. The read one is at the very end of the payload - * buffer. Note that 'payload_len' here is the packet_length - * field which includes the padding but not the MAC. - */ - if (memcmp(macbuf, p->payload + session->fullpacket_payload_len, - session->remote.mac->mac_len)) { - session->fullpacket_macstate = LIBSSH2_MAC_INVALID; - } - } - - session->remote.seqno++; - - /* ignore the padding */ - session->fullpacket_payload_len -= p->padding_length; - - /* Check for and deal with decompression */ - if (session->remote.comp && - session->remote.comp->compress && - session->remote.comp_abstract) { - /* - * The buffer for the decompression (remote.comp_abstract) is - * initialised in time when it is needed so as long it is NULL we - * cannot decompress. - */ - - unsigned char *data; - size_t data_len; - rc = session->remote.comp->decomp(session, - &data, &data_len, - LIBSSH2_PACKET_MAXDECOMP, - p->payload, - session->fullpacket_payload_len, - &session->remote.comp_abstract); - LIBSSH2_FREE(session, p->payload); - if(rc) - return rc; - - p->payload = data; - session->fullpacket_payload_len = data_len; - } - - session->fullpacket_packet_type = p->payload[0]; - - debugdump(session, "libssh2_transport_read() plain", - p->payload, session->fullpacket_payload_len); - - session->fullpacket_state = libssh2_NB_state_created; - } - - if (session->fullpacket_state == libssh2_NB_state_created) { - rc = _libssh2_packet_add(session, p->payload, - session->fullpacket_payload_len, - session->fullpacket_macstate); - if (rc) - return rc; - } - - session->fullpacket_state = libssh2_NB_state_idle; - - return session->fullpacket_packet_type; -} - - -/* - * _libssh2_transport_read - * - * Collect a packet into the input queue. - * - * Returns packet type added to input queue (0 if nothing added), or a - * negative error number. - */ - -/* - * This function reads the binary stream as specified in chapter 6 of RFC4253 - * "The Secure Shell (SSH) Transport Layer Protocol" - * - * DOES NOT call _libssh2_error() for ANY error case. - */ -int _libssh2_transport_read(LIBSSH2_SESSION * session) -{ - int rc; - struct transportpacket *p = &session->packet; - int remainbuf; - int remainpack; - int numbytes; - int numdecrypt; - unsigned char block[MAX_BLOCKSIZE]; - int blocksize; - int encrypted = 1; - size_t total_num; - - /* default clear the bit */ - session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND; - - /* - * All channels, systems, subsystems, etc eventually make it down here - * when looking for more incoming data. If a key exchange is going on - * (LIBSSH2_STATE_EXCHANGING_KEYS bit is set) then the remote end will - * ONLY send key exchange related traffic. In non-blocking mode, there is - * a chance to break out of the kex_exchange function with an EAGAIN - * status, and never come back to it. If LIBSSH2_STATE_EXCHANGING_KEYS is - * active, then we must redirect to the key exchange. However, if - * kex_exchange is active (as in it is the one that calls this execution - * of packet_read, then don't redirect, as that would be an infinite loop! - */ - - if (session->state & LIBSSH2_STATE_EXCHANGING_KEYS && - !(session->state & LIBSSH2_STATE_KEX_ACTIVE)) { - - /* Whoever wants a packet won't get anything until the key re-exchange - * is done! - */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Redirecting into the" - " key re-exchange from _libssh2_transport_read"); - rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state); - if (rc) - return rc; - } - - /* - * =============================== NOTE =============================== - * I know this is very ugly and not a really good use of "goto", but - * this case statement would be even uglier to do it any other way - */ - if (session->readPack_state == libssh2_NB_state_jump1) { - session->readPack_state = libssh2_NB_state_idle; - encrypted = session->readPack_encrypted; - goto libssh2_transport_read_point1; - } - - do { - if (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) { - return LIBSSH2_ERROR_NONE; - } - - if (session->state & LIBSSH2_STATE_NEWKEYS) { - blocksize = session->remote.crypt->blocksize; - } else { - encrypted = 0; /* not encrypted */ - blocksize = 5; /* not strictly true, but we can use 5 here to - make the checks below work fine still */ - } - - /* read/use a whole big chunk into a temporary area stored in - the LIBSSH2_SESSION struct. We will decrypt data from that - buffer into the packet buffer so this temp one doesn't have - to be able to keep a whole SSH packet, just be large enough - so that we can read big chunks from the network layer. */ - - /* how much data there is remaining in the buffer to deal with - before we should read more from the network */ - remainbuf = p->writeidx - p->readidx; - - /* if remainbuf turns negative we have a bad internal error */ - assert(remainbuf >= 0); - - if (remainbuf < blocksize) { - /* If we have less than a blocksize left, it is too - little data to deal with, read more */ - ssize_t nread; - - /* move any remainder to the start of the buffer so - that we can do a full refill */ - if (remainbuf) { - memmove(p->buf, &p->buf[p->readidx], remainbuf); - p->readidx = 0; - p->writeidx = remainbuf; - } else { - /* nothing to move, just zero the indexes */ - p->readidx = p->writeidx = 0; - } - - /* now read a big chunk from the network into the temp buffer */ - nread = - LIBSSH2_RECV(session, &p->buf[remainbuf], - PACKETBUFSIZE - remainbuf, - LIBSSH2_SOCKET_RECV_FLAGS(session)); - if (nread <= 0) { - /* check if this is due to EAGAIN and return the special - return code if so, error out normally otherwise */ - if ((nread < 0) && (nread == -EAGAIN)) { - session->socket_block_directions |= - LIBSSH2_SESSION_BLOCK_INBOUND; - return LIBSSH2_ERROR_EAGAIN; - } - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error recving %d bytes (got %d)", - PACKETBUFSIZE - remainbuf, -nread); - return LIBSSH2_ERROR_SOCKET_RECV; - } - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Recved %d/%d bytes to %p+%d", nread, - PACKETBUFSIZE - remainbuf, p->buf, remainbuf); - - debugdump(session, "libssh2_transport_read() raw", - &p->buf[remainbuf], nread); - /* advance write pointer */ - p->writeidx += nread; - - /* update remainbuf counter */ - remainbuf = p->writeidx - p->readidx; - } - - /* how much data to deal with from the buffer */ - numbytes = remainbuf; - - if (!p->total_num) { - /* No payload package area allocated yet. To know the - size of this payload, we need to decrypt the first - blocksize data. */ - - if (numbytes < blocksize) { - /* we can't act on anything less than blocksize, but this - check is only done for the initial block since once we have - got the start of a block we can in fact deal with fractions - */ - session->socket_block_directions |= - LIBSSH2_SESSION_BLOCK_INBOUND; - return LIBSSH2_ERROR_EAGAIN; - } - - if (encrypted) { - rc = decrypt(session, &p->buf[p->readidx], block, blocksize); - if (rc != LIBSSH2_ERROR_NONE) { - return rc; - } - /* save the first 5 bytes of the decrypted package, to be - used in the hash calculation later down. */ - memcpy(p->init, &p->buf[p->readidx], 5); - } else { - /* the data is plain, just copy it verbatim to - the working block buffer */ - memcpy(block, &p->buf[p->readidx], blocksize); - } - - /* advance the read pointer */ - p->readidx += blocksize; - - /* we now have the initial blocksize bytes decrypted, - * and we can extract packet and padding length from it - */ - p->packet_length = _libssh2_ntohu32(block); - if (p->packet_length < 1) - return LIBSSH2_ERROR_DECRYPT; - - p->padding_length = block[4]; - - /* total_num is the number of bytes following the initial - (5 bytes) packet length and padding length fields */ - total_num = - p->packet_length - 1 + - (encrypted ? session->remote.mac->mac_len : 0); - - /* RFC4253 section 6.1 Maximum Packet Length says: - * - * "All implementations MUST be able to process - * packets with uncompressed payload length of 32768 - * bytes or less and total packet size of 35000 bytes - * or less (including length, padding length, payload, - * padding, and MAC.)." - */ - if (total_num > LIBSSH2_PACKET_MAXPAYLOAD) { - return LIBSSH2_ERROR_OUT_OF_BOUNDARY; - } - - /* Get a packet handle put data into. We get one to - hold all data, including padding and MAC. */ - p->payload = LIBSSH2_ALLOC(session, total_num); - if (!p->payload) { - return LIBSSH2_ERROR_ALLOC; - } - p->total_num = total_num; - /* init write pointer to start of payload buffer */ - p->wptr = p->payload; - - if (blocksize > 5) { - /* copy the data from index 5 to the end of - the blocksize from the temporary buffer to - the start of the decrypted buffer */ - memcpy(p->wptr, &block[5], blocksize - 5); - p->wptr += blocksize - 5; /* advance write pointer */ - } - - /* init the data_num field to the number of bytes of - the package read so far */ - p->data_num = p->wptr - p->payload; - - /* we already dealt with a blocksize worth of data */ - numbytes -= blocksize; - } - - /* how much there is left to add to the current payload - package */ - remainpack = p->total_num - p->data_num; - - if (numbytes > remainpack) { - /* if we have more data in the buffer than what is going into this - particular packet, we limit this round to this packet only */ - numbytes = remainpack; - } - - if (encrypted) { - /* At the end of the incoming stream, there is a MAC, - and we don't want to decrypt that since we need it - "raw". We MUST however decrypt the padding data - since it is used for the hash later on. */ - int skip = session->remote.mac->mac_len; - - /* if what we have plus numbytes is bigger than the - total minus the skip margin, we should lower the - amount to decrypt even more */ - if ((p->data_num + numbytes) > (p->total_num - skip)) { - numdecrypt = (p->total_num - skip) - p->data_num; - } else { - int frac; - numdecrypt = numbytes; - frac = numdecrypt % blocksize; - if (frac) { - /* not an aligned amount of blocks, - align it */ - numdecrypt -= frac; - /* and make it no unencrypted data - after it */ - numbytes = 0; - } - } - } else { - /* unencrypted data should not be decrypted at all */ - numdecrypt = 0; - } - - /* if there are bytes to decrypt, do that */ - if (numdecrypt > 0) { - /* now decrypt the lot */ - rc = decrypt(session, &p->buf[p->readidx], p->wptr, numdecrypt); - if (rc != LIBSSH2_ERROR_NONE) { - return rc; - } - - /* advance the read pointer */ - p->readidx += numdecrypt; - /* advance write pointer */ - p->wptr += numdecrypt; - /* increse data_num */ - p->data_num += numdecrypt; - - /* bytes left to take care of without decryption */ - numbytes -= numdecrypt; - } - - /* if there are bytes to copy that aren't decrypted, simply - copy them as-is to the target buffer */ - if (numbytes > 0) { - memcpy(p->wptr, &p->buf[p->readidx], numbytes); - - /* advance the read pointer */ - p->readidx += numbytes; - /* advance write pointer */ - p->wptr += numbytes; - /* increse data_num */ - p->data_num += numbytes; - } - - /* now check how much data there's left to read to finish the - current packet */ - remainpack = p->total_num - p->data_num; - - if (!remainpack) { - /* we have a full packet */ - libssh2_transport_read_point1: - rc = fullpacket(session, encrypted); - if (rc == LIBSSH2_ERROR_EAGAIN) { - - if (session->packAdd_state != libssh2_NB_state_idle) - { - /* fullpacket only returns LIBSSH2_ERROR_EAGAIN if - * libssh2_packet_add returns LIBSSH2_ERROR_EAGAIN. If that - * returns LIBSSH2_ERROR_EAGAIN but the packAdd_state is idle, - * then the packet has been added to the brigade, but some - * immediate action that was taken based on the packet - * type (such as key re-exchange) is not yet complete. - * Clear the way for a new packet to be read in. - */ - session->readPack_encrypted = encrypted; - session->readPack_state = libssh2_NB_state_jump1; - } - - return rc; - } - - p->total_num = 0; /* no packet buffer available */ - - return rc; - } - } while (1); /* loop */ - - return LIBSSH2_ERROR_SOCKET_RECV; /* we never reach this point */ -} - -static int -send_existing(LIBSSH2_SESSION *session, const unsigned char *data, - size_t data_len, ssize_t *ret) -{ - ssize_t rc; - ssize_t length; - struct transportpacket *p = &session->packet; - - if (!p->olen) { - *ret = 0; - return LIBSSH2_ERROR_NONE; - } - - /* send as much as possible of the existing packet */ - if ((data != p->odata) || (data_len != p->olen)) { - /* When we are about to complete the sending of a packet, it is vital - that the caller doesn't try to send a new/different packet since - we don't add this one up until the previous one has been sent. To - make the caller really notice his/hers flaw, we return error for - this case */ - return LIBSSH2_ERROR_BAD_USE; - } - - *ret = 1; /* set to make our parent return */ - - /* number of bytes left to send */ - length = p->ototal_num - p->osent; - - rc = LIBSSH2_SEND(session, &p->outbuf[p->osent], length, - LIBSSH2_SOCKET_SEND_FLAGS(session)); - if (rc < 0) - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error sending %d bytes: %d", length, -rc); - else { - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Sent %d/%d bytes at %p+%d", rc, length, p->outbuf, - p->osent); - debugdump(session, "libssh2_transport_write send()", - &p->outbuf[p->osent], rc); - } - - if (rc == length) { - /* the remainder of the package was sent */ - p->ototal_num = 0; - p->olen = 0; - /* we leave *ret set so that the parent returns as we MUST return back - a send success now, so that we don't risk sending EAGAIN later - which then would confuse the parent function */ - return LIBSSH2_ERROR_NONE; - - } - else if (rc < 0) { - /* nothing was sent */ - if (rc != -EAGAIN) - /* send failure! */ - return LIBSSH2_ERROR_SOCKET_SEND; - - session->socket_block_directions |= LIBSSH2_SESSION_BLOCK_OUTBOUND; - return LIBSSH2_ERROR_EAGAIN; - } - - p->osent += rc; /* we sent away this much data */ - - return rc < length ? LIBSSH2_ERROR_EAGAIN : LIBSSH2_ERROR_NONE; -} - -/* - * libssh2_transport_send - * - * Send a packet, encrypting it and adding a MAC code if necessary - * Returns 0 on success, non-zero on failure. - * - * The data is provided as _two_ data areas that are combined by this - * function. The 'data' part is sent immediately before 'data2'. 'data2' may - * be set to NULL to only use a single part. - * - * Returns LIBSSH2_ERROR_EAGAIN if it would block or if the whole packet was - * not sent yet. If it does so, the caller should call this function again as - * soon as it is likely that more data can be sent, and this function MUST - * then be called with the same argument set (same data pointer and same - * data_len) until ERROR_NONE or failure is returned. - * - * This function DOES NOT call _libssh2_error() on any errors. - */ -int _libssh2_transport_send(LIBSSH2_SESSION *session, - const unsigned char *data, size_t data_len, - const unsigned char *data2, size_t data2_len) -{ - int blocksize = - (session->state & LIBSSH2_STATE_NEWKEYS) ? - session->local.crypt->blocksize : 8; - int padding_length; - size_t packet_length; - int total_length; -#ifdef RANDOM_PADDING - int rand_max; - int seed = data[0]; /* FIXME: make this random */ -#endif - struct transportpacket *p = &session->packet; - int encrypted; - ssize_t ret; - int rc; - const unsigned char *orgdata = data; - size_t orgdata_len = data_len; - - /* - * If the last read operation was interrupted in the middle of a key - * exchange, we must complete that key exchange before continuing to write - * further data. - * - * See the similar block in _libssh2_transport_read for more details. - */ - if (session->state & LIBSSH2_STATE_EXCHANGING_KEYS && - !(session->state & LIBSSH2_STATE_KEX_ACTIVE)) { - /* Don't write any new packets if we're still in the middle of a key - * exchange. */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Redirecting into the" - " key re-exchange from _libssh2_transport_send"); - rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state); - if (rc) - return rc; - } - - debugdump(session, "libssh2_transport_write plain", data, data_len); - if(data2) - debugdump(session, "libssh2_transport_write plain2", data2, data2_len); - - /* FIRST, check if we have a pending write to complete. send_existing - only sanity-check data and data_len and not data2 and data2_len!! */ - rc = send_existing(session, data, data_len, &ret); - if (rc) - return rc; - - session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_OUTBOUND; - - if (ret) - /* set by send_existing if data was sent */ - return rc; - - encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0; - - if (encrypted && session->local.comp->compress) { - /* the idea here is that these function must fail if the output gets - larger than what fits in the assigned buffer so thus they don't - check the input size as we don't know how much it compresses */ - size_t dest_len = MAX_SSH_PACKET_LEN-5-256; - size_t dest2_len = dest_len; - - /* compress directly to the target buffer */ - rc = session->local.comp->comp(session, - &p->outbuf[5], &dest_len, - data, data_len, - &session->local.comp_abstract); - if(rc) - return rc; /* compression failure */ - - if(data2 && data2_len) { - /* compress directly to the target buffer right after where the - previous call put data */ - dest2_len -= dest_len; - - rc = session->local.comp->comp(session, - &p->outbuf[5+dest_len], &dest2_len, - data2, data2_len, - &session->local.comp_abstract); - } - else - dest2_len = 0; - if(rc) - return rc; /* compression failure */ - - data_len = dest_len + dest2_len; /* use the combined length */ - } - else { - if((data_len + data2_len) >= (MAX_SSH_PACKET_LEN-0x100)) - /* too large packet, return error for this until we make this - function split it up and send multiple SSH packets */ - return LIBSSH2_ERROR_INVAL; - - /* copy the payload data */ - memcpy(&p->outbuf[5], data, data_len); - if(data2 && data2_len) - memcpy(&p->outbuf[5+data_len], data2, data2_len); - data_len += data2_len; /* use the combined length */ - } - - - /* RFC4253 says: Note that the length of the concatenation of - 'packet_length', 'padding_length', 'payload', and 'random padding' - MUST be a multiple of the cipher block size or 8, whichever is - larger. */ - - /* Plain math: (4 + 1 + packet_length + padding_length) % blocksize == 0 */ - - packet_length = data_len + 1 + 4; /* 1 is for padding_length field - 4 for the packet_length field */ - - /* at this point we have it all except the padding */ - - /* first figure out our minimum padding amount to make it an even - block size */ - padding_length = blocksize - (packet_length % blocksize); - - /* if the padding becomes too small we add another blocksize worth - of it (taken from the original libssh2 where it didn't have any - real explanation) */ - if (padding_length < 4) { - padding_length += blocksize; - } -#ifdef RANDOM_PADDING - /* FIXME: we can add padding here, but that also makes the packets - bigger etc */ - - /* now we can add 'blocksize' to the padding_length N number of times - (to "help thwart traffic analysis") but it must be less than 255 in - total */ - rand_max = (255 - padding_length) / blocksize + 1; - padding_length += blocksize * (seed % rand_max); -#endif - - packet_length += padding_length; - - /* append the MAC length to the total_length size */ - total_length = - packet_length + (encrypted ? session->local.mac->mac_len : 0); - - /* store packet_length, which is the size of the whole packet except - the MAC and the packet_length field itself */ - _libssh2_htonu32(p->outbuf, packet_length - 4); - /* store padding_length */ - p->outbuf[4] = padding_length; - - /* fill the padding area with random junk */ - _libssh2_random(p->outbuf + 5 + data_len, padding_length); - - if (encrypted) { - size_t i; - - /* Calculate MAC hash. Put the output at index packet_length, - since that size includes the whole packet. The MAC is - calculated on the entire unencrypted packet, including all - fields except the MAC field itself. */ - session->local.mac->hash(session, p->outbuf + packet_length, - session->local.seqno, p->outbuf, - packet_length, NULL, 0, - &session->local.mac_abstract); - - /* Encrypt the whole packet data, one block size at a time. - The MAC field is not encrypted. */ - for(i = 0; i < packet_length; i += session->local.crypt->blocksize) { - unsigned char *ptr = &p->outbuf[i]; - if (session->local.crypt->crypt(session, ptr, - &session->local.crypt_abstract)) - return LIBSSH2_ERROR_ENCRYPT; /* encryption failure */ - } - } - - session->local.seqno++; - - ret = LIBSSH2_SEND(session, p->outbuf, total_length, - LIBSSH2_SOCKET_SEND_FLAGS(session)); - if (ret < 0) - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error sending %d bytes: %d", total_length, -ret); - else { - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, "Sent %d/%d bytes at %p", - ret, total_length, p->outbuf); - debugdump(session, "libssh2_transport_write send()", p->outbuf, ret); - } - - if (ret != total_length) { - if (ret >= 0 || ret == -EAGAIN) { - /* the whole packet could not be sent, save the rest */ - session->socket_block_directions |= LIBSSH2_SESSION_BLOCK_OUTBOUND; - p->odata = orgdata; - p->olen = orgdata_len; - p->osent = ret <= 0 ? 0 : ret; - p->ototal_num = total_length; - return LIBSSH2_ERROR_EAGAIN; - } - return LIBSSH2_ERROR_SOCKET_SEND; - } - - /* the whole thing got sent away */ - p->odata = NULL; - p->olen = 0; - - return LIBSSH2_ERROR_NONE; /* all is good */ -} diff --git a/vendor/libssh2-1.4.2/src/transport.h b/vendor/libssh2-1.4.2/src/transport.h deleted file mode 100644 index 89982a6..0000000 --- a/vendor/libssh2-1.4.2/src/transport.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef __LIBSSH2_TRANSPORT_H -#define __LIBSSH2_TRANSPORT_H - -/* Copyright (C) 2007 The Written Word, Inc. All rights reserved. - * Copyright (C) 2009-2010 by Daniel Stenberg - * Author: Daniel Stenberg - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file handles reading and writing to the SECSH transport layer. RFC4253. - */ - -#include "libssh2_priv.h" -#include "packet.h" - - -/* - * libssh2_transport_send - * - * Send a packet, encrypting it and adding a MAC code if necessary - * Returns 0 on success, non-zero on failure. - * - * The data is provided as _two_ data areas that are combined by this - * function. The 'data' part is sent immediately before 'data2'. 'data2' can - * be set to NULL (or data2_len to 0) to only use a single part. - * - * Returns LIBSSH2_ERROR_EAGAIN if it would block or if the whole packet was - * not sent yet. If it does so, the caller should call this function again as - * soon as it is likely that more data can be sent, and this function MUST - * then be called with the same argument set (same data pointer and same - * data_len) until ERROR_NONE or failure is returned. - * - * This function DOES NOT call _libssh2_error() on any errors. - */ -int _libssh2_transport_send(LIBSSH2_SESSION *session, - const unsigned char *data, size_t data_len, - const unsigned char *data2, size_t data2_len); - -/* - * _libssh2_transport_read - * - * Collect a packet into the input brigade block only controls whether or not - * to wait for a packet to start. - * - * Returns packet type added to input brigade (PACKET_NONE if nothing added), - * or PACKET_FAIL on failure and PACKET_EAGAIN if it couldn't process a full - * packet. - */ - -/* - * This function reads the binary stream as specified in chapter 6 of RFC4253 - * "The Secure Shell (SSH) Transport Layer Protocol" - */ -int _libssh2_transport_read(LIBSSH2_SESSION * session); - -#endif /* __LIBSSH2_TRANSPORT_H */ diff --git a/vendor/libssh2-1.4.2/src/userauth.c b/vendor/libssh2-1.4.2/src/userauth.c deleted file mode 100644 index a0733d5..0000000 --- a/vendor/libssh2-1.4.2/src/userauth.c +++ /dev/null @@ -1,1687 +0,0 @@ -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2005 Mikhail Gusarov - * Copyright (c) 2009-2011 by Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" - -#include -#include - -#include - -/* Needed for struct iovec on some platforms */ -#ifdef HAVE_SYS_UIO_H -#include -#endif - -#include "transport.h" -#include "session.h" -#include "userauth.h" - -/* libssh2_userauth_list - * - * List authentication methods - * Will yield successful login if "none" happens to be allowable for this user - * Not a common configuration for any SSH server though - * username should be NULL, or a null terminated string - */ -static char *userauth_list(LIBSSH2_SESSION *session, const char *username, - unsigned int username_len) -{ - static const unsigned char reply_codes[3] = - { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 }; - /* packet_type(1) + username_len(4) + service_len(4) + - service(14)"ssh-connection" + method_len(4) = 27 */ - unsigned long methods_len; - unsigned char *s; - int rc; - - if (session->userauth_list_state == libssh2_NB_state_idle) { - /* Zero the whole thing out */ - memset(&session->userauth_list_packet_requirev_state, 0, - sizeof(session->userauth_list_packet_requirev_state)); - - session->userauth_list_data_len = username_len + 27; - - s = session->userauth_list_data = - LIBSSH2_ALLOC(session, session->userauth_list_data_len); - if (!session->userauth_list_data) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for userauth_list"); - return NULL; - } - - *(s++) = SSH_MSG_USERAUTH_REQUEST; - _libssh2_store_str(&s, username, username_len); - _libssh2_store_str(&s, "ssh-connection", 14); - _libssh2_store_u32(&s, 4); /* send "none" separately */ - - session->userauth_list_state = libssh2_NB_state_created; - } - - if (session->userauth_list_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, session->userauth_list_data, - session->userauth_list_data_len, - (unsigned char *)"none", 4); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block requesting userauth list"); - return NULL; - } - /* now free the packet that was sent */ - LIBSSH2_FREE(session, session->userauth_list_data); - session->userauth_list_data = NULL; - - if (rc) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send userauth-none request"); - session->userauth_list_state = libssh2_NB_state_idle; - return NULL; - } - - session->userauth_list_state = libssh2_NB_state_sent; - } - - if (session->userauth_list_state == libssh2_NB_state_sent) { - rc = _libssh2_packet_requirev(session, reply_codes, - &session->userauth_list_data, - &session->userauth_list_data_len, 0, - NULL, 0, - &session->userauth_list_packet_requirev_state); - if (rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block requesting userauth list"); - return NULL; - } else if (rc) { - _libssh2_error(session, rc, "Failed getting response"); - session->userauth_list_state = libssh2_NB_state_idle; - return NULL; - } - - if (session->userauth_list_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - /* Wow, who'dve thought... */ - _libssh2_error(session, LIBSSH2_ERROR_NONE, "No error"); - LIBSSH2_FREE(session, session->userauth_list_data); - session->userauth_list_data = NULL; - session->state |= LIBSSH2_STATE_AUTHENTICATED; - session->userauth_list_state = libssh2_NB_state_idle; - return NULL; - } - - methods_len = _libssh2_ntohu32(session->userauth_list_data + 1); - - /* Do note that the memory areas overlap! */ - memmove(session->userauth_list_data, session->userauth_list_data + 5, - methods_len); - session->userauth_list_data[methods_len] = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Permitted auth methods: %s", - session->userauth_list_data); - } - - session->userauth_list_state = libssh2_NB_state_idle; - return (char *) session->userauth_list_data; -} - -/* libssh2_userauth_list - * - * List authentication methods - * Will yield successful login if "none" happens to be allowable for this user - * Not a common configuration for any SSH server though - * username should be NULL, or a null terminated string - */ -LIBSSH2_API char * -libssh2_userauth_list(LIBSSH2_SESSION * session, const char *user, - unsigned int user_len) -{ - char *ptr; - BLOCK_ADJUST_ERRNO(ptr, session, - userauth_list(session, user, user_len)); - return ptr; -} - -/* - * libssh2_userauth_authenticated - * - * Returns: 0 if not yet authenticated - * 1 if already authenticated - */ -LIBSSH2_API int -libssh2_userauth_authenticated(LIBSSH2_SESSION * session) -{ - return (session->state & LIBSSH2_STATE_AUTHENTICATED)?1:0; -} - - - -/* userauth_password - * Plain ol' login - */ -static int -userauth_password(LIBSSH2_SESSION *session, - const char *username, unsigned int username_len, - const unsigned char *password, unsigned int password_len, - LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb))) -{ - unsigned char *s; - static const unsigned char reply_codes[4] = - { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, - SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0 - }; - int rc; - - if (session->userauth_pswd_state == libssh2_NB_state_idle) { - /* Zero the whole thing out */ - memset(&session->userauth_pswd_packet_requirev_state, 0, - sizeof(session->userauth_pswd_packet_requirev_state)); - - /* - * 40 = acket_type(1) + username_len(4) + service_len(4) + - * service(14)"ssh-connection" + method_len(4) + method(8)"password" + - * chgpwdbool(1) + password_len(4) */ - session->userauth_pswd_data_len = username_len + 40; - - session->userauth_pswd_data0 = ~SSH_MSG_USERAUTH_PASSWD_CHANGEREQ; - - /* TODO: remove this alloc with a fixed buffer in the session - struct */ - s = session->userauth_pswd_data = - LIBSSH2_ALLOC(session, session->userauth_pswd_data_len); - if (!session->userauth_pswd_data) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "userauth-password request"); - } - - *(s++) = SSH_MSG_USERAUTH_REQUEST; - _libssh2_store_str(&s, username, username_len); - _libssh2_store_str(&s, "ssh-connection", sizeof("ssh-connection") - 1); - _libssh2_store_str(&s, "password", sizeof("password") - 1); - *s++ = '\0'; - _libssh2_store_u32(&s, password_len); - /* 'password' is sent separately */ - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting to login using password authentication"); - - session->userauth_pswd_state = libssh2_NB_state_created; - } - - if (session->userauth_pswd_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, session->userauth_pswd_data, - session->userauth_pswd_data_len, - password, password_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block writing password request"); - } - - /* now free the sent packet */ - LIBSSH2_FREE(session, session->userauth_pswd_data); - session->userauth_pswd_data = NULL; - - if (rc) { - session->userauth_pswd_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send userauth-password request"); - } - - session->userauth_pswd_state = libssh2_NB_state_sent; - } - - password_response: - - if ((session->userauth_pswd_state == libssh2_NB_state_sent) - || (session->userauth_pswd_state == libssh2_NB_state_sent1) - || (session->userauth_pswd_state == libssh2_NB_state_sent2)) { - if (session->userauth_pswd_state == libssh2_NB_state_sent) { - rc = _libssh2_packet_requirev(session, reply_codes, - &session->userauth_pswd_data, - &session->userauth_pswd_data_len, - 0, NULL, 0, - &session-> - userauth_pswd_packet_requirev_state); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting"); - } else if (rc) { - session->userauth_pswd_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, - "Would block waiting"); - } - - if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Password authentication successful"); - LIBSSH2_FREE(session, session->userauth_pswd_data); - session->userauth_pswd_data = NULL; - session->state |= LIBSSH2_STATE_AUTHENTICATED; - session->userauth_pswd_state = libssh2_NB_state_idle; - return 0; - } else if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_FAILURE) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Password authentication failed"); - LIBSSH2_FREE(session, session->userauth_pswd_data); - session->userauth_pswd_data = NULL; - session->userauth_pswd_state = libssh2_NB_state_idle; - return _libssh2_error(session, - LIBSSH2_ERROR_AUTHENTICATION_FAILED, - "Authentication failed " - "(username/password)"); - } - - session->userauth_pswd_newpw = NULL; - session->userauth_pswd_newpw_len = 0; - - session->userauth_pswd_state = libssh2_NB_state_sent1; - } - - if ((session->userauth_pswd_data[0] == - SSH_MSG_USERAUTH_PASSWD_CHANGEREQ) - || (session->userauth_pswd_data0 == - SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)) { - session->userauth_pswd_data0 = SSH_MSG_USERAUTH_PASSWD_CHANGEREQ; - - if ((session->userauth_pswd_state == libssh2_NB_state_sent1) || - (session->userauth_pswd_state == libssh2_NB_state_sent2)) { - if (session->userauth_pswd_state == libssh2_NB_state_sent1) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Password change required"); - LIBSSH2_FREE(session, session->userauth_pswd_data); - session->userauth_pswd_data = NULL; - } - if (passwd_change_cb) { - if (session->userauth_pswd_state == libssh2_NB_state_sent1) { - passwd_change_cb(session, - &session->userauth_pswd_newpw, - &session->userauth_pswd_newpw_len, - &session->abstract); - if (!session->userauth_pswd_newpw) { - return _libssh2_error(session, - LIBSSH2_ERROR_PASSWORD_EXPIRED, - "Password expired, and " - "callback failed"); - } - - /* basic data_len + newpw_len(4) */ - session->userauth_pswd_data_len = - username_len + password_len + 44; - - s = session->userauth_pswd_data = - LIBSSH2_ALLOC(session, - session->userauth_pswd_data_len); - if (!session->userauth_pswd_data) { - LIBSSH2_FREE(session, - session->userauth_pswd_newpw); - session->userauth_pswd_newpw = NULL; - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory " - "for userauth password " - "change request"); - } - - *(s++) = SSH_MSG_USERAUTH_REQUEST; - _libssh2_store_str(&s, username, username_len); - _libssh2_store_str(&s, "ssh-connection", - sizeof("ssh-connection") - 1); - _libssh2_store_str(&s, "password", - sizeof("password") - 1); - *s++ = 0x01; - _libssh2_store_str(&s, (char *)password, password_len); - _libssh2_store_u32(&s, - session->userauth_pswd_newpw_len); - /* send session->userauth_pswd_newpw separately */ - - session->userauth_pswd_state = libssh2_NB_state_sent2; - } - - if (session->userauth_pswd_state == libssh2_NB_state_sent2) { - rc = _libssh2_transport_send(session, - session->userauth_pswd_data, - session->userauth_pswd_data_len, - (unsigned char *) - session->userauth_pswd_newpw, - session->userauth_pswd_newpw_len); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting"); - } - - /* free the allocated packets again */ - LIBSSH2_FREE(session, session->userauth_pswd_data); - session->userauth_pswd_data = NULL; - LIBSSH2_FREE(session, session->userauth_pswd_newpw); - session->userauth_pswd_newpw = NULL; - - if (rc) { - return _libssh2_error(session, - LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send userauth " - "password-change request"); - } - - /* - * Ugliest use of goto ever. Blame it on the - * askN => requirev migration. - */ - session->userauth_pswd_state = libssh2_NB_state_sent; - goto password_response; - } - } - } else { - session->userauth_pswd_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, - "Password Expired, and no callback " - "specified"); - } - } - } - - /* FAILURE */ - LIBSSH2_FREE(session, session->userauth_pswd_data); - session->userauth_pswd_data = NULL; - session->userauth_pswd_state = libssh2_NB_state_idle; - - return _libssh2_error(session, LIBSSH2_ERROR_AUTHENTICATION_FAILED, - "Authentication failed"); -} - -/* - * libssh2_userauth_password_ex - * - * Plain ol' login - */ - -LIBSSH2_API int -libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, - unsigned int username_len, const char *password, - unsigned int password_len, - LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb))) -{ - int rc; - BLOCK_ADJUST(rc, session, - userauth_password(session, username, username_len, - (unsigned char *)password, password_len, - passwd_change_cb)); - return rc; -} - -/* - * file_read_publickey - * - * Read a public key from an id_???.pub style file - * - * Returns an allocated string containing the decoded key in *pubkeydata - * on success. - * Returns an allocated string containing the key method (e.g. "ssh-dss") - * in method on success. - */ -static int -file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *pubkeyfile) -{ - FILE *fd; - char c; - unsigned char *pubkey = NULL, *sp1, *sp2, *tmp; - size_t pubkey_len = 0; - unsigned int tmp_len; - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading public key file: %s", - pubkeyfile); - /* Read Public Key */ - fd = fopen(pubkeyfile, "r"); - if (!fd) { - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to open public key file"); - } - while (!feof(fd) && 1 == fread(&c, 1, 1, fd) && c != '\r' && c != '\n') - pubkey_len++; - if (feof(fd)) { - /* the last character was EOF */ - pubkey_len--; - } - rewind(fd); - - if (pubkey_len <= 1) { - fclose(fd); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Invalid data in public key file"); - } - - pubkey = LIBSSH2_ALLOC(session, pubkey_len); - if (!pubkey) { - fclose(fd); - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for public key data"); - } - if (fread(pubkey, 1, pubkey_len, fd) != pubkey_len) { - LIBSSH2_FREE(session, pubkey); - fclose(fd); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to read public key from file"); - } - fclose(fd); - /* - * Remove trailing whitespace - */ - while (pubkey_len && isspace(pubkey[pubkey_len - 1])) - pubkey_len--; - - if (!pubkey_len) { - LIBSSH2_FREE(session, pubkey); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Missing public key data"); - } - - if ((sp1 = memchr(pubkey, ' ', pubkey_len)) == NULL) { - LIBSSH2_FREE(session, pubkey); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Invalid public key data"); - } - - sp1++; - - if ((sp2 = memchr(sp1, ' ', pubkey_len - (sp1 - pubkey - 1))) == NULL) { - /* Assume that the id string is missing, but that it's okay */ - sp2 = pubkey + pubkey_len; - } - - if (libssh2_base64_decode(session, (char **) &tmp, &tmp_len, - (char *) sp1, sp2 - sp1)) { - LIBSSH2_FREE(session, pubkey); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Invalid key data, not base64 encoded"); - } - - /* Wasting some bytes here (okay, more than some), but since it's likely - * to be freed soon anyway, we'll just avoid the extra free/alloc and call - * it a wash */ - *method = pubkey; - *method_len = sp1 - pubkey - 1; - - *pubkeydata = tmp; - *pubkeydata_len = tmp_len; - - return 0; -} - - - -/* libssh2_file_read_privatekey - * Read a PEM encoded private key from an id_??? style file - */ -static int -file_read_privatekey(LIBSSH2_SESSION * session, - const LIBSSH2_HOSTKEY_METHOD ** hostkey_method, - void **hostkey_abstract, - const unsigned char *method, int method_len, - const char *privkeyfile, const char *passphrase) -{ - const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = - libssh2_hostkey_methods(); - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading private key file: %s", - privkeyfile); - *hostkey_method = NULL; - *hostkey_abstract = NULL; - while (*hostkey_methods_avail && (*hostkey_methods_avail)->name) { - if ((*hostkey_methods_avail)->initPEM - && strncmp((*hostkey_methods_avail)->name, (const char *) method, - method_len) == 0) { - *hostkey_method = *hostkey_methods_avail; - break; - } - hostkey_methods_avail++; - } - if (!*hostkey_method) { - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, - "No handler for specified private key"); - } - - if ((*hostkey_method)-> - initPEM(session, privkeyfile, (unsigned char *) passphrase, - hostkey_abstract)) { - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to initialize private key from file"); - } - - return 0; -} - -struct privkey_file { - const char *filename; - const char *passphrase; -}; - -static int -sign_fromfile(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, - const unsigned char *data, size_t data_len, void **abstract) -{ - struct privkey_file *privkey_file = (struct privkey_file *) (*abstract); - const LIBSSH2_HOSTKEY_METHOD *privkeyobj; - void *hostkey_abstract; - struct iovec datavec; - int rc; - - rc = file_read_privatekey(session, &privkeyobj, &hostkey_abstract, - session->userauth_pblc_method, - session->userauth_pblc_method_len, - privkey_file->filename, - privkey_file->passphrase); - if(rc) - return rc; - - datavec.iov_base = (void *)data; - datavec.iov_len = data_len; - - if (privkeyobj->signv(session, sig, sig_len, 1, &datavec, - &hostkey_abstract)) { - if (privkeyobj->dtor) { - privkeyobj->dtor(session, abstract); - } - return -1; - } - - if (privkeyobj->dtor) { - privkeyobj->dtor(session, &hostkey_abstract); - } - return 0; -} - - - -/* userauth_hostbased_fromfile - * Authenticate using a keypair found in the named files - */ -static int -userauth_hostbased_fromfile(LIBSSH2_SESSION *session, - const char *username, size_t username_len, - const char *publickey, const char *privatekey, - const char *passphrase, const char *hostname, - size_t hostname_len, - const char *local_username, - size_t local_username_len) -{ - int rc; - - if (session->userauth_host_state == libssh2_NB_state_idle) { - const LIBSSH2_HOSTKEY_METHOD *privkeyobj; - unsigned char *pubkeydata, *sig; - size_t pubkeydata_len; - size_t sig_len; - void *abstract; - unsigned char buf[5]; - struct iovec datavec[4]; - - /* Zero the whole thing out */ - memset(&session->userauth_host_packet_requirev_state, 0, - sizeof(session->userauth_host_packet_requirev_state)); - - if (publickey) { - rc = file_read_publickey(session, &session->userauth_host_method, - &session->userauth_host_method_len, - &pubkeydata, &pubkeydata_len, publickey); - if(rc) - /* Note: file_read_publickey() calls _libssh2_error() */ - return rc; - } - else { - /* Compute public key from private key. */ - rc = _libssh2_pub_priv_keyfile(session, - &session->userauth_host_method, - &session->userauth_host_method_len, - &pubkeydata, &pubkeydata_len, - privatekey, passphrase); - if (rc) - /* libssh2_pub_priv_keyfile calls _libssh2_error() */ - return rc; - } - - /* - * 52 = packet_type(1) + username_len(4) + servicename_len(4) + - * service_name(14)"ssh-connection" + authmethod_len(4) + - * authmethod(9)"hostbased" + method_len(4) + pubkeydata_len(4) + - * hostname_len(4) + local_username_len(4) - */ - session->userauth_host_packet_len = - username_len + session->userauth_host_method_len + hostname_len + - local_username_len + pubkeydata_len + 52; - - /* - * Preallocate space for an overall length, method name again, - * and the signature, which won't be any larger than the size of - * the publickeydata itself - */ - session->userauth_host_s = session->userauth_host_packet = - LIBSSH2_ALLOC(session, - session->userauth_host_packet_len + 4 + - (4 + session->userauth_host_method_len) + - (4 + pubkeydata_len)); - if (!session->userauth_host_packet) { - LIBSSH2_FREE(session, session->userauth_host_method); - session->userauth_host_method = NULL; - LIBSSH2_FREE(session, pubkeydata); - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Out of memory"); - } - - *(session->userauth_host_s++) = SSH_MSG_USERAUTH_REQUEST; - _libssh2_store_str(&session->userauth_host_s, username, username_len); - _libssh2_store_str(&session->userauth_host_s, "ssh-connection", 14); - _libssh2_store_str(&session->userauth_host_s, "hostbased", 9); - _libssh2_store_str(&session->userauth_host_s, - (const char *)session->userauth_host_method, - session->userauth_host_method_len); - _libssh2_store_str(&session->userauth_host_s, (const char *)pubkeydata, - pubkeydata_len); - LIBSSH2_FREE(session, pubkeydata); - _libssh2_store_str(&session->userauth_host_s, hostname, hostname_len); - _libssh2_store_str(&session->userauth_host_s, local_username, - local_username_len); - - rc = file_read_privatekey(session, &privkeyobj, &abstract, - session->userauth_host_method, - session->userauth_host_method_len, - privatekey, passphrase); - if(rc) { - /* Note: file_read_privatekey() calls _libssh2_error() */ - LIBSSH2_FREE(session, session->userauth_host_method); - session->userauth_host_method = NULL; - LIBSSH2_FREE(session, session->userauth_host_packet); - session->userauth_host_packet = NULL; - return rc; - } - - _libssh2_htonu32(buf, session->session_id_len); - datavec[0].iov_base = (void *)buf; - datavec[0].iov_len = 4; - datavec[1].iov_base = (void *)session->session_id; - datavec[1].iov_len = session->session_id_len; - datavec[2].iov_base = (void *)session->userauth_host_packet; - datavec[2].iov_len = session->userauth_host_packet_len; - - if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) { - LIBSSH2_FREE(session, session->userauth_host_method); - session->userauth_host_method = NULL; - LIBSSH2_FREE(session, session->userauth_host_packet); - session->userauth_host_packet = NULL; - if (privkeyobj->dtor) { - privkeyobj->dtor(session, &abstract); - } - return -1; - } - - if (privkeyobj->dtor) { - privkeyobj->dtor(session, &abstract); - } - - if (sig_len > pubkeydata_len) { - unsigned char *newpacket; - /* Should *NEVER* happen, but...well.. better safe than sorry */ - newpacket = LIBSSH2_REALLOC(session, session->userauth_host_packet, - session->userauth_host_packet_len + 4 + - (4 + session->userauth_host_method_len) - + (4 + sig_len)); /* PK sigblob */ - if (!newpacket) { - LIBSSH2_FREE(session, sig); - LIBSSH2_FREE(session, session->userauth_host_packet); - session->userauth_host_packet = NULL; - LIBSSH2_FREE(session, session->userauth_host_method); - session->userauth_host_method = NULL; - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Failed allocating additional space for " - "userauth-hostbased packet"); - } - session->userauth_host_packet = newpacket; - } - - session->userauth_host_s = - session->userauth_host_packet + session->userauth_host_packet_len; - - _libssh2_store_u32(&session->userauth_host_s, - 4 + session->userauth_host_method_len + 4 + sig_len); - _libssh2_store_str(&session->userauth_host_s, - (const char *)session->userauth_host_method, - session->userauth_host_method_len); - LIBSSH2_FREE(session, session->userauth_host_method); - session->userauth_host_method = NULL; - - _libssh2_store_str(&session->userauth_host_s, (const char *)sig, - sig_len); - LIBSSH2_FREE(session, sig); - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting hostbased authentication"); - - session->userauth_host_state = libssh2_NB_state_created; - } - - if (session->userauth_host_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, session->userauth_host_packet, - session->userauth_host_s - - session->userauth_host_packet, - NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); - } - else if (rc) { - LIBSSH2_FREE(session, session->userauth_host_packet); - session->userauth_host_packet = NULL; - session->userauth_host_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send userauth-hostbased request"); - } - LIBSSH2_FREE(session, session->userauth_host_packet); - session->userauth_host_packet = NULL; - - session->userauth_host_state = libssh2_NB_state_sent; - } - - if (session->userauth_host_state == libssh2_NB_state_sent) { - static const unsigned char reply_codes[3] = - { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 }; - size_t data_len; - rc = _libssh2_packet_requirev(session, reply_codes, - &session->userauth_host_data, - &data_len, 0, NULL, 0, - &session-> - userauth_host_packet_requirev_state); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); - } - - session->userauth_host_state = libssh2_NB_state_idle; - if (rc) { - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Auth failed"); - } - - if (session->userauth_host_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Hostbased authentication successful"); - /* We are us and we've proved it. */ - LIBSSH2_FREE(session, session->userauth_host_data); - session->userauth_host_data = NULL; - session->state |= LIBSSH2_STATE_AUTHENTICATED; - return 0; - } - } - - /* This public key is not allowed for this user on this server */ - LIBSSH2_FREE(session, session->userauth_host_data); - session->userauth_host_data = NULL; - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Invalid signature for supplied public key, or bad " - "username/public key combination"); -} - -/* libssh2_userauth_hostbased_fromfile_ex - * Authenticate using a keypair found in the named files - */ -LIBSSH2_API int -libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, - const char *user, - unsigned int user_len, - const char *publickey, - const char *privatekey, - const char *passphrase, - const char *host, - unsigned int host_len, - const char *localuser, - unsigned int localuser_len) -{ - int rc; - BLOCK_ADJUST(rc, session, - userauth_hostbased_fromfile(session, user, user_len, - publickey, privatekey, - passphrase, host, host_len, - localuser, localuser_len)); - return rc; -} - - - -int -_libssh2_userauth_publickey(LIBSSH2_SESSION *session, - const char *username, - unsigned int username_len, - const unsigned char *pubkeydata, - unsigned long pubkeydata_len, - LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)), - void *abstract) -{ - unsigned char reply_codes[4] = - { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, - SSH_MSG_USERAUTH_PK_OK, 0 - }; - int rc; - unsigned char *s; - - if (session->userauth_pblc_state == libssh2_NB_state_idle) { - - /* - * The call to _libssh2_ntohu32 later relies on pubkeydata having at - * least 4 valid bytes containing the length of the method name. - */ - if (pubkeydata_len < 4) - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Invalid public key, too short"); - - /* Zero the whole thing out */ - memset(&session->userauth_pblc_packet_requirev_state, 0, - sizeof(session->userauth_pblc_packet_requirev_state)); - - /* - * As an optimisation, userauth_publickey_fromfile reuses a - * previously allocated copy of the method name to avoid an extra - * allocation/free. - * For other uses, we allocate and populate it here. - */ - if (!session->userauth_pblc_method) { - session->userauth_pblc_method_len = _libssh2_ntohu32(pubkeydata); - - if(session->userauth_pblc_method_len > pubkeydata_len) - /* the method length simply cannot be longer than the entire - passed in data, so we use this to detect crazy input - data */ - return _libssh2_error(session, - LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Invalid public key"); - - session->userauth_pblc_method = - LIBSSH2_ALLOC(session, session->userauth_pblc_method_len); - if (!session->userauth_pblc_method) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for public key " - "data"); - } - memcpy(session->userauth_pblc_method, pubkeydata + 4, - session->userauth_pblc_method_len); - } - /* - * The length of the method name read from plaintext prefix in the - * file must match length embedded in the key. - * TODO: The data should match too but we don't check that. Should we? - */ - else if (session->userauth_pblc_method_len != - _libssh2_ntohu32(pubkeydata)) - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Invalid public key"); - - /* - * 45 = packet_type(1) + username_len(4) + servicename_len(4) + - * service_name(14)"ssh-connection" + authmethod_len(4) + - * authmethod(9)"publickey" + sig_included(1)'\0' + algmethod_len(4) + - * publickey_len(4) - */ - session->userauth_pblc_packet_len = - username_len + session->userauth_pblc_method_len + pubkeydata_len + - 45; - - /* - * Preallocate space for an overall length, method name again, and the - * signature, which won't be any larger than the size of the - * publickeydata itself. - * - * Note that the 'pubkeydata_len' extra bytes allocated here will not - * be used in this first send, but will be used in the later one where - * this same allocation is re-used. - */ - s = session->userauth_pblc_packet = - LIBSSH2_ALLOC(session, - session->userauth_pblc_packet_len + 4 + - (4 + session->userauth_pblc_method_len) - + (4 + pubkeydata_len)); - if (!session->userauth_pblc_packet) { - LIBSSH2_FREE(session, session->userauth_pblc_method); - session->userauth_pblc_method = NULL; - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Out of memory"); - } - - *s++ = SSH_MSG_USERAUTH_REQUEST; - _libssh2_store_str(&s, username, username_len); - _libssh2_store_str(&s, "ssh-connection", 14); - _libssh2_store_str(&s, "publickey", 9); - - session->userauth_pblc_b = s; - /* Not sending signature with *this* packet */ - *s++ = 0; - - _libssh2_store_str(&s, (const char *)session->userauth_pblc_method, - session->userauth_pblc_method_len); - _libssh2_store_str(&s, (const char *)pubkeydata, pubkeydata_len); - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting publickey authentication"); - - session->userauth_pblc_state = libssh2_NB_state_created; - } - - if (session->userauth_pblc_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, session->userauth_pblc_packet, - session->userauth_pblc_packet_len, - NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); - else if (rc) { - LIBSSH2_FREE(session, session->userauth_pblc_packet); - session->userauth_pblc_packet = NULL; - LIBSSH2_FREE(session, session->userauth_pblc_method); - session->userauth_pblc_method = NULL; - session->userauth_pblc_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send userauth-publickey request"); - } - - session->userauth_pblc_state = libssh2_NB_state_sent; - } - - if (session->userauth_pblc_state == libssh2_NB_state_sent) { - rc = _libssh2_packet_requirev(session, reply_codes, - &session->userauth_pblc_data, - &session->userauth_pblc_data_len, 0, - NULL, 0, - &session-> - userauth_pblc_packet_requirev_state); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); - } - else if (rc) { - LIBSSH2_FREE(session, session->userauth_pblc_packet); - session->userauth_pblc_packet = NULL; - LIBSSH2_FREE(session, session->userauth_pblc_method); - session->userauth_pblc_method = NULL; - session->userauth_pblc_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Waiting for USERAUTH response"); - } - - if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Pubkey authentication prematurely successful"); - /* - * God help any SSH server that allows an UNVERIFIED - * public key to validate the user - */ - LIBSSH2_FREE(session, session->userauth_pblc_data); - session->userauth_pblc_data = NULL; - LIBSSH2_FREE(session, session->userauth_pblc_packet); - session->userauth_pblc_packet = NULL; - LIBSSH2_FREE(session, session->userauth_pblc_method); - session->userauth_pblc_method = NULL; - session->state |= LIBSSH2_STATE_AUTHENTICATED; - session->userauth_pblc_state = libssh2_NB_state_idle; - return 0; - } - - if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_FAILURE) { - /* This public key is not allowed for this user on this server */ - LIBSSH2_FREE(session, session->userauth_pblc_data); - session->userauth_pblc_data = NULL; - LIBSSH2_FREE(session, session->userauth_pblc_packet); - session->userauth_pblc_packet = NULL; - LIBSSH2_FREE(session, session->userauth_pblc_method); - session->userauth_pblc_method = NULL; - session->userauth_pblc_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_AUTHENTICATION_FAILED, - "Username/PublicKey combination invalid"); - } - - /* Semi-Success! */ - LIBSSH2_FREE(session, session->userauth_pblc_data); - session->userauth_pblc_data = NULL; - - *session->userauth_pblc_b = 0x01; - session->userauth_pblc_state = libssh2_NB_state_sent1; - } - - if (session->userauth_pblc_state == libssh2_NB_state_sent1) { - unsigned char *buf; - unsigned char *sig; - size_t sig_len; - - s = buf = LIBSSH2_ALLOC(session, 4 + session->session_id_len - + session->userauth_pblc_packet_len); - if (!buf) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "userauth-publickey signed data"); - } - - _libssh2_store_str(&s, (const char *)session->session_id, - session->session_id_len); - - memcpy (s, session->userauth_pblc_packet, - session->userauth_pblc_packet_len); - s += session->userauth_pblc_packet_len; - - rc = sign_callback(session, &sig, &sig_len, buf, s - buf, abstract); - LIBSSH2_FREE(session, buf); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); - } else if (rc) { - LIBSSH2_FREE(session, session->userauth_pblc_method); - session->userauth_pblc_method = NULL; - LIBSSH2_FREE(session, session->userauth_pblc_packet); - session->userauth_pblc_packet = NULL; - session->userauth_pblc_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Callback returned error"); - } - - /* - * If this function was restarted, pubkeydata_len might still be 0 - * which will cause an unnecessary but harmless realloc here. - */ - if (sig_len > pubkeydata_len) { - unsigned char *newpacket; - /* Should *NEVER* happen, but...well.. better safe than sorry */ - newpacket = LIBSSH2_REALLOC(session, - session->userauth_pblc_packet, - session->userauth_pblc_packet_len + 4 + - (4 + session->userauth_pblc_method_len) - + (4 + sig_len)); /* PK sigblob */ - if (!newpacket) { - LIBSSH2_FREE(session, sig); - LIBSSH2_FREE(session, session->userauth_pblc_packet); - session->userauth_pblc_packet = NULL; - LIBSSH2_FREE(session, session->userauth_pblc_method); - session->userauth_pblc_method = NULL; - session->userauth_pblc_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Failed allocating additional space for " - "userauth-publickey packet"); - } - session->userauth_pblc_packet = newpacket; - } - - s = session->userauth_pblc_packet + session->userauth_pblc_packet_len; - session->userauth_pblc_b = NULL; - - _libssh2_store_u32(&s, - 4 + session->userauth_pblc_method_len + 4 + sig_len); - _libssh2_store_str(&s, (const char *)session->userauth_pblc_method, - session->userauth_pblc_method_len); - - LIBSSH2_FREE(session, session->userauth_pblc_method); - session->userauth_pblc_method = NULL; - - _libssh2_store_str(&s, (const char *)sig, sig_len); - LIBSSH2_FREE(session, sig); - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting publickey authentication -- phase 2"); - - session->userauth_pblc_s = s; - session->userauth_pblc_state = libssh2_NB_state_sent2; - } - - if (session->userauth_pblc_state == libssh2_NB_state_sent2) { - rc = _libssh2_transport_send(session, session->userauth_pblc_packet, - session->userauth_pblc_s - - session->userauth_pblc_packet, - NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); - } else if (rc) { - LIBSSH2_FREE(session, session->userauth_pblc_packet); - session->userauth_pblc_packet = NULL; - session->userauth_pblc_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send userauth-publickey request"); - } - LIBSSH2_FREE(session, session->userauth_pblc_packet); - session->userauth_pblc_packet = NULL; - - session->userauth_pblc_state = libssh2_NB_state_sent3; - } - - /* PK_OK is no longer valid */ - reply_codes[2] = 0; - - rc = _libssh2_packet_requirev(session, reply_codes, - &session->userauth_pblc_data, - &session->userauth_pblc_data_len, 0, NULL, 0, - &session->userauth_pblc_packet_requirev_state); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block requesting userauth list"); - } else if (rc) { - session->userauth_pblc_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Waiting for publickey USERAUTH response"); - } - - if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Publickey authentication successful"); - /* We are us and we've proved it. */ - LIBSSH2_FREE(session, session->userauth_pblc_data); - session->userauth_pblc_data = NULL; - session->state |= LIBSSH2_STATE_AUTHENTICATED; - session->userauth_pblc_state = libssh2_NB_state_idle; - return 0; - } - - /* This public key is not allowed for this user on this server */ - LIBSSH2_FREE(session, session->userauth_pblc_data); - session->userauth_pblc_data = NULL; - session->userauth_pblc_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Invalid signature for supplied public key, or bad " - "username/public key combination"); -} - -/* - * userauth_publickey_fromfile - * Authenticate using a keypair found in the named files - */ -static int -userauth_publickey_fromfile(LIBSSH2_SESSION *session, - const char *username, - size_t username_len, - const char *publickey, - const char *privatekey, - const char *passphrase) -{ - unsigned char *pubkeydata = NULL; - size_t pubkeydata_len = 0; - struct privkey_file privkey_file; - void *abstract = &privkey_file; - int rc; - - privkey_file.filename = privatekey; - privkey_file.passphrase = passphrase; - - if (session->userauth_pblc_state == libssh2_NB_state_idle) { - if (publickey) { - rc = file_read_publickey(session, &session->userauth_pblc_method, - &session->userauth_pblc_method_len, - &pubkeydata, &pubkeydata_len,publickey); - if (rc) - return rc; - } - else { - /* Compute public key from private key. */ - rc = _libssh2_pub_priv_keyfile(session, - &session->userauth_pblc_method, - &session->userauth_pblc_method_len, - &pubkeydata, &pubkeydata_len, - privatekey, passphrase); - - /* _libssh2_pub_priv_keyfile calls _libssh2_error() */ - if (rc) - return rc; - } - } - - rc = _libssh2_userauth_publickey(session, username, username_len, - pubkeydata, pubkeydata_len, - sign_fromfile, &abstract); - if(pubkeydata) - LIBSSH2_FREE(session, pubkeydata); - - return rc; -} - -/* libssh2_userauth_publickey_fromfile_ex - * Authenticate using a keypair found in the named files - */ -LIBSSH2_API int -libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, - const char *user, - unsigned int user_len, - const char *publickey, - const char *privatekey, - const char *passphrase) -{ - int rc; - - if(NULL == passphrase) - /* if given a NULL pointer, make it point to a zero-length - string to save us from having to check this all over */ - passphrase=""; - - BLOCK_ADJUST(rc, session, - userauth_publickey_fromfile(session, user, user_len, - publickey, privatekey, - passphrase)); - return rc; -} - -/* libssh2_userauth_publickey_ex - * Authenticate using an external callback function - */ -LIBSSH2_API int -libssh2_userauth_publickey(LIBSSH2_SESSION *session, - const char *user, - const unsigned char *pubkeydata, - size_t pubkeydata_len, - LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)), - void **abstract) -{ - int rc; - - if(!session) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, session, - _libssh2_userauth_publickey(session, user, strlen(user), - pubkeydata, pubkeydata_len, - sign_callback, abstract)); - return rc; -} - - - -/* - * userauth_keyboard_interactive - * - * Authenticate using a challenge-response authentication - */ -static int -userauth_keyboard_interactive(LIBSSH2_SESSION * session, - const char *username, - unsigned int username_len, - LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback))) -{ - unsigned char *s; - int rc; - - static const unsigned char reply_codes[4] = { - SSH_MSG_USERAUTH_SUCCESS, - SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0 - }; - unsigned int language_tag_len; - unsigned int i; - - if (session->userauth_kybd_state == libssh2_NB_state_idle) { - session->userauth_kybd_auth_name = NULL; - session->userauth_kybd_auth_instruction = NULL; - session->userauth_kybd_num_prompts = 0; - session->userauth_kybd_auth_failure = 1; - session->userauth_kybd_prompts = NULL; - session->userauth_kybd_responses = NULL; - - /* Zero the whole thing out */ - memset(&session->userauth_kybd_packet_requirev_state, 0, - sizeof(session->userauth_kybd_packet_requirev_state)); - - session->userauth_kybd_packet_len = - 1 /* byte SSH_MSG_USERAUTH_REQUEST */ - + 4 + username_len /* string user name (ISO-10646 UTF-8, as - defined in [RFC-3629]) */ - + 4 + 14 /* string service name (US-ASCII) */ - + 4 + 20 /* string "keyboard-interactive" (US-ASCII) */ - + 4 + 0 /* string language tag (as defined in - [RFC-3066]) */ - + 4 + 0 /* string submethods (ISO-10646 UTF-8) */ - ; - - session->userauth_kybd_data = s = - LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len); - if (!s) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive authentication"); - } - - *s++ = SSH_MSG_USERAUTH_REQUEST; - - /* user name */ - _libssh2_store_str(&s, username, username_len); - - /* service name */ - _libssh2_store_str(&s, "ssh-connection", sizeof("ssh-connection") - 1); - - /* "keyboard-interactive" */ - _libssh2_store_str(&s, "keyboard-interactive", - sizeof("keyboard-interactive") - 1); - /* language tag */ - _libssh2_store_u32(&s, 0); - - /* submethods */ - _libssh2_store_u32(&s, 0); - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting keyboard-interactive authentication"); - - session->userauth_kybd_state = libssh2_NB_state_created; - } - - if (session->userauth_kybd_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, session->userauth_kybd_data, - session->userauth_kybd_packet_len, - NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); - } else if (rc) { - LIBSSH2_FREE(session, session->userauth_kybd_data); - session->userauth_kybd_data = NULL; - session->userauth_kybd_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send keyboard-interactive request"); - } - LIBSSH2_FREE(session, session->userauth_kybd_data); - session->userauth_kybd_data = NULL; - - session->userauth_kybd_state = libssh2_NB_state_sent; - } - - for(;;) { - if (session->userauth_kybd_state == libssh2_NB_state_sent) { - rc = _libssh2_packet_requirev(session, reply_codes, - &session->userauth_kybd_data, - &session->userauth_kybd_data_len, - 0, NULL, 0, - &session-> - userauth_kybd_packet_requirev_state); - if (rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block"); - } else if (rc) { - session->userauth_kybd_state = libssh2_NB_state_idle; - return _libssh2_error(session, - LIBSSH2_ERROR_AUTHENTICATION_FAILED, - "Waiting for keyboard USERAUTH response"); - } - - if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Keyboard-interactive authentication successful"); - LIBSSH2_FREE(session, session->userauth_kybd_data); - session->userauth_kybd_data = NULL; - session->state |= LIBSSH2_STATE_AUTHENTICATED; - session->userauth_kybd_state = libssh2_NB_state_idle; - return 0; - } - - if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_FAILURE) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Keyboard-interactive authentication failed"); - LIBSSH2_FREE(session, session->userauth_kybd_data); - session->userauth_kybd_data = NULL; - session->userauth_kybd_state = libssh2_NB_state_idle; - return _libssh2_error(session, - LIBSSH2_ERROR_AUTHENTICATION_FAILED, - "Authentication failed " - "(keyboard-interactive)"); - } - - /* server requested PAM-like conversation */ - s = session->userauth_kybd_data + 1; - - /* string name (ISO-10646 UTF-8) */ - session->userauth_kybd_auth_name_len = _libssh2_ntohu32(s); - s += 4; - if(session->userauth_kybd_auth_name_len) { - session->userauth_kybd_auth_name = - LIBSSH2_ALLOC(session, - session->userauth_kybd_auth_name_len); - if (!session->userauth_kybd_auth_name) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive 'name' " - "request field"); - goto cleanup; - } - memcpy(session->userauth_kybd_auth_name, s, - session->userauth_kybd_auth_name_len); - s += session->userauth_kybd_auth_name_len; - } - - /* string instruction (ISO-10646 UTF-8) */ - session->userauth_kybd_auth_instruction_len = _libssh2_ntohu32(s); - s += 4; - if(session->userauth_kybd_auth_instruction_len) { - session->userauth_kybd_auth_instruction = - LIBSSH2_ALLOC(session, - session->userauth_kybd_auth_instruction_len); - if (!session->userauth_kybd_auth_instruction) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive 'instruction' " - "request field"); - goto cleanup; - } - memcpy(session->userauth_kybd_auth_instruction, s, - session->userauth_kybd_auth_instruction_len); - s += session->userauth_kybd_auth_instruction_len; - } - - /* string language tag (as defined in [RFC-3066]) */ - language_tag_len = _libssh2_ntohu32(s); - s += 4; - - /* ignoring this field as deprecated */ - s += language_tag_len; - - /* int num-prompts */ - session->userauth_kybd_num_prompts = _libssh2_ntohu32(s); - s += 4; - - if(session->userauth_kybd_num_prompts) { - session->userauth_kybd_prompts = - LIBSSH2_ALLOC(session, - sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * - session->userauth_kybd_num_prompts); - if (!session->userauth_kybd_prompts) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive prompts array"); - goto cleanup; - } - memset(session->userauth_kybd_prompts, 0, - sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * - session->userauth_kybd_num_prompts); - - session->userauth_kybd_responses = - LIBSSH2_ALLOC(session, - sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * - session->userauth_kybd_num_prompts); - if (!session->userauth_kybd_responses) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive responses array"); - goto cleanup; - } - memset(session->userauth_kybd_responses, 0, - sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * - session->userauth_kybd_num_prompts); - - for(i = 0; i != session->userauth_kybd_num_prompts; ++i) { - /* string prompt[1] (ISO-10646 UTF-8) */ - session->userauth_kybd_prompts[i].length = - _libssh2_ntohu32(s); - s += 4; - session->userauth_kybd_prompts[i].text = - LIBSSH2_ALLOC(session, - session->userauth_kybd_prompts[i].length); - if (!session->userauth_kybd_prompts[i].text) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive prompt message"); - goto cleanup; - } - memcpy(session->userauth_kybd_prompts[i].text, s, - session->userauth_kybd_prompts[i].length); - s += session->userauth_kybd_prompts[i].length; - - /* boolean echo[1] */ - session->userauth_kybd_prompts[i].echo = *s++; - } - } - - response_callback(session->userauth_kybd_auth_name, - session->userauth_kybd_auth_name_len, - session->userauth_kybd_auth_instruction, - session->userauth_kybd_auth_instruction_len, - session->userauth_kybd_num_prompts, - session->userauth_kybd_prompts, - session->userauth_kybd_responses, - &session->abstract); - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Keyboard-interactive response callback function" - " invoked"); - - session->userauth_kybd_packet_len = - 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */ - + 4 /* int num-responses */ - ; - - for(i = 0; i != session->userauth_kybd_num_prompts; ++i) { - /* string response[1] (ISO-10646 UTF-8) */ - session->userauth_kybd_packet_len += - 4 + session->userauth_kybd_responses[i].length; - } - - /* A new userauth_kybd_data area is to be allocated, free the - former one. */ - LIBSSH2_FREE(session, session->userauth_kybd_data); - - session->userauth_kybd_data = s = - LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len); - if (!s) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for keyboard-" - "interactive response packet"); - goto cleanup; - } - - *s = SSH_MSG_USERAUTH_INFO_RESPONSE; - s++; - _libssh2_store_u32(&s, session->userauth_kybd_num_prompts); - - for(i = 0; i != session->userauth_kybd_num_prompts; ++i) { - _libssh2_store_str(&s, - session->userauth_kybd_responses[i].text, - session->userauth_kybd_responses[i].length); - } - - session->userauth_kybd_state = libssh2_NB_state_sent1; - } - - if (session->userauth_kybd_state == libssh2_NB_state_sent1) { - rc = _libssh2_transport_send(session, session->userauth_kybd_data, - session->userauth_kybd_packet_len, - NULL, 0); - if (rc == LIBSSH2_ERROR_EAGAIN) - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block"); - if (rc) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send userauth-keyboard-interactive" - " request"); - goto cleanup; - } - - session->userauth_kybd_auth_failure = 0; - } - - cleanup: - /* - * It's safe to clean all the data here, because unallocated pointers - * are filled by zeroes - */ - - LIBSSH2_FREE(session, session->userauth_kybd_data); - session->userauth_kybd_data = NULL; - - if (session->userauth_kybd_prompts) { - for(i = 0; i != session->userauth_kybd_num_prompts; ++i) { - LIBSSH2_FREE(session, session->userauth_kybd_prompts[i].text); - session->userauth_kybd_prompts[i].text = NULL; - } - } - - if (session->userauth_kybd_responses) { - for(i = 0; i != session->userauth_kybd_num_prompts; ++i) { - LIBSSH2_FREE(session, - session->userauth_kybd_responses[i].text); - session->userauth_kybd_responses[i].text = NULL; - } - } - - if(session->userauth_kybd_prompts) { - LIBSSH2_FREE(session, session->userauth_kybd_prompts); - session->userauth_kybd_prompts = NULL; - } - if(session->userauth_kybd_responses) { - LIBSSH2_FREE(session, session->userauth_kybd_responses); - session->userauth_kybd_responses = NULL; - } - if(session->userauth_kybd_auth_name) { - LIBSSH2_FREE(session, session->userauth_kybd_auth_name); - session->userauth_kybd_auth_name = NULL; - } - if(session->userauth_kybd_auth_instruction) { - LIBSSH2_FREE(session, session->userauth_kybd_auth_instruction); - session->userauth_kybd_auth_instruction = NULL; - } - - if (session->userauth_kybd_auth_failure) { - session->userauth_kybd_state = libssh2_NB_state_idle; - return -1; - } - - session->userauth_kybd_state = libssh2_NB_state_sent; - } -} - -/* - * libssh2_userauth_keyboard_interactive_ex - * - * Authenticate using a challenge-response authentication - */ -LIBSSH2_API int -libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session, - const char *user, - unsigned int user_len, - LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback))) -{ - int rc; - BLOCK_ADJUST(rc, session, - userauth_keyboard_interactive(session, user, user_len, - response_callback)); - return rc; -} diff --git a/vendor/libssh2-1.4.2/src/userauth.h b/vendor/libssh2-1.4.2/src/userauth.h deleted file mode 100644 index c0442ae..0000000 --- a/vendor/libssh2-1.4.2/src/userauth.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef LIBSSH2_USERAUTH_H -#define LIBSSH2_USERAUTH_H -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2009-2010 by Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -int -_libssh2_userauth_publickey(LIBSSH2_SESSION *session, - const char *username, - unsigned int username_len, - const unsigned char *pubkeydata, - unsigned long pubkeydata_len, - LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)), - void *abstract); - -#endif /* LIBSSH2_USERAUTH_H */ diff --git a/vendor/libssh2-1.4.2/src/version.c b/vendor/libssh2-1.4.2/src/version.c deleted file mode 100644 index 408f83a..0000000 --- a/vendor/libssh2-1.4.2/src/version.c +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright (C) 2009 Daniel Stenberg. All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - */ - -#include "libssh2_priv.h" - -/* - libssh2_version() can be used like this: - - if (!libssh2_version(LIBSSH2_VERSION_NUM)) { - fprintf (stderr, "Runtime libssh2 version too old!\n"); - exit(1); - } -*/ -LIBSSH2_API -const char *libssh2_version(int req_version_num) -{ - if(req_version_num <= LIBSSH2_VERSION_NUM) - return LIBSSH2_VERSION; - return NULL; /* this is not a suitable library! */ -} diff --git a/vendor/sigar/CMakeLists.txt b/vendor/sigar/CMakeLists.txt deleted file mode 100644 index 671ac72..0000000 --- a/vendor/sigar/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -INCLUDE_DIRECTORIES(include) - - -IF(WIN32) - INCLUDE_DIRECTORIES(src/os/win32) - SET( os_sources src/os/win32/peb.c src/os/win32/wmi.cpp src/os/win32/win32_sigar.c ) -ELSE(WIN32) - IF( APPLE ) - ADD_DEFINITIONS( -DDARWIN_HAS_LIBPROC_H ) - INCLUDE_DIRECTORIES(src/os/darwin) - SET( os_sources src/os/darwin/darwin_sigar.c ) - ELSE( APPLE ) - INCLUDE_DIRECTORIES(src/os/linux) - SET( os_sources src/os/linux/linux_sigar.c ) - ENDIF( APPLE ) - -ENDIF(WIN32) - - -SET( sources - ${os_sources} - src/sigar.c - src/sigar_cache.c - src/sigar_fileinfo.c - src/sigar_format.c - src/sigar_getline.c - src/sigar_ptql.c - src/sigar_signal.c - src/sigar_util.c - src/sigar_version_autoconf.c -) - -SETUP_LIBRARY( sigar SOURCES ${sources} LIBRARIES ${libraries} LIBRARY_TYPE STATIC ) diff --git a/vendor/sigar/include/sigar.h b/vendor/sigar/include/sigar.h deleted file mode 100644 index 3b26cb8..0000000 --- a/vendor/sigar/include/sigar.h +++ /dev/null @@ -1,943 +0,0 @@ -/* - * Copyright (c) 2004-2008 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * Copyright (c) 2009-2010 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SIGAR_H -#define SIGAR_H - -/* System Information Gatherer And Reporter */ - -#include - -#ifndef MAX_INTERFACE_NAME_LEN -#define MAX_INTERFACE_NAME_LEN 256 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(_LP64) || \ - defined(__LP64__) || \ - defined(__64BIT__) || \ - defined(__powerpc64__) || \ - defined(__osf__) -#define SIGAR_64BIT -#endif - -/* for printf sigar_uint64_t */ -#ifdef SIGAR_64BIT -# define SIGAR_F_U64 "%lu" -#else -# define SIGAR_F_U64 "%Lu" -#endif - -#if defined(WIN32) - -typedef unsigned __int32 sigar_uint32_t; - -typedef unsigned __int64 sigar_uint64_t; - -typedef __int32 sigar_int32_t; - -typedef __int64 sigar_int64_t; - -#elif ULONG_MAX > 4294967295UL - -typedef unsigned int sigar_uint32_t; - -typedef unsigned long sigar_uint64_t; - -typedef int sigar_int32_t; - -typedef long sigar_int64_t; - -#else - -typedef unsigned int sigar_uint32_t; - -typedef unsigned long long sigar_uint64_t; - -typedef int sigar_int32_t; - -typedef long long sigar_int64_t; - -#endif - -#define SIGAR_FIELD_NOTIMPL -1 - -#define SIGAR_OK 0 -#define SIGAR_START_ERROR 20000 -#define SIGAR_ENOTIMPL (SIGAR_START_ERROR + 1) -#define SIGAR_OS_START_ERROR (SIGAR_START_ERROR*2) - -#ifdef WIN32 -# define SIGAR_ENOENT ERROR_FILE_NOT_FOUND -# define SIGAR_EACCES ERROR_ACCESS_DENIED -# define SIGAR_ENXIO ERROR_BAD_DRIVER_LEVEL -#else -# define SIGAR_ENOENT ENOENT -# define SIGAR_EACCES EACCES -# define SIGAR_ENXIO ENXIO -#endif - -#ifdef WIN32 -# define SIGAR_DECLARE(type) \ - __declspec(dllexport) type __stdcall -#else -# define SIGAR_DECLARE(type) type -#endif - -#if defined(PATH_MAX) -# define SIGAR_PATH_MAX PATH_MAX -#elif defined(MAXPATHLEN) -# define SIGAR_PATH_MAX MAXPATHLEN -#else -# define SIGAR_PATH_MAX 4096 -#endif - -#ifdef WIN32 -typedef sigar_uint64_t sigar_pid_t; -typedef unsigned long sigar_uid_t; -typedef unsigned long sigar_gid_t; -#else -#include -typedef pid_t sigar_pid_t; -typedef uid_t sigar_uid_t; -typedef gid_t sigar_gid_t; -#endif - -typedef struct sigar_t sigar_t; - -SIGAR_DECLARE(int) sigar_open(sigar_t **sigar); - -SIGAR_DECLARE(int) sigar_close(sigar_t *sigar); - -SIGAR_DECLARE(sigar_pid_t) sigar_pid_get(sigar_t *sigar); - -SIGAR_DECLARE(int) sigar_proc_kill(sigar_pid_t pid, int signum); - -SIGAR_DECLARE(int) sigar_signum_get(char *name); - -SIGAR_DECLARE(char *) sigar_strerror(sigar_t *sigar, int err); - -/* system memory info */ - -typedef struct { - sigar_uint64_t - ram, - total, - used, - free, - actual_used, - actual_free; - double used_percent; - double free_percent; -} sigar_mem_t; - -SIGAR_DECLARE(int) sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem); - -typedef struct { - sigar_uint64_t - total, - used, - free, - page_in, - page_out; -} sigar_swap_t; - -SIGAR_DECLARE(int) sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap); - -typedef struct { - sigar_uint64_t - user, - sys, - nice, - idle, - wait, - irq, - soft_irq, - stolen, - total; -} sigar_cpu_t; - -SIGAR_DECLARE(int) sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu); - -typedef struct { - unsigned long number; - unsigned long size; - sigar_cpu_t *data; -} sigar_cpu_list_t; - -SIGAR_DECLARE(int) sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist); - -SIGAR_DECLARE(int) sigar_cpu_list_destroy(sigar_t *sigar, - sigar_cpu_list_t *cpulist); - -typedef struct { - char vendor[128]; - char model[128]; - int mhz; - int mhz_max; - int mhz_min; - sigar_uint64_t cache_size; - int total_sockets; - int total_cores; - int cores_per_socket; -} sigar_cpu_info_t; - -typedef struct { - unsigned long number; - unsigned long size; - sigar_cpu_info_t *data; -} sigar_cpu_info_list_t; - -SIGAR_DECLARE(int) -sigar_cpu_info_list_get(sigar_t *sigar, - sigar_cpu_info_list_t *cpu_infos); - -SIGAR_DECLARE(int) -sigar_cpu_info_list_destroy(sigar_t *sigar, - sigar_cpu_info_list_t *cpu_infos); - -typedef struct { - double uptime; -} sigar_uptime_t; - -SIGAR_DECLARE(int) sigar_uptime_get(sigar_t *sigar, - sigar_uptime_t *uptime); - -typedef struct { - double loadavg[3]; -} sigar_loadavg_t; - -SIGAR_DECLARE(int) sigar_loadavg_get(sigar_t *sigar, - sigar_loadavg_t *loadavg); - -typedef struct { - unsigned long number; - unsigned long size; - sigar_pid_t *data; -} sigar_proc_list_t; - -typedef struct { - /* RLIMIT_CPU */ - sigar_uint64_t cpu_cur, cpu_max; - /* RLIMIT_FSIZE */ - sigar_uint64_t file_size_cur, file_size_max; - /* PIPE_BUF */ - sigar_uint64_t pipe_size_cur, pipe_size_max; - /* RLIMIT_DATA */ - sigar_uint64_t data_cur, data_max; - /* RLIMIT_STACK */ - sigar_uint64_t stack_cur, stack_max; - /* RLIMIT_CORE */ - sigar_uint64_t core_cur, core_max; - /* RLIMIT_RSS */ - sigar_uint64_t memory_cur, memory_max; - /* RLIMIT_NPROC */ - sigar_uint64_t processes_cur, processes_max; - /* RLIMIT_NOFILE */ - sigar_uint64_t open_files_cur, open_files_max; - /* RLIMIT_AS */ - sigar_uint64_t virtual_memory_cur, virtual_memory_max; -} sigar_resource_limit_t; - -SIGAR_DECLARE(int) sigar_resource_limit_get(sigar_t *sigar, - sigar_resource_limit_t *rlimit); - -SIGAR_DECLARE(int) sigar_proc_list_get(sigar_t *sigar, - sigar_proc_list_t *proclist); - -SIGAR_DECLARE(int) sigar_proc_list_destroy(sigar_t *sigar, - sigar_proc_list_t *proclist); - -typedef struct { - sigar_uint64_t total; - sigar_uint64_t sleeping; - sigar_uint64_t running; - sigar_uint64_t zombie; - sigar_uint64_t stopped; - sigar_uint64_t idle; - sigar_uint64_t threads; -} sigar_proc_stat_t; - -SIGAR_DECLARE(int) sigar_proc_stat_get(sigar_t *sigar, - sigar_proc_stat_t *procstat); - -typedef struct { - sigar_uint64_t - size, - resident, - share, - minor_faults, - major_faults, - page_faults; -} sigar_proc_mem_t; - -SIGAR_DECLARE(int) sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_mem_t *procmem); - -typedef struct { - sigar_uid_t uid; - sigar_gid_t gid; - sigar_uid_t euid; - sigar_gid_t egid; -} sigar_proc_cred_t; - -SIGAR_DECLARE(int) sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_cred_t *proccred); - -#define SIGAR_CRED_NAME_MAX 512 - -typedef struct { - char user[SIGAR_CRED_NAME_MAX]; - char group[SIGAR_CRED_NAME_MAX]; -} sigar_proc_cred_name_t; - -SIGAR_DECLARE(int) -sigar_proc_cred_name_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_cred_name_t *proccredname); - -typedef struct { - sigar_uint64_t - start_time, - user, - sys, - total; -} sigar_proc_time_t; - -SIGAR_DECLARE(int) sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_time_t *proctime); - -typedef struct { - /* must match sigar_proc_time_t fields */ - sigar_uint64_t - start_time, - user, - sys, - total; - sigar_uint64_t last_time; - double percent; -} sigar_proc_cpu_t; - -SIGAR_DECLARE(int) sigar_proc_cpu_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_cpu_t *proccpu); - -#define SIGAR_PROC_STATE_SLEEP 'S' -#define SIGAR_PROC_STATE_RUN 'R' -#define SIGAR_PROC_STATE_STOP 'T' -#define SIGAR_PROC_STATE_ZOMBIE 'Z' -#define SIGAR_PROC_STATE_IDLE 'D' - -#define SIGAR_PROC_NAME_LEN 128 - -typedef struct { - char name[SIGAR_PROC_NAME_LEN]; - char state; - sigar_pid_t ppid; - int tty; - int priority; - int nice; - int processor; - sigar_uint64_t threads; -} sigar_proc_state_t; - -SIGAR_DECLARE(int) sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_state_t *procstate); - -typedef struct { - unsigned long number; - unsigned long size; - char **data; -} sigar_proc_args_t; - -SIGAR_DECLARE(int) sigar_proc_args_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_args_t *procargs); - -SIGAR_DECLARE(int) sigar_proc_args_destroy(sigar_t *sigar, - sigar_proc_args_t *procargs); - -typedef struct { - void *data; /* user data */ - - enum { - SIGAR_PROC_ENV_ALL, - SIGAR_PROC_ENV_KEY - } type; - - /* used for SIGAR_PROC_ENV_KEY */ - const char *key; - int klen; - - int (*env_getter)(void *, const char *, int, char *, int); -} sigar_proc_env_t; - -SIGAR_DECLARE(int) sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_env_t *procenv); - -typedef struct { - sigar_uint64_t total; - /* XXX - which are files, sockets, etc. */ -} sigar_proc_fd_t; - -SIGAR_DECLARE(int) sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_fd_t *procfd); - -typedef struct { - char name[SIGAR_PATH_MAX+1]; - char cwd[SIGAR_PATH_MAX+1]; - char root[SIGAR_PATH_MAX+1]; -} sigar_proc_exe_t; - -SIGAR_DECLARE(int) sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_exe_t *procexe); - -typedef struct { - void *data; /* user data */ - - int (*module_getter)(void *, char *, int); -} sigar_proc_modules_t; - -SIGAR_DECLARE(int) sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_modules_t *procmods); - -typedef struct { - sigar_uint64_t user; - sigar_uint64_t sys; - sigar_uint64_t total; -} sigar_thread_cpu_t; - -SIGAR_DECLARE(int) sigar_thread_cpu_get(sigar_t *sigar, - sigar_uint64_t id, - sigar_thread_cpu_t *cpu); - -typedef enum { - SIGAR_FSTYPE_UNKNOWN, - SIGAR_FSTYPE_NONE, - SIGAR_FSTYPE_LOCAL_DISK, - SIGAR_FSTYPE_NETWORK, - SIGAR_FSTYPE_RAM_DISK, - SIGAR_FSTYPE_CDROM, - SIGAR_FSTYPE_SWAP, - SIGAR_FSTYPE_MAX -} sigar_file_system_type_e; - -#define SIGAR_FS_NAME_LEN SIGAR_PATH_MAX -#define SIGAR_FS_INFO_LEN 256 - -typedef struct { - char dir_name[SIGAR_FS_NAME_LEN]; - char dev_name[SIGAR_FS_NAME_LEN]; - char type_name[SIGAR_FS_INFO_LEN]; /* e.g. "local" */ - char sys_type_name[SIGAR_FS_INFO_LEN]; /* e.g. "ext3" */ - char options[SIGAR_FS_INFO_LEN]; - sigar_file_system_type_e type; - unsigned long flags; -} sigar_file_system_t; - -typedef struct { - unsigned long number; - unsigned long size; - sigar_file_system_t *data; -} sigar_file_system_list_t; - -SIGAR_DECLARE(int) -sigar_file_system_list_get(sigar_t *sigar, - sigar_file_system_list_t *fslist); - -SIGAR_DECLARE(int) -sigar_file_system_list_destroy(sigar_t *sigar, - sigar_file_system_list_t *fslist); - -typedef struct { - sigar_uint64_t reads; - sigar_uint64_t writes; - sigar_uint64_t write_bytes; - sigar_uint64_t read_bytes; - sigar_uint64_t rtime; - sigar_uint64_t wtime; - sigar_uint64_t qtime; - sigar_uint64_t time; - sigar_uint64_t snaptime; - double service_time; - double queue; -} sigar_disk_usage_t; - -/* XXX for sigar_file_system_usage_t compat */ -#define disk_reads disk.reads -#define disk_writes disk.writes -#define disk_write_bytes disk.write_bytes -#define disk_read_bytes disk.read_bytes -#define disk_queue disk.queue -#define disk_service_time disk.service_time - -typedef struct { - sigar_disk_usage_t disk; - double use_percent; - sigar_uint64_t total; - sigar_uint64_t free; - sigar_uint64_t used; - sigar_uint64_t avail; - sigar_uint64_t files; - sigar_uint64_t free_files; -} sigar_file_system_usage_t; - -#undef SIGAR_DISK_USAGE_T - -SIGAR_DECLARE(int) -sigar_file_system_usage_get(sigar_t *sigar, - const char *dirname, - sigar_file_system_usage_t *fsusage); - -SIGAR_DECLARE(int) sigar_disk_usage_get(sigar_t *sigar, - const char *name, - sigar_disk_usage_t *disk); - -SIGAR_DECLARE(int) -sigar_file_system_ping(sigar_t *sigar, - sigar_file_system_t *fs); - -typedef struct { - enum { - SIGAR_AF_UNSPEC, - SIGAR_AF_INET, - SIGAR_AF_INET6, - SIGAR_AF_LINK - } family; - union { - sigar_uint32_t in; - sigar_uint32_t in6[4]; - unsigned char mac[8]; - } addr; -} sigar_net_address_t; - -#define SIGAR_INET6_ADDRSTRLEN 46 - -#define SIGAR_MAXDOMAINNAMELEN 256 -#define SIGAR_MAXHOSTNAMELEN 256 - -typedef struct { - char default_gateway[SIGAR_INET6_ADDRSTRLEN]; - char default_gateway_interface[MAX_INTERFACE_NAME_LEN]; - char host_name[SIGAR_MAXHOSTNAMELEN]; - char domain_name[SIGAR_MAXDOMAINNAMELEN]; - char primary_dns[SIGAR_INET6_ADDRSTRLEN]; - char secondary_dns[SIGAR_INET6_ADDRSTRLEN]; -} sigar_net_info_t; - -SIGAR_DECLARE(int) -sigar_net_info_get(sigar_t *sigar, - sigar_net_info_t *netinfo); - -#define SIGAR_RTF_UP 0x1 -#define SIGAR_RTF_GATEWAY 0x2 -#define SIGAR_RTF_HOST 0x4 - -typedef struct { - sigar_net_address_t destination; - sigar_net_address_t gateway; - sigar_net_address_t mask; - sigar_uint64_t - flags, - refcnt, - use, - metric, - mtu, - window, - irtt; - char ifname[MAX_INTERFACE_NAME_LEN]; -} sigar_net_route_t; - -typedef struct { - unsigned long number; - unsigned long size; - sigar_net_route_t *data; -} sigar_net_route_list_t; - -SIGAR_DECLARE(int) sigar_net_route_list_get(sigar_t *sigar, - sigar_net_route_list_t *routelist); - -SIGAR_DECLARE(int) sigar_net_route_list_destroy(sigar_t *sigar, - sigar_net_route_list_t *routelist); - -/* - * platforms define most of these "standard" flags, - * but of course, with different values in some cases. - */ -#define SIGAR_IFF_UP 0x1 -#define SIGAR_IFF_BROADCAST 0x2 -#define SIGAR_IFF_DEBUG 0x4 -#define SIGAR_IFF_LOOPBACK 0x8 -#define SIGAR_IFF_POINTOPOINT 0x10 -#define SIGAR_IFF_NOTRAILERS 0x20 -#define SIGAR_IFF_RUNNING 0x40 -#define SIGAR_IFF_NOARP 0x80 -#define SIGAR_IFF_PROMISC 0x100 -#define SIGAR_IFF_ALLMULTI 0x200 -#define SIGAR_IFF_MULTICAST 0x800 -#define SIGAR_IFF_SLAVE 0x1000 -#define SIGAR_IFF_MASTER 0x2000 -#define SIGAR_IFF_DYNAMIC 0x4000 - -#define SIGAR_NULL_HWADDR "00:00:00:00:00:00" - -/* scope values from linux-2.6/include/net/ipv6.h */ -#define SIGAR_IPV6_ADDR_ANY 0x0000 -#define SIGAR_IPV6_ADDR_UNICAST 0x0001 -#define SIGAR_IPV6_ADDR_MULTICAST 0x0002 -#define SIGAR_IPV6_ADDR_LOOPBACK 0x0010 -#define SIGAR_IPV6_ADDR_LINKLOCAL 0x0020 -#define SIGAR_IPV6_ADDR_SITELOCAL 0x0040 -#define SIGAR_IPV6_ADDR_COMPATv4 0x0080 - -typedef struct { - char name[MAX_INTERFACE_NAME_LEN]; - char type[64]; - char description[256]; - sigar_net_address_t hwaddr; - sigar_net_address_t address; - sigar_net_address_t destination; - sigar_net_address_t broadcast; - sigar_net_address_t netmask; - sigar_net_address_t address6; - int prefix6_length; - int scope6; - sigar_uint64_t - flags, - mtu, - metric; - int tx_queue_len; -} sigar_net_interface_config_t; - -SIGAR_DECLARE(int) -sigar_net_interface_config_get(sigar_t *sigar, - const char *name, - sigar_net_interface_config_t *ifconfig); - -SIGAR_DECLARE(int) -sigar_net_interface_config_primary_get(sigar_t *sigar, - sigar_net_interface_config_t *ifconfig); - -typedef struct { - sigar_uint64_t - /* received */ - rx_packets, - rx_bytes, - rx_errors, - rx_dropped, - rx_overruns, - rx_frame, - /* transmitted */ - tx_packets, - tx_bytes, - tx_errors, - tx_dropped, - tx_overruns, - tx_collisions, - tx_carrier, - speed; -} sigar_net_interface_stat_t; - -SIGAR_DECLARE(int) -sigar_net_interface_stat_get(sigar_t *sigar, - const char *name, - sigar_net_interface_stat_t *ifstat); - -typedef struct { - unsigned long number; - unsigned long size; - char **data; -} sigar_net_interface_list_t; - -SIGAR_DECLARE(int) -sigar_net_interface_list_get(sigar_t *sigar, - sigar_net_interface_list_t *iflist); - -SIGAR_DECLARE(int) -sigar_net_interface_list_destroy(sigar_t *sigar, - sigar_net_interface_list_t *iflist); - -#define SIGAR_NETCONN_CLIENT 0x01 -#define SIGAR_NETCONN_SERVER 0x02 - -#define SIGAR_NETCONN_TCP 0x10 -#define SIGAR_NETCONN_UDP 0x20 -#define SIGAR_NETCONN_RAW 0x40 -#define SIGAR_NETCONN_UNIX 0x80 - -enum { - SIGAR_TCP_ESTABLISHED = 1, - SIGAR_TCP_SYN_SENT, - SIGAR_TCP_SYN_RECV, - SIGAR_TCP_FIN_WAIT1, - SIGAR_TCP_FIN_WAIT2, - SIGAR_TCP_TIME_WAIT, - SIGAR_TCP_CLOSE, - SIGAR_TCP_CLOSE_WAIT, - SIGAR_TCP_LAST_ACK, - SIGAR_TCP_LISTEN, - SIGAR_TCP_CLOSING, - SIGAR_TCP_IDLE, - SIGAR_TCP_BOUND, - SIGAR_TCP_UNKNOWN -}; - -typedef struct { - unsigned long local_port; - sigar_net_address_t local_address; - unsigned long remote_port; - sigar_net_address_t remote_address; - sigar_uid_t uid; - unsigned long inode; - int type; - int state; - unsigned long send_queue; - unsigned long receive_queue; -} sigar_net_connection_t; - -typedef struct { - unsigned long number; - unsigned long size; - sigar_net_connection_t *data; -} sigar_net_connection_list_t; - -SIGAR_DECLARE(int) -sigar_net_connection_list_get(sigar_t *sigar, - sigar_net_connection_list_t *connlist, - int flags); - -SIGAR_DECLARE(int) -sigar_net_connection_list_destroy(sigar_t *sigar, - sigar_net_connection_list_t *connlist); - -typedef struct sigar_net_connection_walker_t sigar_net_connection_walker_t; - -/* alternative to sigar_net_connection_list_get */ -struct sigar_net_connection_walker_t { - sigar_t *sigar; - int flags; - void *data; /* user data */ - int (*add_connection)(sigar_net_connection_walker_t *walker, - sigar_net_connection_t *connection); -}; - -SIGAR_DECLARE(int) -sigar_net_connection_walk(sigar_net_connection_walker_t *walker); - -typedef struct { - int tcp_states[SIGAR_TCP_UNKNOWN]; - sigar_uint32_t tcp_inbound_total; - sigar_uint32_t tcp_outbound_total; - sigar_uint32_t all_inbound_total; - sigar_uint32_t all_outbound_total; -} sigar_net_stat_t; - -SIGAR_DECLARE(int) -sigar_net_stat_get(sigar_t *sigar, - sigar_net_stat_t *netstat, - int flags); - -SIGAR_DECLARE(int) -sigar_net_stat_port_get(sigar_t *sigar, - sigar_net_stat_t *netstat, - int flags, - sigar_net_address_t *address, - unsigned long port); - -/* TCP-MIB */ -typedef struct { - sigar_uint64_t active_opens; - sigar_uint64_t passive_opens; - sigar_uint64_t attempt_fails; - sigar_uint64_t estab_resets; - sigar_uint64_t curr_estab; - sigar_uint64_t in_segs; - sigar_uint64_t out_segs; - sigar_uint64_t retrans_segs; - sigar_uint64_t in_errs; - sigar_uint64_t out_rsts; -} sigar_tcp_t; - -SIGAR_DECLARE(int) -sigar_tcp_get(sigar_t *sigar, - sigar_tcp_t *tcp); - -typedef struct { - sigar_uint64_t null; - sigar_uint64_t getattr; - sigar_uint64_t setattr; - sigar_uint64_t root; - sigar_uint64_t lookup; - sigar_uint64_t readlink; - sigar_uint64_t read; - sigar_uint64_t writecache; - sigar_uint64_t write; - sigar_uint64_t create; - sigar_uint64_t remove; - sigar_uint64_t rename; - sigar_uint64_t link; - sigar_uint64_t symlink; - sigar_uint64_t mkdir; - sigar_uint64_t rmdir; - sigar_uint64_t readdir; - sigar_uint64_t fsstat; -} sigar_nfs_v2_t; - -typedef sigar_nfs_v2_t sigar_nfs_client_v2_t; -typedef sigar_nfs_v2_t sigar_nfs_server_v2_t; - -SIGAR_DECLARE(int) -sigar_nfs_client_v2_get(sigar_t *sigar, - sigar_nfs_client_v2_t *nfs); - -SIGAR_DECLARE(int) -sigar_nfs_server_v2_get(sigar_t *sigar, - sigar_nfs_server_v2_t *nfs); - -typedef struct { - sigar_uint64_t null; - sigar_uint64_t getattr; - sigar_uint64_t setattr; - sigar_uint64_t lookup; - sigar_uint64_t access; - sigar_uint64_t readlink; - sigar_uint64_t read; - sigar_uint64_t write; - sigar_uint64_t create; - sigar_uint64_t mkdir; - sigar_uint64_t symlink; - sigar_uint64_t mknod; - sigar_uint64_t remove; - sigar_uint64_t rmdir; - sigar_uint64_t rename; - sigar_uint64_t link; - sigar_uint64_t readdir; - sigar_uint64_t readdirplus; - sigar_uint64_t fsstat; - sigar_uint64_t fsinfo; - sigar_uint64_t pathconf; - sigar_uint64_t commit; -} sigar_nfs_v3_t; - -typedef sigar_nfs_v3_t sigar_nfs_client_v3_t; -typedef sigar_nfs_v3_t sigar_nfs_server_v3_t; - -SIGAR_DECLARE(int) -sigar_nfs_client_v3_get(sigar_t *sigar, - sigar_nfs_client_v3_t *nfs); - -SIGAR_DECLARE(int) -sigar_nfs_server_v3_get(sigar_t *sigar, - sigar_nfs_server_v3_t *nfs); - -SIGAR_DECLARE(int) -sigar_net_listen_address_get(sigar_t *sigar, - unsigned long port, - sigar_net_address_t *address); - -typedef struct { - char ifname[MAX_INTERFACE_NAME_LEN]; - char type[64]; - sigar_net_address_t hwaddr; - sigar_net_address_t address; - sigar_uint64_t flags; -} sigar_arp_t; - -typedef struct { - unsigned long number; - unsigned long size; - sigar_arp_t *data; -} sigar_arp_list_t; - -SIGAR_DECLARE(int) sigar_arp_list_get(sigar_t *sigar, - sigar_arp_list_t *arplist); - -SIGAR_DECLARE(int) sigar_arp_list_destroy(sigar_t *sigar, - sigar_arp_list_t *arplist); - -typedef struct { - char user[32]; - char device[32]; - char host[256]; - sigar_uint64_t time; -} sigar_who_t; - -typedef struct { - unsigned long number; - unsigned long size; - sigar_who_t *data; -} sigar_who_list_t; - -SIGAR_DECLARE(int) sigar_who_list_get(sigar_t *sigar, - sigar_who_list_t *wholist); - -SIGAR_DECLARE(int) sigar_who_list_destroy(sigar_t *sigar, - sigar_who_list_t *wholist); - -SIGAR_DECLARE(int) sigar_proc_port_get(sigar_t *sigar, - int protocol, unsigned long port, - sigar_pid_t *pid); - -typedef struct { - const char *build_date; - const char *scm_revision; - const char *version; - const char *archname; - const char *archlib; - const char *binname; - const char *description; - int major, minor, maint, build; -} sigar_version_t; - -SIGAR_DECLARE(sigar_version_t *) sigar_version_get(void); - -#define SIGAR_SYS_INFO_LEN SIGAR_MAXHOSTNAMELEN /* more than enough */ - -typedef struct { - char name[SIGAR_SYS_INFO_LEN]; /* canonicalized sysname */ - char version[SIGAR_SYS_INFO_LEN]; /* utsname.release */ - char arch[SIGAR_SYS_INFO_LEN]; - char machine[SIGAR_SYS_INFO_LEN]; - char description[SIGAR_SYS_INFO_LEN]; - char patch_level[SIGAR_SYS_INFO_LEN]; - char vendor[SIGAR_SYS_INFO_LEN]; - char vendor_version[SIGAR_SYS_INFO_LEN]; - char vendor_name[SIGAR_SYS_INFO_LEN]; /* utsname.sysname */ - char vendor_code_name[SIGAR_SYS_INFO_LEN]; -} sigar_sys_info_t; - -SIGAR_DECLARE(int) sigar_sys_info_get(sigar_t *sigar, sigar_sys_info_t *sysinfo); - -#define SIGAR_FQDN_LEN 512 - -SIGAR_DECLARE(int) sigar_fqdn_get(sigar_t *sigar, char *name, int namelen); - -SIGAR_DECLARE(int) sigar_rpc_ping(char *hostname, - int protocol, - unsigned long program, - unsigned long version); - -SIGAR_DECLARE(char *) sigar_rpc_strerror(int err); - -SIGAR_DECLARE(char *) sigar_password_get(const char *prompt); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/vendor/sigar/include/sigar_fileinfo.h b/vendor/sigar/include/sigar_fileinfo.h deleted file mode 100644 index f13a4e4..0000000 --- a/vendor/sigar/include/sigar_fileinfo.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2004-2005 Hyperic, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2003 The Apache Software Foundation. All rights - * reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - */ - -#include "sigar.h" - -typedef enum { - SIGAR_FILETYPE_NOFILE = 0, /**< no file type determined */ - SIGAR_FILETYPE_REG, /**< a regular file */ - SIGAR_FILETYPE_DIR, /**< a directory */ - SIGAR_FILETYPE_CHR, /**< a character device */ - SIGAR_FILETYPE_BLK, /**< a block device */ - SIGAR_FILETYPE_PIPE, /**< a FIFO / pipe */ - SIGAR_FILETYPE_LNK, /**< a symbolic link */ - SIGAR_FILETYPE_SOCK, /**< a [unix domain] socket */ - SIGAR_FILETYPE_UNKFILE /**< a file of some other unknown type */ -} sigar_file_type_e; - -#define SIGAR_UREAD 0x0400 /**< Read by user */ -#define SIGAR_UWRITE 0x0200 /**< Write by user */ -#define SIGAR_UEXECUTE 0x0100 /**< Execute by user */ - -#define SIGAR_GREAD 0x0040 /**< Read by group */ -#define SIGAR_GWRITE 0x0020 /**< Write by group */ -#define SIGAR_GEXECUTE 0x0010 /**< Execute by group */ - -#define SIGAR_WREAD 0x0004 /**< Read by others */ -#define SIGAR_WWRITE 0x0002 /**< Write by others */ -#define SIGAR_WEXECUTE 0x0001 /**< Execute by others */ - -typedef struct { - /** The access permissions of the file. Mimics Unix access rights. */ - sigar_uint64_t permissions; - sigar_file_type_e type; - /** The user id that owns the file */ - sigar_uid_t uid; - /** The group id that owns the file */ - sigar_gid_t gid; - /** The inode of the file. */ - sigar_uint64_t inode; - /** The id of the device the file is on. */ - sigar_uint64_t device; - /** The number of hard links to the file. */ - sigar_uint64_t nlink; - /** The size of the file */ - sigar_uint64_t size; - /** The time the file was last accessed */ - sigar_uint64_t atime; - /** The time the file was last modified */ - sigar_uint64_t mtime; - /** The time the file was last changed */ - sigar_uint64_t ctime; -} sigar_file_attrs_t; - -typedef struct { - sigar_uint64_t total; - sigar_uint64_t files; - sigar_uint64_t subdirs; - sigar_uint64_t symlinks; - sigar_uint64_t chrdevs; - sigar_uint64_t blkdevs; - sigar_uint64_t sockets; - sigar_uint64_t disk_usage; -} sigar_dir_stat_t; - -typedef sigar_dir_stat_t sigar_dir_usage_t; - -SIGAR_DECLARE(const char *) -sigar_file_attrs_type_string_get(sigar_file_type_e type); - -SIGAR_DECLARE(int) sigar_file_attrs_get(sigar_t *sigar, - const char *file, - sigar_file_attrs_t *fileattrs); - -SIGAR_DECLARE(int) sigar_link_attrs_get(sigar_t *sigar, - const char *file, - sigar_file_attrs_t *fileattrs); - -SIGAR_DECLARE(int)sigar_file_attrs_mode_get(sigar_uint64_t permissions); - -SIGAR_DECLARE(char *) -sigar_file_attrs_permissions_string_get(sigar_uint64_t permissions, - char *str); - -SIGAR_DECLARE(int) sigar_dir_stat_get(sigar_t *sigar, - const char *dir, - sigar_dir_stat_t *dirstats); - -SIGAR_DECLARE(int) sigar_dir_usage_get(sigar_t *sigar, - const char *dir, - sigar_dir_usage_t *dirusage); diff --git a/vendor/sigar/include/sigar_format.h b/vendor/sigar/include/sigar_format.h deleted file mode 100644 index 3bce29b..0000000 --- a/vendor/sigar/include/sigar_format.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2007-2008 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SIGAR_FORMAT_H -#define SIGAR_FORMAT_H - -typedef struct { - double user; - double sys; - double nice; - double idle; - double wait; - double irq; - double soft_irq; - double stolen; - double combined; -} sigar_cpu_perc_t; - -SIGAR_DECLARE(int) sigar_cpu_perc_calculate(sigar_cpu_t *prev, - sigar_cpu_t *curr, - sigar_cpu_perc_t *perc); - -SIGAR_DECLARE(int) sigar_uptime_string(sigar_t *sigar, - sigar_uptime_t *uptime, - char *buffer, - int buflen); - -SIGAR_DECLARE(char *) sigar_format_size(sigar_uint64_t size, char *buf); - -SIGAR_DECLARE(int) sigar_net_address_equals(sigar_net_address_t *addr1, - sigar_net_address_t *addr2); - -SIGAR_DECLARE(int) sigar_net_address_to_string(sigar_t *sigar, - sigar_net_address_t *address, - char *addr_str); - -SIGAR_DECLARE(const char *)sigar_net_scope_to_string(int type); - -SIGAR_DECLARE(sigar_uint32_t) sigar_net_address_hash(sigar_net_address_t *address); - -SIGAR_DECLARE(const char *)sigar_net_connection_type_get(int type); - -SIGAR_DECLARE(const char *)sigar_net_connection_state_get(int state); - -SIGAR_DECLARE(char *) sigar_net_interface_flags_to_string(sigar_uint64_t flags, char *buf); - -SIGAR_DECLARE(char *)sigar_net_services_name_get(sigar_t *sigar, - int protocol, unsigned long port); - -#endif - diff --git a/vendor/sigar/include/sigar_getline.h b/vendor/sigar/include/sigar_getline.h deleted file mode 100644 index f5bbc7c..0000000 --- a/vendor/sigar/include/sigar_getline.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef SIGAR_GETLINE_H -#define SIGAR_GETLINE_H - -#include "sigar.h" - -typedef int (*sigar_getline_completer_t)(char *, int, int *); - -SIGAR_DECLARE(char *) sigar_getline(char *prompt); -SIGAR_DECLARE(void) sigar_getline_setwidth(int width); -SIGAR_DECLARE(void) sigar_getline_redraw(void); -SIGAR_DECLARE(void) sigar_getline_reset(void); -SIGAR_DECLARE(void) sigar_getline_windowchanged(); -SIGAR_DECLARE(void) sigar_getline_histinit(char *file); -SIGAR_DECLARE(void) sigar_getline_histadd(char *buf); -SIGAR_DECLARE(int) sigar_getline_eof(); -SIGAR_DECLARE(void) sigar_getline_completer_set(sigar_getline_completer_t func); - -#endif /* SIGAR_GETLINE_H */ diff --git a/vendor/sigar/include/sigar_log.h b/vendor/sigar/include/sigar_log.h deleted file mode 100644 index cc32f9a..0000000 --- a/vendor/sigar/include/sigar_log.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2004, 2006 Hyperic, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SIGAR_LOG_H -#define SIGAR_LOG_H - -#include - -#define SIGAR_LOG_FATAL 0 -#define SIGAR_LOG_ERROR 1 -#define SIGAR_LOG_WARN 2 -#define SIGAR_LOG_INFO 3 -#define SIGAR_LOG_DEBUG 4 -#define SIGAR_LOG_TRACE 5 - -#define SIGAR_LOG_IS_FATAL(sigar) \ - (sigar->log_level >= SIGAR_LOG_FATAL) - -#define SIGAR_LOG_IS_ERROR(sigar) \ - (sigar->log_level >= SIGAR_LOG_ERROR) - -#define SIGAR_LOG_IS_WARN(sigar) \ - (sigar->log_level >= SIGAR_LOG_WARN) - -#define SIGAR_LOG_IS_INFO(sigar) \ - (sigar->log_level >= SIGAR_LOG_INFO) - -#define SIGAR_LOG_IS_DEBUG(sigar) \ - (sigar->log_level >= SIGAR_LOG_DEBUG) - -#define SIGAR_LOG_IS_TRACE(sigar) \ - (sigar->log_level >= SIGAR_LOG_TRACE) - -#define SIGAR_STRINGIFY(n) #n - -#define SIGAR_LOG_FILELINE \ - __FILE__ ":" SIGAR_STRINGIFY(__LINE__) - -#if defined(__GNUC__) -# if (__GNUC__ > 2) -# define SIGAR_FUNC __func__ -# else -# define SIGAR_FUNC __FUNCTION__ -# endif -#else -# define SIGAR_FUNC SIGAR_LOG_FILELINE -#endif - -typedef void (*sigar_log_impl_t)(sigar_t *, void *, int, char *); - -SIGAR_DECLARE(void) sigar_log_printf(sigar_t *sigar, int level, - const char *format, ...); - -SIGAR_DECLARE(void) sigar_log(sigar_t *sigar, int level, char *message); - -SIGAR_DECLARE(void) sigar_log_impl_set(sigar_t *sigar, void *data, - sigar_log_impl_t impl); - -SIGAR_DECLARE(void) sigar_log_impl_file(sigar_t *sigar, void *data, - int level, char *message); - -SIGAR_DECLARE(int) sigar_log_level_get(sigar_t *sigar); - -SIGAR_DECLARE(void) sigar_log_level_set(sigar_t *sigar, int level); - - -#endif /* SIGAR_LOG_H */ diff --git a/vendor/sigar/include/sigar_private.h b/vendor/sigar/include/sigar_private.h deleted file mode 100644 index cfc9aa2..0000000 --- a/vendor/sigar/include/sigar_private.h +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright (c) 2004-2008 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * Copyright (c) 2009-2010 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SIGAR_PRIVATE_DOT_H -#define SIGAR_PRIVATE_DOT_H - -#include "sigar_log.h" -#include "sigar_ptql.h" - -#include -#include -#include - -#ifndef WIN32 -#include -#include -#ifndef DARWIN -#include -#endif -#endif - -#ifdef DMALLOC -#define _MEMORY_H /* exclude memory.h on solaris */ -#define DMALLOC_FUNC_CHECK -#include -#endif - -/* common to all os sigar_t's */ -/* XXX: this is ugly; but don't want the same stuffs - * duplicated on 4 platforms and am too lazy to change - * sigar_t to the way it was originally where sigar_t was - * common and contained a sigar_os_t. - * feel free trav ;-) - */ -#define SIGAR_T_BASE \ - int cpu_list_cores; \ - int log_level; \ - void *log_data; \ - sigar_log_impl_t log_impl; \ - void *ptql_re_data; \ - sigar_ptql_re_impl_t ptql_re_impl; \ - unsigned int ncpu; \ - unsigned long version; \ - unsigned long boot_time; \ - int ticks; \ - sigar_pid_t pid; \ - char errbuf[256]; \ - char *ifconf_buf; \ - int ifconf_len; \ - char *self_path; \ - sigar_proc_list_t *pids; \ - sigar_cache_t *fsdev; \ - sigar_cache_t *proc_cpu; \ - sigar_cache_t *net_listen; \ - sigar_cache_t *net_services_tcp; \ - sigar_cache_t *net_services_udp - -#if defined(WIN32) -# define SIGAR_INLINE __inline -#elif defined(__GNUC__) -# define SIGAR_INLINE inline -#else -# define SIGAR_INLINE -#endif - -#ifdef DMALLOC -/* linux has its own strdup macro, make sure we use dmalloc's */ -#define sigar_strdup(s) \ - dmalloc_strndup(__FILE__, __LINE__, (s), -1, 0) -#else -# ifdef WIN32 -# define sigar_strdup(s) _strdup(s) -# else -# define sigar_strdup(s) strdup(s) -# endif -#endif - -#define SIGAR_ZERO(s) \ - memset(s, '\0', sizeof(*(s))) - -#define SIGAR_STRNCPY(dest, src, len) \ - strncpy(dest, src, len); \ - dest[len-1] = '\0' - -/* we use fixed size buffers pretty much everywhere */ -/* this is strncpy + ensured \0 terminator */ -#define SIGAR_SSTRCPY(dest, src) \ - SIGAR_STRNCPY(dest, src, sizeof(dest)) - -#ifndef strEQ -#define strEQ(s1, s2) (strcmp(s1, s2) == 0) -#endif - -#ifndef strnEQ -#define strnEQ(s1, s2, n) (strncmp(s1, s2, n) == 0) -#endif - -#ifdef WIN32 -#define strcasecmp stricmp -#define strncasecmp strnicmp -#endif - -#ifndef strcaseEQ -#define strcaseEQ(s1, s2) (strcasecmp(s1, s2) == 0) -#endif - -#ifndef strncaseEQ -#define strncaseEQ(s1, s2, n) (strncasecmp(s1, s2, n) == 0) -#endif - -#ifdef offsetof -#define sigar_offsetof offsetof -#else -#define sigar_offsetof(type, field) ((size_t)(&((type *)0)->field)) -#endif - -#define SIGAR_MSEC 1000L -#define SIGAR_USEC 1000000L -#define SIGAR_NSEC 1000000000L - -#define SIGAR_SEC2NANO(s) \ - ((sigar_uint64_t)(s) * (sigar_uint64_t)SIGAR_NSEC) - -/* cpu ticks to milliseconds */ -#define SIGAR_TICK2MSEC(s) \ - ((sigar_uint64_t)(s) * ((sigar_uint64_t)SIGAR_MSEC / (double)sigar->ticks)) - -#define SIGAR_TICK2NSEC(s) \ - ((sigar_uint64_t)(s) * ((sigar_uint64_t)SIGAR_NSEC / (double)sigar->ticks)) - -/* nanoseconds to milliseconds */ -#define SIGAR_NSEC2MSEC(s) \ - ((sigar_uint64_t)(s) / ((sigar_uint64_t)1000000L)) - -#define IFTYPE_LO 2 -#define IFTYPE_ETH 3 - -#define SIGAR_LAST_PROC_EXPIRE 2 - -#define SIGAR_FS_MAX 10 - -#define SIGAR_CPU_INFO_MAX 4 - -#define SIGAR_CPU_LIST_MAX 4 - -#define SIGAR_PROC_LIST_MAX 256 - -#define SIGAR_PROC_ARGS_MAX 12 - -#define SIGAR_NET_ROUTE_LIST_MAX 6 - -#define SIGAR_NET_IFLIST_MAX 20 - -#define SIGAR_NET_CONNLIST_MAX 20 - -#define SIGAR_ARP_LIST_MAX 12 - -#define SIGAR_WHO_LIST_MAX 12 - -int sigar_os_open(sigar_t **sigar); - -int sigar_os_close(sigar_t *sigar); - -char *sigar_os_error_string(sigar_t *sigar, int err); - -char *sigar_strerror_get(int err, char *errbuf, int buflen); - -void sigar_strerror_set(sigar_t *sigar, char *msg); - -void sigar_strerror_printf(sigar_t *sigar, const char *format, ...); - -int sigar_sys_info_get_uname(sigar_sys_info_t *sysinfo); - -int sigar_os_sys_info_get(sigar_t *sigar, sigar_sys_info_t *sysinfo); - -int sigar_os_proc_list_get(sigar_t *sigar, - sigar_proc_list_t *proclist); - -int sigar_proc_list_create(sigar_proc_list_t *proclist); - -int sigar_proc_list_grow(sigar_proc_list_t *proclist); - -#define SIGAR_PROC_LIST_GROW(proclist) \ - if (proclist->number >= proclist->size) { \ - sigar_proc_list_grow(proclist); \ - } - -int sigar_proc_args_create(sigar_proc_args_t *proclist); - -int sigar_proc_args_grow(sigar_proc_args_t *procargs); - -#define SIGAR_PROC_ARGS_GROW(procargs) \ - if (procargs->number >= procargs->size) { \ - sigar_proc_args_grow(procargs); \ - } - -int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_args_t *procargs); - -int sigar_file_system_list_create(sigar_file_system_list_t *fslist); - -int sigar_file_system_list_grow(sigar_file_system_list_t *fslist); - -#define SIGAR_FILE_SYSTEM_LIST_GROW(fslist) \ - if (fslist->number >= fslist->size) { \ - sigar_file_system_list_grow(fslist); \ - } - -int sigar_os_fs_type_get(sigar_file_system_t *fsp); - -/* os plugins that set fsp->type call fs_type_get directly */ -#define sigar_fs_type_init(fsp) \ - fsp->type = SIGAR_FSTYPE_UNKNOWN; \ - sigar_fs_type_get(fsp) - -void sigar_fs_type_get(sigar_file_system_t *fsp); - -int sigar_cpu_info_list_create(sigar_cpu_info_list_t *cpu_infos); - -int sigar_cpu_info_list_grow(sigar_cpu_info_list_t *cpu_infos); - -#define SIGAR_CPU_INFO_LIST_GROW(cpu_infos) \ - if (cpu_infos->number >= cpu_infos->size) { \ - sigar_cpu_info_list_grow(cpu_infos); \ - } - -int sigar_cpu_list_create(sigar_cpu_list_t *cpulist); - -int sigar_cpu_list_grow(sigar_cpu_list_t *cpulist); - -#define SIGAR_CPU_LIST_GROW(cpulist) \ - if (cpulist->number >= cpulist->size) { \ - sigar_cpu_list_grow(cpulist); \ - } - -int sigar_net_route_list_create(sigar_net_route_list_t *routelist); - -int sigar_net_route_list_grow(sigar_net_route_list_t *net_routelist); - -#define SIGAR_NET_ROUTE_LIST_GROW(routelist) \ - if (routelist->number >= routelist->size) { \ - sigar_net_route_list_grow(routelist); \ - } - -int sigar_net_interface_list_create(sigar_net_interface_list_t *iflist); - -int sigar_net_interface_list_grow(sigar_net_interface_list_t *iflist); - -#define SIGAR_NET_IFLIST_GROW(iflist) \ - if (iflist->number >= iflist->size) { \ - sigar_net_interface_list_grow(iflist); \ - } - -int sigar_net_connection_list_create(sigar_net_connection_list_t *connlist); - -int sigar_net_connection_list_grow(sigar_net_connection_list_t *connlist); - -#define SIGAR_NET_CONNLIST_GROW(connlist) \ - if (connlist->number >= connlist->size) { \ - sigar_net_connection_list_grow(connlist); \ - } - -#define sigar_net_address_set(a, val) \ - (a).addr.in = val; \ - (a).family = SIGAR_AF_INET - -#define sigar_net_address6_set(a, val) \ - memcpy(&((a).addr.in6), val, sizeof((a).addr.in6)); \ - (a).family = SIGAR_AF_INET6 - -#define SIGAR_IFHWADDRLEN 6 - -#define sigar_net_address_mac_set(a, val, len) \ - memcpy(&((a).addr.mac), val, len); \ - (a).family = SIGAR_AF_LINK - -#define sigar_hwaddr_set_null(ifconfig) \ - SIGAR_ZERO(&ifconfig->hwaddr.addr.mac); \ - ifconfig->hwaddr.family = SIGAR_AF_LINK - -int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, - sigar_net_interface_config_t *ifconfig); - -#define sigar_net_interface_ipv6_config_init(ifconfig) \ - ifconfig->address6.family = SIGAR_AF_INET6; \ - ifconfig->prefix6_length = 0; \ - ifconfig->scope6 = 0 - -#define SIGAR_SIN6(s) ((struct sockaddr_in6 *)(s)) - -#define SIGAR_SIN6_ADDR(s) &SIGAR_SIN6(s)->sin6_addr - -#define sigar_net_interface_scope6_set(ifconfig, addr) \ - if (IN6_IS_ADDR_LINKLOCAL(addr)) \ - ifconfig->scope6 = SIGAR_IPV6_ADDR_LINKLOCAL; \ - else if (IN6_IS_ADDR_SITELOCAL(addr)) \ - ifconfig->scope6 = SIGAR_IPV6_ADDR_SITELOCAL; \ - else if (IN6_IS_ADDR_V4COMPAT(addr)) \ - ifconfig->scope6 = SIGAR_IPV6_ADDR_COMPATv4; \ - else if (IN6_IS_ADDR_LOOPBACK(addr)) \ - ifconfig->scope6 = SIGAR_IPV6_ADDR_LOOPBACK; \ - else \ - ifconfig->scope6 = SIGAR_IPV6_ADDR_ANY - -int sigar_tcp_curr_estab(sigar_t *sigar, sigar_tcp_t *tcp); - -int sigar_arp_list_create(sigar_arp_list_t *arplist); - -int sigar_arp_list_grow(sigar_arp_list_t *arplist); - -#define SIGAR_ARP_LIST_GROW(arplist) \ - if (arplist->number >= arplist->size) { \ - sigar_arp_list_grow(arplist); \ - } - -int sigar_who_list_create(sigar_who_list_t *wholist); - -int sigar_who_list_grow(sigar_who_list_t *wholist); - -#define SIGAR_WHO_LIST_GROW(wholist) \ - if (wholist->number >= wholist->size) { \ - sigar_who_list_grow(wholist); \ - } - -int sigar_user_id_get(sigar_t *sigar, const char *name, int *uid); - -int sigar_user_name_get(sigar_t *sigar, int uid, char *buf, int buflen); - -int sigar_group_name_get(sigar_t *sigar, int gid, char *buf, int buflen); - -#define SIGAR_PROC_ENV_KEY_LOOKUP() \ - if ((procenv->type == SIGAR_PROC_ENV_KEY) && \ - (pid == sigar->pid)) \ - { \ - char *value = getenv(procenv->key); \ - if (value != NULL) { \ - procenv->env_getter(procenv->data, \ - procenv->key, \ - procenv->klen, \ - value, strlen(value)); \ - } \ - return SIGAR_OK; \ - } - -#define SIGAR_DISK_STATS_INIT(disk) \ - (disk)->reads = (disk)->writes = \ - (disk)->read_bytes = (disk)->write_bytes = \ - (disk)->rtime = (disk)->wtime = (disk)->qtime = (disk)->time = \ - (disk)->queue = (disk)->service_time = SIGAR_FIELD_NOTIMPL; \ - (disk)->snaptime = 0 - -/* key used for filesystem (/) -> device (/dev/hda1) mapping */ -/* and disk_usage cache for service_time */ -#define SIGAR_FSDEV_ID(sb) \ - (S_ISBLK((sb).st_mode) ? (sb).st_rdev : ((sb).st_ino + (sb).st_dev)) - -#if defined(WIN32) || defined(NETWARE) -int sigar_get_iftype(const char *name, int *type, int *inst); -#endif - -#define SIGAR_NIC_LOOPBACK "Local Loopback" -#define SIGAR_NIC_UNSPEC "UNSPEC" -#define SIGAR_NIC_SLIP "Serial Line IP" -#define SIGAR_NIC_CSLIP "VJ Serial Line IP" -#define SIGAR_NIC_SLIP6 "6-bit Serial Line IP" -#define SIGAR_NIC_CSLIP6 "VJ 6-bit Serial Line IP" -#define SIGAR_NIC_ADAPTIVE "Adaptive Serial Line IP" -#define SIGAR_NIC_ETHERNET "Ethernet" -#define SIGAR_NIC_ASH "Ash" -#define SIGAR_NIC_FDDI "Fiber Distributed Data Interface" -#define SIGAR_NIC_HIPPI "HIPPI" -#define SIGAR_NIC_AX25 "AMPR AX.25" -#define SIGAR_NIC_ROSE "AMPR ROSE" -#define SIGAR_NIC_NETROM "AMPR NET/ROM" -#define SIGAR_NIC_X25 "generic X.25" -#define SIGAR_NIC_TUNNEL "IPIP Tunnel" -#define SIGAR_NIC_PPP "Point-to-Point Protocol" -#define SIGAR_NIC_HDLC "(Cisco)-HDLC" -#define SIGAR_NIC_LAPB "LAPB" -#define SIGAR_NIC_ARCNET "ARCnet" -#define SIGAR_NIC_DLCI "Frame Relay DLCI" -#define SIGAR_NIC_FRAD "Frame Relay Access Device" -#define SIGAR_NIC_SIT "IPv6-in-IPv4" -#define SIGAR_NIC_IRDA "IrLAP" -#define SIGAR_NIC_EC "Econet" - -#ifndef WIN32 -#include -#endif - -#define SIGAR_HOSTENT_LEN 1024 -#if defined(_AIX) -#define SIGAR_HAS_HOSTENT_DATA -#endif - -typedef struct { - char buffer[SIGAR_HOSTENT_LEN]; - int error; -#ifndef WIN32 - struct hostent hs; -#endif -#ifdef SIGAR_HAS_HOSTENT_DATA - struct hostent_data hd; -#endif -} sigar_hostent_t; - -#endif diff --git a/vendor/sigar/include/sigar_ptql.h b/vendor/sigar/include/sigar_ptql.h deleted file mode 100644 index 53d28ec..0000000 --- a/vendor/sigar/include/sigar_ptql.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2006-2007 Hyperic, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SIGAR_PTQL_H -#define SIGAR_PTQL_H - -#define SIGAR_PTQL_MALFORMED_QUERY -1 - -typedef struct sigar_ptql_query_t sigar_ptql_query_t; - -#define SIGAR_PTQL_ERRMSG_SIZE 1024 - -typedef struct { - char message[SIGAR_PTQL_ERRMSG_SIZE]; -} sigar_ptql_error_t; - -typedef int (*sigar_ptql_re_impl_t)(void *, char *, char *); - -SIGAR_DECLARE(void) sigar_ptql_re_impl_set(sigar_t *sigar, void *data, - sigar_ptql_re_impl_t impl); - -SIGAR_DECLARE(int) sigar_ptql_query_create(sigar_ptql_query_t **query, - char *ptql, - sigar_ptql_error_t *error); - -SIGAR_DECLARE(int) sigar_ptql_query_match(sigar_t *sigar, - sigar_ptql_query_t *query, - sigar_pid_t pid); - -SIGAR_DECLARE(int) sigar_ptql_query_destroy(sigar_ptql_query_t *query); - -SIGAR_DECLARE(int) sigar_ptql_query_find_process(sigar_t *sigar, - sigar_ptql_query_t *query, - sigar_pid_t *pid); - -SIGAR_DECLARE(int) sigar_ptql_query_find(sigar_t *sigar, - sigar_ptql_query_t *query, - sigar_proc_list_t *proclist); - -#endif /*SIGAR_PTQL_H*/ diff --git a/vendor/sigar/include/sigar_util.h b/vendor/sigar/include/sigar_util.h deleted file mode 100644 index bc605fc..0000000 --- a/vendor/sigar/include/sigar_util.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2004-2008 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SIGAR_UTIL_H -#define SIGAR_UTIL_H - -/* most of this is crap for dealing with linux /proc */ -#define UITOA_BUFFER_SIZE \ - (sizeof(int) * 3 + 1) - -#define SSTRLEN(s) \ - (sizeof(s)-1) - -#define sigar_strtoul(ptr) \ - strtoul(ptr, &ptr, 10) - -#define sigar_strtoull(ptr) \ - strtoull(ptr, &ptr, 10) - -#define sigar_isspace(c) \ - (isspace(((unsigned char)(c)))) - -#define sigar_isdigit(c) \ - (isdigit(((unsigned char)(c)))) - -#define sigar_isalpha(c) \ - (isalpha(((unsigned char)(c)))) - -#define sigar_isupper(c) \ - (isupper(((unsigned char)(c)))) - -#define sigar_tolower(c) \ - (tolower(((unsigned char)(c)))) - -#ifdef WIN32 -#define sigar_fileno _fileno -#define sigar_isatty _isatty -#define sigar_write _write -#else -#define sigar_fileno fileno -#define sigar_isatty isatty -#define sigar_write write -#endif - -#ifndef PROC_FS_ROOT -#define PROC_FS_ROOT "/proc/" -#endif - -#ifndef PROCP_FS_ROOT -#define PROCP_FS_ROOT "/proc/" -#endif - -sigar_int64_t sigar_time_now_millis(void); - -char *sigar_uitoa(char *buf, unsigned int n, int *len); - -int sigar_inet_ntoa(sigar_t *sigar, - sigar_uint32_t address, - char *addr_str); - -struct hostent *sigar_gethostbyname(const char *name, - sigar_hostent_t *data); - -SIGAR_INLINE char *sigar_skip_line(char *buffer, int buflen); - -SIGAR_INLINE char *sigar_skip_token(char *p); - -SIGAR_INLINE char *sigar_skip_multiple_token(char *p, int count); - -char *sigar_getword(char **line, char stop); - -char *sigar_strcasestr(const char *s1, const char *s2); - -int sigar_file2str(const char *fname, char *buffer, int buflen); - -int sigar_proc_file2str(char *buffer, int buflen, - sigar_pid_t pid, - const char *fname, - int fname_len); - -#define SIGAR_PROC_FILE2STR(buffer, pid, fname) \ - sigar_proc_file2str(buffer, sizeof(buffer), \ - pid, fname, SSTRLEN(fname)) - -#define SIGAR_PROC_FILENAME(buffer, pid, fname) \ - sigar_proc_filename(buffer, sizeof(buffer), \ - pid, fname, SSTRLEN(fname)) - -#define SIGAR_SKIP_SPACE(ptr) \ - while (sigar_isspace(*ptr)) ++ptr - -char *sigar_proc_filename(char *buffer, int buflen, - sigar_pid_t pid, - const char *fname, int fname_len); - -int sigar_proc_list_procfs_get(sigar_t *sigar, - sigar_proc_list_t *proclist); - -int sigar_proc_fd_count(sigar_t *sigar, sigar_pid_t pid, - sigar_uint64_t *total); - -/* linux + freebsd */ -int sigar_procfs_args_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_args_t *procargs); - -int sigar_mem_calc_ram(sigar_t *sigar, sigar_mem_t *mem); - -int sigar_statvfs(sigar_t *sigar, - const char *dirname, - sigar_file_system_usage_t *fsusage); - -double sigar_file_system_usage_calc_used(sigar_t *sigar, - sigar_file_system_usage_t *fs); - -#define SIGAR_DEV_PREFIX "/dev/" - -#define SIGAR_NAME_IS_DEV(dev) \ - strnEQ(dev, SIGAR_DEV_PREFIX, SSTRLEN(SIGAR_DEV_PREFIX)) - -typedef struct { - char name[256]; - int is_partition; - sigar_disk_usage_t disk; -} sigar_iodev_t; - -sigar_iodev_t *sigar_iodev_get(sigar_t *sigar, - const char *dirname); - -int sigar_cpu_core_count(sigar_t *sigar); - -/* e.g. VM guest may have 1 virtual ncpu on multicore hosts */ -#define sigar_cpu_socket_count(sigar) \ - (sigar->ncpu < sigar->lcpu) ? sigar->ncpu : \ - (sigar->ncpu / sigar->lcpu) - -int sigar_cpu_core_rollup(sigar_t *sigar); - -void sigar_cpu_model_adjust(sigar_t *sigar, sigar_cpu_info_t *info); - -int sigar_cpu_mhz_from_model(char *model); - -char *sigar_get_self_path(sigar_t *sigar); - -#if defined(__sun) || defined(__FreeBSD__) - -#define SIGAR_HAS_DLINFO_MODULES -#include -#include - -int sigar_dlinfo_modules(sigar_t *sigar, sigar_proc_modules_t *procmods); -#endif - -typedef struct sigar_cache_entry_t sigar_cache_entry_t; - -struct sigar_cache_entry_t { - sigar_cache_entry_t *next; - sigar_uint64_t id; - void *value; -}; - -typedef struct { - sigar_cache_entry_t **entries; - unsigned int count, size; - void (*free_value)(void *ptr); -} sigar_cache_t; - -sigar_cache_t *sigar_cache_new(int size); - -sigar_cache_entry_t *sigar_cache_get(sigar_cache_t *table, - sigar_uint64_t key); - -sigar_cache_entry_t *sigar_cache_find(sigar_cache_t *table, - sigar_uint64_t key); - -void sigar_cache_destroy(sigar_cache_t *table); - -#endif /* SIGAR_UTIL_H */ diff --git a/vendor/sigar/src/os/aix/aix_sigar.c b/vendor/sigar/src/os/aix/aix_sigar.c deleted file mode 100644 index a4c0a88..0000000 --- a/vendor/sigar/src/os/aix/aix_sigar.c +++ /dev/null @@ -1,2151 +0,0 @@ -/* - * Copyright (c) 2004-2009 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * Copyright (c) 2009-2010 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* pull in time.h before resource.h does w/ _KERNEL */ -#include -#define _KERNEL 1 -#include /* for struct file */ -#include /* for rlimit32 in 64-bit mode */ -#undef _KERNEL - -#include "sigar.h" -#include "sigar_private.h" -#include "sigar_util.h" -#include "sigar_os.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* for proc_port */ -#include -#include -#include -#include - -/* for net_connection_list */ -#include -#include -#include -#include - -/* for odm api */ -#include -#include -#include - -#include - -/* for net_interface_config ipv6 */ -#include -#include - -/* for getkerninfo */ -#include - -/* not defined in aix 4.3 */ -#ifndef SBITS -#define SBITS 16 -#endif - -#ifndef PTHRDSINFO_RUSAGE_START -#define PTHRDSINFO_RUSAGE_START 0x00000001 -#define PTHRDSINFO_RUSAGE_STOP 0x00000002 -#define PTHRDSINFO_RUSAGE_COLLECT 0x00000004 -#endif - -/* - * from libperfstat.h: - * "To calculate the load average, divide the numbers by (1<." - */ -#define FIXED_TO_DOUBLE(x) (((double)x) / (1<koffsets[i] = klist[i].n_value; - } - - return SIGAR_OK; -} - -static int kread(sigar_t *sigar, void *data, int size, long offset) -{ - if (sigar->kmem < 0) { - return SIGAR_EPERM_KMEM; - } - - if (lseek(sigar->kmem, offset, SEEK_SET) != offset) { - return errno; - } - - if (read(sigar->kmem, data, size) != size) { - return errno; - } - - return SIGAR_OK; -} - -static int sigar_thread_rusage(struct rusage *usage, int mode) -{ - return pthread_getrusage_np(pthread_self(), usage, mode); -} - -static int sigar_perfstat_memory(perfstat_memory_total_t *memory) -{ - return perfstat_memory_total(NULL, memory, sizeof(*memory), 1); -} - -static int sigar_perfstat_cpu(perfstat_cpu_total_t *cpu_total) -{ - return perfstat_cpu_total(NULL, cpu_total, sizeof(*cpu_total), 1); -} - -int sigar_os_open(sigar_t **sigar) -{ - int status, i; - int kmem = -1; - struct utsname name; - - kmem = open("/dev/kmem", O_RDONLY); - - *sigar = malloc(sizeof(**sigar)); - - (*sigar)->getprocfd = NULL; /*XXX*/ - (*sigar)->kmem = kmem; - (*sigar)->pagesize = 0; - (*sigar)->ticks = sysconf(_SC_CLK_TCK); - (*sigar)->boot_time = 0; - (*sigar)->last_pid = -1; - (*sigar)->pinfo = NULL; - (*sigar)->cpuinfo = NULL; - (*sigar)->cpuinfo_size = 0; - SIGAR_ZERO(&(*sigar)->swaps); - - i = getpagesize(); - while ((i >>= 1) > 0) { - (*sigar)->pagesize++; - } - - if (kmem > 0) { - if ((status = get_koffsets(*sigar)) != SIGAR_OK) { - /* libperfstat only mode (aix 6) */ - close((*sigar)->kmem); - (*sigar)->kmem = -1; - } - } - - (*sigar)->cpu_mhz = -1; - - (*sigar)->model[0] = '\0'; - - uname(&name); - - (*sigar)->aix_version = atoi(name.version); - - (*sigar)->thrusage = PTHRDSINFO_RUSAGE_STOP; - - (*sigar)->diskmap = NULL; - - return SIGAR_OK; -} - -static void swaps_free(swaps_t *swaps); - -int sigar_os_close(sigar_t *sigar) -{ - swaps_free(&sigar->swaps); - if (sigar->kmem > 0) { - close(sigar->kmem); - } - if (sigar->pinfo) { - free(sigar->pinfo); - } - if (sigar->cpuinfo) { - free(sigar->cpuinfo); - } - if (sigar->diskmap) { - sigar_cache_destroy(sigar->diskmap); - } - if (sigar->thrusage == PTHRDSINFO_RUSAGE_START) { - struct rusage usage; - sigar_thread_rusage(&usage, - PTHRDSINFO_RUSAGE_STOP); - } - free(sigar); - return SIGAR_OK; -} - -char *sigar_os_error_string(sigar_t *sigar, int err) -{ - switch (err) { - case SIGAR_EPERM_KMEM: - return "Failed to open /dev/kmem for reading"; - default: - return NULL; - } -} - -#define PAGESHIFT(v) \ - ((v) << sigar->pagesize) - -int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem) -{ - int status; - perfstat_memory_total_t minfo; - sigar_uint64_t kern; - - if (sigar_perfstat_memory(&minfo) == 1) { - mem->total = PAGESHIFT(minfo.real_total); - mem->free = PAGESHIFT(minfo.real_free); - kern = PAGESHIFT(minfo.numperm); /* number of pages in file cache */ - } - else { - return errno; - } - - mem->used = mem->total - mem->free; - mem->actual_used = mem->used - kern; - mem->actual_free = mem->free + kern; - - sigar_mem_calc_ram(sigar, mem); - - return SIGAR_OK; -} - -static void swaps_free(swaps_t *swaps) -{ - if (swaps->num) { - int i; - - for (i=0; inum; i++) { - free(swaps->devs[i]); - } - - free(swaps->devs); - - swaps->num = 0; - } -} - -/* - * there is no public api for parsing this file. - * well, there is something, but its super ugly and requires - * linking 2 static libraries (libodm and something else) - * maybe will switch to that if it can add value elsewhere too. - */ -#define SWAPSPACES "/etc/swapspaces" - -static int swaps_get(swaps_t *swaps) -{ - FILE *fp; - char buf[512]; - char *ptr; - struct stat statbuf; - - if (stat(SWAPSPACES, &statbuf) < 0) { - return errno; - } - - /* only re-parse if file has changed */ - if (swaps->mtime == statbuf.st_mtime) { - return 0; - } - - swaps->mtime = statbuf.st_mtime; - - /* easier to just start from scratch */ - swaps_free(swaps); - - if (!(fp = fopen(SWAPSPACES, "r"))) { - return errno; - } - - while ((ptr = fgets(buf, sizeof(buf), fp))) { - if (!isalpha(*ptr)) { - continue; - } - - if (strchr(ptr, ':')) { - int len; - - ptr = fgets(buf, sizeof(buf), fp); - - while (isspace(*ptr)) { - ++ptr; - } - - if (strncmp(ptr, "dev", 3)) { - continue; - } - ptr += 3; - while (isspace(*ptr) || (*ptr == '=')) { - ++ptr; - } - - len = strlen(ptr); - ptr[len-1] = '\0'; /* -1 == chomp \n */ - - swaps->devs = realloc(swaps->devs, swaps->num+1 * sizeof(char *)); - swaps->devs[swaps->num] = malloc(len); - memcpy(swaps->devs[swaps->num], ptr, len); - - swaps->num++; - } - } - - fclose(fp); - - return 0; -} - -/* - * documented in aix tech ref, - * but this prototype is not in any friggin header file. - * struct pginfo is in sys/vminfo.h - */ - -int swapqry(char *path, struct pginfo *info); - -static int sigar_swap_get_swapqry(sigar_t *sigar, sigar_swap_t *swap) -{ - int status, i; - - if ((status = swaps_get(&sigar->swaps)) != SIGAR_OK) { - return status; - } - - if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[swap] pagesize=%d, shift=%d", - getpagesize(), sigar->pagesize); - } - - swap->total = swap->free = 0; - - for (i=0; iswaps.num; i++) { - struct pginfo info; - - status = swapqry(sigar->swaps.devs[i], &info); - - if (status != 0) { - if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[swap] swapqry(%s) failed: %s", - sigar->swaps.devs[i], - sigar_strerror(sigar, errno)); - } - continue; - } - - if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[swap] %s total=%d/%d, free=%d/%d", - sigar->swaps.devs[i], - info.size, PAGESHIFT(info.size), - info.free, PAGESHIFT(info.free)); - } - - swap->total += PAGESHIFT(info.size); /* lsps -a */ - swap->free += PAGESHIFT(info.free); - } - - swap->used = swap->total - swap->free; - - return SIGAR_OK; -} - -#define SWAP_DEV(ps) \ - ((ps.type == LV_PAGING) ? \ - ps.u.lv_paging.vgname : \ - ps.u.nfs_paging.filename) - -#define SWAP_MB_TO_BYTES(v) ((v) * (1024 * 1024)) - -int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap) -{ - perfstat_memory_total_t minfo; - perfstat_pagingspace_t ps; - perfstat_id_t id; - - id.name[0] = '\0'; - - SIGAR_ZERO(swap); - - do { - if (perfstat_pagingspace(&id, &ps, sizeof(ps), 1) != 1) { - if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[swap] dev=%s query failed: %s", - SWAP_DEV(ps), - sigar_strerror(sigar, errno)); - } - continue; - } - if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[swap] dev=%s: active=%s, " - "total=%lluMb, used=%lluMb", - SWAP_DEV(ps), - ((ps.active == 1) ? "yes" : "no"), - ps.mb_size, ps.mb_used); - } - if (ps.active != 1) { - continue; - } - /* convert MB sizes to bytes */ - swap->total += SWAP_MB_TO_BYTES(ps.mb_size); - swap->used += SWAP_MB_TO_BYTES(ps.mb_used); - } while (id.name[0] != '\0'); - - swap->free = swap->total - swap->used; - - if (sigar_perfstat_memory(&minfo) == 1) { - swap->page_in = minfo.pgins; - swap->page_out = minfo.pgouts; - } - else { - swap->page_in = swap->page_out = -1; - } - return SIGAR_OK; -} - -int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu) -{ - int i, status; - struct sysinfo data; - perfstat_cpu_total_t cpu_data; - - if (sigar_perfstat_cpu(&cpu_data) == 1) { - cpu->user = SIGAR_TICK2MSEC(cpu_data.user); - cpu->nice = SIGAR_FIELD_NOTIMPL; /* N/A */ - cpu->sys = SIGAR_TICK2MSEC(cpu_data.sys); - cpu->idle = SIGAR_TICK2MSEC(cpu_data.idle); - cpu->wait = SIGAR_TICK2MSEC(cpu_data.wait); - cpu->irq = 0; /*N/A*/ - cpu->soft_irq = 0; /*N/A*/ - cpu->stolen = 0; /*N/A*/ - cpu->total = cpu->user + cpu->sys + cpu->idle + cpu->wait; - return SIGAR_OK; - } - else { - return errno; - } -} - -/* - * other possible metrics we could add: - * struct cpuinfo { - * long cpu[CPU_NTIMES]; - * long pswitch; - * long syscall; - * long sysread; - * long syswrite; - * long sysfork; - * long sysexec; - * long readch; - * long writech; - * long iget; - * long namei; - * long dirblk; - * long msg; - * long sema; - * long bread; - * long bwrite; - * long lread; - * long lwrite; - * long phread; - * long phwrite; - * }; - */ - -int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist) -{ - perfstat_cpu_t data; - int i, ncpu = _system_configuration.ncpus; /* this can change */ - perfstat_id_t id; - - id.name[0] = '\0'; - - sigar_cpu_list_create(cpulist); - - for (i=0; idata[cpulist->number++]; - - if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "cpu%d perfstat_id='%s'", - i, id.name); - } - - if (perfstat_cpu(&id, &data, sizeof(data), 1) == 1) { - cpu->user = SIGAR_TICK2MSEC(data.user); - cpu->nice = SIGAR_FIELD_NOTIMPL; /* N/A */ - cpu->sys = SIGAR_TICK2MSEC(data.sys); - cpu->idle = SIGAR_TICK2MSEC(data.idle); - cpu->wait = SIGAR_TICK2MSEC(data.wait); - cpu->irq = 0; /*N/A*/ - cpu->soft_irq = 0; /*N/A*/ - cpu->stolen = 0; /*N/A*/ - cpu->total = cpu->user + cpu->sys + cpu->idle + cpu->wait; - } - else { - sigar_log_printf(sigar, SIGAR_LOG_ERROR, - "cpu%d perfstat_cpu(%s) failed: %s", - i, id.name, sigar_strerror(sigar, errno)); - SIGAR_ZERO(cpu); - } - } - - return SIGAR_OK; -} - -static int boot_time(sigar_t *sigar, time_t *time) -{ - int fd; - struct utmp data; - - if ((fd = open(UTMP_FILE, O_RDONLY)) < 0) { - return errno; - } - - do { - if (read(fd, &data, sizeof(data)) != sizeof(data)) { - int status = errno; - close(fd); - return status; - } - } while (data.ut_type != BOOT_TIME); - - *time = data.ut_time; - - close(fd); - - return SIGAR_OK; -} - -int sigar_uptime_get(sigar_t *sigar, - sigar_uptime_t *uptime) -{ - if (sigar->boot_time == 0) { - int status; - time_t time; - - if ((status = boot_time(sigar, &time)) != SIGAR_OK) { - return status; - } - - sigar->boot_time = time; - } - - uptime->uptime = time(NULL) - sigar->boot_time; - - return SIGAR_OK; -} - -#define WHOCPY(dest, src) \ - SIGAR_SSTRCPY(dest, src); \ - if (sizeof(src) < sizeof(dest)) \ - dest[sizeof(dest)-1] = '\0' - -static int sigar_who_utmp(sigar_t *sigar, - sigar_who_list_t *wholist) -{ - struct utmp ut; - FILE *fp; - - if (!(fp = fopen(UTMP_FILE, "r"))) { - return errno; - } - - while (fread(&ut, sizeof(ut), 1, fp) == 1) { - sigar_who_t *who; - - if (*ut.ut_name == '\0') { - continue; - } - - if (ut.ut_type != USER_PROCESS) { - continue; - } - - SIGAR_WHO_LIST_GROW(wholist); - who = &wholist->data[wholist->number++]; - - WHOCPY(who->user, ut.ut_user); - WHOCPY(who->device, ut.ut_line); - WHOCPY(who->host, ut.ut_host); - - who->time = ut.ut_time; - } - - fclose(fp); - - return SIGAR_OK; -} - -int sigar_who_list_get(sigar_t *sigar, - sigar_who_list_t *wholist) -{ - int status; - - sigar_who_list_create(wholist); - - status = sigar_who_utmp(sigar, wholist); - if (status != SIGAR_OK) { - sigar_who_list_destroy(sigar, wholist); - return status; - } - - return SIGAR_OK; -} - -int sigar_loadavg_get(sigar_t *sigar, - sigar_loadavg_t *loadavg) -{ - int status, i; - int data[3]; - perfstat_cpu_total_t cpu_data; - - if (sigar_perfstat_cpu(&cpu_data) == 1) { - for (i=0; i<3; i++) { - loadavg->loadavg[i] = FIXED_TO_DOUBLE(cpu_data.loadavg[i]); - } - return SIGAR_OK; - } - else { - return errno; - } -} - -int sigar_os_proc_list_get(sigar_t *sigar, - sigar_proc_list_t *proclist) -{ - pid_t pid = 0; - struct procsinfo info; - - for (;;) { - int num = getprocs(&info, sizeof(info), - NULL, 0, &pid, 1); - - if (num == 0) { - break; - } - - SIGAR_PROC_LIST_GROW(proclist); - - proclist->data[proclist->number++] = info.pi_pid; - } - - return SIGAR_OK; -} - -static int sigar_getprocs(sigar_t *sigar, sigar_pid_t pid) -{ - int status, num; - time_t timenow = time(NULL); - - if (sigar->pinfo == NULL) { - sigar->pinfo = malloc(sizeof(*sigar->pinfo)); - } - - if (sigar->last_pid == pid) { - if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) { - return SIGAR_OK; - } - } - - sigar->last_pid = pid; - sigar->last_getprocs = timenow; - - num = getprocs(sigar->pinfo, sizeof(*sigar->pinfo), - NULL, 0, &pid, 1); - - if (num != 1) { - return ESRCH; - } - - return SIGAR_OK; -} - -int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_mem_t *procmem) -{ - int status = sigar_getprocs(sigar, pid); - struct procsinfo64 *pinfo = sigar->pinfo; - - if (status != SIGAR_OK) { - return status; - } - - procmem->size = PAGESHIFT(pinfo->pi_size); /* XXX fold in pi_dvm ? */ - procmem->share = PAGESHIFT(pinfo->pi_sdsize); - procmem->resident = PAGESHIFT(pinfo->pi_drss + pinfo->pi_trss); - - procmem->minor_faults = pinfo->pi_minflt; - procmem->major_faults = pinfo->pi_majflt; - procmem->page_faults = - procmem->minor_faults + - procmem->major_faults; - - return SIGAR_OK; -} - -int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_cred_t *proccred) -{ - int status = sigar_getprocs(sigar, pid); - struct procsinfo64 *pinfo = sigar->pinfo; - - if (status != SIGAR_OK) { - return status; - } - - proccred->uid = pinfo->pi_cred.cr_ruid; - proccred->euid = pinfo->pi_cred.cr_uid; - if (proccred->uid == -1) { - /* - * aix 5.2 has a process named 'jfsz' - * where uid is '-1', getpwuid returns EPERM - */ - proccred->uid = proccred->euid = 0; - } - proccred->gid = pinfo->pi_cred.cr_rgid; - proccred->egid = pinfo->pi_cred.cr_gid; - - return SIGAR_OK; -} - -int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_time_t *proctime) -{ - int status = sigar_getprocs(sigar, pid); - struct procsinfo64 *pinfo = sigar->pinfo; - - if (status != SIGAR_OK) { - return status; - } - - proctime->start_time = pinfo->pi_start; - proctime->start_time *= SIGAR_MSEC; /* convert to ms */ - proctime->user = pinfo->pi_utime * SIGAR_MSEC; - proctime->sys = pinfo->pi_stime * SIGAR_MSEC; - proctime->total = proctime->user + proctime->sys; - - return SIGAR_OK; -} - -int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_state_t *procstate) -{ - int status = sigar_getprocs(sigar, pid); - struct procsinfo64 *pinfo = sigar->pinfo; - tid_t tid = 0; - struct thrdsinfo64 thrinfo; - - if (status != SIGAR_OK) { - return status; - } - - if (getthrds(pid, &thrinfo, sizeof(thrinfo), &tid, 1) == 1) { - procstate->processor = thrinfo.ti_affinity; - } - else { - procstate->processor = SIGAR_FIELD_NOTIMPL; - } - - SIGAR_SSTRCPY(procstate->name, pinfo->pi_comm); - procstate->ppid = pinfo->pi_ppid; - procstate->nice = pinfo->pi_nice; - procstate->tty = pinfo->pi_ttyd; - procstate->priority = pinfo->pi_pri; - procstate->threads = pinfo->pi_thcount; - - switch (pinfo->pi_state) { - case SACTIVE: - procstate->state = 'R'; - break; - case SIDL: - procstate->state = 'D'; - break; - case SSTOP: - procstate->state = 'S'; - break; - case SZOMB: - procstate->state = 'Z'; - break; - case SSWAP: - procstate->state = 'S'; - break; - } - - return SIGAR_OK; -} - -int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_args_t *procargs) -{ - /* XXX if buffer is not large enough args are truncated */ - char buffer[8192], *ptr; - struct procsinfo pinfo; - - pinfo.pi_pid = pid; - - if (getargs(&pinfo, sizeof(pinfo), - buffer, sizeof(buffer)) != 0) - { - return errno; - } - - ptr = buffer; - - while (*ptr) { - int alen = strlen(ptr)+1; - char *arg = malloc(alen); - - SIGAR_PROC_ARGS_GROW(procargs); - memcpy(arg, ptr, alen); - - procargs->data[procargs->number++] = arg; - - ptr += alen; - } - - return SIGAR_OK; -} - -int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_env_t *procenv) -{ - /* XXX if buffer is not large enough args are truncated */ - char buffer[8192], *ptr; - struct procsinfo pinfo; - - pinfo.pi_pid = pid; - - if (getevars(&pinfo, sizeof(pinfo), - buffer, sizeof(buffer)) != 0) - { - return errno; - } - - ptr = buffer; - - while (*ptr) { - char *val = strchr(ptr, '='); - int klen, vlen, status; - char key[128]; /* XXX is there a max key size? */ - - if (val == NULL) { - /* not key=val format */ - procenv->env_getter(procenv->data, ptr, strlen(ptr), NULL, 0); - break; - } - - klen = val - ptr; - SIGAR_SSTRCPY(key, ptr); - key[klen] = '\0'; - ++val; - - vlen = strlen(val); - status = procenv->env_getter(procenv->data, - key, klen, val, vlen); - - if (status != SIGAR_OK) { - /* not an error; just stop iterating */ - break; - } - - ptr += (klen + 1 + vlen + 1); - } - - return SIGAR_OK; -} - -int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_fd_t *procfd) -{ -#ifdef SIGAR_64BIT - /* XXX no getuser() in 64-bit mode */ - return SIGAR_ENOTIMPL; -#else - int i; - struct procsinfo pinfo; - struct user uinfo; - - procfd->total = 0; - pinfo.pi_pid = pid; - - if (getuser(&pinfo, sizeof(pinfo), - &uinfo, sizeof(uinfo)) != 0) { - if (errno == EINVAL) { - return SIGAR_ENOTIMPL; /*XXX 5.2+*/ - } - } - - /* see sys/user.h */ - for (i=0; itotal++; - } - } - - return SIGAR_OK; -#endif -} - -int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_exe_t *procexe) -{ - int len; - char buffer[8192]; - struct procsinfo pinfo; - - pinfo.pi_pid = pid; - - if (getargs(&pinfo, sizeof(pinfo), - buffer, sizeof(buffer)) != 0) - { - return errno; - } - /* XXX argv[0] might be relative */ - len = strlen(buffer); - SIGAR_SSTRCPY(procexe->name, buffer); - - (void)SIGAR_PROC_FILENAME(buffer, pid, "/cwd"); - - if ((len = readlink(buffer, procexe->cwd, - sizeof(procexe->cwd)-1)) < 0) - { - return errno; - } - procexe->cwd[len] = '\0'; - - procexe->root[0] = '\0'; - - return SIGAR_OK; -} - -static int sigar_proc_modules_local_get(sigar_t *sigar, - sigar_proc_modules_t *procmods) -{ - struct ld_info *info; - char *buffer; - int size = 2048, status; - unsigned int offset; - - buffer = malloc(size); - while ((loadquery(L_GETINFO, buffer, size) == -1) && - (errno == ENOMEM)) - { - size += 2048; - buffer = realloc(buffer, size); - } - - info = (struct ld_info *)buffer; - - do { - char *name = info->ldinfo_filename; - - status = - procmods->module_getter(procmods->data, name, strlen(name)); - - if (status != SIGAR_OK) { - /* not an error; just stop iterating */ - free(buffer); - return status; - } - - offset = info->ldinfo_next; - info = (struct ld_info *)((char*)info + offset); - } while(offset); - - free(buffer); - - return SIGAR_OK; -} - -int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_modules_t *procmods) -{ - if (pid == sigar_pid_get(sigar)) { - return sigar_proc_modules_local_get(sigar, procmods); - } - else { - return SIGAR_ENOTIMPL; - } -} - -#define SIGAR_MICROSEC2NANO(s) \ - ((sigar_uint64_t)(s) * (sigar_uint64_t)1000) - -#define TIME_NSEC(t) \ - (SIGAR_SEC2NANO((t).tv_sec) + SIGAR_MICROSEC2NANO((t).tv_usec)) - -int sigar_thread_cpu_get(sigar_t *sigar, - sigar_uint64_t id, - sigar_thread_cpu_t *cpu) -{ - struct rusage usage; - int retval; - - if (sigar->thrusage != PTHRDSINFO_RUSAGE_START) { - sigar->thrusage = PTHRDSINFO_RUSAGE_START; - retval = - sigar_thread_rusage(&usage, - PTHRDSINFO_RUSAGE_START); - if (retval != 0) { - return retval; - } - } - - retval = - sigar_thread_rusage(&usage, - PTHRDSINFO_RUSAGE_COLLECT); - if (retval != 0) { - return retval; - } - - cpu->user = TIME_NSEC(usage.ru_utime); - cpu->sys = TIME_NSEC(usage.ru_stime); - cpu->total = TIME_NSEC(usage.ru_utime) + TIME_NSEC(usage.ru_stime); - - return SIGAR_OK; -} - -int sigar_os_fs_type_get(sigar_file_system_t *fsp) -{ - return fsp->type; -} - -#ifndef MNT_NFS4 -/* another one documented in aix tech ref - * with no friggin prototype in any header file... - * ...but added in 5.2 - */ -int mntctl(int command, int size, char *buffer); -#endif - -int sigar_file_system_list_get(sigar_t *sigar, - sigar_file_system_list_t *fslist) -{ - int i, size, num; - char *buf, *mntlist; - - /* get required size */ - if (mntctl(MCTL_QUERY, sizeof(size), (char *)&size) < 0) { - return errno; - } - - mntlist = buf = malloc(size); - - if ((num = mntctl(MCTL_QUERY, size, buf)) < 0) { - free(buf); - return errno; - } - - sigar_file_system_list_create(fslist); - - for (i=0; ivmt_length; - - SIGAR_FILE_SYSTEM_LIST_GROW(fslist); - - fsp = &fslist->data[fslist->number++]; - - switch (ent->vmt_gfstype) { - case MNT_AIX: - typename = "aix"; - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - break; - case MNT_JFS: - typename = "jfs"; - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - break; - case MNT_NFS: - case MNT_NFS3: - typename = "nfs"; - fsp->type = SIGAR_FSTYPE_NETWORK; - break; - case MNT_CDROM: - fsp->type = SIGAR_FSTYPE_CDROM; - break; - case MNT_SFS: - case MNT_CACHEFS: - case MNT_AUTOFS: - default: - if (ent->vmt_flags & MNT_REMOTE) { - fsp->type = SIGAR_FSTYPE_NETWORK; - } - else { - fsp->type = SIGAR_FSTYPE_NONE; - } - } - - SIGAR_SSTRCPY(fsp->dir_name, vmt2dataptr(ent, VMT_STUB)); - SIGAR_SSTRCPY(fsp->options, vmt2dataptr(ent, VMT_ARGS)); - - devname = vmt2dataptr(ent, VMT_OBJECT); - - if (fsp->type == SIGAR_FSTYPE_NETWORK) { - char *hostname = vmt2dataptr(ent, VMT_HOSTNAME); -#if 0 - /* XXX: these do not seem reliable */ - int hostname_len = vmt2datasize(ent, VMT_HOSTNAME)-1; /* -1 == skip '\0' */ - int devname_len = vmt2datasize(ent, VMT_OBJECT); /* includes '\0' */ -#else - int hostname_len = strlen(hostname); - int devname_len = strlen(devname) + 1; -#endif - int total_len = hostname_len + devname_len + 1; /* 1 == strlen(":") */ - - if (total_len > sizeof(fsp->dev_name)) { - /* justincase - prevent overflow. chances: slim..none */ - SIGAR_SSTRCPY(fsp->dev_name, devname); - } - else { - /* sprintf(fsp->devname, "%s:%s", hostname, devname) */ - char *ptr = fsp->dev_name; - - memcpy(ptr, hostname, hostname_len); - ptr += hostname_len; - - *ptr++ = ':'; - - memcpy(ptr, devname, devname_len); - } - } - else { - SIGAR_SSTRCPY(fsp->dev_name, devname); - } - - /* we set fsp->type, just looking up sigar.c:fstype_names[type] */ - sigar_fs_type_get(fsp); - - if (typename == NULL) { - typename = fsp->type_name; - } - - SIGAR_SSTRCPY(fsp->sys_type_name, typename); - } - - free(buf); - - return SIGAR_OK; -} - -typedef struct { - char name[IDENTIFIER_LENGTH]; - long addr; -} aix_diskio_t; - -static int create_diskmap(sigar_t *sigar) -{ - int i, total, num; - perfstat_disk_t *disk; - perfstat_id_t id; - - total = perfstat_disk(NULL, NULL, sizeof(*disk), 0); - if (total < 1) { - return ENOENT; - } - - disk = malloc(total * sizeof(*disk)); - id.name[0] = '\0'; - - num = perfstat_disk(&id, disk, sizeof(*disk), total); - if (num < 1) { - free(disk); - return ENOENT; - } - - sigar->diskmap = sigar_cache_new(25); - - odm_initialize(); - - for (i=0; iname, "label", 0, &num))) { - retval = stat(attr->value, &sb); - - if (retval == 0) { - aix_diskio_t *diskio = malloc(sizeof(*diskio)); - SIGAR_SSTRCPY(diskio->name, disk[i].name); - diskio->addr = -1; - ent = sigar_cache_get(sigar->diskmap, SIGAR_FSDEV_ID(sb)); - ent->value = diskio; - } - - free(attr); - } - } - - odm_free_list(dv, &info); - } - - free(disk); - odm_terminate(); - - return SIGAR_OK; -} - -int sigar_disk_usage_get(sigar_t *sigar, const char *name, - sigar_disk_usage_t *usage) -{ - perfstat_disk_t disk; - perfstat_id_t id; - - SIGAR_SSTRCPY(id.name, name); - - if (perfstat_disk(&id, &disk, sizeof(disk), 1) != 1) { - return ENXIO; - } - - usage->reads = disk.rblks; - usage->writes = disk.wblks; - usage->read_bytes = disk.rblks * disk.bsize; - usage->write_bytes = disk.wblks * disk.bsize; - usage->queue = disk.qdepth; - usage->time = disk.time; - usage->rtime = SIGAR_FIELD_NOTIMPL; - usage->wtime = SIGAR_FIELD_NOTIMPL; - - return SIGAR_OK; -} - -int sigar_file_system_usage_get(sigar_t *sigar, - const char *dirname, - sigar_file_system_usage_t *fsusage) -{ - sigar_cache_entry_t *ent; - struct stat sb; - int status; - - status = sigar_statvfs(sigar, dirname, fsusage); - - if (status != SIGAR_OK) { - return status; - } - - fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage); - - SIGAR_DISK_STATS_INIT(&fsusage->disk); - - if (!sigar->diskmap) { - status = create_diskmap(sigar); - if (status != SIGAR_OK) { - return SIGAR_OK; - } - } - - status = stat(dirname, &sb); - if (status == 0) { - sigar_cache_entry_t *ent = - sigar_cache_get(sigar->diskmap, SIGAR_FSDEV_ID(sb)); - if (!ent->value) { - return SIGAR_OK; - } - sigar_disk_usage_get(sigar, ((aix_diskio_t *)ent->value)->name, &fsusage->disk); - } - - return SIGAR_OK; -} - -/* from sys/systemcfg.h, not defined in 4.3 headers */ -#ifndef POWER_4 -#define POWER_4 0x0800 -#endif -#ifndef POWER_MPC7450 -#define POWER_MPC7450 0x1000 -#endif -#ifndef POWER_5 -#define POWER_5 0x2000 -#endif - -static char *sigar_get_odm_model(sigar_t *sigar) -{ - if (sigar->model[0] == '\0') { - struct CuAt *odm_obj; - int num; - - odm_initialize(); - - if ((odm_obj = getattr("proc0", "type", 0, &num))) { - SIGAR_SSTRCPY(sigar->model, odm_obj->value); - free(odm_obj); - } - - odm_terminate(); - } - - return sigar->model; -} - -#define SIGAR_CPU_CACHE_SIZE \ - (_system_configuration.L2_cache_size / 1024) - -static int sigar_get_cpu_mhz(sigar_t *sigar) -{ - if (sigar->cpu_mhz == SIGAR_FIELD_NOTIMPL) { - perfstat_cpu_total_t data; - - if (sigar_perfstat_cpu(&data) == 1) { - sigar->cpu_mhz = data.processorHZ / 1000000; - } - else { - sigar_log_printf(sigar, SIGAR_LOG_ERROR, - "perfstat_cpu_total failed: %s", - sigar_strerror(sigar, errno)); - } - } - - return sigar->cpu_mhz; -} - -static char *get_cpu_arch(void) -{ - switch (_system_configuration.architecture) { - case POWER_RS: - return "Power Classic"; - case POWER_PC: - return "PowerPC"; - case IA64: - return "IA64"; - default: - return "PowerPC"; /* what else could it be */ - } -} - -static char *get_ppc_cpu_model(void) -{ - switch (_system_configuration.implementation) { - case POWER_RS1: - return "RS1"; - case POWER_RSC: - return "RSC"; - case POWER_RS2: - return "RS2"; - case POWER_601: - return "601"; - case POWER_603: - return "603"; - case POWER_604: - return "604"; - case POWER_620: - return "620"; - case POWER_630: - return "630"; - case POWER_A35: - return "A35"; - case POWER_RS64II: - return "RS64-II"; - case POWER_RS64III: - return "RS64-III"; - case POWER_4: - return "POWER4"; - case POWER_MPC7450: - return "MPC7450"; - case POWER_5: - return "POWER5"; - default: - return "Unknown"; - } -} - -static char *get_ia64_cpu_model(void) -{ - switch (_system_configuration.implementation) { - case IA64_M1: - return "M1"; - case IA64_M2: - return "M2"; - default: - return "Unknown"; - } -} - -static char *get_cpu_model(void) -{ - if (_system_configuration.architecture == IA64) { - return get_ia64_cpu_model(); - } - else { - return get_ppc_cpu_model(); - } -} - -int sigar_cpu_info_list_get(sigar_t *sigar, - sigar_cpu_info_list_t *cpu_infos) -{ - int i; - int ncpu = _system_configuration.ncpus; /* this can change */ - char *arch = get_cpu_arch(), *model = get_cpu_model(); - - /*XXX should only do this once*/ - sigar_cpu_info_list_create(cpu_infos); - - for (i=0; idata[cpu_infos->number++]; - - info->total_cores = ncpu; - info->cores_per_socket = 1; /*XXX*/ - info->total_sockets = ncpu; /*XXX*/ - - info->cache_size = SIGAR_CPU_CACHE_SIZE; - - info->mhz = sigar_get_cpu_mhz(sigar); - - if (*arch == 'P') { - SIGAR_SSTRCPY(info->vendor, "IBM"); - } - else if (*arch == 'I') { - SIGAR_SSTRCPY(info->vendor, "Intel"); - } - else { - SIGAR_SSTRCPY(info->vendor, "Unknown"); - } - - snprintf(info->model, sizeof(info->model), - "%s %s", arch, model); - } - - return SIGAR_OK; -} -/* XXX net_route_list copy-n-pasted from darwin_sigar.c; only diff is getkerninfo instead of sysctl */ -#define rt_s_addr(sa) ((struct sockaddr_in *)(sa))->sin_addr.s_addr - -#ifndef SA_SIZE -#define SA_SIZE(sa) \ - ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \ - sizeof(long) : \ - 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) -#endif - -int sigar_net_route_list_get(sigar_t *sigar, - sigar_net_route_list_t *routelist) -{ - int needed; - int bit; - char *buf, *next, *lim; - struct rt_msghdr *rtm; - - needed = getkerninfo(KINFO_RT_DUMP, NULL, NULL, 0); - if (needed <= 0) { - return errno; - } - - buf = malloc(needed); - - if (getkerninfo(KINFO_RT_DUMP, buf, &needed, 0) < 0) { - return errno; - } - - sigar_net_route_list_create(routelist); - - lim = buf + needed; - - for (next = buf; next < lim; next += rtm->rtm_msglen) { - struct sockaddr *sa; - sigar_net_route_t *route; - rtm = (struct rt_msghdr *)next; - - if (rtm->rtm_type != RTM_GET) { - continue; - } - - sa = (struct sockaddr *)(rtm + 1); - - if (sa->sa_family != AF_INET) { - continue; - } - - SIGAR_NET_ROUTE_LIST_GROW(routelist); - route = &routelist->data[routelist->number++]; - SIGAR_ZERO(route); - - route->flags = rtm->rtm_flags; - if_indextoname(rtm->rtm_index, route->ifname); - - for (bit=RTA_DST; - bit && ((char *)sa < lim); - bit <<= 1) - { - if ((rtm->rtm_addrs & bit) == 0) { - continue; - } - switch (bit) { - case RTA_DST: - sigar_net_address_set(route->destination, - rt_s_addr(sa)); - break; - case RTA_GATEWAY: - if (sa->sa_family == AF_INET) { - sigar_net_address_set(route->gateway, - rt_s_addr(sa)); - } - break; - case RTA_NETMASK: - sigar_net_address_set(route->mask, - rt_s_addr(sa)); - break; - case RTA_IFA: - break; - } - - sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa)); - } - } - - free(buf); - - return SIGAR_OK; -} - -int sigar_net_interface_stat_get(sigar_t *sigar, - const char *name, - sigar_net_interface_stat_t *ifstat) -{ - perfstat_id_t id; - perfstat_netinterface_t data; - - sigar_log(sigar, SIGAR_LOG_DEBUG, "[ifstat] using libperfstat"); - - SIGAR_SSTRCPY(id.name, name); - - if (perfstat_netinterface(&id, &data, sizeof(data), 1) == 1) { - ifstat->rx_bytes = data.ibytes; - ifstat->rx_packets = data.ipackets; - ifstat->rx_errors = data.ierrors; - ifstat->rx_dropped = SIGAR_FIELD_NOTIMPL; - ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL; - ifstat->rx_frame = SIGAR_FIELD_NOTIMPL; - - ifstat->tx_bytes = data.obytes; - ifstat->tx_packets = data.opackets; - ifstat->tx_errors = data.oerrors; - ifstat->tx_dropped = SIGAR_FIELD_NOTIMPL; - ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL; - ifstat->tx_collisions = data.collisions; - ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL; - - ifstat->speed = data.bitrate; - - return SIGAR_OK; - } - else { - return errno; - } -} - -int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, - sigar_net_interface_config_t *ifconfig) -{ - int sock; - struct in6_ifreq ifr; - - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { - return errno; - } - - SIGAR_SSTRCPY(ifr.ifr_name, name); - - if (ioctl(sock, SIOCGIFADDR6, &ifr) == 0) { - struct in6_addr *addr = SIGAR_SIN6_ADDR(&ifr.ifr_Addr); - - sigar_net_address6_set(ifconfig->address6, addr); - sigar_net_interface_scope6_set(ifconfig, addr); - - if (ioctl(sock, SIOCGIFNETMASK6, &ifr) == 0) { - addr = SIGAR_SIN6_ADDR(&ifr.ifr_Addr); - ifconfig->prefix6_length = SIGAR_SIN6(&ifr.ifr_Addr)->sin6_len; /*XXX*/ - } - } - - close(sock); - return SIGAR_OK; -} - -#define IS_TCP_SERVER(state, flags) \ - ((flags & SIGAR_NETCONN_SERVER) && (state == TCPS_LISTEN)) - -#define IS_TCP_CLIENT(state, flags) \ - ((flags & SIGAR_NETCONN_CLIENT) && (state != TCPS_LISTEN)) - -static int net_conn_get_tcp(sigar_net_connection_walker_t *walker) -{ - sigar_t *sigar = walker->sigar; - int flags = walker->flags; - int status; - struct inpcb tcp_inpcb; - struct tcpcb tcpcb; - struct inpcb *entry; - - status = kread(sigar, &tcp_inpcb, sizeof(tcp_inpcb), - sigar->koffsets[KOFFSET_TCB]); - - if (status != SIGAR_OK) { - return status; - } - - entry = tcp_inpcb.inp_next; - while (entry) { - struct inpcb pcb; - int state; - - status = kread(sigar, &pcb, sizeof(pcb), (long)entry); - if (status != SIGAR_OK) { - return status; - } - status = kread(sigar, &tcpcb, sizeof(tcpcb), (long)pcb.inp_ppcb); - if (status != SIGAR_OK) { - return status; - } - - state = tcpcb.t_state; - if ((IS_TCP_SERVER(state, flags) || - IS_TCP_CLIENT(state, flags))) - { - sigar_net_connection_t conn; - - SIGAR_ZERO(&conn); - - conn.type = SIGAR_NETCONN_TCP; - - sigar_net_address_set(conn.local_address, - pcb.inp_laddr.s_addr); - - sigar_net_address_set(conn.remote_address, - pcb.inp_faddr.s_addr); - - conn.local_port = ntohs(pcb.inp_lport); - conn.remote_port = ntohs(pcb.inp_fport); - - conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL; - - switch (state) { - case TCPS_CLOSED: - conn.state = SIGAR_TCP_CLOSE; - break; - case TCPS_LISTEN: - conn.state = SIGAR_TCP_LISTEN; - break; - case TCPS_SYN_SENT: - conn.state = SIGAR_TCP_SYN_SENT; - break; - case TCPS_SYN_RECEIVED: - conn.state = SIGAR_TCP_SYN_RECV; - break; - case TCPS_ESTABLISHED: - conn.state = SIGAR_TCP_ESTABLISHED; - break; - case TCPS_CLOSE_WAIT: - conn.state = SIGAR_TCP_CLOSE_WAIT; - break; - case TCPS_FIN_WAIT_1: - conn.state = SIGAR_TCP_FIN_WAIT1; - break; - case TCPS_CLOSING: - conn.state = SIGAR_TCP_CLOSING; - break; - case TCPS_LAST_ACK: - conn.state = SIGAR_TCP_LAST_ACK; - break; - case TCPS_FIN_WAIT_2: - conn.state = SIGAR_TCP_FIN_WAIT2; - break; - case TCPS_TIME_WAIT: - conn.state = SIGAR_TCP_TIME_WAIT; - break; - default: - conn.state = SIGAR_TCP_UNKNOWN; - break; - } - - if (walker->add_connection(walker, &conn) != SIGAR_OK) { - break; - } - } - - entry = pcb.inp_next; - if (entry == tcp_inpcb.inp_next) { - break; - } - } - - return SIGAR_OK; -} - -int sigar_net_connection_walk(sigar_net_connection_walker_t *walker) -{ - int status; - - if (walker->flags & SIGAR_NETCONN_TCP) { - status = net_conn_get_tcp(walker); - - if (status != SIGAR_OK) { - return status; - } - } -#if 0 - if (walker->flags & SIGAR_NETCONN_UDP) { - status = net_conn_get_udp(walker); - - if (status != SIGAR_OK) { - return status; - } - } -#endif - return SIGAR_OK; -} - -SIGAR_DECLARE(int) -sigar_tcp_get(sigar_t *sigar, - sigar_tcp_t *tcp) -{ - perfstat_id_t id; - perfstat_protocol_t proto; - - SIGAR_SSTRCPY(id.name, "tcp"); - - if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) { - return ENOENT; - } - - tcp->active_opens = proto.u.tcp.initiated; - tcp->passive_opens = proto.u.tcp.accepted; - tcp->attempt_fails = proto.u.tcp.dropped; - tcp->estab_resets = proto.u.tcp.dropped; - tcp->curr_estab = proto.u.tcp.established; - tcp->in_segs = proto.u.tcp.ipackets; - tcp->out_segs = proto.u.tcp.opackets; - tcp->retrans_segs = 0; - tcp->in_errs = proto.u.tcp.ierrors; - tcp->out_rsts = 0; -} - -#define NFS_V2_STAT_SET(type) \ - nfs->null = proto.u.nfsv2.type.null; \ - nfs->getattr = proto.u.nfsv2.type.getattr; \ - nfs->setattr = proto.u.nfsv2.type.setattr; \ - nfs->root = proto.u.nfsv2.type.root; \ - nfs->lookup = proto.u.nfsv2.type.lookup; \ - nfs->readlink = proto.u.nfsv2.type.readlink; \ - nfs->read = proto.u.nfsv2.type.read; \ - nfs->writecache = proto.u.nfsv2.type.writecache; \ - nfs->write = proto.u.nfsv2.type.write; \ - nfs->create = proto.u.nfsv2.type.create; \ - nfs->remove = proto.u.nfsv2.type.remove; \ - nfs->rename = proto.u.nfsv2.type.rename; \ - nfs->link = proto.u.nfsv2.type.link; \ - nfs->symlink = proto.u.nfsv2.type.symlink; \ - nfs->mkdir = proto.u.nfsv2.type.mkdir; \ - nfs->rmdir = proto.u.nfsv2.type.rmdir; \ - nfs->readdir = proto.u.nfsv2.type.readdir; \ - nfs->fsstat = proto.u.nfsv2.type.statfs - -int sigar_nfs_client_v2_get(sigar_t *sigar, - sigar_nfs_client_v2_t *nfs) -{ - perfstat_id_t id; - perfstat_protocol_t proto; - - SIGAR_SSTRCPY(id.name, "nfsv2"); - - if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) { - return ENOENT; - } - - NFS_V2_STAT_SET(client); - - return SIGAR_OK; -} - -int sigar_nfs_server_v2_get(sigar_t *sigar, - sigar_nfs_server_v2_t *nfs) -{ - perfstat_id_t id; - perfstat_protocol_t proto; - - SIGAR_SSTRCPY(id.name, "nfsv2"); - - if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) { - return ENOENT; - } - - NFS_V2_STAT_SET(server); - - return SIGAR_OK; -} - -#define NFS_V3_STAT_SET(type) \ - nfs->null = proto.u.nfsv3.type.null; \ - nfs->getattr = proto.u.nfsv3.type.getattr; \ - nfs->setattr = proto.u.nfsv3.type.setattr; \ - nfs->lookup = proto.u.nfsv3.type.lookup; \ - nfs->access = proto.u.nfsv3.type.access; \ - nfs->readlink = proto.u.nfsv3.type.readlink; \ - nfs->read = proto.u.nfsv3.type.read; \ - nfs->write = proto.u.nfsv3.type.write; \ - nfs->create = proto.u.nfsv3.type.create; \ - nfs->mkdir = proto.u.nfsv3.type.mkdir; \ - nfs->symlink = proto.u.nfsv3.type.symlink; \ - nfs->mknod = proto.u.nfsv3.type.mknod; \ - nfs->remove = proto.u.nfsv3.type.remove; \ - nfs->rmdir = proto.u.nfsv3.type.rmdir; \ - nfs->rename = proto.u.nfsv3.type.rename; \ - nfs->link = proto.u.nfsv3.type.link; \ - nfs->readdir = proto.u.nfsv3.type.readdir; \ - nfs->readdirplus = proto.u.nfsv3.type.readdirplus; \ - nfs->fsstat = proto.u.nfsv3.type.fsstat; \ - nfs->fsinfo = proto.u.nfsv3.type.fsinfo; \ - nfs->pathconf = proto.u.nfsv3.type.pathconf; \ - nfs->commit = proto.u.nfsv3.type.commit - -int sigar_nfs_client_v3_get(sigar_t *sigar, - sigar_nfs_client_v3_t *nfs) -{ - perfstat_id_t id; - perfstat_protocol_t proto; - - SIGAR_SSTRCPY(id.name, "nfsv3"); - - if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) { - return ENOENT; - } - - NFS_V3_STAT_SET(client); - - return SIGAR_OK; -} - -int sigar_nfs_server_v3_get(sigar_t *sigar, - sigar_nfs_server_v3_t *nfs) -{ - perfstat_id_t id; - perfstat_protocol_t proto; - - SIGAR_SSTRCPY(id.name, "nfsv3"); - - if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) { - return ENOENT; - } - - NFS_V3_STAT_SET(server); - - return SIGAR_OK; -} - -#include -/* - * cannot find any related aix docs on reading the ARP table, - * this impl was gleaned from the above .h file and truss -f arp -an - */ -int sigar_arp_list_get(sigar_t *sigar, - sigar_arp_list_t *arplist) -{ - int status = SIGAR_OK; - long arptabsize; - int i, size, retval; - struct arptab *arptabp; - - size = sizeof(arptabsize); - retval = getkerninfo(KINFO_READ, &arptabsize, &size, - sigar->koffsets[KOFFSET_ARPTABSIZE]); - if (retval != sizeof(arptabsize)) { - return errno; - } - - size = sizeof(arptabp); - retval = getkerninfo(KINFO_READ, &arptabp, &size, - sigar->koffsets[KOFFSET_ARPTABP]); - if (retval != sizeof(arptabp)) { - return errno; - } - - sigar_arp_list_create(arplist); - status = SIGAR_OK; - - for (i=0; idata[arplist->number++]; - - sigar_net_address_set(arp->address, - ent.at_iaddr.s_addr); - - sigar_net_address_mac_set(arp->hwaddr, - ent.hwaddr, - sizeof(arp->hwaddr.addr.mac)); - - if_indextoname(ifp.if_index, arp->ifname); - - arp->flags = ent.at_flags; - SIGAR_SSTRCPY(arp->type, "ether"); /* XXX ifp.if_type */ - } - - if (status != SIGAR_OK) { - sigar_arp_list_destroy(sigar, arplist); - } - - return status; -} - -/* derived from pidentd's k_aix432.c */ -int sigar_proc_port_get(sigar_t *sigar, int protocol, - unsigned long port, sigar_pid_t *pidp) -{ - struct procsinfo pinfo; - struct fdsinfo finfo; - pid_t pid = 0; - int type; - - switch (protocol) { - case SIGAR_NETCONN_TCP: - type = IPPROTO_TCP; - break; - case SIGAR_NETCONN_UDP: - type = IPPROTO_UDP; - break; - default: - return SIGAR_ENOTIMPL; - } - - for (;;) { - int fd, status; - int num = getprocs(&pinfo, sizeof(pinfo), - &finfo, sizeof(finfo), - &pid, 1); - - if (num == 0) { - break; - } - - if ((pinfo.pi_state == 0) || (pinfo.pi_state == SZOMB)) { - continue; - } - - for (fd = 0; fd < pinfo.pi_maxofile; fd++) { - struct file file; - struct socket socket, *sockp; - struct protosw protosw; - struct domain domain; - struct inpcb inpcb; - long ptr; - - if (!(ptr = (long)finfo.pi_ufd[fd].fp)) { - continue; - } - - status = kread(sigar, &file, sizeof(file), ptr); - if (status != SIGAR_OK) { - continue; - } - - if (file.f_type != DTYPE_SOCKET) { - continue; - } - - if (!(sockp = (struct socket *)file.f_data)) { - continue; - } - - status = kread(sigar, &socket, sizeof(socket), (long)sockp); - if (status != SIGAR_OK) { - continue; - } - - if (!(ptr = (long)socket.so_proto)) { - continue; - } - - status = kread(sigar, &protosw, sizeof(protosw), ptr); - if (status != SIGAR_OK) { - continue; - } - - if (protosw.pr_protocol != type) { - continue; - } - - if (!(ptr = (long)protosw.pr_domain)) { - continue; - } - - status = kread(sigar, &domain, sizeof(domain), ptr); - if (status != SIGAR_OK) { - continue; - } - - if ((domain.dom_family != AF_INET) && - domain.dom_family != AF_INET6) - { - continue; - } - - if (!(ptr = (long)socket.so_pcb)) { - continue; - } - - status = kread(sigar, &inpcb, sizeof(inpcb), ptr); - if (status != SIGAR_OK) { - continue; - } - - if (sockp != inpcb.inp_socket) { - continue; - } - - if (inpcb.inp_lport != port) { - continue; - } - - *pidp = pinfo.pi_pid; - - return SIGAR_OK; - } - } - - return ENOENT; -} - -int sigar_os_sys_info_get(sigar_t *sigar, - sigar_sys_info_t *sysinfo) -{ - struct utsname name; - - uname(&name); - - SIGAR_SSTRCPY(sysinfo->vendor, "IBM"); - SIGAR_SSTRCPY(sysinfo->arch, get_cpu_arch()); - /* utsname.machine is a sequence number */ - /* XXX odm might have something better */ - snprintf(sysinfo->machine, - sizeof(sysinfo->machine), - "%s %s", - sysinfo->arch, get_cpu_model()); - - snprintf(sysinfo->version, - sizeof(sysinfo->version), - "%s.%s", - name.version, name.release); - - SIGAR_SSTRCPY(sysinfo->vendor_version, sysinfo->version); - - snprintf(sysinfo->description, - sizeof(sysinfo->description), - "%s %s", - sysinfo->name, sysinfo->version); - - return SIGAR_OK; -} diff --git a/vendor/sigar/src/os/aix/sigar_os.h b/vendor/sigar/src/os/aix/sigar_os.h deleted file mode 100644 index 5ee7cf0..0000000 --- a/vendor/sigar/src/os/aix/sigar_os.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2004-2007, 2009 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * Copyright (c) 2010 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SIGAR_OS_H -#define SIGAR_OS_H - -#include -#include -#include -#include -#include - -enum { - KOFFSET_LOADAVG, - KOFFSET_VAR, - KOFFSET_SYSINFO, - KOFFSET_IFNET, - KOFFSET_VMINFO, - KOFFSET_CPUINFO, - KOFFSET_TCB, - KOFFSET_ARPTABSIZE, - KOFFSET_ARPTABP, - KOFFSET_MAX -}; - -typedef struct { - time_t mtime; - int num; - char **devs; -} swaps_t; - -typedef int (*proc_fd_func_t) (sigar_t *, sigar_pid_t, sigar_proc_fd_t *); - -struct sigar_t { - SIGAR_T_BASE; - int kmem; - /* offsets for seeking on kmem */ - long koffsets[KOFFSET_MAX]; - proc_fd_func_t getprocfd; - int pagesize; - swaps_t swaps; - time_t last_getprocs; - sigar_pid_t last_pid; - struct procsinfo64 *pinfo; - struct cpuinfo *cpuinfo; - int cpuinfo_size; - int cpu_mhz; - char model[128]; - int aix_version; - int thrusage; - sigar_cache_t *diskmap; -}; - -#define HAVE_STRERROR_R - -#define SIGAR_EPERM_KMEM (SIGAR_OS_START_ERROR+EACCES) - -#endif /* SIGAR_OS_H */ diff --git a/vendor/sigar/src/os/darwin/darwin_sigar.c b/vendor/sigar/src/os/darwin/darwin_sigar.c deleted file mode 100644 index 0e154b0..0000000 --- a/vendor/sigar/src/os/darwin/darwin_sigar.c +++ /dev/null @@ -1,3711 +0,0 @@ -/* - * Copyright (c) 2004-2009 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * Copyright (c) 2009-2010 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sigar.h" -#include "sigar_private.h" -#include "sigar_util.h" -#include "sigar_os.h" - -#include -#include -#if !(defined(__FreeBSD__) && (__FreeBSD_version >= 800000)) -#include -#endif -#include - -#ifdef DARWIN -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if !defined(HAVE_SHARED_REGION_H) && defined(__MAC_10_5) /* see Availability.h */ -# define HAVE_SHARED_REGION_H /* suckit autoconf */ -#endif -#ifdef HAVE_SHARED_REGION_H -#include /* does not exist in 10.4 SDK */ -#else -#include /* deprecated in Leopard */ -#endif -#include -#define __OPENTRANSPORTPROVIDERS__ -#include -#include -#include -#include -#include -#include -#else -#include -#include -#include -#include -#include -#include -#include -#endif - -#if defined(__FreeBSD__) && (__FreeBSD_version >= 500013) -#define SIGAR_FREEBSD5_NFSSTAT -#include -#include -#else -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#ifdef __NetBSD__ -#include -#include -#include -#define SRUN LSRUN -#define SSLEEP LSSLEEP -#define SDEAD LSDEAD -#define SONPROC LSONPROC -#define SSUSPENDED LSSUSPENDED -#include -#endif -#include -#include - -#define NMIB(mib) (sizeof(mib)/sizeof(mib[0])) - -#ifdef __FreeBSD__ -# if (__FreeBSD_version >= 500013) -# define SIGAR_FREEBSD5 -# else -# define SIGAR_FREEBSD4 -# endif -#endif - -#if defined(SIGAR_FREEBSD5) - -#define KI_FD ki_fd -#define KI_PID ki_pid -#define KI_PPID ki_ppid -#define KI_PRI ki_pri.pri_user -#define KI_NICE ki_nice -#define KI_COMM ki_comm -#define KI_STAT ki_stat -#define KI_UID ki_ruid -#define KI_GID ki_rgid -#define KI_EUID ki_svuid -#define KI_EGID ki_svgid -#define KI_SIZE ki_size -#define KI_RSS ki_rssize -#define KI_TSZ ki_tsize -#define KI_DSZ ki_dsize -#define KI_SSZ ki_ssize -#define KI_FLAG ki_flag -#define KI_START ki_start - -#elif defined(DARWIN) || defined(SIGAR_FREEBSD4) || defined(__OpenBSD__) || defined(__NetBSD__) - -#define KI_FD kp_proc.p_fd -#define KI_PID kp_proc.p_pid -#define KI_PPID kp_eproc.e_ppid -#define KI_PRI kp_proc.p_priority -#define KI_NICE kp_proc.p_nice -#define KI_COMM kp_proc.p_comm -#define KI_STAT kp_proc.p_stat -#define KI_UID kp_eproc.e_pcred.p_ruid -#define KI_GID kp_eproc.e_pcred.p_rgid -#define KI_EUID kp_eproc.e_pcred.p_svuid -#define KI_EGID kp_eproc.e_pcred.p_svgid -#define KI_SIZE XXX -#define KI_RSS kp_eproc.e_vm.vm_rssize -#define KI_TSZ kp_eproc.e_vm.vm_tsize -#define KI_DSZ kp_eproc.e_vm.vm_dsize -#define KI_SSZ kp_eproc.e_vm.vm_ssize -#define KI_FLAG kp_eproc.e_flag -#define KI_START kp_proc.p_starttime - -#endif - -#ifndef DARWIN - -#define PROCFS_STATUS(status) \ - ((((status) != SIGAR_OK) && !sigar->proc_mounted) ? \ - SIGAR_ENOTIMPL : status) - -static int get_koffsets(sigar_t *sigar) -{ - int i; - struct nlist klist[] = { - { "_cp_time" }, - { "_cnt" }, -#if defined(__OpenBSD__) || defined(__NetBSD__) - { "_tcpstat" }, - { "_tcbtable" }, -#endif - { NULL } - }; - - if (!sigar->kmem) { - return SIGAR_EPERM_KMEM; - } - - kvm_nlist(sigar->kmem, klist); - - for (i=0; ikoffsets[i] = klist[i].n_value; - } - - return SIGAR_OK; -} - -static int kread(sigar_t *sigar, void *data, int size, long offset) -{ - if (!sigar->kmem) { - return SIGAR_EPERM_KMEM; - } - - if (kvm_read(sigar->kmem, offset, data, size) != size) { - return errno; - } - - return SIGAR_OK; -} -#endif - -int sigar_os_open(sigar_t **sigar) -{ - int mib[2]; - int ncpu; - size_t len; - struct timeval boottime; -#ifndef DARWIN - struct stat sb; -#endif - - len = sizeof(ncpu); - mib[0] = CTL_HW; - mib[1] = HW_NCPU; - if (sysctl(mib, NMIB(mib), &ncpu, &len, NULL, 0) < 0) { - return errno; - } - - len = sizeof(boottime); - mib[0] = CTL_KERN; - mib[1] = KERN_BOOTTIME; - if (sysctl(mib, NMIB(mib), &boottime, &len, NULL, 0) < 0) { - return errno; - } - - *sigar = malloc(sizeof(**sigar)); - -#ifdef DARWIN - (*sigar)->mach_port = mach_host_self(); -# ifdef DARWIN_HAS_LIBPROC_H - if (((*sigar)->libproc = dlopen("/usr/lib/libproc.dylib", 0))) { - (*sigar)->proc_pidinfo = dlsym((*sigar)->libproc, "proc_pidinfo"); - (*sigar)->proc_pidfdinfo = dlsym((*sigar)->libproc, "proc_pidfdinfo"); - } -# endif -#else - (*sigar)->kmem = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL); - if (stat("/proc/curproc", &sb) < 0) { - (*sigar)->proc_mounted = 0; - } - else { - (*sigar)->proc_mounted = 1; - } -#endif - -#ifndef DARWIN - get_koffsets(*sigar); -#endif - - (*sigar)->ncpu = ncpu; - (*sigar)->lcpu = -1; - (*sigar)->argmax = 0; - (*sigar)->boot_time = boottime.tv_sec; /* XXX seems off a bit */ - - (*sigar)->pagesize = getpagesize(); -#ifdef __FreeBSD__ - (*sigar)->ticks = 100; /* sysconf(_SC_CLK_TCK) == 128 !? */ -#else - (*sigar)->ticks = sysconf(_SC_CLK_TCK); -#endif - (*sigar)->last_pid = -1; - - (*sigar)->pinfo = NULL; - - return SIGAR_OK; -} - -int sigar_os_close(sigar_t *sigar) -{ - if (sigar->pinfo) { - free(sigar->pinfo); - } -#ifndef DARWIN - if (sigar->kmem) { - kvm_close(sigar->kmem); - } -#endif - free(sigar); - return SIGAR_OK; -} - -char *sigar_os_error_string(sigar_t *sigar, int err) -{ - switch (err) { - case SIGAR_EPERM_KMEM: - return "Failed to open /dev/kmem for reading"; - case SIGAR_EPROC_NOENT: - return "/proc filesystem is not mounted"; - default: - return NULL; - } -} - -/* ARG_MAX in FreeBSD 6.0 == 262144, which blows up the stack */ -#define SIGAR_ARG_MAX 65536 - -#ifdef DARWIN -static size_t sigar_argmax_get(sigar_t *sigar) -{ -#ifdef KERN_ARGMAX - int mib[] = { CTL_KERN, KERN_ARGMAX }; - size_t size = sizeof(sigar->argmax); - - if (sigar->argmax != 0) { - return sigar->argmax; - } - if (sysctl(mib, NMIB(mib), &sigar->argmax, &size, NULL, 0) == 0) { - return sigar->argmax; - } -#endif - return SIGAR_ARG_MAX; -} -#endif /* DARWIN */ - -#if defined(DARWIN) -static int sigar_vmstat(sigar_t *sigar, vm_statistics_data_t *vmstat) -{ - kern_return_t status; - mach_msg_type_number_t count = sizeof(*vmstat) / sizeof(integer_t); - - status = host_statistics(sigar->mach_port, HOST_VM_INFO, - (host_info_t)vmstat, &count); - - if (status == KERN_SUCCESS) { - return SIGAR_OK; - } - else { - return errno; - } -} -#elif defined(__FreeBSD__) -static int sigar_vmstat(sigar_t *sigar, struct vmmeter *vmstat) -{ - int status; - size_t size = sizeof(unsigned int); - - status = kread(sigar, vmstat, sizeof(*vmstat), - sigar->koffsets[KOFFSET_VMMETER]); - - if (status == SIGAR_OK) { - return SIGAR_OK; - } - - SIGAR_ZERO(vmstat); - - /* derived from src/usr.bin/vmstat/vmstat.c */ - /* only collect the ones we actually use */ -#define GET_VM_STATS(cat, name, used) \ - if (used) sysctlbyname("vm.stats." #cat "." #name, &vmstat->name, &size, NULL, 0) - - /* sys */ - GET_VM_STATS(sys, v_swtch, 0); - GET_VM_STATS(sys, v_trap, 0); - GET_VM_STATS(sys, v_syscall, 0); - GET_VM_STATS(sys, v_intr, 0); - GET_VM_STATS(sys, v_soft, 0); - - /* vm */ - GET_VM_STATS(vm, v_vm_faults, 0); - GET_VM_STATS(vm, v_cow_faults, 0); - GET_VM_STATS(vm, v_cow_optim, 0); - GET_VM_STATS(vm, v_zfod, 0); - GET_VM_STATS(vm, v_ozfod, 0); - GET_VM_STATS(vm, v_swapin, 1); - GET_VM_STATS(vm, v_swapout, 1); - GET_VM_STATS(vm, v_swappgsin, 0); - GET_VM_STATS(vm, v_swappgsout, 0); - GET_VM_STATS(vm, v_vnodein, 1); - GET_VM_STATS(vm, v_vnodeout, 1); - GET_VM_STATS(vm, v_vnodepgsin, 0); - GET_VM_STATS(vm, v_vnodepgsout, 0); - GET_VM_STATS(vm, v_intrans, 0); - GET_VM_STATS(vm, v_reactivated, 0); - GET_VM_STATS(vm, v_pdwakeups, 0); - GET_VM_STATS(vm, v_pdpages, 0); - GET_VM_STATS(vm, v_dfree, 0); - GET_VM_STATS(vm, v_pfree, 0); - GET_VM_STATS(vm, v_tfree, 0); - GET_VM_STATS(vm, v_page_size, 0); - GET_VM_STATS(vm, v_page_count, 0); - GET_VM_STATS(vm, v_free_reserved, 0); - GET_VM_STATS(vm, v_free_target, 0); - GET_VM_STATS(vm, v_free_min, 0); - GET_VM_STATS(vm, v_free_count, 1); - GET_VM_STATS(vm, v_wire_count, 0); - GET_VM_STATS(vm, v_active_count, 0); - GET_VM_STATS(vm, v_inactive_target, 0); - GET_VM_STATS(vm, v_inactive_count, 1); - GET_VM_STATS(vm, v_cache_count, 1); - GET_VM_STATS(vm, v_cache_min, 0); - GET_VM_STATS(vm, v_cache_max, 0); - GET_VM_STATS(vm, v_pageout_free_min, 0); - GET_VM_STATS(vm, v_interrupt_free_min, 0); - GET_VM_STATS(vm, v_forks, 0); - GET_VM_STATS(vm, v_vforks, 0); - GET_VM_STATS(vm, v_rforks, 0); - GET_VM_STATS(vm, v_kthreads, 0); - GET_VM_STATS(vm, v_forkpages, 0); - GET_VM_STATS(vm, v_vforkpages, 0); - GET_VM_STATS(vm, v_rforkpages, 0); - GET_VM_STATS(vm, v_kthreadpages, 0); -#undef GET_VM_STATS - - return SIGAR_OK; -} -#elif defined(__OpenBSD__) || defined(__NetBSD__) -static int sigar_vmstat(sigar_t *sigar, struct uvmexp *vmstat) -{ - size_t size = sizeof(*vmstat); - int mib[] = { CTL_VM, VM_UVMEXP }; - if (sysctl(mib, NMIB(mib), vmstat, &size, NULL, 0) < 0) { - return errno; - } - else { - return SIGAR_OK; - } -} -#endif - -int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem) -{ - sigar_uint64_t kern = 0; -#ifdef DARWIN - vm_statistics_data_t vmstat; - uint64_t mem_total; -#else - unsigned long mem_total; -#endif -#if defined(__FreeBSD__) - struct vmmeter vmstat; -#elif defined(__OpenBSD__) || defined(__NetBSD__) - struct uvmexp vmstat; -#endif - int mib[2]; - size_t len; - int status; - - mib[0] = CTL_HW; - - mib[1] = HW_PAGESIZE; - len = sizeof(sigar->pagesize); - if (sysctl(mib, NMIB(mib), &sigar->pagesize, &len, NULL, 0) < 0) { - return errno; - } - -#ifdef DARWIN - mib[1] = HW_MEMSIZE; -#else - mib[1] = HW_PHYSMEM; -#endif - len = sizeof(mem_total); - if (sysctl(mib, NMIB(mib), &mem_total, &len, NULL, 0) < 0) { - return errno; - } - - mem->total = mem_total; - -#if defined(DARWIN) - if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) { - return status; - } - - mem->free = vmstat.free_count; - mem->free *= sigar->pagesize; - kern = vmstat.inactive_count; - kern *= sigar->pagesize; -#elif defined(__FreeBSD__) - if ((status = sigar_vmstat(sigar, &vmstat)) == SIGAR_OK) { - kern = vmstat.v_cache_count + vmstat.v_inactive_count; - kern *= sigar->pagesize; - mem->free = vmstat.v_free_count; - mem->free *= sigar->pagesize; - } -#elif defined(__OpenBSD__) || defined(__NetBSD__) - if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) { - return status; - } - mem->free = vmstat.free; - kern = vmstat.inactive; -# if defined(__OpenBSD__) - kern += vmstat.vnodepages + vmstat.vtextpages; -# elif defined(__NetBSD__) - kern += vmstat.filepages + vmstat.execpages; -# endif - kern *= sigar->pagesize; -#endif - - mem->used = mem->total - mem->free; - - mem->actual_free = mem->free + kern; - mem->actual_used = mem->used - kern; - - sigar_mem_calc_ram(sigar, mem); - - return SIGAR_OK; -} - -#define SWI_MAXMIB 3 - -#ifdef SIGAR_FREEBSD5 -/* code in this function is based on FreeBSD 5.3 kvm_getswapinfo.c */ -static int getswapinfo_sysctl(struct kvm_swap *swap_ary, - int swap_max) -{ - int ti, ttl; - size_t mibi, len, size; - int soid[SWI_MAXMIB]; - struct xswdev xsd; - struct kvm_swap tot; - int unswdev, dmmax; - - /* XXX this can be optimized by using os_open */ - size = sizeof(dmmax); - if (sysctlbyname("vm.dmmax", &dmmax, &size, NULL, 0) == -1) { - return errno; - } - - mibi = SWI_MAXMIB - 1; - if (sysctlnametomib("vm.swap_info", soid, &mibi) == -1) { - return errno; - } - - bzero(&tot, sizeof(tot)); - for (unswdev = 0;; unswdev++) { - soid[mibi] = unswdev; - len = sizeof(xsd); - if (sysctl(soid, mibi + 1, &xsd, &len, NULL, 0) == -1) { - if (errno == ENOENT) { - break; - } - return errno; - } -#if 0 - if (len != sizeof(xsd)) { - _kvm_err(kd, kd->program, "struct xswdev has unexpected " - "size; kernel and libkvm out of sync?"); - return -1; - } - if (xsd.xsw_version != XSWDEV_VERSION) { - _kvm_err(kd, kd->program, "struct xswdev version " - "mismatch; kernel and libkvm out of sync?"); - return -1; - } -#endif - ttl = xsd.xsw_nblks - dmmax; - if (unswdev < swap_max - 1) { - bzero(&swap_ary[unswdev], sizeof(swap_ary[unswdev])); - swap_ary[unswdev].ksw_total = ttl; - swap_ary[unswdev].ksw_used = xsd.xsw_used; - swap_ary[unswdev].ksw_flags = xsd.xsw_flags; - } - tot.ksw_total += ttl; - tot.ksw_used += xsd.xsw_used; - } - - ti = unswdev; - if (ti >= swap_max) { - ti = swap_max - 1; - } - if (ti >= 0) { - swap_ary[ti] = tot; - } - - return SIGAR_OK; -} -#else -#define getswapinfo_sysctl(swap_ary, swap_max) SIGAR_ENOTIMPL -#endif - -#define SIGAR_FS_BLOCKS_TO_BYTES(val, bsize) ((val * bsize) >> 1) - -#ifdef DARWIN -#define VM_DIR "/private/var/vm" -#define SWAPFILE "swapfile" - -static int sigar_swap_fs_get(sigar_t *sigar, sigar_swap_t *swap) /* <= 10.3 */ -{ - DIR *dirp; - struct dirent *ent; - char swapfile[SSTRLEN(VM_DIR) + SSTRLEN("/") + SSTRLEN(SWAPFILE) + 12]; - struct stat swapstat; - struct statfs vmfs; - sigar_uint64_t val, bsize; - - swap->used = swap->total = swap->free = 0; - - if (!(dirp = opendir(VM_DIR))) { - return errno; - } - - /* looking for "swapfile0", "swapfile1", etc. */ - while ((ent = readdir(dirp))) { - char *ptr = swapfile; - - if ((ent->d_namlen < SSTRLEN(SWAPFILE)+1) || /* n/a, see comment above */ - (ent->d_namlen > SSTRLEN(SWAPFILE)+11)) /* ensure no overflow */ - { - continue; - } - - if (!strnEQ(ent->d_name, SWAPFILE, SSTRLEN(SWAPFILE))) { - continue; - } - - /* sprintf(swapfile, "%s/%s", VM_DIR, ent->d_name) */ - - memcpy(ptr, VM_DIR, SSTRLEN(VM_DIR)); - ptr += SSTRLEN(VM_DIR); - - *ptr++ = '/'; - - memcpy(ptr, ent->d_name, ent->d_namlen+1); - - if (stat(swapfile, &swapstat) < 0) { - continue; - } - - swap->used += swapstat.st_size; - } - - closedir(dirp); - - if (statfs(VM_DIR, &vmfs) < 0) { - return errno; - } - - bsize = vmfs.f_bsize / 512; - val = vmfs.f_bfree; - swap->total = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize) + swap->used; - - swap->free = swap->total - swap->used; - - return SIGAR_OK; -} - -static int sigar_swap_sysctl_get(sigar_t *sigar, sigar_swap_t *swap) - -{ -#ifdef VM_SWAPUSAGE /* => 10.4 */ - struct xsw_usage sw_usage; - size_t size = sizeof(sw_usage); - int mib[] = { CTL_VM, VM_SWAPUSAGE }; - - if (sysctl(mib, NMIB(mib), &sw_usage, &size, NULL, 0) != 0) { - return errno; - } - - swap->total = sw_usage.xsu_total; - swap->used = sw_usage.xsu_used; - swap->free = sw_usage.xsu_avail; - - return SIGAR_OK; -#else - return SIGAR_ENOTIMPL; /* <= 10.3 */ -#endif -} -#endif /* DARWIN */ - -int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap) -{ - int status; -#if defined(DARWIN) - vm_statistics_data_t vmstat; - - if (sigar_swap_sysctl_get(sigar, swap) != SIGAR_OK) { - status = sigar_swap_fs_get(sigar, swap); /* <= 10.3 */ - if (status != SIGAR_OK) { - return status; - } - } - - if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) { - return status; - } - swap->page_in = vmstat.pageins; - swap->page_out = vmstat.pageouts; -#elif defined(__FreeBSD__) - struct kvm_swap kswap[1]; - struct vmmeter vmstat; - - if (getswapinfo_sysctl(kswap, 1) != SIGAR_OK) { - if (!sigar->kmem) { - return SIGAR_EPERM_KMEM; - } - - if (kvm_getswapinfo(sigar->kmem, kswap, 1, 0) < 0) { - return errno; - } - } - - if (kswap[0].ksw_total == 0) { - swap->total = 0; - swap->used = 0; - swap->free = 0; - return SIGAR_OK; - } - - swap->total = kswap[0].ksw_total * sigar->pagesize; - swap->used = kswap[0].ksw_used * sigar->pagesize; - swap->free = swap->total - swap->used; - - if ((status = sigar_vmstat(sigar, &vmstat)) == SIGAR_OK) { - swap->page_in = vmstat.v_swapin + vmstat.v_vnodein; - swap->page_out = vmstat.v_swapout + vmstat.v_vnodeout; - } - else { - swap->page_in = swap->page_out = -1; - } -#elif defined(__OpenBSD__) || defined(__NetBSD__) - struct uvmexp vmstat; - - if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) { - return status; - } - swap->total = vmstat.swpages * sigar->pagesize; - swap->used = vmstat.swpginuse * sigar->pagesize; - swap->free = swap->total - swap->used; - swap->page_in = vmstat.pageins; - swap->page_out = vmstat.pdpageouts; -#endif - - return SIGAR_OK; -} - -#ifndef KERN_CPTIME -#define KERN_CPTIME KERN_CP_TIME -#endif - -#if defined(__NetBSD__) -typedef uint64_t cp_time_t; -#else -typedef unsigned long cp_time_t; -#endif - -int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu) -{ -#if defined(DARWIN) - kern_return_t status; - mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT; - host_cpu_load_info_data_t cpuload; - - status = host_statistics(sigar->mach_port, HOST_CPU_LOAD_INFO, - (host_info_t)&cpuload, &count); - - if (status != KERN_SUCCESS) { - return errno; - } - - cpu->user = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_USER]); - cpu->sys = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_SYSTEM]); - cpu->idle = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_IDLE]); - cpu->nice = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_NICE]); - cpu->wait = 0; /*N/A*/ - cpu->irq = 0; /*N/A*/ - cpu->soft_irq = 0; /*N/A*/ - cpu->stolen = 0; /*N/A*/ - cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle; - -#elif defined(__FreeBSD__) || (__OpenBSD__) || defined(__NetBSD__) - int status; - cp_time_t cp_time[CPUSTATES]; - size_t size = sizeof(cp_time); - -# if defined(__OpenBSD__) || defined(__NetBSD__) - int mib[] = { CTL_KERN, KERN_CPTIME }; - if (sysctl(mib, NMIB(mib), &cp_time, &size, NULL, 0) == -1) { - status = errno; - } -# else - /* try sysctl first, does not require /dev/kmem perms */ - if (sysctlbyname("kern.cp_time", &cp_time, &size, NULL, 0) == -1) { - status = kread(sigar, &cp_time, sizeof(cp_time), - sigar->koffsets[KOFFSET_CPUINFO]); - } -# endif - else { - status = SIGAR_OK; - } - - if (status != SIGAR_OK) { - return status; - } - - cpu->user = SIGAR_TICK2MSEC(cp_time[CP_USER]); - cpu->nice = SIGAR_TICK2MSEC(cp_time[CP_NICE]); - cpu->sys = SIGAR_TICK2MSEC(cp_time[CP_SYS]); - cpu->idle = SIGAR_TICK2MSEC(cp_time[CP_IDLE]); - cpu->wait = 0; /*N/A*/ - cpu->irq = SIGAR_TICK2MSEC(cp_time[CP_INTR]); - cpu->soft_irq = 0; /*N/A*/ - cpu->stolen = 0; /*N/A*/ - cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle + cpu->irq; -#endif - - return SIGAR_OK; -} - -#if defined(__FreeBSD__) && (__FreeBSD_version >= 700000) -#define HAVE_KERN_CP_TIMES /* kern.cp_times came later than 7.0, not sure exactly when */ -static int sigar_cp_times_get(sigar_t *sigar, sigar_cpu_list_t *cpulist) -{ - int maxcpu, status; - size_t len = sizeof(maxcpu), size; - long *times; - - if (sysctlbyname("kern.smp.maxcpus", &maxcpu, &len, NULL, 0) == -1) { - return errno; - } - - size = sizeof(long) * maxcpu * CPUSTATES; - times = malloc(size); - if (sysctlbyname("kern.cp_times", times, &size, NULL, 0) == -1) { - status = errno; - } - else { - int i, maxid = (size / CPUSTATES / sizeof(long)); - long *cp_time = times; - status = SIGAR_OK; - - for (i=0; idata[cpulist->number++]; - cpu->user = SIGAR_TICK2MSEC(cp_time[CP_USER]); - cpu->nice = SIGAR_TICK2MSEC(cp_time[CP_NICE]); - cpu->sys = SIGAR_TICK2MSEC(cp_time[CP_SYS]); - cpu->idle = SIGAR_TICK2MSEC(cp_time[CP_IDLE]); - cpu->wait = 0; /*N/A*/ - cpu->irq = SIGAR_TICK2MSEC(cp_time[CP_INTR]); - cpu->soft_irq = 0; /*N/A*/ - cpu->stolen = 0; /*N/A*/ - cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle + cpu->irq; - cp_time += CPUSTATES; - } - } - - free(times); - return status; -} -#endif - -int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist) -{ -#ifdef DARWIN - kern_return_t status; - mach_msg_type_number_t count; - processor_cpu_load_info_data_t *cpuload; - natural_t i, ncpu; - - status = host_processor_info(sigar->mach_port, - PROCESSOR_CPU_LOAD_INFO, - &ncpu, - (processor_info_array_t*)&cpuload, - &count); - - if (status != KERN_SUCCESS) { - return errno; - } - - sigar_cpu_list_create(cpulist); - - for (i=0; idata[cpulist->number++]; - - cpu->user = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_USER]); - cpu->sys = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_SYSTEM]); - cpu->idle = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_IDLE]); - cpu->nice = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_NICE]); - cpu->wait = 0; /*N/A*/ - cpu->irq = 0; /*N/A*/ - cpu->soft_irq = 0; /*N/A*/ - cpu->stolen = 0; /*N/A*/ - cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle; - } - - vm_deallocate(mach_task_self(), (vm_address_t)cpuload, count); - - return SIGAR_OK; -#else - int status, i; - sigar_cpu_t *cpu; - - sigar_cpu_list_create(cpulist); - -#ifdef HAVE_KERN_CP_TIMES - if ((status = sigar_cp_times_get(sigar, cpulist)) == SIGAR_OK) { - return SIGAR_OK; - } -#endif - /* XXX no multi cpu in freebsd < 7.0, howbout others? - * for now just report all metrics on the 1st cpu - * 0's for the rest - */ - cpu = &cpulist->data[cpulist->number++]; - - status = sigar_cpu_get(sigar, cpu); - if (status != SIGAR_OK) { - return status; - } - - for (i=1; incpu; i++) { - SIGAR_CPU_LIST_GROW(cpulist); - - cpu = &cpulist->data[cpulist->number++]; - SIGAR_ZERO(cpu); - } - - return SIGAR_OK; -#endif -} - -int sigar_uptime_get(sigar_t *sigar, - sigar_uptime_t *uptime) -{ - uptime->uptime = time(NULL) - sigar->boot_time; - - return SIGAR_OK; -} - -int sigar_loadavg_get(sigar_t *sigar, - sigar_loadavg_t *loadavg) -{ - getloadavg(loadavg->loadavg, 3); - - return SIGAR_OK; -} - -#if defined(DARWIN) && defined(DARWIN_HAS_LIBPROC_H) - -static int proc_fdinfo_get(sigar_t *sigar, sigar_pid_t pid, int *num) -{ - int rsize; - const int init_size = PROC_PIDLISTFD_SIZE * 32; - - if (!sigar->libproc) { - return SIGAR_ENOTIMPL; - } - - if (sigar->ifconf_len == 0) { - sigar->ifconf_len = init_size; - sigar->ifconf_buf = malloc(sigar->ifconf_len); - } - - while (1) { - rsize = sigar->proc_pidinfo(pid, PROC_PIDLISTFDS, 0, - sigar->ifconf_buf, sigar->ifconf_len); - if (rsize <= 0) { - return errno; - } - if ((rsize + PROC_PIDLISTFD_SIZE) < sigar->ifconf_len) { - break; - } - - sigar->ifconf_len += init_size; - sigar->ifconf_buf = realloc(sigar->ifconf_buf, sigar->ifconf_len); - } - - *num = rsize / PROC_PIDLISTFD_SIZE; - - return SIGAR_OK; -} - -#endif - -#ifndef KERN_PROC_PROC -/* freebsd 4.x */ -#define KERN_PROC_PROC KERN_PROC_ALL -#endif - -int sigar_os_proc_list_get(sigar_t *sigar, - sigar_proc_list_t *proclist) -{ -#if defined(DARWIN) || defined(SIGAR_FREEBSD5) || defined(__OpenBSD__) || defined(__NetBSD__) - int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 }; - int i, num; - size_t len; - struct kinfo_proc *proc; - - if (sysctl(mib, NMIB(mib), NULL, &len, NULL, 0) < 0) { - return errno; - } - - proc = malloc(len); - - if (sysctl(mib, NMIB(mib), proc, &len, NULL, 0) < 0) { - free(proc); - return errno; - } - - num = len/sizeof(*proc); - - for (i=0; idata[proclist->number++] = proc[i].KI_PID; - } - - free(proc); - - return SIGAR_OK; -#else - int i, num; - struct kinfo_proc *proc; - - if (!sigar->kmem) { - return SIGAR_EPERM_KMEM; - } - - proc = kvm_getprocs(sigar->kmem, KERN_PROC_PROC, 0, &num); - - for (i=0; idata[proclist->number++] = proc[i].KI_PID; - } -#endif - - return SIGAR_OK; -} - -static int sigar_get_pinfo(sigar_t *sigar, sigar_pid_t pid) -{ -#if defined(__OpenBSD__) || defined(__NetBSD__) - int mib[] = { CTL_KERN, KERN_PROC2, KERN_PROC_PID, 0, sizeof(*sigar->pinfo), 1 }; -#else - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 }; -#endif - size_t len = sizeof(*sigar->pinfo); - time_t timenow = time(NULL); - mib[3] = pid; - - if (sigar->pinfo == NULL) { - sigar->pinfo = malloc(len); - } - - if (sigar->last_pid == pid) { - if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) { - return SIGAR_OK; - } - } - - sigar->last_pid = pid; - sigar->last_getprocs = timenow; - - if (sysctl(mib, NMIB(mib), sigar->pinfo, &len, NULL, 0) < 0) { - return errno; - } - - return SIGAR_OK; -} - -#if defined(SHARED_TEXT_REGION_SIZE) && defined(SHARED_DATA_REGION_SIZE) -# define GLOBAL_SHARED_SIZE (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE) /* 10.4 SDK */ -#endif - -#if defined(DARWIN) && defined(DARWIN_HAS_LIBPROC_H) && !defined(GLOBAL_SHARED_SIZE) -/* get the CPU type of the process for the given pid */ -static int sigar_proc_cpu_type(sigar_t *sigar, sigar_pid_t pid, cpu_type_t *type) -{ - int status; - int mib[CTL_MAXNAME]; - size_t len, miblen = NMIB(mib); - - status = sysctlnametomib("sysctl.proc_cputype", mib, &miblen); - if (status != SIGAR_OK) { - return status; - } - - mib[miblen] = pid; - len = sizeof(*type); - return sysctl(mib, miblen + 1, type, &len, NULL, 0); -} - -/* shared memory region size for the given cpu_type_t */ -static mach_vm_size_t sigar_shared_region_size(cpu_type_t type) -{ - switch (type) { - case CPU_TYPE_ARM: - return SHARED_REGION_SIZE_ARM; - case CPU_TYPE_POWERPC: - return SHARED_REGION_SIZE_PPC; - case CPU_TYPE_POWERPC64: - return SHARED_REGION_SIZE_PPC64; - case CPU_TYPE_I386: - return SHARED_REGION_SIZE_I386; - case CPU_TYPE_X86_64: - return SHARED_REGION_SIZE_X86_64; - default: - return SHARED_REGION_SIZE_I386; /* assume 32-bit x86|ppc */ - } -} -#endif /* DARWIN */ - -int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_mem_t *procmem) -{ -#if defined(DARWIN) - mach_port_t task, self = mach_task_self(); - kern_return_t status; - task_basic_info_data_t info; - task_events_info_data_t events; - mach_msg_type_number_t count; -# ifdef DARWIN_HAS_LIBPROC_H - struct proc_taskinfo pti; - struct proc_regioninfo pri; - - if (sigar->libproc) { - int sz = - sigar->proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti)); - - if (sz == sizeof(pti)) { - procmem->size = pti.pti_virtual_size; - procmem->resident = pti.pti_resident_size; - procmem->page_faults = pti.pti_faults; - procmem->minor_faults = SIGAR_FIELD_NOTIMPL; - procmem->major_faults = SIGAR_FIELD_NOTIMPL; - procmem->share = SIGAR_FIELD_NOTIMPL; - - sz = sigar->proc_pidinfo(pid, PROC_PIDREGIONINFO, 0, &pri, sizeof(pri)); - if (sz == sizeof(pri)) { - if (pri.pri_share_mode == SM_EMPTY) { - mach_vm_size_t shared_size; -#ifdef GLOBAL_SHARED_SIZE - shared_size = GLOBAL_SHARED_SIZE; /* 10.4 SDK */ -#else - cpu_type_t cpu_type; - - if (sigar_proc_cpu_type(sigar, pid, &cpu_type) == SIGAR_OK) { - shared_size = sigar_shared_region_size(cpu_type); - } - else { - shared_size = SHARED_REGION_SIZE_I386; /* assume 32-bit x86|ppc */ - } -#endif - if (procmem->size > shared_size) { - procmem->size -= shared_size; /* SIGAR-123 */ - } - } - } - return SIGAR_OK; - } - } -# endif - - status = task_for_pid(self, pid, &task); - - if (status != KERN_SUCCESS) { - return errno; - } - - count = TASK_BASIC_INFO_COUNT; - status = task_info(task, TASK_BASIC_INFO, (task_info_t)&info, &count); - if (status != KERN_SUCCESS) { - return errno; - } - - count = TASK_EVENTS_INFO_COUNT; - status = task_info(task, TASK_EVENTS_INFO, (task_info_t)&events, &count); - if (status == KERN_SUCCESS) { - procmem->page_faults = events.faults; - } - else { - procmem->page_faults = SIGAR_FIELD_NOTIMPL; - } - - procmem->minor_faults = SIGAR_FIELD_NOTIMPL; - procmem->major_faults = SIGAR_FIELD_NOTIMPL; - - if (task != self) { - mach_port_deallocate(self, task); - } - - procmem->size = info.virtual_size; - procmem->resident = info.resident_size; - procmem->share = SIGAR_FIELD_NOTIMPL; - - return SIGAR_OK; -#elif defined(__FreeBSD__) - int status = sigar_get_pinfo(sigar, pid); - bsd_pinfo_t *pinfo = sigar->pinfo; - - if (status != SIGAR_OK) { - return status; - } - - procmem->size = - (pinfo->KI_TSZ + pinfo->KI_DSZ + pinfo->KI_SSZ) * sigar->pagesize; - - procmem->resident = pinfo->KI_RSS * sigar->pagesize; - - procmem->share = SIGAR_FIELD_NOTIMPL; - - procmem->page_faults = SIGAR_FIELD_NOTIMPL; - procmem->minor_faults = SIGAR_FIELD_NOTIMPL; - procmem->major_faults = SIGAR_FIELD_NOTIMPL; -#elif defined(__OpenBSD__) || defined(__NetBSD__) - int status = sigar_get_pinfo(sigar, pid); - bsd_pinfo_t *pinfo = sigar->pinfo; - - if (status != SIGAR_OK) { - return status; - } - - procmem->size = - (pinfo->p_vm_tsize + pinfo->p_vm_dsize + pinfo->p_vm_ssize) * sigar->pagesize; - - procmem->resident = pinfo->p_vm_rssize * sigar->pagesize; - - procmem->share = SIGAR_FIELD_NOTIMPL; - - procmem->minor_faults = pinfo->p_uru_minflt; - procmem->major_faults = pinfo->p_uru_majflt; - procmem->page_faults = procmem->minor_faults + procmem->major_faults; -#endif - return SIGAR_OK; -} - -int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_cred_t *proccred) -{ - int status = sigar_get_pinfo(sigar, pid); - bsd_pinfo_t *pinfo = sigar->pinfo; - - if (status != SIGAR_OK) { - return status; - } - -#if defined(__OpenBSD__) || defined(__NetBSD__) - proccred->uid = pinfo->p_ruid; - proccred->gid = pinfo->p_rgid; - proccred->euid = pinfo->p_uid; - proccred->egid = pinfo->p_gid; -#else - proccred->uid = pinfo->KI_UID; - proccred->gid = pinfo->KI_GID; - proccred->euid = pinfo->KI_EUID; - proccred->egid = pinfo->KI_EGID; -#endif - - return SIGAR_OK; -} - -#define tv2msec(tv) \ - (((sigar_uint64_t)tv.tv_sec * SIGAR_MSEC) + (((sigar_uint64_t)tv.tv_usec) / 1000)) - -#ifdef DARWIN -#define tval2msec(tval) \ - ((tval.seconds * SIGAR_MSEC) + (tval.microseconds / 1000)) - -#define tval2nsec(tval) \ - (SIGAR_SEC2NANO((tval).seconds) + SIGAR_MICROSEC2NANO((tval).microseconds)) - -static int get_proc_times(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *time) -{ - unsigned int count; - time_value_t utime = {0, 0}, stime = {0, 0}; - task_basic_info_data_t ti; - task_thread_times_info_data_t tti; - task_port_t task, self; - kern_return_t status; -# ifdef DARWIN_HAS_LIBPROC_H - if (sigar->libproc) { - struct proc_taskinfo pti; - int sz = - sigar->proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti)); - - if (sz == sizeof(pti)) { - time->user = SIGAR_NSEC2MSEC(pti.pti_total_user); - time->sys = SIGAR_NSEC2MSEC(pti.pti_total_system); - time->total = time->user + time->sys; - return SIGAR_OK; - } - } -# endif - - self = mach_task_self(); - status = task_for_pid(self, pid, &task); - if (status != KERN_SUCCESS) { - return errno; - } - - count = TASK_BASIC_INFO_COUNT; - status = task_info(task, TASK_BASIC_INFO, - (task_info_t)&ti, &count); - if (status != KERN_SUCCESS) { - if (task != self) { - mach_port_deallocate(self, task); - } - return errno; - } - - count = TASK_THREAD_TIMES_INFO_COUNT; - status = task_info(task, TASK_THREAD_TIMES_INFO, - (task_info_t)&tti, &count); - if (status != KERN_SUCCESS) { - if (task != self) { - mach_port_deallocate(self, task); - } - return errno; - } - - time_value_add(&utime, &ti.user_time); - time_value_add(&stime, &ti.system_time); - time_value_add(&utime, &tti.user_time); - time_value_add(&stime, &tti.system_time); - - time->user = tval2msec(utime); - time->sys = tval2msec(stime); - time->total = time->user + time->sys; - - return SIGAR_OK; -} -#endif - -int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_time_t *proctime) -{ -#ifdef SIGAR_FREEBSD4 - struct user user; -#endif - int status = sigar_get_pinfo(sigar, pid); - bsd_pinfo_t *pinfo = sigar->pinfo; - - if (status != SIGAR_OK) { - return status; - } - -#if defined(DARWIN) - if ((status = get_proc_times(sigar, pid, proctime)) != SIGAR_OK) { - return status; - } - proctime->start_time = tv2msec(pinfo->KI_START); -#elif defined(SIGAR_FREEBSD5) - proctime->user = tv2msec(pinfo->ki_rusage.ru_utime); - proctime->sys = tv2msec(pinfo->ki_rusage.ru_stime); - proctime->total = proctime->user + proctime->sys; - proctime->start_time = tv2msec(pinfo->KI_START); -#elif defined(SIGAR_FREEBSD4) - if (!sigar->kmem) { - return SIGAR_EPERM_KMEM; - } - - status = kread(sigar, &user, sizeof(user), - (u_long)pinfo->kp_proc.p_addr); - if (status != SIGAR_OK) { - return status; - } - - proctime->user = tv2msec(user.u_stats.p_ru.ru_utime); - proctime->sys = tv2msec(user.u_stats.p_ru.ru_stime); - proctime->total = proctime->user + proctime->sys; - proctime->start_time = tv2msec(user.u_stats.p_start); -#elif defined(__OpenBSD__) || defined(__NetBSD__) - /* XXX *_usec */ - proctime->user = pinfo->p_uutime_sec * SIGAR_MSEC; - proctime->sys = pinfo->p_ustime_sec * SIGAR_MSEC; - proctime->total = proctime->user + proctime->sys; - proctime->start_time = pinfo->p_ustart_sec * SIGAR_MSEC; -#endif - - return SIGAR_OK; -} - -#ifdef DARWIN -/* thread state mapping derived from ps.tproj */ -static const char const thread_states[] = { - /*0*/ '-', - /*1*/ SIGAR_PROC_STATE_RUN, - /*2*/ SIGAR_PROC_STATE_ZOMBIE, - /*3*/ SIGAR_PROC_STATE_SLEEP, - /*4*/ SIGAR_PROC_STATE_IDLE, - /*5*/ SIGAR_PROC_STATE_STOP, - /*6*/ SIGAR_PROC_STATE_STOP, - /*7*/ '?' -}; - -static int thread_state_get(thread_basic_info_data_t *info) -{ - switch (info->run_state) { - case TH_STATE_RUNNING: - return 1; - case TH_STATE_UNINTERRUPTIBLE: - return 2; - case TH_STATE_WAITING: - return (info->sleep_time > 20) ? 4 : 3; - case TH_STATE_STOPPED: - return 5; - case TH_STATE_HALTED: - return 6; - default: - return 7; - } -} - -static int sigar_proc_threads_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_state_t *procstate) -{ - mach_port_t task, self = mach_task_self(); - kern_return_t status; - thread_array_t threads; - mach_msg_type_number_t count, i; - int state = TH_STATE_HALTED + 1; - - status = task_for_pid(self, pid, &task); - if (status != KERN_SUCCESS) { - return errno; - } - - status = task_threads(task, &threads, &count); - if (status != KERN_SUCCESS) { - return errno; - } - - procstate->threads = count; - - for (i=0; istate = thread_states[state]; - - return SIGAR_OK; -} -#endif - -int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_state_t *procstate) -{ - int status = sigar_get_pinfo(sigar, pid); - bsd_pinfo_t *pinfo = sigar->pinfo; -#if defined(__OpenBSD__) || defined(__NetBSD__) - int state = pinfo->p_stat; -#else - int state = pinfo->KI_STAT; -#endif - - if (status != SIGAR_OK) { - return status; - } - -#if defined(__OpenBSD__) || defined(__NetBSD__) - SIGAR_SSTRCPY(procstate->name, pinfo->p_comm); - procstate->ppid = pinfo->p_ppid; - procstate->priority = pinfo->p_priority; - procstate->nice = pinfo->p_nice; - procstate->tty = pinfo->p_tdev; - procstate->threads = SIGAR_FIELD_NOTIMPL; - procstate->processor = pinfo->p_cpuid; -#else - SIGAR_SSTRCPY(procstate->name, pinfo->KI_COMM); - procstate->ppid = pinfo->KI_PPID; - procstate->priority = pinfo->KI_PRI; - procstate->nice = pinfo->KI_NICE; - procstate->tty = SIGAR_FIELD_NOTIMPL; /*XXX*/ - procstate->threads = SIGAR_FIELD_NOTIMPL; - procstate->processor = SIGAR_FIELD_NOTIMPL; -#endif - -#ifdef DARWIN - status = sigar_proc_threads_get(sigar, pid, procstate); - if (status == SIGAR_OK) { - return status; - } -#endif - - switch (state) { - case SIDL: - procstate->state = 'D'; - break; - case SRUN: -#ifdef SONPROC - case SONPROC: -#endif - procstate->state = 'R'; - break; - case SSLEEP: - procstate->state = 'S'; - break; - case SSTOP: - procstate->state = 'T'; - break; - case SZOMB: - procstate->state = 'Z'; - break; - default: - procstate->state = '?'; - break; - } - - return SIGAR_OK; -} - -#if defined(DARWIN) -typedef struct { - char *buf, *ptr, *end; - int count; -} sigar_kern_proc_args_t; - -static void sigar_kern_proc_args_destroy(sigar_kern_proc_args_t *kargs) -{ - if (kargs->buf) { - free(kargs->buf); - kargs->buf = NULL; - } -} - -/* re-usable hack for use by proc_args and proc_env */ -static int sigar_kern_proc_args_get(sigar_t *sigar, - sigar_pid_t pid, - char *exe, - sigar_kern_proc_args_t *kargs) -{ - /* - * derived from: - * http://darwinsource.opendarwin.org/10.4.1/adv_cmds-79.1/ps.tproj/print.c - */ - int mib[3], len; - size_t size = sigar_argmax_get(sigar); - - kargs->buf = malloc(size); - - mib[0] = CTL_KERN; - mib[1] = KERN_PROCARGS2; - mib[2] = pid; - - if (sysctl(mib, NMIB(mib), kargs->buf, &size, NULL, 0) < 0) { - sigar_kern_proc_args_destroy(kargs); - return errno; - } - - kargs->end = &kargs->buf[size]; - - memcpy(&kargs->count, kargs->buf, sizeof(kargs->count)); - kargs->ptr = kargs->buf + sizeof(kargs->count); - - len = strlen(kargs->ptr); - if (exe) { - memcpy(exe, kargs->ptr, len+1); - } - kargs->ptr += len+1; - - if (kargs->ptr == kargs->end) { - sigar_kern_proc_args_destroy(kargs); - return exe ? SIGAR_OK : ENOENT; - } - - for (; kargs->ptr < kargs->end; kargs->ptr++) { - if (*kargs->ptr != '\0') { - break; /* start of argv[0] */ - } - } - - if (kargs->ptr == kargs->end) { - sigar_kern_proc_args_destroy(kargs); - return exe ? SIGAR_OK : ENOENT; - } - - return SIGAR_OK; -} - -static int kern_proc_args_skip_argv(sigar_kern_proc_args_t *kargs) -{ - char *ptr = kargs->ptr; - char *end = kargs->end; - int count = kargs->count; - - /* skip over argv */ - while ((ptr < end) && (count-- > 0)) { - int alen = strlen(ptr)+1; - - ptr += alen; - } - - kargs->ptr = ptr; - kargs->end = end; - kargs->count = 0; - - if (ptr >= end) { - return ENOENT; - } - - return SIGAR_OK; -} -#endif - -int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_args_t *procargs) -{ -#if defined(DARWIN) - int status, count; - sigar_kern_proc_args_t kargs; - char *ptr, *end; - - status = sigar_kern_proc_args_get(sigar, pid, NULL, &kargs); - if (status != SIGAR_OK) { - return status; - } - - count = kargs.count; - ptr = kargs.ptr; - end = kargs.end; - - while ((ptr < end) && (count-- > 0)) { - int slen = strlen(ptr); - int alen = slen+1; - char *arg; - - /* - * trim trailing whitespace. - * seen w/ postgresql, probably related - * to messing with argv[0] - */ - while (*(ptr + (slen-1)) == ' ') { - if (--slen <= 0) { - break; - } - } - - arg = malloc(slen+1); - - SIGAR_PROC_ARGS_GROW(procargs); - memcpy(arg, ptr, slen); - *(arg+slen) = '\0'; - - procargs->data[procargs->number++] = arg; - - ptr += alen; - } - - sigar_kern_proc_args_destroy(&kargs); - return SIGAR_OK; -#elif defined(__FreeBSD__) || defined(__NetBSD__) - char buffer[SIGAR_ARG_MAX+1], *ptr=buffer; - size_t len = sizeof(buffer); -# ifdef __NetBSD__ - int mib[] = { CTL_KERN, KERN_PROC_ARGS, 0, KERN_PROC_ARGV }; - mib[2] = pid; -# else - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, 0 }; - mib[3] = pid; -# endif - - if (sysctl(mib, NMIB(mib), buffer, &len, NULL, 0) < 0) { - return errno; - } - - if (len == 0) { - procargs->number = 0; - return SIGAR_OK; - } - - buffer[len] = '\0'; - - while (len > 0) { - int alen = strlen(ptr)+1; - char *arg = malloc(alen); - - SIGAR_PROC_ARGS_GROW(procargs); - memcpy(arg, ptr, alen); - - procargs->data[procargs->number++] = arg; - - len -= alen; - if (len > 0) { - ptr += alen; - } - } - - return SIGAR_OK; -#elif defined(__OpenBSD__) - char buffer[SIGAR_ARG_MAX+1], **ptr=(char **)buffer; - size_t len = sizeof(buffer); - int mib[] = { CTL_KERN, KERN_PROC_ARGS, 0, KERN_PROC_ARGV }; - mib[2] = pid; - - if (sysctl(mib, NMIB(mib), buffer, &len, NULL, 0) < 0) { - return errno; - } - - if (len == 0) { - procargs->number = 0; - return SIGAR_OK; - } - - for (; *ptr; ptr++) { - int alen = strlen(*ptr)+1; - char *arg = malloc(alen); - - SIGAR_PROC_ARGS_GROW(procargs); - memcpy(arg, *ptr, alen); - - procargs->data[procargs->number++] = arg; - } - - return SIGAR_OK; -#else - return SIGAR_ENOTIMPL; -#endif -} - -int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_env_t *procenv) -{ -#ifdef DARWIN - int status, count; - sigar_kern_proc_args_t kargs; - char *ptr, *end; - - status = sigar_kern_proc_args_get(sigar, pid, NULL, &kargs); - if (status != SIGAR_OK) { - return status; - } - - status = kern_proc_args_skip_argv(&kargs); - if (status != SIGAR_OK) { - sigar_kern_proc_args_destroy(&kargs); - return status; - } - - count = kargs.count; - ptr = kargs.ptr; - end = kargs.end; - - /* into environ */ - while (ptr < end) { - char *val = strchr(ptr, '='); - int klen, vlen, status; - char key[256]; /* XXX is there a max key size? */ - - if (val == NULL) { - /* not key=val format */ - break; - } - - klen = val - ptr; - SIGAR_SSTRCPY(key, ptr); - key[klen] = '\0'; - ++val; - - vlen = strlen(val); - status = procenv->env_getter(procenv->data, - key, klen, val, vlen); - - if (status != SIGAR_OK) { - /* not an error; just stop iterating */ - break; - } - - ptr += (klen + 1 + vlen + 1); - - if (*ptr == '\0') { - break; - } - } - - sigar_kern_proc_args_destroy(&kargs); - return SIGAR_OK; -#else - char **env; - struct kinfo_proc *pinfo; - int num; - - if (!sigar->kmem) { - return SIGAR_EPERM_KMEM; - } - - pinfo = kvm_getprocs(sigar->kmem, KERN_PROC_PID, pid, &num); - if (!pinfo || (num < 1)) { - return errno; - } - - if (!(env = kvm_getenvv(sigar->kmem, pinfo, 9086))) { - return errno; - } - - while (*env) { - char *ptr = *env++; - char *val = strchr(ptr, '='); - int klen, vlen, status; - char key[128]; /* XXX is there a max key size? */ - - if (val == NULL) { - /* not key=val format */ - procenv->env_getter(procenv->data, ptr, strlen(ptr), NULL, 0); - break; - } - - klen = val - ptr; - SIGAR_SSTRCPY(key, ptr); - key[klen] = '\0'; - ++val; - - vlen = strlen(val); - status = procenv->env_getter(procenv->data, - key, klen, val, vlen); - - if (status != SIGAR_OK) { - /* not an error; just stop iterating */ - break; - } - - ptr += (klen + 1 + vlen + 1); - } - - return SIGAR_OK; -#endif -} - -int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_fd_t *procfd) -{ -#ifdef __FreeBSD__ - int status; - bsd_pinfo_t *pinfo; - struct filedesc filed; -#if 0 - struct file **ofiles; - int nfiles, i; - size_t size; -#endif - if (!sigar->kmem) { - return SIGAR_EPERM_KMEM; - } - - if ((status = sigar_get_pinfo(sigar, pid)) != SIGAR_OK) { - return status; - } - pinfo = sigar->pinfo; - - status = kread(sigar, &filed, sizeof(filed), (u_long)pinfo->KI_FD); - if (status != SIGAR_OK) { - return status; - } -#if 0 - nfiles = filed.fd_lastfile+1; - size = sizeof(*ofiles) * nfiles; - ofiles = malloc(size); - status = kread(sigar, ofiles, size, (u_long)filed.fd_ofiles); - if (status != SIGAR_OK) { - free(ofiles); - return status; - } - - procfd->total = 0; - for (i=0; itotal++; - } - - free(ofiles); -#else - /* seems the same as the above */ - procfd->total = filed.fd_lastfile; -#endif - - return SIGAR_OK; -#else - return SIGAR_ENOTIMPL; -#endif -} - -int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_exe_t *procexe) -{ -#ifdef DARWIN - int status; - sigar_kern_proc_args_t kargs; - - status = sigar_kern_proc_args_get(sigar, pid, procexe->name, &kargs); - if (status != SIGAR_OK) { - return status; - } - - procexe->cwd[0] = '\0'; - procexe->root[0] = '\0'; - - /* attempt to determine cwd from $PWD */ - status = kern_proc_args_skip_argv(&kargs); - if (status == SIGAR_OK) { - char *ptr = kargs.ptr; - char *end = kargs.end; - - /* into environ */ - while (ptr < end) { - int len = strlen(ptr); - - if ((len > 4) && - (ptr[0] == 'P') && - (ptr[1] == 'W') && - (ptr[2] == 'D') && - (ptr[3] == '=')) - { - memcpy(procexe->cwd, ptr+4, len-3); - break; - } - - ptr += len+1; - } - } - - sigar_kern_proc_args_destroy(&kargs); - - return SIGAR_OK; -#else - int len; - char name[1024]; - - procexe->cwd[0] = '\0'; - procexe->root[0] = '\0'; - - (void)SIGAR_PROC_FILENAME(name, pid, "/file"); - - if ((len = readlink(name, procexe->name, - sizeof(procexe->name)-1)) < 0) - { - return PROCFS_STATUS(errno); - } - - procexe->name[len] = '\0'; - - return SIGAR_OK; -#endif -} - -#ifdef DARWIN -static int sigar_dlinfo_modules(sigar_t *sigar, sigar_proc_modules_t *procmods) -{ - uint32_t i, count = _dyld_image_count(); - - for (i=0; imodule_getter(procmods->data, - (char *)name, strlen(name)); - - if (status != SIGAR_OK) { - /* not an error; just stop iterating */ - break; - } - } - return SIGAR_OK; -} -#endif /* DARWIN */ - -int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_modules_t *procmods) -{ -#if defined(SIGAR_HAS_DLINFO_MODULES) || defined(DARWIN) - if (pid == sigar_pid_get(sigar)) { - return sigar_dlinfo_modules(sigar, procmods); - } -#endif - return SIGAR_ENOTIMPL; -} - -#define SIGAR_MICROSEC2NANO(s) \ - ((sigar_uint64_t)(s) * (sigar_uint64_t)1000) - -#define TIME_NSEC(t) \ - (SIGAR_SEC2NANO((t).tv_sec) + SIGAR_MICROSEC2NANO((t).tv_usec)) - -int sigar_thread_cpu_get(sigar_t *sigar, - sigar_uint64_t id, - sigar_thread_cpu_t *cpu) -{ -#if defined(DARWIN) - mach_port_t self = mach_thread_self(); - thread_basic_info_data_t info; - mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; - kern_return_t status; - - status = thread_info(self, THREAD_BASIC_INFO, - (thread_info_t)&info, &count); - if (status != KERN_SUCCESS) { - return errno; - } - - mach_port_deallocate(mach_task_self(), self); - - cpu->user = tval2nsec(info.user_time); - cpu->sys = tval2nsec(info.system_time); - cpu->total = cpu->user + cpu->sys; -#elif defined(__NetBSD__) - return SIGAR_ENOTIMPL; /* http://tinyurl.com/chbvln */ -#else - /* XXX this is not per-thread, it is for the whole-process. - * just want to use for the shell time command at the moment. - */ - struct rusage usage; - getrusage(RUSAGE_SELF, &usage); - - cpu->user = TIME_NSEC(usage.ru_utime); - cpu->sys = TIME_NSEC(usage.ru_stime); - cpu->total = TIME_NSEC(usage.ru_utime) + TIME_NSEC(usage.ru_stime); -#endif - - return SIGAR_OK; -} - -int sigar_os_fs_type_get(sigar_file_system_t *fsp) -{ - char *type = fsp->sys_type_name; - - /* see sys/disklabel.h */ - switch (*type) { - case 'f': - if (strEQ(type, "ffs")) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - case 'h': - if (strEQ(type, "hfs")) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - case 'u': - if (strEQ(type, "ufs")) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - } - - return fsp->type; -} - -static void get_fs_options(char *opts, int osize, long flags) -{ - *opts = '\0'; - if (flags & MNT_RDONLY) strncat(opts, "ro", osize); - else strncat(opts, "rw", osize); - if (flags & MNT_SYNCHRONOUS) strncat(opts, ",sync", osize); - if (flags & MNT_NOEXEC) strncat(opts, ",noexec", osize); - if (flags & MNT_NOSUID) strncat(opts, ",nosuid", osize); -#ifdef MNT_NODEV - if (flags & MNT_NODEV) strncat(opts, ",nodev", osize); -#endif -#ifdef MNT_UNION - if (flags & MNT_UNION) strncat(opts, ",union", osize); -#endif - if (flags & MNT_ASYNC) strncat(opts, ",async", osize); -#ifdef MNT_NOATIME - if (flags & MNT_NOATIME) strncat(opts, ",noatime", osize); -#endif -#ifdef MNT_NOCLUSTERR - if (flags & MNT_NOCLUSTERR) strncat(opts, ",noclusterr", osize); -#endif -#ifdef MNT_NOCLUSTERW - if (flags & MNT_NOCLUSTERW) strncat(opts, ",noclusterw", osize); -#endif -#ifdef MNT_NOSYMFOLLOW - if (flags & MNT_NOSYMFOLLOW) strncat(opts, ",nosymfollow", osize); -#endif -#ifdef MNT_SUIDDIR - if (flags & MNT_SUIDDIR) strncat(opts, ",suiddir", osize); -#endif -#ifdef MNT_SOFTDEP - if (flags & MNT_SOFTDEP) strncat(opts, ",soft-updates", osize); -#endif - if (flags & MNT_LOCAL) strncat(opts, ",local", osize); - if (flags & MNT_QUOTA) strncat(opts, ",quota", osize); - if (flags & MNT_ROOTFS) strncat(opts, ",rootfs", osize); -#ifdef MNT_USER - if (flags & MNT_USER) strncat(opts, ",user", osize); -#endif -#ifdef MNT_IGNORE - if (flags & MNT_IGNORE) strncat(opts, ",ignore", osize); -#endif - if (flags & MNT_EXPORTED) strncat(opts, ",nfs", osize); -} - -#ifdef __NetBSD__ -#define sigar_statfs statvfs -#define sigar_getfsstat getvfsstat -#define sigar_f_flags f_flag -#else -#define sigar_statfs statfs -#define sigar_getfsstat getfsstat -#define sigar_f_flags f_flags -#endif - -int sigar_file_system_list_get(sigar_t *sigar, - sigar_file_system_list_t *fslist) -{ - struct sigar_statfs *fs; - int num, i; - int is_debug = SIGAR_LOG_IS_DEBUG(sigar); - long len; - - if ((num = sigar_getfsstat(NULL, 0, MNT_NOWAIT)) < 0) { - return errno; - } - - len = sizeof(*fs) * num; - fs = malloc(len); - - if ((num = sigar_getfsstat(fs, len, MNT_NOWAIT)) < 0) { - free(fs); - return errno; - } - - sigar_file_system_list_create(fslist); - - for (i=0; idata[fslist->number++]; - - SIGAR_SSTRCPY(fsp->dir_name, fs[i].f_mntonname); - SIGAR_SSTRCPY(fsp->dev_name, fs[i].f_mntfromname); - SIGAR_SSTRCPY(fsp->sys_type_name, fs[i].f_fstypename); - get_fs_options(fsp->options, sizeof(fsp->options)-1, fs[i].sigar_f_flags); - - sigar_fs_type_init(fsp); - } - - free(fs); - return SIGAR_OK; -} - -#ifdef DARWIN -#define IoStatGetValue(key, val) \ - if ((number = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatistics##key)))) \ - CFNumberGetValue(number, kCFNumberSInt64Type, &val) -#endif - -int sigar_disk_usage_get(sigar_t *sigar, const char *name, - sigar_disk_usage_t *disk) -{ -#if defined(DARWIN) - kern_return_t status; - io_registry_entry_t parent; - io_service_t service; - CFDictionaryRef props; - CFNumberRef number; - sigar_iodev_t *iodev = sigar_iodev_get(sigar, name); - char dname[256], *ptr; - - SIGAR_DISK_STATS_INIT(disk); - - if (!iodev) { - return ENXIO; - } - - /* "/dev/disk0s1" -> "disk0" */ /* XXX better way? */ - ptr = &iodev->name[SSTRLEN(SIGAR_DEV_PREFIX)]; - SIGAR_SSTRCPY(dname, ptr); - ptr = dname; - if (strnEQ(ptr, "disk", 4)) { - ptr += 4; - if ((ptr = strchr(ptr, 's')) && isdigit(*(ptr+1))) { - *ptr = '\0'; - } - } - - if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[disk_usage] map %s -> %s", - iodev->name, dname); - } - - /* e.g. name == "disk0" */ - service = IOServiceGetMatchingService(kIOMasterPortDefault, - IOBSDNameMatching(kIOMasterPortDefault, 0, dname)); - - if (!service) { - return errno; - } - - status = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent); - if (status != KERN_SUCCESS) { - IOObjectRelease(service); - return status; - } - - status = IORegistryEntryCreateCFProperties(parent, - (CFMutableDictionaryRef *)&props, - kCFAllocatorDefault, - kNilOptions); - if (props) { - CFDictionaryRef stats = - (CFDictionaryRef)CFDictionaryGetValue(props, - CFSTR(kIOBlockStorageDriverStatisticsKey)); - - if (stats) { - IoStatGetValue(ReadsKey, disk->reads); - IoStatGetValue(BytesReadKey, disk->read_bytes); - IoStatGetValue(TotalReadTimeKey, disk->rtime); - IoStatGetValue(WritesKey, disk->writes); - IoStatGetValue(BytesWrittenKey, disk->write_bytes); - IoStatGetValue(TotalWriteTimeKey, disk->wtime); - disk->time = disk->rtime + disk->wtime; - } - - CFRelease(props); - } - - IOObjectRelease(service); - IOObjectRelease(parent); - - return SIGAR_OK; -#elif defined(__FreeBSD__) - /* XXX incomplete */ - struct sigar_statfs buf; - - if (sigar_statfs(name, &buf) < 0) { - return errno; - } - - SIGAR_DISK_STATS_INIT(disk); - - disk->reads = buf.f_syncreads + buf.f_asyncreads; - disk->writes = buf.f_syncwrites + buf.f_asyncwrites; - return SIGAR_OK; -#else - SIGAR_DISK_STATS_INIT(disk); - return SIGAR_ENOTIMPL; -#endif -} - -int sigar_file_system_usage_get(sigar_t *sigar, - const char *dirname, - sigar_file_system_usage_t *fsusage) -{ - int status = sigar_statvfs(sigar, dirname, fsusage); - - if (status != SIGAR_OK) { - return status; - } - - fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage); - - sigar_disk_usage_get(sigar, dirname, &fsusage->disk); - - return SIGAR_OK; -} - -#ifdef DARWIN -#define CTL_HW_FREQ_MAX "hw.cpufrequency_max" -#define CTL_HW_FREQ_MIN "hw.cpufrequency_min" -#else -/* XXX FreeBSD 5.x+ only? */ -#define CTL_HW_FREQ "machdep.tsc_freq" -#endif - -int sigar_cpu_info_list_get(sigar_t *sigar, - sigar_cpu_info_list_t *cpu_infos) -{ - int i; - unsigned int mhz, mhz_min, mhz_max; - int cache_size=SIGAR_FIELD_NOTIMPL; - size_t size; - char model[128], vendor[128], *ptr; - - size = sizeof(mhz); - - (void)sigar_cpu_core_count(sigar); - -#if defined(DARWIN) - { - int mib[] = { CTL_HW, HW_CPU_FREQ }; - size = sizeof(mhz); - if (sysctl(mib, NMIB(mib), &mhz, &size, NULL, 0) < 0) { - mhz = SIGAR_FIELD_NOTIMPL; - } - } - if (sysctlbyname(CTL_HW_FREQ_MAX, &mhz_max, &size, NULL, 0) < 0) { - mhz_max = SIGAR_FIELD_NOTIMPL; - } - if (sysctlbyname(CTL_HW_FREQ_MIN, &mhz_min, &size, NULL, 0) < 0) { - mhz_min = SIGAR_FIELD_NOTIMPL; - } -#elif defined(__FreeBSD__) - if (sysctlbyname(CTL_HW_FREQ, &mhz, &size, NULL, 0) < 0) { - mhz = SIGAR_FIELD_NOTIMPL; - } - /* TODO */ - mhz_max = SIGAR_FIELD_NOTIMPL; - mhz_min = SIGAR_FIELD_NOTIMPL; -#else - /*XXX OpenBSD*/ - mhz = SIGAR_FIELD_NOTIMPL; - mhz_max = SIGAR_FIELD_NOTIMPL; - mhz_min = SIGAR_FIELD_NOTIMPL; -#endif - - if (mhz != SIGAR_FIELD_NOTIMPL) { - mhz /= 1000000; - } - if (mhz_max != SIGAR_FIELD_NOTIMPL) { - mhz_max /= 1000000; - } - if (mhz_min != SIGAR_FIELD_NOTIMPL) { - mhz_min /= 1000000; - } - - size = sizeof(model); -#ifdef __OpenBSD__ - if (1) { -#else - if (sysctlbyname("hw.model", &model, &size, NULL, 0) < 0) { -#endif - int mib[] = { CTL_HW, HW_MODEL }; - size = sizeof(model); - if (sysctl(mib, NMIB(mib), &model[0], &size, NULL, 0) < 0) { -#ifdef DARWIN - strcpy(model, "powerpc"); -#else - strcpy(model, "Unknown"); -#endif - } - } - - if (mhz == SIGAR_FIELD_NOTIMPL) { - /* freebsd4 */ - mhz = sigar_cpu_mhz_from_model(model); - } - /* XXX not sure */ - if (mhz_max == SIGAR_FIELD_NOTIMPL) { - mhz_max = 0; - } - if (mhz_min == SIGAR_FIELD_NOTIMPL) { - mhz_min = 0; - } - - -#ifdef DARWIN - size = sizeof(vendor); - if (sysctlbyname("machdep.cpu.vendor", &vendor, &size, NULL, 0) < 0) { - SIGAR_SSTRCPY(vendor, "Apple"); - } - else { - /* GenuineIntel -> Intel */ - if (strstr(vendor, "Intel")) { - SIGAR_SSTRCPY(vendor, "Intel"); - } - } -#endif - - if ((ptr = strchr(model, ' '))) { - if (strstr(model, "Intel")) { - SIGAR_SSTRCPY(vendor, "Intel"); - } - else if (strstr(model, "AMD")) { - SIGAR_SSTRCPY(vendor, "AMD"); - } - else { - SIGAR_SSTRCPY(vendor, "Unknown"); - } - SIGAR_SSTRCPY(model, ptr+1); - } - -#ifdef DARWIN - { - int mib[] = { CTL_HW, HW_L2CACHESIZE }; /* in bytes */ - size = sizeof(cache_size); - if (sysctl(mib, NMIB(mib), &cache_size, &size, NULL, 0) < 0) { - cache_size = SIGAR_FIELD_NOTIMPL; - } - else { - cache_size /= 1024; /* convert to KB */ - } - } -#endif - - sigar_cpu_info_list_create(cpu_infos); - - for (i=0; incpu; i++) { - sigar_cpu_info_t *info; - - SIGAR_CPU_INFO_LIST_GROW(cpu_infos); - - info = &cpu_infos->data[cpu_infos->number++]; - - SIGAR_SSTRCPY(info->vendor, vendor); - SIGAR_SSTRCPY(info->model, model); - sigar_cpu_model_adjust(sigar, info); - - info->mhz = mhz; - info->mhz_max = mhz_max; - info->mhz_min = mhz_min; - info->cache_size = cache_size; - info->total_cores = sigar->ncpu; - info->cores_per_socket = sigar->lcpu; - info->total_sockets = sigar_cpu_socket_count(sigar); - } - - return SIGAR_OK; -} - -#define rt_s_addr(sa) ((struct sockaddr_in *)(sa))->sin_addr.s_addr - -#ifndef SA_SIZE -#define SA_SIZE(sa) \ - ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \ - sizeof(long) : \ - 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) -#endif - -int sigar_net_route_list_get(sigar_t *sigar, - sigar_net_route_list_t *routelist) -{ - size_t needed; - int bit; - char *buf, *next, *lim; - struct rt_msghdr *rtm; - int mib[6] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_DUMP, 0 }; - - if (sysctl(mib, NMIB(mib), NULL, &needed, NULL, 0) < 0) { - return errno; - } -#if __FreeBSD_version >= 800000 - if (needed == 0) { - return SIGAR_ENOTIMPL; /*XXX hoping this is an 8.0beta bug*/ - } -#endif - buf = malloc(needed); - - if (sysctl(mib, NMIB(mib), buf, &needed, NULL, 0) < 0) { - free(buf); - return errno; - } - - sigar_net_route_list_create(routelist); - - lim = buf + needed; - for (next = buf; next < lim; next += rtm->rtm_msglen) { - struct sockaddr *sa; - sigar_net_route_t *route; - rtm = (struct rt_msghdr *)next; - - if (rtm->rtm_type != RTM_GET) { - continue; - } - - sa = (struct sockaddr *)(rtm + 1); - - if (sa->sa_family != AF_INET) { - continue; - } - - SIGAR_NET_ROUTE_LIST_GROW(routelist); - route = &routelist->data[routelist->number++]; - SIGAR_ZERO(route); - - route->flags = rtm->rtm_flags; - if_indextoname(rtm->rtm_index, route->ifname); - - for (bit=RTA_DST; - bit && ((char *)sa < lim); - bit <<= 1) - { - if ((rtm->rtm_addrs & bit) == 0) { - continue; - } - switch (bit) { - case RTA_DST: - sigar_net_address_set(route->destination, - rt_s_addr(sa)); - break; - case RTA_GATEWAY: - if (sa->sa_family == AF_INET) { - sigar_net_address_set(route->gateway, - rt_s_addr(sa)); - } - break; - case RTA_NETMASK: - sigar_net_address_set(route->mask, - rt_s_addr(sa)); - break; - case RTA_IFA: - break; - } - - sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa)); - } - } - - free(buf); - - return SIGAR_OK; -} - -typedef enum { - IFMSG_ITER_LIST, - IFMSG_ITER_GET -} ifmsg_iter_e; - -typedef struct { - const char *name; - ifmsg_iter_e type; - union { - sigar_net_interface_list_t *iflist; - struct if_msghdr *ifm; - } data; -} ifmsg_iter_t; - -static int sigar_ifmsg_init(sigar_t *sigar) -{ - int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, 0 }; - size_t len; - - if (sysctl(mib, NMIB(mib), NULL, &len, NULL, 0) < 0) { - return errno; - } - - if (sigar->ifconf_len < len) { - sigar->ifconf_buf = realloc(sigar->ifconf_buf, len); - sigar->ifconf_len = len; - } - - if (sysctl(mib, NMIB(mib), sigar->ifconf_buf, &len, NULL, 0) < 0) { - return errno; - } - - return SIGAR_OK; -} - -/** - * @param name name of the interface - * @param name_len length of name (w/o \0) - */ -static int has_ifaddr(char *name, size_t name_len) -{ - int sock, status; - struct ifreq ifr; - - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - return errno; - } - strncpy(ifr.ifr_name, name, MIN(sizeof(ifr.ifr_name) - 1, name_len)); - ifr.ifr_name[MIN(sizeof(ifr.ifr_name) - 1, name_len)] = '\0'; - if (ioctl(sock, SIOCGIFADDR, &ifr) == 0) { - status = SIGAR_OK; - } - else { - status = errno; - } - - close(sock); - return status; -} - -static int sigar_ifmsg_iter(sigar_t *sigar, ifmsg_iter_t *iter) -{ - char *end = sigar->ifconf_buf + sigar->ifconf_len; - char *ptr = sigar->ifconf_buf; - - if (iter->type == IFMSG_ITER_LIST) { - sigar_net_interface_list_create(iter->data.iflist); - } - - while (ptr < end) { - char *name; - struct sockaddr_dl *sdl; - struct if_msghdr *ifm = (struct if_msghdr *)ptr; - - if (ifm->ifm_type != RTM_IFINFO) { - break; - } - - ptr += ifm->ifm_msglen; - - while (ptr < end) { - struct if_msghdr *next = (struct if_msghdr *)ptr; - - if (next->ifm_type != RTM_NEWADDR) { - break; - } - - ptr += next->ifm_msglen; - } - - sdl = (struct sockaddr_dl *)(ifm + 1); - if (sdl->sdl_family != AF_LINK) { - continue; - } - - switch (iter->type) { - case IFMSG_ITER_LIST: - if (sdl->sdl_type == IFT_OTHER) { - if (has_ifaddr(sdl->sdl_data, sdl->sdl_nlen) != SIGAR_OK) { - break; - } - } - else if (!((sdl->sdl_type == IFT_ETHER) || - (sdl->sdl_type == IFT_LOOP))) - { - break; /* XXX deal w/ other weirdo interfaces */ - } - - SIGAR_NET_IFLIST_GROW(iter->data.iflist); - - /* sdl_data doesn't include a trailing \0, it is only sdl_nlen long */ - name = malloc(sdl->sdl_nlen+1); - memcpy(name, sdl->sdl_data, sdl->sdl_nlen); - name[sdl->sdl_nlen] = '\0'; /* add the missing \0 */ - - iter->data.iflist->data[iter->data.iflist->number++] = name; - break; - - case IFMSG_ITER_GET: - if (strlen(iter->name) == sdl->sdl_nlen && 0 == memcmp(iter->name, sdl->sdl_data, sdl->sdl_nlen)) { - iter->data.ifm = ifm; - return SIGAR_OK; - } - } - } - - switch (iter->type) { - case IFMSG_ITER_LIST: - return SIGAR_OK; - - case IFMSG_ITER_GET: - default: - return ENXIO; - } -} - -int sigar_net_interface_list_get(sigar_t *sigar, - sigar_net_interface_list_t *iflist) -{ - int status; - ifmsg_iter_t iter; - - if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) { - return status; - } - - iter.type = IFMSG_ITER_LIST; - iter.data.iflist = iflist; - - return sigar_ifmsg_iter(sigar, &iter); -} - -#include - -/* in6_prefixlen derived from freebsd/sbin/ifconfig/af_inet6.c */ -static int sigar_in6_prefixlen(struct sockaddr *netmask) -{ - struct in6_addr *addr = SIGAR_SIN6_ADDR(netmask); - u_char *name = (u_char *)addr; - int size = sizeof(*addr); - int byte, bit, plen = 0; - - for (byte = 0; byte < size; byte++, plen += 8) { - if (name[byte] != 0xff) { - break; - } - } - if (byte == size) { - return plen; - } - for (bit = 7; bit != 0; bit--, plen++) { - if (!(name[byte] & (1 << bit))) { - break; - } - } - for (; bit != 0; bit--) { - if (name[byte] & (1 << bit)) { - return 0; - } - } - byte++; - for (; byte < size; byte++) { - if (name[byte]) { - return 0; - } - } - return plen; -} - -int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, - sigar_net_interface_config_t *ifconfig) -{ - int status = SIGAR_ENOENT; - struct ifaddrs *addrs, *ifa; - - if (getifaddrs(&addrs) != 0) { - return errno; - } - - for (ifa=addrs; ifa; ifa=ifa->ifa_next) { - if (ifa->ifa_addr && - (ifa->ifa_addr->sa_family == AF_INET6) && - strEQ(ifa->ifa_name, name)) - { - status = SIGAR_OK; - break; - } - } - - if (status == SIGAR_OK) { - struct in6_addr *addr = SIGAR_SIN6_ADDR(ifa->ifa_addr); - - sigar_net_address6_set(ifconfig->address6, addr); - sigar_net_interface_scope6_set(ifconfig, addr); - ifconfig->prefix6_length = sigar_in6_prefixlen(ifa->ifa_netmask); - } - - freeifaddrs(addrs); - - return status; -} - -int sigar_net_interface_config_get(sigar_t *sigar, const char *name, - sigar_net_interface_config_t *ifconfig) -{ - int sock; - int status; - ifmsg_iter_t iter; - struct if_msghdr *ifm; - struct sockaddr_dl *sdl; - struct ifreq ifr; - - if (!name) { - return sigar_net_interface_config_primary_get(sigar, ifconfig); - } - - if (sigar->ifconf_len == 0) { - if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) { - return status; - } - } - - SIGAR_ZERO(ifconfig); - - iter.type = IFMSG_ITER_GET; - iter.name = name; - - if ((status = sigar_ifmsg_iter(sigar, &iter)) != SIGAR_OK) { - return status; - } - - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - return errno; - } - - ifm = iter.data.ifm; - - SIGAR_SSTRCPY(ifconfig->name, name); - - sdl = (struct sockaddr_dl *)(ifm + 1); - - sigar_net_address_mac_set(ifconfig->hwaddr, - LLADDR(sdl), - sdl->sdl_alen); - - ifconfig->flags = ifm->ifm_flags; - ifconfig->mtu = ifm->ifm_data.ifi_mtu; - ifconfig->metric = ifm->ifm_data.ifi_metric; - - SIGAR_SSTRCPY(ifr.ifr_name, name); - -#define ifr_s_addr(ifr) \ - ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr - - if (!ioctl(sock, SIOCGIFADDR, &ifr)) { - sigar_net_address_set(ifconfig->address, - ifr_s_addr(ifr)); - } - - if (!ioctl(sock, SIOCGIFNETMASK, &ifr)) { - sigar_net_address_set(ifconfig->netmask, - ifr_s_addr(ifr)); - } - - if (ifconfig->flags & IFF_LOOPBACK) { - sigar_net_address_set(ifconfig->destination, - ifconfig->address.addr.in); - sigar_net_address_set(ifconfig->broadcast, 0); - SIGAR_SSTRCPY(ifconfig->type, - SIGAR_NIC_LOOPBACK); - } - else { - if (!ioctl(sock, SIOCGIFDSTADDR, &ifr)) { - sigar_net_address_set(ifconfig->destination, - ifr_s_addr(ifr)); - } - - if (!ioctl(sock, SIOCGIFBRDADDR, &ifr)) { - sigar_net_address_set(ifconfig->broadcast, - ifr_s_addr(ifr)); - } - SIGAR_SSTRCPY(ifconfig->type, - SIGAR_NIC_ETHERNET); - } - - close(sock); - - /* XXX can we get a better description like win32? */ - SIGAR_SSTRCPY(ifconfig->description, - ifconfig->name); - - sigar_net_interface_ipv6_config_init(ifconfig); - sigar_net_interface_ipv6_config_get(sigar, name, ifconfig); - - return SIGAR_OK; -} - -int sigar_net_interface_stat_get(sigar_t *sigar, const char *name, - sigar_net_interface_stat_t *ifstat) -{ - int status; - ifmsg_iter_t iter; - struct if_msghdr *ifm; - - if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) { - return status; - } - - iter.type = IFMSG_ITER_GET; - iter.name = name; - - if ((status = sigar_ifmsg_iter(sigar, &iter)) != SIGAR_OK) { - return status; - } - - ifm = iter.data.ifm; - - ifstat->rx_bytes = ifm->ifm_data.ifi_ibytes; - ifstat->rx_packets = ifm->ifm_data.ifi_ipackets; - ifstat->rx_errors = ifm->ifm_data.ifi_ierrors; - ifstat->rx_dropped = ifm->ifm_data.ifi_iqdrops; - ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL; - ifstat->rx_frame = SIGAR_FIELD_NOTIMPL; - - ifstat->tx_bytes = ifm->ifm_data.ifi_obytes; - ifstat->tx_packets = ifm->ifm_data.ifi_opackets; - ifstat->tx_errors = ifm->ifm_data.ifi_oerrors; - ifstat->tx_collisions = ifm->ifm_data.ifi_collisions; - ifstat->tx_dropped = SIGAR_FIELD_NOTIMPL; - ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL; - ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL; - - ifstat->speed = ifm->ifm_data.ifi_baudrate; - - return SIGAR_OK; -} - -static int net_connection_state_get(int state) -{ - switch (state) { - case TCPS_CLOSED: - return SIGAR_TCP_CLOSE; - case TCPS_LISTEN: - return SIGAR_TCP_LISTEN; - case TCPS_SYN_SENT: - return SIGAR_TCP_SYN_SENT; - case TCPS_SYN_RECEIVED: - return SIGAR_TCP_SYN_RECV; - case TCPS_ESTABLISHED: - return SIGAR_TCP_ESTABLISHED; - case TCPS_CLOSE_WAIT: - return SIGAR_TCP_CLOSE_WAIT; - case TCPS_FIN_WAIT_1: - return SIGAR_TCP_FIN_WAIT1; - case TCPS_CLOSING: - return SIGAR_TCP_CLOSING; - case TCPS_LAST_ACK: - return SIGAR_TCP_LAST_ACK; - case TCPS_FIN_WAIT_2: - return SIGAR_TCP_FIN_WAIT2; - case TCPS_TIME_WAIT: - return SIGAR_TCP_TIME_WAIT; - default: - return SIGAR_TCP_UNKNOWN; - } -} - -#if defined(__OpenBSD__) || defined(__NetBSD__) -static int net_connection_get(sigar_net_connection_walker_t *walker, int proto) -{ - int status; - int istcp = 0, type; - int flags = walker->flags; - struct inpcbtable table; - struct inpcb *head, *next, *prev; - sigar_t *sigar = walker->sigar; - u_long offset; - - switch (proto) { - case IPPROTO_TCP: - offset = sigar->koffsets[KOFFSET_TCBTABLE]; - istcp = 1; - type = SIGAR_NETCONN_TCP; - break; - case IPPROTO_UDP: - default: - return SIGAR_ENOTIMPL; - } - - - status = kread(sigar, &table, sizeof(table), offset); - - if (status != SIGAR_OK) { - return status; - } - - prev = head = - (struct inpcb *)&CIRCLEQ_FIRST(&((struct inpcbtable *)offset)->inpt_queue); - - next = (struct inpcb *)CIRCLEQ_FIRST(&table.inpt_queue); - - while (next != head) { - struct inpcb inpcb; - struct tcpcb tcpcb; - struct socket socket; - - status = kread(sigar, &inpcb, sizeof(inpcb), (long)next); - prev = next; - next = (struct inpcb *)CIRCLEQ_NEXT(&inpcb, inp_queue); - - kread(sigar, &socket, sizeof(socket), (u_long)inpcb.inp_socket); - - if ((((flags & SIGAR_NETCONN_SERVER) && socket.so_qlimit) || - ((flags & SIGAR_NETCONN_CLIENT) && !socket.so_qlimit))) - { - sigar_net_connection_t conn; - - SIGAR_ZERO(&conn); - - if (istcp) { - kread(sigar, &tcpcb, sizeof(tcpcb), (u_long)inpcb.inp_ppcb); - } - -#ifdef __NetBSD__ - if (inpcb.inp_af == AF_INET6) { - /*XXX*/ - continue; - } -#else - if (inpcb.inp_flags & INP_IPV6) { - sigar_net_address6_set(conn.local_address, - &inpcb.inp_laddr6.s6_addr); - - sigar_net_address6_set(conn.remote_address, - &inpcb.inp_faddr6.s6_addr); - } -#endif - else { - sigar_net_address_set(conn.local_address, - inpcb.inp_laddr.s_addr); - - sigar_net_address_set(conn.remote_address, - inpcb.inp_faddr.s_addr); - } - - conn.local_port = ntohs(inpcb.inp_lport); - conn.remote_port = ntohs(inpcb.inp_fport); - conn.receive_queue = socket.so_rcv.sb_cc; - conn.send_queue = socket.so_snd.sb_cc; - conn.uid = socket.so_pgid; - conn.type = type; - - if (!istcp) { - conn.state = SIGAR_TCP_UNKNOWN; - if (walker->add_connection(walker, &conn) != SIGAR_OK) { - break; - } - continue; - } - - conn.state = net_connection_state_get(tcpcb.t_state); - - if (walker->add_connection(walker, &conn) != SIGAR_OK) { - break; - } - } - } - - return SIGAR_OK; -} -#else -static int net_connection_get(sigar_net_connection_walker_t *walker, int proto) -{ - int flags = walker->flags; - int type, istcp = 0; - char *buf; - const char *mibvar; - struct tcpcb *tp = NULL; - struct inpcb *inp; - struct xinpgen *xig, *oxig; - struct xsocket *so; - size_t len; - - switch (proto) { - case IPPROTO_TCP: - mibvar = "net.inet.tcp.pcblist"; - istcp = 1; - type = SIGAR_NETCONN_TCP; - break; - case IPPROTO_UDP: - mibvar = "net.inet.udp.pcblist"; - type = SIGAR_NETCONN_UDP; - break; - default: - mibvar = "net.inet.raw.pcblist"; - type = SIGAR_NETCONN_RAW; - break; - } - - len = 0; - if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { - return errno; - } - if ((buf = malloc(len)) == 0) { - return errno; - } - if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) { - free(buf); - return errno; - } - - oxig = xig = (struct xinpgen *)buf; - for (xig = (struct xinpgen *)((char *)xig + xig->xig_len); - xig->xig_len > sizeof(struct xinpgen); - xig = (struct xinpgen *)((char *)xig + xig->xig_len)) - { - if (istcp) { - struct xtcpcb *cb = (struct xtcpcb *)xig; - tp = &cb->xt_tp; - inp = &cb->xt_inp; - so = &cb->xt_socket; - } - else { - struct xinpcb *cb = (struct xinpcb *)xig; - inp = &cb->xi_inp; - so = &cb->xi_socket; - } - - if (so->xso_protocol != proto) { - continue; - } - - if (inp->inp_gencnt > oxig->xig_gen) { - continue; - } - - if ((((flags & SIGAR_NETCONN_SERVER) && so->so_qlimit) || - ((flags & SIGAR_NETCONN_CLIENT) && !so->so_qlimit))) - { - sigar_net_connection_t conn; - - SIGAR_ZERO(&conn); - - if (inp->inp_vflag & INP_IPV6) { - sigar_net_address6_set(conn.local_address, - &inp->in6p_laddr.s6_addr); - - sigar_net_address6_set(conn.remote_address, - &inp->in6p_faddr.s6_addr); - } - else { - sigar_net_address_set(conn.local_address, - inp->inp_laddr.s_addr); - - sigar_net_address_set(conn.remote_address, - inp->inp_faddr.s_addr); - } - - conn.local_port = ntohs(inp->inp_lport); - conn.remote_port = ntohs(inp->inp_fport); - conn.receive_queue = so->so_rcv.sb_cc; - conn.send_queue = so->so_snd.sb_cc; - conn.uid = so->so_pgid; - conn.type = type; - - if (!istcp) { - conn.state = SIGAR_TCP_UNKNOWN; - if (walker->add_connection(walker, &conn) != SIGAR_OK) { - break; - } - continue; - } - - conn.state = net_connection_state_get(tp->t_state); - - if (walker->add_connection(walker, &conn) != SIGAR_OK) { - break; - } - } - } - - free(buf); - - return SIGAR_OK; -} -#endif - -int sigar_net_connection_walk(sigar_net_connection_walker_t *walker) -{ - int flags = walker->flags; - int status; - - if (flags & SIGAR_NETCONN_TCP) { - status = net_connection_get(walker, IPPROTO_TCP); - if (status != SIGAR_OK) { - return status; - } - } - if (flags & SIGAR_NETCONN_UDP) { - status = net_connection_get(walker, IPPROTO_UDP); - if (status != SIGAR_OK) { - return status; - } - } - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) -sigar_tcp_get(sigar_t *sigar, - sigar_tcp_t *tcp) -{ - struct tcpstat mib; -#if !defined(TCPCTL_STATS) && (defined(__OpenBSD__) || defined(__NetBSD__)) - int status = - kread(sigar, &mib, sizeof(mib), - sigar->koffsets[KOFFSET_TCPSTAT]); - if (status != SIGAR_OK) { - return status; - } -#else - int var[4] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS }; - size_t len = sizeof(mib); - - if (sysctl(var, NMIB(var), &mib, &len, NULL, 0) < 0) { - return errno; - } -#endif - - tcp->active_opens = mib.tcps_connattempt; - tcp->passive_opens = mib.tcps_accepts; - tcp->attempt_fails = mib.tcps_conndrops; - tcp->estab_resets = mib.tcps_drops; - if (sigar_tcp_curr_estab(sigar, tcp) != SIGAR_OK) { - tcp->curr_estab = -1; - } - tcp->in_segs = mib.tcps_rcvtotal; - tcp->out_segs = mib.tcps_sndtotal - mib.tcps_sndrexmitpack; - tcp->retrans_segs = mib.tcps_sndrexmitpack; - tcp->in_errs = - mib.tcps_rcvbadsum + - mib.tcps_rcvbadoff + - mib.tcps_rcvmemdrop + - mib.tcps_rcvshort; - tcp->out_rsts = -1; /* XXX mib.tcps_sndctrl - mib.tcps_closed; ? */ - - return SIGAR_OK; -} - -#ifndef SIGAR_FREEBSD5_NFSSTAT -static int get_nfsstats(struct nfsstats *stats) -{ - size_t len = sizeof(*stats); - int mib[] = { CTL_VFS, 2, NFS_NFSSTATS }; - - if (sysctl(mib, NMIB(mib), stats, &len, NULL, 0) < 0) { - return errno; - } - else { - return SIGAR_OK; - } -} -#endif - -#if defined(__OpenBSD__) -typedef uint64_t rpc_cnt_t; -#else -typedef int rpc_cnt_t; -#endif - -static void map_nfs_stats(sigar_nfs_v3_t *nfs, rpc_cnt_t *rpc) -{ - nfs->null = rpc[NFSPROC_NULL]; - nfs->getattr = rpc[NFSPROC_GETATTR]; - nfs->setattr = rpc[NFSPROC_SETATTR]; - nfs->lookup = rpc[NFSPROC_LOOKUP]; - nfs->access = rpc[NFSPROC_ACCESS]; - nfs->readlink = rpc[NFSPROC_READLINK]; - nfs->read = rpc[NFSPROC_READ]; - nfs->write = rpc[NFSPROC_WRITE]; - nfs->create = rpc[NFSPROC_CREATE]; - nfs->mkdir = rpc[NFSPROC_MKDIR]; - nfs->symlink = rpc[NFSPROC_SYMLINK]; - nfs->mknod = rpc[NFSPROC_MKNOD]; - nfs->remove = rpc[NFSPROC_REMOVE]; - nfs->rmdir = rpc[NFSPROC_RMDIR]; - nfs->rename = rpc[NFSPROC_RENAME]; - nfs->link = rpc[NFSPROC_LINK]; - nfs->readdir = rpc[NFSPROC_READDIR]; - nfs->readdirplus = rpc[NFSPROC_READDIRPLUS]; - nfs->fsstat = rpc[NFSPROC_FSSTAT]; - nfs->fsinfo = rpc[NFSPROC_FSINFO]; - nfs->pathconf = rpc[NFSPROC_PATHCONF]; - nfs->commit = rpc[NFSPROC_COMMIT]; -} - -int sigar_nfs_client_v2_get(sigar_t *sigar, - sigar_nfs_client_v2_t *nfs) -{ - return SIGAR_ENOTIMPL; -} - -int sigar_nfs_server_v2_get(sigar_t *sigar, - sigar_nfs_server_v2_t *nfs) -{ - return SIGAR_ENOTIMPL; -} - -int sigar_nfs_client_v3_get(sigar_t *sigar, - sigar_nfs_client_v3_t *nfs) -{ -#ifdef SIGAR_FREEBSD5_NFSSTAT - struct nfsstats stats; - size_t size = sizeof(stats); - - if (sysctlbyname("vfs.nfs.nfsstats", &stats, &size, NULL, 0) == -1) { - return errno; - } - - map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.rpccnt[0]); -#else - int status; - struct nfsstats stats; - - if ((status = get_nfsstats(&stats)) != SIGAR_OK) { - return status; - } - - map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.rpccnt[0]); -#endif - - return SIGAR_OK; -} - -int sigar_nfs_server_v3_get(sigar_t *sigar, - sigar_nfs_server_v3_t *nfs) -{ -#ifdef SIGAR_FREEBSD5_NFSSTAT - struct nfsrvstats stats; - size_t size = sizeof(stats); - - if (sysctlbyname("vfs.nfsrv.nfsrvstats", &stats, &size, NULL, 0) == -1) { - return errno; - } - - map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.srvrpccnt[0]); -#else - int status; - struct nfsstats stats; - - if ((status = get_nfsstats(&stats)) != SIGAR_OK) { - return status; - } - - map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.srvrpccnt[0]); -#endif - - return SIGAR_OK; -} - -static char *get_hw_type(int type) -{ - switch (type) { - case IFT_ETHER: - return "ether"; - case IFT_ISO88025: - return "tr"; - case IFT_FDDI: - return "fddi"; - case IFT_ATM: - return "atm"; - case IFT_L2VLAN: - return "vlan"; - case IFT_IEEE1394: - return "firewire"; -#ifdef IFT_BRIDGE - case IFT_BRIDGE: - return "bridge"; -#endif - default: - return "unknown"; - } -} - -int sigar_arp_list_get(sigar_t *sigar, - sigar_arp_list_t *arplist) -{ - size_t needed; - char *lim, *buf, *next; - struct rt_msghdr *rtm; - struct sockaddr_inarp *sin; - struct sockaddr_dl *sdl; - int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO }; - - if (sysctl(mib, NMIB(mib), NULL, &needed, NULL, 0) < 0) { - return errno; - } - - if (needed == 0) { /* empty cache */ - return 0; - } - - buf = malloc(needed); - - if (sysctl(mib, NMIB(mib), buf, &needed, NULL, 0) < 0) { - free(buf); - return errno; - } - - sigar_arp_list_create(arplist); - - lim = buf + needed; - for (next = buf; next < lim; next += rtm->rtm_msglen) { - sigar_arp_t *arp; - - SIGAR_ARP_LIST_GROW(arplist); - arp = &arplist->data[arplist->number++]; - - rtm = (struct rt_msghdr *)next; - sin = (struct sockaddr_inarp *)(rtm + 1); - sdl = (struct sockaddr_dl *)((char *)sin + SA_SIZE(sin)); - - sigar_net_address_set(arp->address, sin->sin_addr.s_addr); - sigar_net_address_mac_set(arp->hwaddr, LLADDR(sdl), sdl->sdl_alen); - if_indextoname(sdl->sdl_index, arp->ifname); - arp->flags = rtm->rtm_flags; - - SIGAR_SSTRCPY(arp->type, get_hw_type(sdl->sdl_type)); - } - - free(buf); - - return SIGAR_OK; -} - -#if defined(__FreeBSD__) && /*XXX*/ (__FreeBSD_version < 800000) - -#define _KERNEL -#include -#undef _KERNEL - -/* derived from - * /usr/ports/security/pidentd/work/pidentd-3.0.16/src/k_freebsd2.c - */ -int sigar_proc_port_get(sigar_t *sigar, int protocol, - unsigned long port, sigar_pid_t *pid) -{ - struct nlist nl[2]; - struct inpcbhead tcb; - struct socket *sockp = NULL; - struct kinfo_proc *pinfo; - struct inpcb *head, pcbp; - int i, nentries, status; - - if (protocol != SIGAR_NETCONN_TCP) { - return SIGAR_ENOTIMPL; - } - - if (!sigar->kmem) { - return SIGAR_EPERM_KMEM; - } - - nl[0].n_name = "_tcb"; /* XXX cache */ - nl[1].n_name = ""; - if (kvm_nlist(sigar->kmem, nl) < 0) { - return errno; - } - - status = kread(sigar, &tcb, sizeof(tcb), nl[0].n_value); - if (status != SIGAR_OK) { - return status; - } - - for (head = tcb.lh_first; head != NULL; - head = pcbp.inp_list.le_next) - { - status = kread(sigar, &pcbp, sizeof(pcbp), (long)head); - if (status != SIGAR_OK) { - return status; - } - if (!(pcbp.inp_vflag & INP_IPV4)) { - continue; - } - if (pcbp.inp_fport != 0) { - continue; - } - if (ntohs(pcbp.inp_lport) == port) { - sockp = pcbp.inp_socket; - break; - } - } - - if (!sockp) { - return ENOENT; - } - - pinfo = kvm_getprocs(sigar->kmem, KERN_PROC_PROC, 0, &nentries); - if (!pinfo) { - return errno; - } - - for (i=0; ilibproc) { - return SIGAR_ENOTIMPL; - } - - status = sigar_proc_list_get(sigar, &pids); - if (status != SIGAR_OK) { - return status; - } - - for (i=0; iifconf_buf; - - for (n=0; nproc_fdtype != PROX_FDTYPE_SOCKET) { - continue; - } - rsize = sigar->proc_pidfdinfo(pids.data[i], fdp->proc_fd, - PROC_PIDFDSOCKETINFO, &si, sizeof(si)); - if (rsize != sizeof(si)) { - continue; - } - if (si.psi.soi_kind != SOCKINFO_TCP) { - continue; - } - if (si.psi.soi_proto.pri_tcp.tcpsi_state != TSI_S_LISTEN) { - continue; - } - family = si.psi.soi_family; - if (!((family == AF_INET) || (family == AF_INET6))) { - continue; - } - lport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport); - if (lport == port) { - *pid = pids.data[i]; - found = 1; - break; - } - } - } - - sigar_proc_list_destroy(sigar, &pids); - - return found ? SIGAR_OK : ENOENT; -} - -#else - -int sigar_proc_port_get(sigar_t *sigar, int protocol, - unsigned long port, sigar_pid_t *pid) -{ - return SIGAR_ENOTIMPL; -} - -#endif - -int sigar_os_sys_info_get(sigar_t *sigar, - sigar_sys_info_t *sysinfo) -{ -#ifdef DARWIN - char *codename = NULL; - SInt32 version, version_major, version_minor, version_fix; - - SIGAR_SSTRCPY(sysinfo->name, "MacOSX"); - SIGAR_SSTRCPY(sysinfo->vendor_name, "Mac OS X"); - SIGAR_SSTRCPY(sysinfo->vendor, "Apple"); - - if (Gestalt(gestaltSystemVersion, &version) == noErr) { - if (version >= 0x00001040) { - Gestalt('sys1' /*gestaltSystemVersionMajor*/, &version_major); - Gestalt('sys2' /*gestaltSystemVersionMinor*/, &version_minor); - Gestalt('sys3' /*gestaltSystemVersionBugFix*/, &version_fix); - } - else { - version_fix = version & 0xf; - version >>= 4; - version_minor = version & 0xf; - version >>= 4; - version_major = version - (version >> 4) * 6; - } - } - else { - return SIGAR_ENOTIMPL; - } - - snprintf(sysinfo->vendor_version, - sizeof(sysinfo->vendor_version), - "%d.%d", - (int)version_major, (int)version_minor); - - snprintf(sysinfo->version, - sizeof(sysinfo->version), - "%s.%d", - sysinfo->vendor_version, (int)version_fix); - - if (version_major == 10) { - switch (version_minor) { - case 2: - codename = "Jaguar"; - break; - case 3: - codename = "Panther"; - break; - case 4: - codename = "Tiger"; - break; - case 5: - codename = "Leopard"; - break; - case 6: - codename = "Snow Leopard"; - break; - case 7: - codename = "Lion"; - break; - default: - codename = "Unknown"; - break; - } - } - else { - return SIGAR_ENOTIMPL; - } - - SIGAR_SSTRCPY(sysinfo->vendor_code_name, codename); - - snprintf(sysinfo->description, - sizeof(sysinfo->description), - "%s %s", - sysinfo->vendor_name, sysinfo->vendor_code_name); -#else - char *ptr; - -#if defined(__FreeBSD__) - SIGAR_SSTRCPY(sysinfo->name, "FreeBSD"); -#elif defined(__OpenBSD__) - SIGAR_SSTRCPY(sysinfo->name, "OpenBSD"); -#elif defined(__NetBSD__) - SIGAR_SSTRCPY(sysinfo->name, "NetBSD"); -#else - SIGAR_SSTRCPY(sysinfo->name, "Unknown"); -#endif - SIGAR_SSTRCPY(sysinfo->vendor_name, sysinfo->name); - SIGAR_SSTRCPY(sysinfo->vendor, sysinfo->name); - SIGAR_SSTRCPY(sysinfo->vendor_version, - sysinfo->version); - - if ((ptr = strstr(sysinfo->vendor_version, "-"))) { - /* STABLE, RELEASE, CURRENT */ - *ptr++ = '\0'; - SIGAR_SSTRCPY(sysinfo->vendor_code_name, ptr); - } - - snprintf(sysinfo->description, - sizeof(sysinfo->description), - "%s %s", - sysinfo->name, sysinfo->version); -#endif - - return SIGAR_OK; -} diff --git a/vendor/sigar/src/os/darwin/sigar_os.h b/vendor/sigar/src/os/darwin/sigar_os.h deleted file mode 100644 index ee00100..0000000 --- a/vendor/sigar/src/os/darwin/sigar_os.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2004-2006, 2008 Hyperic, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SIGAR_OS_H -#define SIGAR_OS_H -#ifdef __APPLE__ -#define DARWIN -#endif - -#ifdef DARWIN -/// Added to allow this code to compile with gcc4.7 vs Apple's built in compiler. -#define __private_extern__ extern - - - - -#include -#include -#ifdef DARWIN_HAS_LIBPROC_H -#include -#include -typedef int (*proc_pidinfo_func_t)(int, int, uint64_t, void *, int); -typedef int (*proc_pidfdinfo_func_t)(int, int, int, void *, int); -#endif -#else -#include -#endif - -#ifdef __NetBSD__ -#include -#endif -#include - -enum { - KOFFSET_CPUINFO, - KOFFSET_VMMETER, -#if defined(__OpenBSD__) || defined(__NetBSD__) - KOFFSET_TCPSTAT, - KOFFSET_TCBTABLE, -#endif - KOFFSET_MAX -}; - -#if defined(__OpenBSD__) || defined(__NetBSD__) -typedef struct kinfo_proc2 bsd_pinfo_t; -#else -typedef struct kinfo_proc bsd_pinfo_t; -#endif - -struct sigar_t { - SIGAR_T_BASE; - int pagesize; - time_t last_getprocs; - sigar_pid_t last_pid; - bsd_pinfo_t *pinfo; - int lcpu; - size_t argmax; -#ifdef DARWIN - mach_port_t mach_port; -# ifdef DARWIN_HAS_LIBPROC_H - void *libproc; - proc_pidinfo_func_t proc_pidinfo; - proc_pidfdinfo_func_t proc_pidfdinfo; -# endif -#else - kvm_t *kmem; - /* offsets for seeking on kmem */ - unsigned long koffsets[KOFFSET_MAX]; - int proc_mounted; -#endif -}; - -#define SIGAR_EPERM_KMEM (SIGAR_OS_START_ERROR+EACCES) -#define SIGAR_EPROC_NOENT (SIGAR_OS_START_ERROR+2) - -#endif /* SIGAR_OS_H */ diff --git a/vendor/sigar/src/os/hpux/hpux_sigar.c b/vendor/sigar/src/os/hpux/hpux_sigar.c deleted file mode 100644 index f7a7adc..0000000 --- a/vendor/sigar/src/os/hpux/hpux_sigar.c +++ /dev/null @@ -1,1342 +0,0 @@ -/* - * Copyright (c) 2004-2009 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * Copyright (c) 2009-2010 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sigar.h" -#include "sigar_private.h" -#include "sigar_util.h" -#include "sigar_os.h" - -#include -#include -#ifndef __ia64__ -#include -#endif -#include -#include -#include - -#ifdef _PSTAT64 -typedef int64_t pstat_int_t; -#else -typedef int32_t pstat_int_t; -#endif - -int sigar_os_open(sigar_t **sigar) -{ - *sigar = malloc(sizeof(**sigar)); - - /* does not change while system is running */ - pstat_getstatic(&(*sigar)->pstatic, - sizeof((*sigar)->pstatic), - 1, 0); - - (*sigar)->ticks = sysconf(_SC_CLK_TCK); - - (*sigar)->last_pid = -1; - - (*sigar)->pinfo = NULL; - - (*sigar)->mib = -1; - - return SIGAR_OK; - -} - -int sigar_os_close(sigar_t *sigar) -{ - if (sigar->pinfo) { - free(sigar->pinfo); - } - if (sigar->mib >= 0) { - close_mib(sigar->mib); - } - free(sigar); - return SIGAR_OK; -} - -char *sigar_os_error_string(sigar_t *sigar, int err) -{ - return NULL; -} - -int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem) -{ - struct pst_dynamic stats; - struct pst_vminfo vminfo; - sigar_uint64_t pagesize = sigar->pstatic.page_size; - sigar_uint64_t kern; - - mem->total = sigar->pstatic.physical_memory * pagesize; - - pstat_getdynamic(&stats, sizeof(stats), 1, 0); - - mem->free = stats.psd_free * pagesize; - mem->used = mem->total - mem->free; - - pstat_getvminfo(&vminfo, sizeof(vminfo), 1, 0); - - /* "kernel dynamic memory" */ - kern = vminfo.psv_kern_dynmem * pagesize; - mem->actual_free = mem->free + kern; - mem->actual_used = mem->used - kern; - - sigar_mem_calc_ram(sigar, mem); - - return SIGAR_OK; -} - -int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap) -{ - struct pst_swapinfo swapinfo; - struct pst_vminfo vminfo; - int i=0; - - swap->total = swap->free = 0; - - while (pstat_getswap(&swapinfo, sizeof(swapinfo), 1, i++) > 0) { - swapinfo.pss_nfpgs *= 4; /* nfpgs is in 512 byte blocks */ - - if (swapinfo.pss_nblksenabled == 0) { - swapinfo.pss_nblksenabled = swapinfo.pss_nfpgs; - } - - swap->total += swapinfo.pss_nblksenabled; - swap->free += swapinfo.pss_nfpgs; - } - - swap->used = swap->total - swap->free; - - pstat_getvminfo(&vminfo, sizeof(vminfo), 1, 0); - - swap->page_in = vminfo.psv_spgin; - swap->page_out = vminfo.psv_spgout; - - return SIGAR_OK; -} - -static void get_cpu_metrics(sigar_t *sigar, - sigar_cpu_t *cpu, - pstat_int_t *cpu_time) -{ - cpu->user = SIGAR_TICK2MSEC(cpu_time[CP_USER]); - - cpu->sys = SIGAR_TICK2MSEC(cpu_time[CP_SYS] + - cpu_time[CP_SSYS]); - - cpu->nice = SIGAR_TICK2MSEC(cpu_time[CP_NICE]); - - cpu->idle = SIGAR_TICK2MSEC(cpu_time[CP_IDLE]); - - cpu->wait = SIGAR_TICK2MSEC(cpu_time[CP_SWAIT] + - cpu_time[CP_BLOCK]); - - cpu->irq = SIGAR_TICK2MSEC(cpu_time[CP_INTR]); - cpu->soft_irq = 0; /*N/A*/ - cpu->stolen = 0; /*N/A*/ - - cpu->total = - cpu->user + cpu->sys + cpu->nice + cpu->idle + cpu->wait + cpu->irq; -} - -int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu) -{ - struct pst_dynamic stats; - - pstat_getdynamic(&stats, sizeof(stats), 1, 0); - sigar->ncpu = stats.psd_proc_cnt; - - get_cpu_metrics(sigar, cpu, stats.psd_cpu_time); - - return SIGAR_OK; -} - -int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist) -{ - int i; - struct pst_dynamic stats; - - pstat_getdynamic(&stats, sizeof(stats), 1, 0); - sigar->ncpu = stats.psd_proc_cnt; - - sigar_cpu_list_create(cpulist); - - for (i=0; incpu; i++) { - sigar_cpu_t *cpu; - struct pst_processor proc; - - if (pstat_getprocessor(&proc, sizeof(proc), 1, i) < 0) { - continue; - } - - SIGAR_CPU_LIST_GROW(cpulist); - - cpu = &cpulist->data[cpulist->number++]; - - get_cpu_metrics(sigar, cpu, proc.psp_cpu_time); - } - - return SIGAR_OK; -} - -int sigar_uptime_get(sigar_t *sigar, - sigar_uptime_t *uptime) -{ - uptime->uptime = time(NULL) - sigar->pstatic.boot_time; - - return SIGAR_OK; -} - -int sigar_loadavg_get(sigar_t *sigar, - sigar_loadavg_t *loadavg) -{ - struct pst_dynamic stats; - - pstat_getdynamic(&stats, sizeof(stats), 1, 0); - - loadavg->loadavg[0] = stats.psd_avg_1_min; - loadavg->loadavg[1] = stats.psd_avg_5_min; - loadavg->loadavg[2] = stats.psd_avg_15_min; - - return SIGAR_OK; -} - -#define PROC_ELTS 16 - -int sigar_os_proc_list_get(sigar_t *sigar, - sigar_proc_list_t *proclist) -{ - int num, idx=0; - struct pst_status proctab[PROC_ELTS]; - - while ((num = pstat_getproc(proctab, sizeof(proctab[0]), - PROC_ELTS, idx)) > 0) - { - int i; - - for (i=0; idata[proclist->number++] = - proctab[i].pst_pid; - } - - idx = proctab[num-1].pst_idx + 1; - } - - if (proclist->number == 0) { - return errno; - } - - return SIGAR_OK; -} - -static int sigar_pstat_getproc(sigar_t *sigar, sigar_pid_t pid) -{ - int status, num; - time_t timenow = time(NULL); - - if (sigar->pinfo == NULL) { - sigar->pinfo = malloc(sizeof(*sigar->pinfo)); - } - - if (sigar->last_pid == pid) { - if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) { - return SIGAR_OK; - } - } - - sigar->last_pid = pid; - sigar->last_getprocs = timenow; - - if (pstat_getproc(sigar->pinfo, - sizeof(*sigar->pinfo), - 0, pid) == -1) - { - return errno; - } - - return SIGAR_OK; -} - -int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_mem_t *procmem) -{ - int pagesize = sigar->pstatic.page_size; - int status = sigar_pstat_getproc(sigar, pid); - struct pst_status *pinfo = sigar->pinfo; - - if (status != SIGAR_OK) { - return status; - } - - procmem->size = - pinfo->pst_vtsize + /* text */ - pinfo->pst_vdsize + /* data */ - pinfo->pst_vssize + /* stack */ - pinfo->pst_vshmsize + /* shared memory */ - pinfo->pst_vmmsize + /* mem-mapped files */ - pinfo->pst_vusize + /* U-Area & K-Stack */ - pinfo->pst_viosize; /* I/O dev mapping */ - - procmem->size *= pagesize; - - procmem->resident = pinfo->pst_rssize * pagesize; - - procmem->share = pinfo->pst_vshmsize * pagesize; - - procmem->minor_faults = pinfo->pst_minorfaults; - procmem->major_faults = pinfo->pst_majorfaults; - procmem->page_faults = - procmem->minor_faults + - procmem->major_faults; - - return SIGAR_OK; -} - -int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_cred_t *proccred) -{ - int status = sigar_pstat_getproc(sigar, pid); - struct pst_status *pinfo = sigar->pinfo; - - if (status != SIGAR_OK) { - return status; - } - - proccred->uid = pinfo->pst_uid; - proccred->gid = pinfo->pst_gid; - proccred->euid = pinfo->pst_euid; - proccred->egid = pinfo->pst_egid; - - return SIGAR_OK; -} - -int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_time_t *proctime) -{ - int status = sigar_pstat_getproc(sigar, pid); - struct pst_status *pinfo = sigar->pinfo; - - if (status != SIGAR_OK) { - return status; - } - - proctime->start_time = pinfo->pst_start; - proctime->start_time *= SIGAR_MSEC; - proctime->user = pinfo->pst_utime * SIGAR_MSEC; - proctime->sys = pinfo->pst_stime * SIGAR_MSEC; - proctime->total = proctime->user + proctime->sys; - - return SIGAR_OK; -} - -int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_state_t *procstate) -{ - int status = sigar_pstat_getproc(sigar, pid); - struct pst_status *pinfo = sigar->pinfo; - - if (status != SIGAR_OK) { - return status; - } - - - SIGAR_SSTRCPY(procstate->name, pinfo->pst_ucomm); - procstate->ppid = pinfo->pst_ppid; - procstate->tty = makedev(pinfo->pst_term.psd_major, - pinfo->pst_term.psd_minor); - procstate->priority = pinfo->pst_pri; - procstate->nice = pinfo->pst_nice; - procstate->threads = pinfo->pst_nlwps; - procstate->processor = pinfo->pst_procnum; - - /* cast to prevent compiler warning: */ - /* Case label too big for the type of the switch expression */ - switch ((int32_t)pinfo->pst_stat) { - case PS_SLEEP: - procstate->state = 'S'; - break; - case PS_RUN: - procstate->state = 'R'; - break; - case PS_STOP: - procstate->state = 'T'; - break; - case PS_ZOMBIE: - procstate->state = 'Z'; - break; - case PS_IDLE: - procstate->state = 'D'; - break; - } - - return SIGAR_OK; -} - -int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_args_t *procargs) -{ - char *args, *arg; -#ifdef PSTAT_GETCOMMANDLINE - char buf[1024]; /* kernel limit */ - -# ifdef pstat_getcommandline /* 11i v2 + */ - if (pstat_getcommandline(buf, sizeof(buf), sizeof(buf[0]), pid) == -1) { - return errno; - } -# else - union pstun pu; - - pu.pst_command = buf; - if (pstat(PSTAT_GETCOMMANDLINE, pu, sizeof(buf), sizeof(buf[0]), pid) == -1) { - return errno; - } -# endif /* pstat_getcommandline */ - - args = buf; -#else - struct pst_status status; - - if (pstat_getproc(&status, sizeof(status), 0, pid) == -1) { - return errno; - } - - args = status.pst_cmd; -#endif - - while (*args && (arg = sigar_getword(&args, ' '))) { - SIGAR_PROC_ARGS_GROW(procargs); - procargs->data[procargs->number++] = arg; - } - - return SIGAR_OK; -} - -int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_env_t *procenv) -{ - return SIGAR_ENOTIMPL; -} - -int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_fd_t *procfd) -{ - struct pst_status status; - int idx=0, n; - struct pst_fileinfo2 psf[16]; - - procfd->total = 0; - - if (pstat_getproc(&status, sizeof(status), 0, pid) == -1) { - return errno; - } - - /* HPUX 11.31 removed the deprecated pstat_getfile call */ - while ((n = pstat_getfile2(psf, sizeof(psf[0]), - sizeof(psf)/sizeof(psf[0]), - idx, pid)) > 0) - { - procfd->total += n; - idx = psf[n-1].psf_fd + 1; - } - - if (n == -1) { - return errno; - } - - return SIGAR_OK; -} - -int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_exe_t *procexe) -{ -#ifdef __pst_fid /* 11.11+ */ - int rc; - struct pst_status status; - - if (pstat_getproc(&status, sizeof(status), 0, pid) == -1) { - return errno; - } - - rc = pstat_getpathname(procexe->cwd, - sizeof(procexe->cwd), - &status.pst_fid_cdir); - if (rc == -1) { - return errno; - } - - rc = pstat_getpathname(procexe->name, - sizeof(procexe->name), - &status.pst_fid_text); - if (rc == -1) { - return errno; - } - - rc = pstat_getpathname(procexe->root, - sizeof(procexe->root), - &status.pst_fid_rdir); - if (rc == -1) { - return errno; - } - - return SIGAR_OK; -#else - return SIGAR_ENOTIMPL; /* 11.00 */ -#endif -} - -int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_modules_t *procmods) -{ - return SIGAR_ENOTIMPL; -} - -#define TIME_NSEC(t) \ - (SIGAR_SEC2NANO((t).tv_sec) + (sigar_uint64_t)(t).tv_nsec) - -int sigar_thread_cpu_get(sigar_t *sigar, - sigar_uint64_t id, - sigar_thread_cpu_t *cpu) -{ -#ifdef __ia64__ - /* XXX seems _lwp funcs were for solaris compat and dont exist - * on itanium. hp docs claim that have equiv functions, - * but wtf is it for _lwp_info? - */ - return SIGAR_ENOTIMPL; -#else - struct lwpinfo info; - - if (id != 0) { - return SIGAR_ENOTIMPL; - } - - _lwp_info(&info); - - cpu->user = TIME_NSEC(info.lwp_utime); - cpu->sys = TIME_NSEC(info.lwp_stime); - cpu->total = TIME_NSEC(info.lwp_utime) + TIME_NSEC(info.lwp_stime); - - return SIGAR_OK; -#endif -} - -#include - -int sigar_os_fs_type_get(sigar_file_system_t *fsp) -{ - char *type = fsp->sys_type_name; - - switch (*type) { - case 'h': - if (strEQ(type, "hfs")) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - case 'c': - if (strEQ(type, "cdfs")) { - fsp->type = SIGAR_FSTYPE_CDROM; - } - break; - } - - return fsp->type; -} - -int sigar_file_system_list_get(sigar_t *sigar, - sigar_file_system_list_t *fslist) -{ - struct mntent *ent; - - FILE *fp; - sigar_file_system_t *fsp; - - if (!(fp = setmntent(MNT_MNTTAB, "r"))) { - return errno; - } - - sigar_file_system_list_create(fslist); - - while ((ent = getmntent(fp))) { - if ((*(ent->mnt_type) == 's') && - strEQ(ent->mnt_type, "swap")) - { - /* - * in this case, devname == "...", for - * which statfs chokes on. so skip it. - * also notice hpux df command has no swap info. - */ - continue; - } - - SIGAR_FILE_SYSTEM_LIST_GROW(fslist); - - fsp = &fslist->data[fslist->number++]; - - SIGAR_SSTRCPY(fsp->dir_name, ent->mnt_dir); - SIGAR_SSTRCPY(fsp->dev_name, ent->mnt_fsname); - SIGAR_SSTRCPY(fsp->sys_type_name, ent->mnt_type); - SIGAR_SSTRCPY(fsp->options, ent->mnt_opts); - sigar_fs_type_init(fsp); - } - - endmntent(fp); - - return SIGAR_OK; -} - -static int create_fsdev_cache(sigar_t *sigar) -{ - sigar_file_system_list_t fslist; - int i; - int status = - sigar_file_system_list_get(sigar, &fslist); - - if (status != SIGAR_OK) { - return status; - } - - sigar->fsdev = sigar_cache_new(15); - - for (i=0; itype == SIGAR_FSTYPE_LOCAL_DISK) { - sigar_cache_entry_t *ent; - struct stat sb; - - if (stat(fsp->dir_name, &sb) < 0) { - continue; - } - - ent = sigar_cache_get(sigar->fsdev, SIGAR_FSDEV_ID(sb)); - ent->value = strdup(fsp->dev_name); - } - } - - return SIGAR_OK; -} - -int sigar_disk_usage_get(sigar_t *sigar, const char *name, - sigar_disk_usage_t *usage) -{ - return SIGAR_ENOTIMPL; -} - -int sigar_file_system_usage_get(sigar_t *sigar, - const char *dirname, - sigar_file_system_usage_t *fsusage) -{ - struct stat sb; - int status = sigar_statvfs(sigar, dirname, fsusage); - - if (status != SIGAR_OK) { - return status; - } - - fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage); - - SIGAR_DISK_STATS_INIT(&fsusage->disk); - - if (!sigar->fsdev) { - if (create_fsdev_cache(sigar) != SIGAR_OK) { - return SIGAR_OK; - } - } - - if (stat(dirname, &sb) == 0) { - sigar_cache_entry_t *ent; - struct pst_lvinfo lv; - struct stat devsb; - char *devname; - int retval; - - ent = sigar_cache_get(sigar->fsdev, SIGAR_FSDEV_ID(sb)); - if (ent->value == NULL) { - return SIGAR_OK; - } - - if (stat((char *)ent->value, &devsb) < 0) { - return SIGAR_OK; - } - - retval = pstat_getlv(&lv, sizeof(lv), 0, (int)devsb.st_rdev); - - if (retval == 1) { - fsusage->disk.reads = lv.psl_rxfer; - fsusage->disk.writes = lv.psl_wxfer; - fsusage->disk.read_bytes = lv.psl_rcount; - fsusage->disk.write_bytes = lv.psl_wcount; - fsusage->disk.queue = SIGAR_FIELD_NOTIMPL; - } - } - - return SIGAR_OK; -} - -int sigar_cpu_info_list_get(sigar_t *sigar, - sigar_cpu_info_list_t *cpu_infos) -{ - int i; - struct pst_dynamic stats; - - pstat_getdynamic(&stats, sizeof(stats), 1, 0); - sigar->ncpu = stats.psd_proc_cnt; - - sigar_cpu_info_list_create(cpu_infos); - - for (i=0; incpu; i++) { - sigar_cpu_info_t *info; - struct pst_processor proc; - - if (pstat_getprocessor(&proc, sizeof(proc), 1, i) < 0) { - perror("pstat_getprocessor"); - continue; - } - - SIGAR_CPU_INFO_LIST_GROW(cpu_infos); - - info = &cpu_infos->data[cpu_infos->number++]; - - info->total_cores = sigar->ncpu; - info->cores_per_socket = 1; /*XXX*/ - info->total_sockets = sigar->ncpu; /*XXX*/ - -#ifdef __ia64__ - SIGAR_SSTRCPY(info->vendor, "Intel"); /*XXX*/ - SIGAR_SSTRCPY(info->model, "Itanium"); /*XXX*/ -#else - SIGAR_SSTRCPY(info->vendor, "HP"); /*XXX*/ - SIGAR_SSTRCPY(info->model, "PA RISC"); /*XXX*/ -#endif -#ifdef PSP_MAX_CACHE_LEVELS /* 11.31+; see SIGAR-196 */ - info->mhz = proc.psp_cpu_frequency / 1000000; -#else - info->mhz = sigar->ticks * proc.psp_iticksperclktick / 1000000; -#endif - info->cache_size = SIGAR_FIELD_NOTIMPL; /*XXX*/ - } - - return SIGAR_OK; -} - -static int sigar_get_mib_info(sigar_t *sigar, - struct nmparms *parms) -{ - if (sigar->mib < 0) { - if ((sigar->mib = open_mib("/dev/ip", O_RDONLY, 0, 0)) < 0) { - return errno; - } - } - return get_mib_info(sigar->mib, parms); -} - -/* wrapper around get_physical_stat() */ -static int sigar_get_physical_stat(sigar_t *sigar, int *count) -{ - int status; - unsigned int len; - struct nmparms parms; - - len = sizeof(*count); - parms.objid = ID_ifNumber; - parms.buffer = count; - parms.len = &len; - - if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) { - return status; - } - - len = sizeof(nmapi_phystat) * *count; - - if (sigar->ifconf_len < len) { - sigar->ifconf_buf = realloc(sigar->ifconf_buf, len); - sigar->ifconf_len = len; - } - - if (get_physical_stat(sigar->ifconf_buf, &len) < 0) { - return errno; - } - else { - return SIGAR_OK; - } -} - -#define SIGAR_IF_NAMESIZE 16 -/* hpux if_indextoname() does not work as advertised in 11.11 */ -static int sigar_if_indextoname(sigar_t *sigar, - char *name, - int index) -{ - int i, status, count; - nmapi_phystat *stat; - - if ((status = sigar_get_physical_stat(sigar, &count) != SIGAR_OK)) { - return status; - } - - for (i=0, stat = (nmapi_phystat *)sigar->ifconf_buf; - iif_entry.ifIndex == index) { - strncpy(name, stat->nm_device, SIGAR_IF_NAMESIZE); - return SIGAR_OK; - } - } - - return ENXIO; -} - -int sigar_net_route_list_get(sigar_t *sigar, - sigar_net_route_list_t *routelist) -{ - int status, count, i; - unsigned int len; - struct nmparms parms; - mib_ipRouteEnt *routes; - sigar_net_route_t *route; - - len = sizeof(count); - parms.objid = ID_ipRouteNumEnt; - parms.buffer = &count; - parms.len = &len; - - if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) { - return status; - } - - len = count * sizeof(*routes); - routes = malloc(len); - - parms.objid = ID_ipRouteTable; - parms.buffer = routes; - parms.len = &len; - - if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) { - free(routes); - return status; - } - - routelist->size = routelist->number = 0; - - sigar_net_route_list_create(routelist); - - for (i=0; idata[routelist->number++]; - SIGAR_ZERO(route); /* XXX: other fields */ - - sigar_net_address_set(route->destination, - ent->Dest); - - sigar_net_address_set(route->mask, - ent->Mask); - - sigar_net_address_set(route->gateway, - ent->NextHop); - - sigar_if_indextoname(sigar, route->ifname, ent->IfIndex); - - route->flags = SIGAR_RTF_UP; - if ((ent->Dest == 0) && - (ent->Mask == 0)) - { - route->flags |= SIGAR_RTF_GATEWAY; - } - } - - free(routes); - - return SIGAR_OK; -} - -static int get_mib_ifstat(sigar_t *sigar, - const char *name, - mib_ifEntry *mib) -{ - int i, status, count; - nmapi_phystat *stat; - - if ((status = sigar_get_physical_stat(sigar, &count) != SIGAR_OK)) { - return status; - } - - for (i=0, stat = (nmapi_phystat *)sigar->ifconf_buf; - inm_device, name)) { - memcpy(mib, &stat->if_entry, sizeof(*mib)); - return SIGAR_OK; - } - } - - return ENXIO; -} - -int sigar_net_interface_stat_get(sigar_t *sigar, const char *name, - sigar_net_interface_stat_t *ifstat) -{ - int status; - mib_ifEntry mib; - - status = get_mib_ifstat(sigar, name, &mib); - - if (status != SIGAR_OK) { - return status; - } - - ifstat->rx_bytes = mib.ifInOctets; - ifstat->rx_packets = mib.ifInUcastPkts + mib.ifInNUcastPkts; - ifstat->rx_errors = mib.ifInErrors; - ifstat->rx_dropped = mib.ifInDiscards; - ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL; - ifstat->rx_frame = SIGAR_FIELD_NOTIMPL; - - ifstat->tx_bytes = mib.ifOutOctets; - ifstat->tx_packets = mib.ifOutUcastPkts + mib.ifOutNUcastPkts; - ifstat->tx_errors = mib.ifOutErrors; - ifstat->tx_dropped = mib.ifOutDiscards; - ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL; - ifstat->tx_collisions = SIGAR_FIELD_NOTIMPL; - ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL; - - ifstat->speed = mib.ifSpeed; - - return SIGAR_OK; -} - -int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, - sigar_net_interface_config_t *ifconfig) -{ - int sock; - struct if_laddrreq iflr; - - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { - return errno; - } - - SIGAR_SSTRCPY(iflr.iflr_name, name); - - if (ioctl(sock, SIOCGLIFADDR, &iflr) == 0) { - struct in6_addr *addr = SIGAR_SIN6_ADDR(&iflr.iflr_addr); - - sigar_net_address6_set(ifconfig->address6, addr); - sigar_net_interface_scope6_set(ifconfig, addr); - - if (ioctl(sock, SIOCGLIFNETMASK, &iflr) == 0) { - addr = SIGAR_SIN6_ADDR(&iflr.iflr_addr); - ifconfig->prefix6_length = 10; /*XXX*/ - } - } - - close(sock); - return SIGAR_OK; -} - -static int net_conn_get_udp_listen(sigar_net_connection_walker_t *walker) -{ - sigar_t *sigar = walker->sigar; - int flags = walker->flags; - int status, count, i; - unsigned int len; - mib_udpLsnEnt *entries; - struct nmparms parms; - - len = sizeof(count); - parms.objid = ID_udpLsnNumEnt; - parms.buffer = &count; - parms.len = &len; - - if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) { - return status; - } - - if (count <= 0) { - return ENOENT; - } - - len = count * sizeof(*entries); - entries = malloc(len); - parms.objid = ID_udpLsnTable; - parms.buffer = entries; - parms.len = &len; - - if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) { - free(entries); - return status; - } - - for (i=0; iLocalPort; - conn.remote_port = 0; - - sigar_net_address_set(conn.local_address, - entry->LocalAddress); - - sigar_net_address_set(conn.remote_address, 0); - - conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL; - - if (walker->add_connection(walker, &conn) != SIGAR_OK) { - break; - } - } - - free(entries); - return SIGAR_OK; -} - -static int net_conn_get_udp(sigar_net_connection_walker_t *walker) -{ - int status = SIGAR_OK; - - if (walker->flags & SIGAR_NETCONN_SERVER) { - status = net_conn_get_udp_listen(walker); - } - - return status; -} - -#define IS_TCP_SERVER(state, flags) \ - ((flags & SIGAR_NETCONN_SERVER) && (state == TCLISTEN)) - -#define IS_TCP_CLIENT(state, flags) \ - ((flags & SIGAR_NETCONN_CLIENT) && (state != TCLISTEN)) - -static int net_conn_get_tcp(sigar_net_connection_walker_t *walker) -{ - sigar_t *sigar = walker->sigar; - int flags = walker->flags; - int status, count, i; - unsigned int len; - mib_tcpConnEnt *entries; - struct nmparms parms; - - len = sizeof(count); - parms.objid = ID_tcpConnNumEnt; - parms.buffer = &count; - parms.len = &len; - - if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) { - return status; - } - - if (count <= 0) { - return ENOENT; - } - - len = count * sizeof(*entries); - entries = malloc(len); - parms.objid = ID_tcpConnTable; - parms.buffer = entries; - parms.len = &len; - - if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) { - free(entries); - return status; - } - - for (i=0; iState; - - if (!(IS_TCP_SERVER(state, flags) || - IS_TCP_CLIENT(state, flags))) - { - continue; - } - - SIGAR_ZERO(&conn); - - switch (state) { - case TCCLOSED: - conn.state = SIGAR_TCP_CLOSE; - break; - case TCLISTEN: - conn.state = SIGAR_TCP_LISTEN; - break; - case TCSYNSENT: - conn.state = SIGAR_TCP_SYN_SENT; - break; - case TCSYNRECEIVE: - conn.state = SIGAR_TCP_SYN_RECV; - break; - case TCESTABLISED: - conn.state = SIGAR_TCP_ESTABLISHED; - break; - case TCFINWAIT1: - conn.state = SIGAR_TCP_FIN_WAIT1; - break; - case TCFINWAIT2: - conn.state = SIGAR_TCP_FIN_WAIT2; - break; - case TCCLOSEWAIT: - conn.state = SIGAR_TCP_CLOSE_WAIT; - break; - case TCCLOSING: - conn.state = SIGAR_TCP_CLOSING; - break; - case TCLASTACK: - conn.state = SIGAR_TCP_LAST_ACK; - break; - case TCTIMEWAIT: - conn.state = SIGAR_TCP_TIME_WAIT; - break; - case TCDELETETCB: - default: - conn.state = SIGAR_TCP_UNKNOWN; - break; - } - - conn.local_port = (unsigned short)entry->LocalPort; - conn.remote_port = (unsigned short)entry->RemPort; - conn.type = SIGAR_NETCONN_TCP; - - sigar_net_address_set(conn.local_address, entry->LocalAddress); - sigar_net_address_set(conn.remote_address, entry->RemAddress); - - conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL; - - if (walker->add_connection(walker, &conn) != SIGAR_OK) { - break; - } - } - - free(entries); - - return SIGAR_OK; -} - -int sigar_net_connection_walk(sigar_net_connection_walker_t *walker) -{ - int status; - - if (walker->flags & SIGAR_NETCONN_TCP) { - status = net_conn_get_tcp(walker); - - if (status != SIGAR_OK) { - return status; - } - } - - if (walker->flags & SIGAR_NETCONN_UDP) { - status = net_conn_get_udp(walker); - - if (status != SIGAR_OK) { - return status; - } - } - - return SIGAR_OK; -} - -#define tcpsoff(x) sigar_offsetof(sigar_tcp_t, x) - -static struct { - unsigned int id; - size_t offset; -} tcps_lu[] = { -#if 0 - { ID_tcpRtoAlgorithm, tcpsoff(xxx) }, - { ID_tcpRtoMin, tcpsoff(xxx) }, - { ID_tcpRtoMax, tcpsoff(xxx) }, - { ID_tcpMaxConn, tcpsoff(max_conn) }, -#endif - { ID_tcpActiveOpens, tcpsoff(active_opens) }, - { ID_tcpPassiveOpens, tcpsoff(passive_opens) }, - { ID_tcpAttemptFails, tcpsoff(attempt_fails) }, - { ID_tcpEstabResets, tcpsoff(estab_resets) }, - { ID_tcpCurrEstab, tcpsoff(curr_estab) }, - { ID_tcpInSegs, tcpsoff(in_segs) }, - { ID_tcpOutSegs, tcpsoff(out_segs) }, - { ID_tcpRetransSegs, tcpsoff(retrans_segs) }, - { ID_tcpInErrs, tcpsoff(in_errs) }, - { ID_tcpOutRsts, tcpsoff(out_rsts) } -}; - -SIGAR_DECLARE(int) -sigar_tcp_get(sigar_t *sigar, - sigar_tcp_t *tcp) -{ - int i; - - for (i=0; idata[arplist->number++]; - - sigar_net_address_set(arp->address, - ent->NetAddr); - - sigar_net_address_mac_set(arp->hwaddr, - ent->PhysAddr.o_bytes, - ent->PhysAddr.o_length); - - sigar_if_indextoname(sigar, arp->ifname, ent->IfIndex); - - SIGAR_SSTRCPY(arp->type, "ether"); /*XXX*/ - arp->flags = 0; /*XXX*/ - } - - free(entries); - - return SIGAR_OK; -} - -int sigar_proc_port_get(sigar_t *sigar, int protocol, - unsigned long port, sigar_pid_t *pid) -{ - return SIGAR_ENOTIMPL; -} - - -int sigar_os_sys_info_get(sigar_t *sigar, - sigar_sys_info_t *sysinfo) -{ - char *vendor_version, *arch; - long cpu = sysconf(_SC_CPU_VERSION); - - switch (cpu) { - case CPU_PA_RISC1_0: - arch = "PA_RISC1.0"; - break; - case CPU_PA_RISC1_1: - arch = "PA_RISC1.1"; - break; - case CPU_PA_RISC2_0: - arch = "PA_RISC2.0"; - break; -#ifdef CPU_IA64_ARCHREV_0 - case CPU_IA64_ARCHREV_0: - arch = "ia64"; - break; -#endif - default: - arch = "unknown"; - break; - } - - SIGAR_SSTRCPY(sysinfo->arch, arch); - - SIGAR_SSTRCPY(sysinfo->name, "HPUX"); - SIGAR_SSTRCPY(sysinfo->vendor, "Hewlett-Packard"); - - if (strstr(sysinfo->version, ".11.")) { - vendor_version = "11"; - } - else { - vendor_version = sysinfo->version; - } - - SIGAR_SSTRCPY(sysinfo->vendor_version, vendor_version); - - snprintf(sysinfo->description, - sizeof(sysinfo->description), - "%s %s", - sysinfo->vendor_name, sysinfo->vendor_version); - - return SIGAR_OK; -} diff --git a/vendor/sigar/src/os/hpux/sigar_os.h b/vendor/sigar/src/os/hpux/sigar_os.h deleted file mode 100644 index ee2434a..0000000 --- a/vendor/sigar/src/os/hpux/sigar_os.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2004-2007 Hyperic, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SIGAR_OS_H -#define SIGAR_OS_H - -#if defined(__ia64) && !defined(__ia64__) -#define __ia64__ -#endif - -#ifdef __ia64__ -#ifndef _LP64 -#define _LP64 -#endif -#endif - -#define _PSTAT64 - -#include -#include -#include -#include - -struct sigar_t { - SIGAR_T_BASE; - struct pst_static pstatic; - time_t last_getprocs; - sigar_pid_t last_pid; - struct pst_status *pinfo; - - int mib; -}; - -int hpux_get_mib_ifentry(int ppa, mib_ifEntry *mib); - -#endif /* SIGAR_OS_H */ diff --git a/vendor/sigar/src/os/linux/linux_sigar.c b/vendor/sigar/src/os/linux/linux_sigar.c deleted file mode 100644 index 0e4283f..0000000 --- a/vendor/sigar/src/os/linux/linux_sigar.c +++ /dev/null @@ -1,2782 +0,0 @@ -/* - * Copyright (c) 2004-2009 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * Copyright (c) 2009-2010 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sigar.h" -#include "sigar_private.h" -#include "sigar_util.h" -#include "sigar_os.h" - -#define pageshift(x) ((x) << sigar->pagesize) - -#define PROC_MEMINFO PROC_FS_ROOT "meminfo" -#define PROC_VMSTAT PROC_FS_ROOT "vmstat" -#define PROC_MTRR PROC_FS_ROOT "mtrr" -#define PROC_STAT PROC_FS_ROOT "stat" -#define PROC_UPTIME PROC_FS_ROOT "uptime" -#define PROC_LOADAVG PROC_FS_ROOT "loadavg" - -#define PROC_PSTAT "/stat" -#define PROC_PSTATUS "/status" - -#define SYS_BLOCK "/sys/block" -#define PROC_PARTITIONS PROC_FS_ROOT "partitions" -#define PROC_DISKSTATS PROC_FS_ROOT "diskstats" - -/* - * /proc/self/stat fields: - * 1 - pid - * 2 - comm - * 3 - state - * 4 - ppid - * 5 - pgrp - * 6 - session - * 7 - tty_nr - * 8 - tpgid - * 9 - flags - * 10 - minflt - * 11 - cminflt - * 12 - majflt - * 13 - cmajflt - * 14 - utime - * 15 - stime - * 16 - cutime - * 17 - cstime - * 18 - priority - * 19 - nice - * 20 - 0 (removed field) - * 21 - itrealvalue - * 22 - starttime - * 23 - vsize - * 24 - rss - * 25 - rlim - * 26 - startcode - * 27 - endcode - * 28 - startstack - * 29 - kstkesp - * 30 - kstkeip - * 31 - signal - * 32 - blocked - * 33 - sigignore - * 34 - sigcache - * 35 - wchan - * 36 - nswap - * 37 - cnswap - * 38 - exit_signal <-- looking for this. - * 39 - processor - * ... more for newer RH - */ - -#define PROC_SIGNAL_IX 38 - -static int get_proc_signal_offset(void) -{ - char buffer[BUFSIZ], *ptr=buffer; - int fields = 0; - int status = sigar_file2str(PROCP_FS_ROOT "self/stat", - buffer, sizeof(buffer)); - - if (status != SIGAR_OK) { - return 1; - } - - while (*ptr) { - if (*ptr++ == ' ') { - fields++; - } - } - - return (fields - PROC_SIGNAL_IX) + 1; -} - -sigar_pid_t sigar_pid_get(sigar_t *sigar) -{ - /* XXX cannot safely cache getpid unless using nptl */ - /* we can however, cache it for optimizations in the - * case of proc_env_get for example. - */ - sigar->pid = getpid(); - return sigar->pid; -} - -static int sigar_boot_time_get(sigar_t *sigar) -{ - FILE *fp; - char buffer[BUFSIZ], *ptr; - int found = 0; - - if (!(fp = fopen(PROC_STAT, "r"))) { - return errno; - } - - while ((ptr = fgets(buffer, sizeof(buffer), fp))) { - if (strnEQ(ptr, "btime", 5)) { - if ((ptr = sigar_skip_token(ptr))) { - sigar->boot_time = sigar_strtoul(ptr); - found = 1; - } - break; - } - } - - fclose(fp); - - if (!found) { - /* should never happen */ - sigar->boot_time = time(NULL); - } - - return SIGAR_OK; -} - -int sigar_os_open(sigar_t **sigar) -{ - int i, status; - int kernel_rev, has_nptl; - struct stat sb; - struct utsname name; - - *sigar = malloc(sizeof(**sigar)); - - (*sigar)->pagesize = 0; - i = getpagesize(); - while ((i >>= 1) > 0) { - (*sigar)->pagesize++; - } - - status = sigar_boot_time_get(*sigar); - if (status != SIGAR_OK) { - return status; - } - - (*sigar)->ticks = sysconf(_SC_CLK_TCK); - - (*sigar)->ram = -1; - - (*sigar)->proc_signal_offset = -1; - - (*sigar)->last_proc_stat.pid = -1; - - (*sigar)->lcpu = -1; - - if (stat(PROC_DISKSTATS, &sb) == 0) { - (*sigar)->iostat = IOSTAT_DISKSTATS; - } - else if (stat(SYS_BLOCK, &sb) == 0) { - (*sigar)->iostat = IOSTAT_SYS; - } - else if (stat(PROC_PARTITIONS, &sb) == 0) { - /* XXX file exists does not mean is has the fields */ - (*sigar)->iostat = IOSTAT_PARTITIONS; - } - else { - (*sigar)->iostat = IOSTAT_NONE; - } - - /* hook for using mirrored /proc/net/tcp file */ - (*sigar)->proc_net = getenv("SIGAR_PROC_NET"); - - uname(&name); - /* 2.X.y.z -> just need X (unless there is ever a kernel version 3!) */ - kernel_rev = atoi(&name.release[2]); - if (kernel_rev >= 6) { - has_nptl = 1; - } - else { - has_nptl = getenv("SIGAR_HAS_NPTL") ? 1 : 0; - } - (*sigar)->has_nptl = has_nptl; - - return SIGAR_OK; -} - -int sigar_os_close(sigar_t *sigar) -{ - free(sigar); - return SIGAR_OK; -} - -char *sigar_os_error_string(sigar_t *sigar, int err) -{ - return NULL; -} - -static int sigar_cpu_total_count(sigar_t *sigar) -{ - sigar->ncpu = (int)sysconf(_SC_NPROCESSORS_CONF); - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[cpu] ncpu=%d\n", - sigar->ncpu); - return sigar->ncpu; -} - -static int get_ram(sigar_t *sigar, sigar_mem_t *mem) -{ - char buffer[BUFSIZ], *ptr; - FILE *fp; - int total = 0; - sigar_uint64_t sys_total = (mem->total / (1024 * 1024)); - - if (sigar->ram > 0) { - /* return cached value */ - mem->ram = sigar->ram; - return SIGAR_OK; - } - - if (sigar->ram == 0) { - return ENOENT; - } - - /* - * Memory Type Range Registers - * write-back registers add up to the total. - * Well, they are supposed to add up, but seen - * at least one configuration where that is not the - * case. - */ - if (!(fp = fopen(PROC_MTRR, "r"))) { - return errno; - } - - while ((ptr = fgets(buffer, sizeof(buffer), fp))) { - if (!(ptr = strstr(ptr, "size="))) { - continue; - } - - if (!strstr(ptr, "write-back")) { - continue; - } - - ptr += 5; - while (sigar_isspace(*ptr)) { - ++ptr; - } - - total += atoi(ptr); - } - - fclose(fp); - - if ((total - sys_total) > 256) { - /* mtrr write-back registers are way off - * kernel should not be using more that 256MB of mem - */ - total = 0; /* punt */ - } - - if (total == 0) { - return ENOENT; - } - - mem->ram = sigar->ram = total; - - return SIGAR_OK; -} - -#define MEMINFO_PARAM(a) a ":", SSTRLEN(a ":") - -static SIGAR_INLINE sigar_uint64_t sigar_meminfo(char *buffer, - char *attr, int len) -{ - sigar_uint64_t val = 0; - char *ptr, *tok; - - if ((ptr = strstr(buffer, attr))) { - ptr += len; - val = strtoull(ptr, &tok, 0); - while (*tok == ' ') { - ++tok; - } - if (*tok == 'k') { - val *= 1024; - } - else if (*tok == 'M') { - val *= (1024 * 1024); - } - } - - return val; -} - -int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem) -{ - sigar_uint64_t buffers, cached, kern; - char buffer[BUFSIZ]; - - int status = sigar_file2str(PROC_MEMINFO, - buffer, sizeof(buffer)); - - if (status != SIGAR_OK) { - return status; - } - - mem->total = sigar_meminfo(buffer, MEMINFO_PARAM("MemTotal")); - mem->free = sigar_meminfo(buffer, MEMINFO_PARAM("MemFree")); - mem->used = mem->total - mem->free; - - buffers = sigar_meminfo(buffer, MEMINFO_PARAM("Buffers")); - cached = sigar_meminfo(buffer, MEMINFO_PARAM("Cached")); - - kern = buffers + cached; - mem->actual_free = mem->free + kern; - mem->actual_used = mem->used - kern; - - sigar_mem_calc_ram(sigar, mem); - - if (get_ram(sigar, mem) != SIGAR_OK) { - /* XXX other options on failure? */ - } - - return SIGAR_OK; -} - -int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap) -{ - char buffer[BUFSIZ], *ptr; - - /* XXX: we open/parse the same file here as sigar_mem_get */ - int status = sigar_file2str(PROC_MEMINFO, - buffer, sizeof(buffer)); - - if (status != SIGAR_OK) { - return status; - } - - swap->total = sigar_meminfo(buffer, MEMINFO_PARAM("SwapTotal")); - swap->free = sigar_meminfo(buffer, MEMINFO_PARAM("SwapFree")); - swap->used = swap->total - swap->free; - - swap->page_in = swap->page_out = -1; - - status = sigar_file2str(PROC_VMSTAT, - buffer, sizeof(buffer)); - - if (status == SIGAR_OK) { - /* 2.6+ kernel */ - if ((ptr = strstr(buffer, "\npswpin"))) { - ptr = sigar_skip_token(ptr); - swap->page_in = sigar_strtoull(ptr); - ptr = sigar_skip_token(ptr); - swap->page_out = sigar_strtoull(ptr); - } - } - else { - /* 2.2, 2.4 kernels */ - status = sigar_file2str(PROC_STAT, - buffer, sizeof(buffer)); - if (status != SIGAR_OK) { - return status; - } - - if ((ptr = strstr(buffer, "\nswap"))) { - ptr = sigar_skip_token(ptr); - swap->page_in = sigar_strtoull(ptr); - swap->page_out = sigar_strtoull(ptr); - } - } - - return SIGAR_OK; -} - -static void get_cpu_metrics(sigar_t *sigar, sigar_cpu_t *cpu, char *line) -{ - char *ptr = sigar_skip_token(line); /* "cpu%d" */ - - cpu->user += SIGAR_TICK2MSEC(sigar_strtoull(ptr)); - cpu->nice += SIGAR_TICK2MSEC(sigar_strtoull(ptr)); - cpu->sys += SIGAR_TICK2MSEC(sigar_strtoull(ptr)); - cpu->idle += SIGAR_TICK2MSEC(sigar_strtoull(ptr)); - if (*ptr == ' ') { - /* 2.6+ kernels only */ - cpu->wait += SIGAR_TICK2MSEC(sigar_strtoull(ptr)); - cpu->irq += SIGAR_TICK2MSEC(sigar_strtoull(ptr)); - cpu->soft_irq += SIGAR_TICK2MSEC(sigar_strtoull(ptr)); - } - if (*ptr == ' ') { - /* 2.6.11+ kernels only */ - cpu->stolen += SIGAR_TICK2MSEC(sigar_strtoull(ptr)); - } - cpu->total = - cpu->user + cpu->nice + cpu->sys + cpu->idle + - cpu->wait + cpu->irq + cpu->soft_irq + cpu->stolen; -} - -int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu) -{ - char buffer[BUFSIZ]; - int status = sigar_file2str(PROC_STAT, buffer, sizeof(buffer)); - - if (status != SIGAR_OK) { - return status; - } - - SIGAR_ZERO(cpu); - get_cpu_metrics(sigar, cpu, buffer); - - return SIGAR_OK; -} - -int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist) -{ - FILE *fp; - char buffer[BUFSIZ], cpu_total[BUFSIZ], *ptr; - int core_rollup = sigar_cpu_core_rollup(sigar), i=0; - sigar_cpu_t *cpu; - - if (!(fp = fopen(PROC_STAT, "r"))) { - return errno; - } - - /* skip first line */ - (void)fgets(cpu_total, sizeof(cpu_total), fp); - - sigar_cpu_list_create(cpulist); - - /* XXX: merge times of logical processors if hyperthreading */ - while ((ptr = fgets(buffer, sizeof(buffer), fp))) { - if (!strnEQ(ptr, "cpu", 3)) { - break; - } - - if (core_rollup && (i % sigar->lcpu)) { - /* merge times of logical processors */ - cpu = &cpulist->data[cpulist->number-1]; - } - else { - SIGAR_CPU_LIST_GROW(cpulist); - cpu = &cpulist->data[cpulist->number++]; - SIGAR_ZERO(cpu); - } - - get_cpu_metrics(sigar, cpu, ptr); - - i++; - } - - fclose(fp); - - if (cpulist->number == 0) { - /* likely older kernel where cpu\d is not present */ - cpu = &cpulist->data[cpulist->number++]; - SIGAR_ZERO(cpu); - get_cpu_metrics(sigar, cpu, cpu_total); - } - - return SIGAR_OK; -} - -int sigar_uptime_get(sigar_t *sigar, - sigar_uptime_t *uptime) -{ - char buffer[BUFSIZ], *ptr = buffer; - int status = sigar_file2str(PROC_UPTIME, buffer, sizeof(buffer)); - - if (status != SIGAR_OK) { - return status; - } - - uptime->uptime = strtod(buffer, &ptr); - - return SIGAR_OK; -} - -int sigar_loadavg_get(sigar_t *sigar, - sigar_loadavg_t *loadavg) -{ - char buffer[BUFSIZ], *ptr = buffer; - int status = sigar_file2str(PROC_LOADAVG, buffer, sizeof(buffer)); - - if (status != SIGAR_OK) { - return status; - } - - loadavg->loadavg[0] = strtod(buffer, &ptr); - loadavg->loadavg[1] = strtod(ptr, &ptr); - loadavg->loadavg[2] = strtod(ptr, &ptr); - - return SIGAR_OK; -} - -/* - * seems the easiest/fastest way to tell if a process listed in /proc - * is a thread is to check the "exit signal" flag in /proc/num/stat. - * any value other than SIGCHLD seems to be a thread. this make hulk mad. - * redhat's procps patch (named "threadbadhack.pat") does not use - * this flag to filter out threads. instead does much more expensive - * comparisions. their patch also bubbles up thread cpu times to the main - * process. functionality we currently lack. - * when nptl is in use, this is not the case and all threads spawned from - * a process have the same pid. however, it seems both old-style linux - * threads and nptl threads can be run on the same machine. - * there is also the "Tgid" field in /proc/self/status which could be used - * to detect threads, but this is not available in older kernels. - */ -static SIGAR_INLINE int proc_isthread(sigar_t *sigar, char *pidstr, int len) -{ - char buffer[BUFSIZ], *ptr=buffer; - int fd, n, offset=sigar->proc_signal_offset; - - /* sprintf(buffer, "/proc/%s/stat", pidstr) */ - memcpy(ptr, PROCP_FS_ROOT, SSTRLEN(PROCP_FS_ROOT)); - ptr += SSTRLEN(PROCP_FS_ROOT); - - memcpy(ptr, pidstr, len); - ptr += len; - - memcpy(ptr, PROC_PSTAT, SSTRLEN(PROC_PSTAT)); - ptr += SSTRLEN(PROC_PSTAT); - - *ptr = '\0'; - - if ((fd = open(buffer, O_RDONLY)) < 0) { - /* unlikely if pid was from readdir proc */ - return 0; - } - - n = read(fd, buffer, sizeof(buffer)); - close(fd); - - if (n < 0) { - return 0; /* chances: slim..none */ - } - - buffer[n--] = '\0'; - - /* exit_signal is the second to last field so we look backwards. - * XXX if newer kernels drop more turds in this file we'll need - * to go the other way. luckily linux has no real api for this shit. - */ - - /* skip trailing crap */ - while ((n > 0) && !isdigit(buffer[n--])) ; - - while (offset-- > 0) { - /* skip last field */ - while ((n > 0) && isdigit(buffer[n--])) ; - - /* skip whitespace */ - while ((n > 0) && !isdigit(buffer[n--])) ; - } - - if (n < 3) { - return 0; /* hulk smashed /proc? */ - } - - ptr = &buffer[n]; - /* - * '17' == SIGCHLD == real process. - * '33' and '0' are threads - */ - if ((*ptr++ == '1') && - (*ptr++ == '7') && - (*ptr++ == ' ')) - { - return 0; - } - - return 1; -} - -int sigar_os_proc_list_get(sigar_t *sigar, - sigar_proc_list_t *proclist) -{ - DIR *dirp = opendir(PROCP_FS_ROOT); - struct dirent *ent, dbuf; - register const int threadbadhack = !sigar->has_nptl; - - if (!dirp) { - return errno; - } - - if (threadbadhack && (sigar->proc_signal_offset == -1)) { - sigar->proc_signal_offset = get_proc_signal_offset(); - } - - while (readdir_r(dirp, &dbuf, &ent) == 0) { - if (!ent) { - break; - } - - if (!sigar_isdigit(*ent->d_name)) { - continue; - } - - if (threadbadhack && - proc_isthread(sigar, ent->d_name, strlen(ent->d_name))) - { - continue; - } - - /* XXX: more sanity checking */ - - SIGAR_PROC_LIST_GROW(proclist); - - proclist->data[proclist->number++] = - strtoul(ent->d_name, NULL, 10); - } - - closedir(dirp); - - return SIGAR_OK; -} - -static int proc_stat_read(sigar_t *sigar, sigar_pid_t pid) -{ - char buffer[BUFSIZ], *ptr=buffer, *tmp; - unsigned int len; - linux_proc_stat_t *pstat = &sigar->last_proc_stat; - int status; - - time_t timenow = time(NULL); - - /* - * short-lived cache read/parse of last /proc/pid/stat - * as this info is spread out across a few functions. - */ - if (pstat->pid == pid) { - if ((timenow - pstat->mtime) < SIGAR_LAST_PROC_EXPIRE) { - return SIGAR_OK; - } - } - - pstat->pid = pid; - pstat->mtime = timenow; - - status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTAT); - - if (status != SIGAR_OK) { - return status; - } - - if (!(ptr = strchr(ptr, '('))) { - return EINVAL; - } - if (!(tmp = strrchr(++ptr, ')'))) { - return EINVAL; - } - len = tmp-ptr; - - if (len >= sizeof(pstat->name)) { - len = sizeof(pstat->name)-1; - } - - /* (1,2) */ - memcpy(pstat->name, ptr, len); - pstat->name[len] = '\0'; - ptr = tmp+1; - - SIGAR_SKIP_SPACE(ptr); - pstat->state = *ptr++; /* (3) */ - SIGAR_SKIP_SPACE(ptr); - - pstat->ppid = sigar_strtoul(ptr); /* (4) */ - ptr = sigar_skip_token(ptr); /* (5) pgrp */ - ptr = sigar_skip_token(ptr); /* (6) session */ - pstat->tty = sigar_strtoul(ptr); /* (7) */ - ptr = sigar_skip_token(ptr); /* (8) tty pgrp */ - - ptr = sigar_skip_token(ptr); /* (9) flags */ - pstat->minor_faults = sigar_strtoull(ptr); /* (10) */ - ptr = sigar_skip_token(ptr); /* (11) cmin flt */ - pstat->major_faults = sigar_strtoull(ptr); /* (12) */ - ptr = sigar_skip_token(ptr); /* (13) cmaj flt */ - - pstat->utime = SIGAR_TICK2MSEC(sigar_strtoull(ptr)); /* (14) */ - pstat->stime = SIGAR_TICK2MSEC(sigar_strtoull(ptr)); /* (15) */ - - ptr = sigar_skip_token(ptr); /* (16) cutime */ - ptr = sigar_skip_token(ptr); /* (17) cstime */ - - pstat->priority = sigar_strtoul(ptr); /* (18) */ - pstat->nice = sigar_strtoul(ptr); /* (19) */ - - ptr = sigar_skip_token(ptr); /* (20) timeout */ - ptr = sigar_skip_token(ptr); /* (21) it_real_value */ - - pstat->start_time = sigar_strtoul(ptr); /* (22) */ - pstat->start_time /= sigar->ticks; - pstat->start_time += sigar->boot_time; /* seconds */ - pstat->start_time *= 1000; /* milliseconds */ - - pstat->vsize = sigar_strtoull(ptr); /* (23) */ - pstat->rss = pageshift(sigar_strtoull(ptr)); /* (24) */ - - ptr = sigar_skip_token(ptr); /* (25) rlim */ - ptr = sigar_skip_token(ptr); /* (26) startcode */ - ptr = sigar_skip_token(ptr); /* (27) endcode */ - ptr = sigar_skip_token(ptr); /* (28) startstack */ - ptr = sigar_skip_token(ptr); /* (29) kstkesp */ - ptr = sigar_skip_token(ptr); /* (30) kstkeip */ - ptr = sigar_skip_token(ptr); /* (31) signal */ - ptr = sigar_skip_token(ptr); /* (32) blocked */ - ptr = sigar_skip_token(ptr); /* (33) sigignore */ - ptr = sigar_skip_token(ptr); /* (34) sigcache */ - ptr = sigar_skip_token(ptr); /* (35) wchan */ - ptr = sigar_skip_token(ptr); /* (36) nswap */ - ptr = sigar_skip_token(ptr); /* (37) cnswap */ - ptr = sigar_skip_token(ptr); /* (38) exit_signal */ - - pstat->processor = sigar_strtoul(ptr); /* (39) */ - - return SIGAR_OK; -} - -int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_mem_t *procmem) -{ - char buffer[BUFSIZ], *ptr=buffer; - int status = proc_stat_read(sigar, pid); - linux_proc_stat_t *pstat = &sigar->last_proc_stat; - - procmem->minor_faults = pstat->minor_faults; - procmem->major_faults = pstat->major_faults; - procmem->page_faults = - procmem->minor_faults + procmem->major_faults; - - status = SIGAR_PROC_FILE2STR(buffer, pid, "/statm"); - - if (status != SIGAR_OK) { - return status; - } - - procmem->size = pageshift(sigar_strtoull(ptr)); - procmem->resident = pageshift(sigar_strtoull(ptr)); - procmem->share = pageshift(sigar_strtoull(ptr)); - - return SIGAR_OK; -} - -#define NO_ID_MSG "[proc_cred] /proc/%lu" PROC_PSTATUS " missing " - -int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_cred_t *proccred) -{ - char buffer[BUFSIZ], *ptr; - int status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTATUS); - - if (status != SIGAR_OK) { - return status; - } - - if ((ptr = strstr(buffer, "\nUid:"))) { - ptr = sigar_skip_token(ptr); - - proccred->uid = sigar_strtoul(ptr); - proccred->euid = sigar_strtoul(ptr); - } - else { - sigar_log_printf(sigar, SIGAR_LOG_WARN, - NO_ID_MSG "Uid", pid); - return ENOENT; - } - - if ((ptr = strstr(ptr, "\nGid:"))) { - ptr = sigar_skip_token(ptr); - - proccred->gid = sigar_strtoul(ptr); - proccred->egid = sigar_strtoul(ptr); - } - else { - sigar_log_printf(sigar, SIGAR_LOG_WARN, - NO_ID_MSG "Gid", pid); - return ENOENT; - } - - return SIGAR_OK; -} - -int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_time_t *proctime) -{ - int status = proc_stat_read(sigar, pid); - linux_proc_stat_t *pstat = &sigar->last_proc_stat; - - if (status != SIGAR_OK) { - return status; - } - - proctime->user = pstat->utime; - proctime->sys = pstat->stime; - proctime->total = proctime->user + proctime->sys; - proctime->start_time = pstat->start_time; - - return SIGAR_OK; -} - -static int proc_status_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_state_t *procstate) -{ - char buffer[BUFSIZ], *ptr; - int status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTATUS); - - if (status != SIGAR_OK) { - return status; - } - - ptr = strstr(buffer, "\nThreads:"); - if (ptr) { - /* 2.6+ kernel only */ - ptr = sigar_skip_token(ptr); - procstate->threads = sigar_strtoul(ptr); - } - else { - procstate->threads = SIGAR_FIELD_NOTIMPL; - } - - return SIGAR_OK; -} - -int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_state_t *procstate) -{ - int status = proc_stat_read(sigar, pid); - linux_proc_stat_t *pstat = &sigar->last_proc_stat; - - if (status != SIGAR_OK) { - return status; - } - - memcpy(procstate->name, pstat->name, sizeof(procstate->name)); - procstate->state = pstat->state; - - procstate->ppid = pstat->ppid; - procstate->tty = pstat->tty; - procstate->priority = pstat->priority; - procstate->nice = pstat->nice; - procstate->processor = pstat->processor; - - if (sigar_cpu_core_rollup(sigar)) { - procstate->processor /= sigar->lcpu; - } - - proc_status_get(sigar, pid, procstate); - - return SIGAR_OK; -} - -int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_args_t *procargs) -{ - return sigar_procfs_args_get(sigar, pid, procargs); -} - -/* glibc 2.8 XXX use sysconf(_SC_ARG_MAX) */ -#ifndef ARG_MAX -#define ARG_MAX 131072 -#endif - -int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_env_t *procenv) -{ - int fd; - char buffer[ARG_MAX]; /* XXX: ARG_MAX == 130k */ - char name[BUFSIZ]; - size_t len; - char *ptr, *end; - - /* optimize if pid == $$ and type == ENV_KEY */ - SIGAR_PROC_ENV_KEY_LOOKUP(); - - (void)SIGAR_PROC_FILENAME(name, pid, "/environ"); - - if ((fd = open(name, O_RDONLY)) < 0) { - if (errno == ENOENT) { - return ESRCH; - } - return errno; - } - - len = read(fd, buffer, sizeof(buffer)); - - close(fd); - - buffer[len] = '\0'; - ptr = buffer; - - end = buffer + len; - while (ptr < end) { - char *val = strchr(ptr, '='); - int klen, vlen, status; - char key[128]; /* XXX is there a max key size? */ - - if (val == NULL) { - /* not key=val format */ - break; - } - - klen = val - ptr; - SIGAR_SSTRCPY(key, ptr); - key[klen] = '\0'; - ++val; - - vlen = strlen(val); - status = procenv->env_getter(procenv->data, - key, klen, val, vlen); - - if (status != SIGAR_OK) { - /* not an error; just stop iterating */ - break; - } - - ptr += (klen + 1 + vlen + 1); - } - - return SIGAR_OK; -} - -int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_fd_t *procfd) -{ - int status = - sigar_proc_fd_count(sigar, pid, &procfd->total); - - return status; -} - -int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_exe_t *procexe) -{ - int len; - char name[BUFSIZ]; - - (void)SIGAR_PROC_FILENAME(name, pid, "/cwd"); - - if ((len = readlink(name, procexe->cwd, - sizeof(procexe->cwd)-1)) < 0) - { - return errno; - } - - procexe->cwd[len] = '\0'; - - (void)SIGAR_PROC_FILENAME(name, pid, "/exe"); - - if ((len = readlink(name, procexe->name, - sizeof(procexe->name)-1)) < 0) - { - return errno; - } - - procexe->name[len] = '\0'; - - (void)SIGAR_PROC_FILENAME(name, pid, "/root"); - - if ((len = readlink(name, procexe->root, - sizeof(procexe->root)-1)) < 0) - { - return errno; - } - - procexe->root[len] = '\0'; - - return SIGAR_OK; -} - -int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_modules_t *procmods) -{ - FILE *fp; - char buffer[BUFSIZ], *ptr; - unsigned long inode, last_inode = 0; - - (void)SIGAR_PROC_FILENAME(buffer, pid, "/maps"); - - if (!(fp = fopen(buffer, "r"))) { - return errno; - } - - while ((ptr = fgets(buffer, sizeof(buffer), fp))) { - int len, status; - /* skip region, flags, offset, dev */ - ptr = sigar_skip_multiple_token(ptr, 4); - inode = sigar_strtoul(ptr); - - if ((inode == 0) || (inode == last_inode)) { - last_inode = 0; - continue; - } - - last_inode = inode; - SIGAR_SKIP_SPACE(ptr); - len = strlen(ptr); - ptr[len-1] = '\0'; /* chop \n */ - - status = - procmods->module_getter(procmods->data, - ptr, len-1); - - if (status != SIGAR_OK) { - /* not an error; just stop iterating */ - break; - } - } - - fclose(fp); - - return SIGAR_OK; -} - -int sigar_thread_cpu_get(sigar_t *sigar, - sigar_uint64_t id, - sigar_thread_cpu_t *cpu) -{ - struct tms now; - - if (id != 0) { - return SIGAR_ENOTIMPL; - } - - times(&now); - - cpu->user = SIGAR_TICK2NSEC(now.tms_utime); - cpu->sys = SIGAR_TICK2NSEC(now.tms_stime); - cpu->total = SIGAR_TICK2NSEC(now.tms_utime + now.tms_stime); - - return SIGAR_OK; -} - -#include - -int sigar_os_fs_type_get(sigar_file_system_t *fsp) -{ - char *type = fsp->sys_type_name; - - switch (*type) { - case 'e': - if (strnEQ(type, "ext", 3)) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - case 'g': - if (strEQ(type, "gfs")) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - case 'h': - if (strEQ(type, "hpfs")) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - case 'j': - if (strnEQ(type, "jfs", 3)) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - case 'o': - if (strnEQ(type, "ocfs", 4)) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - case 'p': - if (strnEQ(type, "psfs", 4)) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - case 'r': - if (strEQ(type, "reiserfs")) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - case 'v': - if (strEQ(type, "vzfs")) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - case 'x': - if (strEQ(type, "xfs") || strEQ(type, "xiafs")) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - } - - return fsp->type; -} - -int sigar_file_system_list_get(sigar_t *sigar, - sigar_file_system_list_t *fslist) -{ - struct mntent ent; - char buf[1025]; /* buffer for strings within ent */ - FILE *fp; - sigar_file_system_t *fsp; - - if (!(fp = setmntent(MOUNTED, "r"))) { - return errno; - } - - sigar_file_system_list_create(fslist); - - while (getmntent_r(fp, &ent, buf, sizeof(buf))) { - SIGAR_FILE_SYSTEM_LIST_GROW(fslist); - - fsp = &fslist->data[fslist->number++]; - - fsp->type = SIGAR_FSTYPE_UNKNOWN; /* unknown, will be set later */ - SIGAR_SSTRCPY(fsp->dir_name, ent.mnt_dir); - SIGAR_SSTRCPY(fsp->dev_name, ent.mnt_fsname); - SIGAR_SSTRCPY(fsp->sys_type_name, ent.mnt_type); - SIGAR_SSTRCPY(fsp->options, ent.mnt_opts); - sigar_fs_type_get(fsp); - } - - endmntent(fp); - - return SIGAR_OK; -} - -#define ST_MAJOR(sb) major((sb).st_rdev) -#define ST_MINOR(sb) minor((sb).st_rdev) - -static int get_iostat_sys(sigar_t *sigar, - const char *dirname, - sigar_disk_usage_t *disk, - sigar_iodev_t **iodev) -{ - char stat[1025], dev[1025]; - char *name, *ptr, *fsdev; - int partition, status; - - if (!(*iodev = sigar_iodev_get(sigar, dirname))) { - return ENXIO; - } - - name = fsdev = (*iodev)->name; - - if (SIGAR_NAME_IS_DEV(name)) { - name += SSTRLEN(SIGAR_DEV_PREFIX); /* strip "/dev/" */ - } - - while (!sigar_isdigit(*fsdev)) { - fsdev++; - } - - partition = strtoul(fsdev, NULL, 0); - *fsdev = '\0'; - - snprintf(stat, sizeof(stat), - SYS_BLOCK "/%s/%s%d/stat", name, name, partition); - - status = sigar_file2str(stat, dev, sizeof(dev)); - if (status != SIGAR_OK) { - return status; - } - - ptr = dev; - ptr = sigar_skip_token(ptr); - disk->reads = sigar_strtoull(ptr); - ptr = sigar_skip_token(ptr); - disk->writes = sigar_strtoull(ptr); - - disk->read_bytes = SIGAR_FIELD_NOTIMPL; - disk->write_bytes = SIGAR_FIELD_NOTIMPL; - disk->queue = SIGAR_FIELD_NOTIMPL; - - return SIGAR_OK; -} - -static int get_iostat_proc_dstat(sigar_t *sigar, - const char *dirname, - sigar_disk_usage_t *disk, - sigar_iodev_t **iodev, - sigar_disk_usage_t *device_usage) -{ - FILE *fp; - char buffer[1025]; - char *ptr; - struct stat sb; - int status=ENOENT; - - SIGAR_DISK_STATS_INIT(device_usage); - - if (!(*iodev = sigar_iodev_get(sigar, dirname))) { - return ENXIO; - } - - if (stat((*iodev)->name, &sb) < 0) { - return errno; - } - - if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - PROC_DISKSTATS " %s -> %s [%d,%d]", - dirname, (*iodev)->name, - ST_MAJOR(sb), ST_MINOR(sb)); - } - - if (!(fp = fopen(PROC_DISKSTATS, "r"))) { - return errno; - } - - while ((ptr = fgets(buffer, sizeof(buffer), fp))) { - unsigned long major, minor; - - major = sigar_strtoul(ptr); - minor = sigar_strtoul(ptr); - - if ((major == ST_MAJOR(sb)) && - ((minor == ST_MINOR(sb)) || (minor == 0))) - { - int num; - unsigned long - rio, rmerge, rsect, ruse, - wio, wmerge, wsect, wuse, - running, use, aveq; - - ptr = sigar_skip_token(ptr); /* name */ - - num = sscanf(ptr, - "%lu %lu %lu %lu " - "%lu %lu %lu %lu " - "%lu %lu %lu", - &rio, /* 1 # reads issued */ - &rmerge, /* 2 # reads merged */ - &rsect, /* 3 # sectors read */ - &ruse, /* 4 # millis spent reading */ - &wio, /* 5 # writes completed */ - &wmerge, /* 6 # writes merged */ - &wsect, /* 7 # sectors written */ - &wuse, /* 8 # millis spent writing */ - &running, /* 9 # I/Os currently in progress */ - &use, /* 10 # millis spent doing I/Os */ - &aveq); /* 11 # of millis spent doing I/Os (weighted) */ - - if (num == 11) { - disk->rtime = ruse; - disk->wtime = wuse; - disk->time = use; - disk->qtime = aveq; - } - else if (num == 4) { - wio = rsect; - rsect = rmerge; - wsect = ruse; - disk->time = disk->qtime = SIGAR_FIELD_NOTIMPL; - } - else { - status = ENOENT; - } - - disk->reads = rio; - disk->writes = wio; - disk->read_bytes = rsect; - disk->write_bytes = wsect; - - /* convert sectors to bytes (512 is fixed size in 2.6 kernels) */ - disk->read_bytes *= 512; - disk->write_bytes *= 512; - - if (minor == ST_MINOR(sb)) { - status = SIGAR_OK; - break; - } - else if (minor == 0) { - memcpy(device_usage, disk, sizeof(*device_usage)); - } - } - } - - fclose(fp); - - return status; -} - -static int get_iostat_procp(sigar_t *sigar, - const char *dirname, - sigar_disk_usage_t *disk, - sigar_iodev_t **iodev) -{ - FILE *fp; - char buffer[1025]; - char *ptr; - struct stat sb; - - if (!(*iodev = sigar_iodev_get(sigar, dirname))) { - return ENXIO; - } - - if (stat((*iodev)->name, &sb) < 0) { - return errno; - } - - if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - PROC_PARTITIONS " %s -> %s [%d,%d]", - dirname, (*iodev)->name, - ST_MAJOR(sb), ST_MINOR(sb)); - } - - if (!(fp = fopen(PROC_PARTITIONS, "r"))) { - return errno; - } - - (void)fgets(buffer, sizeof(buffer), fp); /* skip header */ - while ((ptr = fgets(buffer, sizeof(buffer), fp))) { - unsigned long major, minor; - - major = sigar_strtoul(ptr); - minor = sigar_strtoul(ptr); - - if ((major == ST_MAJOR(sb)) && (minor == ST_MINOR(sb))) { - ptr = sigar_skip_token(ptr); /* blocks */ - ptr = sigar_skip_token(ptr); /* name */ - disk->reads = sigar_strtoull(ptr); /* rio */ - ptr = sigar_skip_token(ptr); /* rmerge */ - disk->read_bytes = sigar_strtoull(ptr); /* rsect */ - disk->rtime = sigar_strtoull(ptr); /* ruse */ - disk->writes = sigar_strtoull(ptr); /* wio */ - ptr = sigar_skip_token(ptr); /* wmerge */ - disk->write_bytes = sigar_strtoull(ptr); /* wsect */ - disk->wtime = sigar_strtoull(ptr); /* wuse */ - ptr = sigar_skip_token(ptr); /* running */ - disk->time = sigar_strtoull(ptr); /* use */ - disk->qtime = sigar_strtoull(ptr); /* aveq */ - - /* convert sectors to bytes (512 is fixed size in 2.6 kernels) */ - disk->read_bytes *= 512; - disk->write_bytes *= 512; - - fclose(fp); - return SIGAR_OK; - } - } - - fclose(fp); - - return ENOENT; -} - -int sigar_disk_usage_get(sigar_t *sigar, const char *name, - sigar_disk_usage_t *disk) -{ - int status; - sigar_iodev_t *iodev = NULL; - sigar_disk_usage_t device_usage; - SIGAR_DISK_STATS_INIT(disk); - - /* - * 2.2 has metrics /proc/stat, but wtf is the device mapping? - * 2.4 has /proc/partitions w/ the metrics. - * 2.6 has /proc/partitions w/o the metrics. - * instead the metrics are within the /proc-like /sys filesystem. - * also has /proc/diskstats - */ - switch (sigar->iostat) { - case IOSTAT_SYS: - status = get_iostat_sys(sigar, name, disk, &iodev); - break; - case IOSTAT_DISKSTATS: - status = get_iostat_proc_dstat(sigar, name, disk, &iodev, &device_usage); - break; - case IOSTAT_PARTITIONS: - status = get_iostat_procp(sigar, name, disk, &iodev); - break; - /* - * case IOSTAT_SOME_OTHER_WIERD_THING: - * break; - */ - case IOSTAT_NONE: - default: - status = ENOENT; - break; - } - - if ((status == SIGAR_OK) && iodev) { - sigar_uptime_t uptime; - sigar_uint64_t interval, ios; - double tput, util; - sigar_disk_usage_t *partition_usage=NULL; - - sigar_uptime_get(sigar, &uptime); - - if (iodev->is_partition && - (sigar->iostat == IOSTAT_DISKSTATS)) - { - /* 2.6 kernels do not have per-partition times */ - partition_usage = disk; - disk = &device_usage; - } - - disk->snaptime = uptime.uptime; - - if (iodev->disk.snaptime) { - interval = disk->snaptime - iodev->disk.snaptime; - } - else { - interval = disk->snaptime; - } - - ios = - (disk->reads - iodev->disk.reads) + - (disk->writes - iodev->disk.writes); - - if (disk->time == SIGAR_FIELD_NOTIMPL) { - disk->service_time = SIGAR_FIELD_NOTIMPL; - } - else { - tput = ((double)ios) * HZ / interval; - util = ((double)(disk->time - iodev->disk.time)) / interval * HZ; - disk->service_time = tput ? util / tput : 0.0; - } - if (disk->qtime == SIGAR_FIELD_NOTIMPL) { - disk->queue = SIGAR_FIELD_NOTIMPL; - } - else { - util = ((double)(disk->qtime - iodev->disk.qtime)) / interval; - disk->queue = util / 1000.0; - } - - memcpy(&iodev->disk, disk, sizeof(iodev->disk)); - if (partition_usage) { - partition_usage->service_time = disk->service_time; - partition_usage->queue = disk->queue; - } - } - - return status; -} - -int sigar_file_system_usage_get(sigar_t *sigar, - const char *dirname, - sigar_file_system_usage_t *fsusage) -{ - int status = sigar_statvfs(sigar, dirname, fsusage); - - if (status != SIGAR_OK) { - return status; - } - - fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage); - - (void)sigar_disk_usage_get(sigar, dirname, &fsusage->disk); - - return SIGAR_OK; -} - -static SIGAR_INLINE char *cpu_info_strval(char *ptr) -{ - if ((ptr = strchr(ptr, ':'))) { - ptr++; - while (isspace (*ptr)) ptr++; - return ptr; - } - return NULL; -} - -static SIGAR_INLINE void cpu_info_strcpy(char *ptr, char *buf, int len) -{ - int slen; - ptr = cpu_info_strval(ptr); - if (!ptr) { - return; - } - slen = strlen(ptr); - strncpy(buf, ptr, len); - buf[len] = '\0'; - if (slen < len) { - buf[slen-1] = '\0'; /* rid \n */ - } -} - -static int get_cpu_info(sigar_t *sigar, sigar_cpu_info_t *info, - FILE *fp) -{ - char buffer[BUFSIZ], *ptr; - - int found = 0; - - /* UML vm wont have "cpu MHz" or "cache size" fields */ - info->mhz = 0; - info->cache_size = 0; - -#ifdef __powerpc64__ - SIGAR_SSTRCPY(info->vendor, "IBM"); -#endif - - while ((ptr = fgets(buffer, sizeof(buffer), fp))) { - switch (*ptr) { - case 'p': /* processor : 0 */ - if (strnEQ(ptr, "processor", 9)) { - found = 1; - } - break; - case 'v': - /* "vendor_id" or "vendor" */ - if (strnEQ(ptr, "vendor", 6)) { - cpu_info_strcpy(ptr, info->vendor, sizeof(info->vendor)); - if (strEQ(info->vendor, "GenuineIntel")) { - SIGAR_SSTRCPY(info->vendor, "Intel"); - } - else if (strEQ(info->vendor, "AuthenticAMD")) { - SIGAR_SSTRCPY(info->vendor, "AMD"); - } - } - break; - case 'f': - if (strnEQ(ptr, "family", 6)) { - /* IA64 version of "model name" */ - cpu_info_strcpy(ptr, info->model, sizeof(info->model)); - sigar_cpu_model_adjust(sigar, info); - } - break; - case 'm': - if (strnEQ(ptr, "model name", 10)) { - cpu_info_strcpy(ptr, info->model, sizeof(info->model)); - sigar_cpu_model_adjust(sigar, info); - } - break; - case 'c': - if (strnEQ(ptr, "cpu MHz", 7)) { - ptr = cpu_info_strval(ptr); - info->mhz = atoi(ptr); - } - else if (strnEQ(ptr, "cache size", 10)) { - ptr = cpu_info_strval(ptr); - info->cache_size = sigar_strtoul(ptr); - } -#ifdef __powerpc64__ - /* each /proc/cpuinfo entry looks like so: - * processor : 0 - * cpu : POWER5 (gr) - * clock : 1656.392000MHz - * revision : 2.2 - */ - else if (strnEQ(ptr, "clock", 5)) { - ptr = cpu_info_strval(ptr); - info->mhz = atoi(ptr); - } - else if (strnEQ(ptr, "cpu", 3)) { - cpu_info_strcpy(ptr, info->model, sizeof(info->model)); - - if ((ptr = strchr(info->model, ' '))) { - /* "POWER5 (gr)" -> "POWER5" */ - *ptr = '\0'; - } - } -#endif - break; - /* lone \n means end of info for this processor */ - case '\n': - return found; - } - } - - return found; -} - -/* /proc/cpuinfo MHz will change w/ AMD + PowerNow */ -static void get_cpuinfo_max_freq(sigar_cpu_info_t *cpu_info, int num) -{ - int status; - char max_freq[PATH_MAX]; - snprintf(max_freq, sizeof(max_freq), - "/sys/devices/system/cpu/cpu%d" - "/cpufreq/cpuinfo_max_freq", num); - - status = - sigar_file2str(max_freq, max_freq, sizeof(max_freq)-1); - - if (status == SIGAR_OK) { - cpu_info->mhz_max = atoi(max_freq) / 1000; - } -} - -static void get_cpuinfo_min_freq(sigar_cpu_info_t *cpu_info, int num) -{ - int status; - char min_freq[PATH_MAX]; - snprintf(min_freq, sizeof(min_freq), - "/sys/devices/system/cpu/cpu%d" - "/cpufreq/cpuinfo_min_freq", num); - - status = - sigar_file2str(min_freq, min_freq, sizeof(min_freq)-1); - - if (status == SIGAR_OK) { - cpu_info->mhz_min = atoi(min_freq) / 1000; - } -} - -int sigar_cpu_info_list_get(sigar_t *sigar, - sigar_cpu_info_list_t *cpu_infos) -{ - FILE *fp; - int core_rollup = sigar_cpu_core_rollup(sigar), i=0; - - if (!(fp = fopen(PROC_FS_ROOT "cpuinfo", "r"))) { - return errno; - } - - (void)sigar_cpu_total_count(sigar); - sigar_cpu_info_list_create(cpu_infos); - - while (get_cpu_info(sigar, &cpu_infos->data[cpu_infos->number], fp)) { - sigar_cpu_info_t *info; - - if (core_rollup && (i++ % sigar->lcpu)) { - continue; /* fold logical processors */ - } - - info = &cpu_infos->data[cpu_infos->number]; - get_cpuinfo_max_freq(info, cpu_infos->number); - get_cpuinfo_min_freq(info, cpu_infos->number); - - info->total_cores = sigar->ncpu; - info->cores_per_socket = sigar->lcpu; - info->total_sockets = sigar_cpu_socket_count(sigar); - - ++cpu_infos->number; - SIGAR_CPU_INFO_LIST_GROW(cpu_infos); - } - - fclose(fp); - - return SIGAR_OK; -} - -static SIGAR_INLINE unsigned int hex2int(const char *x, int len) -{ - int i; - unsigned int j; - - for (i=0, j=0; isize = routelist->number = 0; - - if (!(fp = fopen(PROC_FS_ROOT "net/route", "r"))) { - return errno; - } - - sigar_net_route_list_create(routelist); - - (void)fgets(buffer, sizeof(buffer), fp); /* skip header */ - while (fgets(buffer, sizeof(buffer), fp)) { - int num; - - SIGAR_NET_ROUTE_LIST_GROW(routelist); - route = &routelist->data[routelist->number++]; - - /* XXX rid sscanf */ - num = sscanf(buffer, ROUTE_FMT, - route->ifname, net_addr, gate_addr, - &flags, &route->refcnt, &route->use, - &route->metric, mask_addr, - &route->mtu, &route->window, &route->irtt); - - if ((num < 10) || !(flags & RTF_UP)) { - --routelist->number; - continue; - } - - route->flags = flags; - - sigar_net_address_set(route->destination, hex2int(net_addr, HEX_ENT_LEN)); - sigar_net_address_set(route->gateway, hex2int(gate_addr, HEX_ENT_LEN)); - sigar_net_address_set(route->mask, hex2int(mask_addr, HEX_ENT_LEN)); - } - - fclose(fp); - - return SIGAR_OK; -} - -int sigar_net_interface_stat_get(sigar_t *sigar, const char *name, - sigar_net_interface_stat_t *ifstat) -{ - int found = 0; - char buffer[BUFSIZ]; - FILE *fp = fopen(PROC_FS_ROOT "net/dev", "r"); - - if (!fp) { - return errno; - } - - /* skip header */ - fgets(buffer, sizeof(buffer), fp); - fgets(buffer, sizeof(buffer), fp); - - while (fgets(buffer, sizeof(buffer), fp)) { - char *ptr, *dev; - - dev = buffer; - while (isspace(*dev)) { - dev++; - } - - if (!(ptr = strchr(dev, ':'))) { - continue; - } - - *ptr++ = 0; - - if (!strEQ(dev, name)) { - continue; - } - - found = 1; - ifstat->rx_bytes = sigar_strtoull(ptr); - ifstat->rx_packets = sigar_strtoull(ptr); - ifstat->rx_errors = sigar_strtoull(ptr); - ifstat->rx_dropped = sigar_strtoull(ptr); - ifstat->rx_overruns = sigar_strtoull(ptr); - ifstat->rx_frame = sigar_strtoull(ptr); - - /* skip: compressed multicast */ - ptr = sigar_skip_multiple_token(ptr, 2); - - ifstat->tx_bytes = sigar_strtoull(ptr); - ifstat->tx_packets = sigar_strtoull(ptr); - ifstat->tx_errors = sigar_strtoull(ptr); - ifstat->tx_dropped = sigar_strtoull(ptr); - ifstat->tx_overruns = sigar_strtoull(ptr); - ifstat->tx_collisions = sigar_strtoull(ptr); - ifstat->tx_carrier = sigar_strtoull(ptr); - - ifstat->speed = SIGAR_FIELD_NOTIMPL; - - break; - } - - fclose(fp); - - return found ? SIGAR_OK : ENXIO; -} - -static SIGAR_INLINE void convert_hex_address(sigar_net_address_t *address, - char *ptr, int len) -{ - if (len > HEX_ENT_LEN) { - int i; - for (i=0; i<=3; i++, ptr+=HEX_ENT_LEN) { - address->addr.in6[i] = hex2int(ptr, HEX_ENT_LEN); - } - - address->family = SIGAR_AF_INET6; - } - else { - address->addr.in = - (len == HEX_ENT_LEN) ? hex2int(ptr, HEX_ENT_LEN) : 0; - - address->family = SIGAR_AF_INET; - } -} - -typedef struct { - sigar_net_connection_list_t *connlist; - sigar_net_connection_t *conn; - unsigned long port; -} net_conn_getter_t; - -static int proc_net_walker(sigar_net_connection_walker_t *walker, - sigar_net_connection_t *conn) -{ - net_conn_getter_t *getter = - (net_conn_getter_t *)walker->data; - - if (getter->connlist) { - SIGAR_NET_CONNLIST_GROW(getter->connlist); - memcpy(&getter->connlist->data[getter->connlist->number++], - conn, sizeof(*conn)); - } - else { - if ((getter->port == conn->local_port) && - (conn->remote_port == 0)) - { - memcpy(getter->conn, conn, sizeof(*conn)); - return !SIGAR_OK; /* break loop */ - } - } - - return SIGAR_OK; /* continue loop */ -} - -#define SKIP_WHILE(p, c) while (*p == c) p++ -#define SKIP_PAST(p, c) \ - while(*p && (*p != c)) p++; \ - SKIP_WHILE(p, c) - -typedef struct { - FILE *fp; - int (*close)(FILE *); -} xproc_t; - -static FILE *xproc_open(const char *command, xproc_t *xproc) -{ - struct stat sb; - if (stat(command, &sb) == 0) { - if (sb.st_mode & S_IXUSR) { - /* executable script for testing large - * conn table where we can sleep() to better - * simulate /proc/net/tcp behavior - */ - xproc->fp = popen(command, "r"); - xproc->close = pclose; - } - else { - xproc->fp = fopen(command, "r"); - xproc->close = fclose; - } - return xproc->fp; - } - else { - return NULL; - } -} - -static int proc_net_read(sigar_net_connection_walker_t *walker, - const char *fname, - int type) -{ - FILE *fp = NULL; - char buffer[8192]; - sigar_t *sigar = walker->sigar; - char *ptr = sigar->proc_net; - int flags = walker->flags; - xproc_t xproc = { NULL, fclose }; - - if (ptr) { - snprintf(buffer, sizeof(buffer), - "%s/%s", ptr, - fname + sizeof(PROC_FS_ROOT)-1); - - if ((fp = xproc_open(buffer, &xproc))) { - if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[proc_net] using %s", - buffer); - } - } - else if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[proc_net] cannot open %s", - buffer); - } - } - - if (!(fp || (fp = fopen(fname, "r")))) { - return errno; - } - - fgets(buffer, sizeof(buffer), fp); /* skip header */ - - while ((ptr = fgets(buffer, sizeof(buffer), fp))) { - sigar_net_connection_t conn; - char *laddr, *raddr; - int laddr_len=0, raddr_len=0; - int more; - - /* skip leading space */ - SKIP_WHILE(ptr, ' '); - - /* skip "%d: " */ - SKIP_PAST(ptr, ' '); - - laddr = ptr; - while (*ptr && (*ptr != ':')) { - laddr_len++; - ptr++; - } - SKIP_WHILE(ptr, ':'); - - conn.local_port = (strtoul(ptr, &ptr, 16) & 0xffff); - - SKIP_WHILE(ptr, ' '); - - raddr = ptr; - while (*ptr && (*ptr != ':')) { - raddr_len++; - ptr++; - } - SKIP_WHILE(ptr, ':'); - - conn.remote_port = (strtoul(ptr, &ptr, 16) & 0xffff); - - SKIP_WHILE(ptr, ' '); - - if (!((conn.remote_port && (flags & SIGAR_NETCONN_CLIENT)) || - (!conn.remote_port && (flags & SIGAR_NETCONN_SERVER)))) - { - continue; - } - - conn.type = type; - - convert_hex_address(&conn.local_address, - laddr, laddr_len); - - convert_hex_address(&conn.remote_address, - raddr, raddr_len); - - /* SIGAR_TCP_* currently matches TCP_* in linux/tcp.h */ - conn.state = hex2int(ptr, 2); - ptr += 2; - SKIP_WHILE(ptr, ' '); - - conn.send_queue = hex2int(ptr, HEX_ENT_LEN); - ptr += HEX_ENT_LEN+1; /* tx + ':' */; - - conn.receive_queue = hex2int(ptr, HEX_ENT_LEN); - ptr += HEX_ENT_LEN; - SKIP_WHILE(ptr, ' '); - - SKIP_PAST(ptr, ' '); /* tr:tm->whem */ - SKIP_PAST(ptr, ' '); /* retrnsmt */ - - conn.uid = sigar_strtoul(ptr); - - SKIP_WHILE(ptr, ' '); - SKIP_PAST(ptr, ' '); /* timeout */ - - conn.inode = sigar_strtoul(ptr); - - more = walker->add_connection(walker, &conn); - if (more != SIGAR_OK) { - xproc.close(fp); - return SIGAR_OK; - } - } - - xproc.close(fp); - - return SIGAR_OK; -} - -int sigar_net_connection_walk(sigar_net_connection_walker_t *walker) -{ - int flags = walker->flags; - int status; - - if (flags & SIGAR_NETCONN_TCP) { - status = proc_net_read(walker, - PROC_FS_ROOT "net/tcp", - SIGAR_NETCONN_TCP); - - if (status != SIGAR_OK) { - return status; - } - - status = proc_net_read(walker, - PROC_FS_ROOT "net/tcp6", - SIGAR_NETCONN_TCP); - - if (!((status == SIGAR_OK) || (status == ENOENT))) { - return status; - } - } - - if (flags & SIGAR_NETCONN_UDP) { - status = proc_net_read(walker, - PROC_FS_ROOT "net/udp", - SIGAR_NETCONN_UDP); - - if (status != SIGAR_OK) { - return status; - } - - status = proc_net_read(walker, - PROC_FS_ROOT "net/udp6", - SIGAR_NETCONN_UDP); - - if (!((status == SIGAR_OK) || (status == ENOENT))) { - return status; - } - } - - if (flags & SIGAR_NETCONN_RAW) { - status = proc_net_read(walker, - PROC_FS_ROOT "net/raw", - SIGAR_NETCONN_RAW); - - if (status != SIGAR_OK) { - return status; - } - - status = proc_net_read(walker, - PROC_FS_ROOT "net/raw6", - SIGAR_NETCONN_RAW); - - if (!((status == SIGAR_OK) || (status == ENOENT))) { - return status; - } - } - - /* XXX /proc/net/unix */ - - return SIGAR_OK; -} - -int sigar_net_connection_list_get(sigar_t *sigar, - sigar_net_connection_list_t *connlist, - int flags) -{ - int status; - sigar_net_connection_walker_t walker; - net_conn_getter_t getter; - - sigar_net_connection_list_create(connlist); - - getter.conn = NULL; - getter.connlist = connlist; - - walker.sigar = sigar; - walker.flags = flags; - walker.data = &getter; - walker.add_connection = proc_net_walker; - - status = sigar_net_connection_walk(&walker); - - if (status != SIGAR_OK) { - sigar_net_connection_list_destroy(sigar, connlist); - } - - return status; -} - -static int sigar_net_connection_get(sigar_t *sigar, - sigar_net_connection_t *netconn, - unsigned long port, - int flags) -{ - int status; - sigar_net_connection_walker_t walker; - net_conn_getter_t getter; - - getter.conn = netconn; - getter.connlist = NULL; - getter.port = port; - - walker.sigar = sigar; - walker.flags = flags; - walker.data = &getter; - walker.add_connection = proc_net_walker; - - status = sigar_net_connection_walk(&walker); - - return status; -} - -int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, - sigar_net_interface_config_t *ifconfig) -{ - FILE *fp; - char addr[32+1], ifname[8+1]; - int status = SIGAR_ENOENT; - int idx, prefix, scope, flags; - - if (!(fp = fopen(PROC_FS_ROOT "net/if_inet6", "r"))) { - return errno; - } - - while (fscanf(fp, "%32s %02x %02x %02x %02x %8s\n", - addr, &idx, &prefix, &scope, &flags, ifname) != EOF) - { - if (strEQ(name, ifname)) { - status = SIGAR_OK; - break; - } - } - - fclose(fp); - - if (status == SIGAR_OK) { - int i=0; - unsigned char *addr6 = (unsigned char *)&(ifconfig->address6.addr.in6); - char *ptr = addr; - - for (i=0; i<16; i++, ptr+=2) { - addr6[i] = (unsigned char)hex2int(ptr, 2); - } - - ifconfig->prefix6_length = prefix; - ifconfig->scope6 = scope; - } - - return status; -} - -#define SNMP_TCP_PREFIX "Tcp: " - -SIGAR_DECLARE(int) -sigar_tcp_get(sigar_t *sigar, - sigar_tcp_t *tcp) -{ - FILE *fp; - char buffer[1024], *ptr=buffer; - int status = SIGAR_ENOENT; - - if (!(fp = fopen(PROC_FS_ROOT "net/snmp", "r"))) { - return errno; - } - - while (fgets(buffer, sizeof(buffer), fp)) { - if (strnEQ(buffer, SNMP_TCP_PREFIX, sizeof(SNMP_TCP_PREFIX)-1)) { - if (fgets(buffer, sizeof(buffer), fp)) { - status = SIGAR_OK; - break; - } - } - } - - fclose(fp); - - if (status == SIGAR_OK) { - /* assuming field order, same in 2.2, 2.4 and 2.6 kernels */ - /* Tcp: RtoAlgorithm RtoMin RtoMax MaxConn */ - ptr = sigar_skip_multiple_token(ptr, 5); - tcp->active_opens = sigar_strtoull(ptr); - tcp->passive_opens = sigar_strtoull(ptr); - tcp->attempt_fails = sigar_strtoull(ptr); - tcp->estab_resets = sigar_strtoull(ptr); - tcp->curr_estab = sigar_strtoull(ptr); - tcp->in_segs = sigar_strtoull(ptr); - tcp->out_segs = sigar_strtoull(ptr); - tcp->retrans_segs = sigar_strtoull(ptr); - tcp->in_errs = sigar_strtoull(ptr); - tcp->out_rsts = sigar_strtoull(ptr); - } - - return status; -} - -static int sigar_proc_nfs_gets(char *file, char *tok, - char *buffer, size_t size) -{ - int status = ENOENT; - int len = strlen(tok); - FILE *fp = fopen(file, "r"); - - if (!fp) { - return SIGAR_ENOTIMPL; - } - - while (fgets(buffer, size, fp)) { - if (strnEQ(buffer, tok, len)) { - status = SIGAR_OK; - break; - } - } - - fclose(fp); - - return status; -} - -static int sigar_nfs_v2_get(char *file, sigar_nfs_v2_t *nfs) -{ - char buffer[BUFSIZ], *ptr=buffer; - int status = - sigar_proc_nfs_gets(file, - "proc2", buffer, sizeof(buffer)); - - if (status != SIGAR_OK) { - return status; - } - - ptr = sigar_skip_multiple_token(ptr, 2); - - nfs->null = sigar_strtoull(ptr); - nfs->getattr = sigar_strtoull(ptr); - nfs->setattr = sigar_strtoull(ptr); - nfs->root = sigar_strtoull(ptr); - nfs->lookup = sigar_strtoull(ptr); - nfs->readlink = sigar_strtoull(ptr); - nfs->read = sigar_strtoull(ptr); - nfs->writecache = sigar_strtoull(ptr); - nfs->write = sigar_strtoull(ptr); - nfs->create = sigar_strtoull(ptr); - nfs->remove = sigar_strtoull(ptr); - nfs->rename = sigar_strtoull(ptr); - nfs->link = sigar_strtoull(ptr); - nfs->symlink = sigar_strtoull(ptr); - nfs->mkdir = sigar_strtoull(ptr); - nfs->rmdir = sigar_strtoull(ptr); - nfs->readdir = sigar_strtoull(ptr); - nfs->fsstat = sigar_strtoull(ptr); - - return SIGAR_OK; -} - -int sigar_nfs_client_v2_get(sigar_t *sigar, - sigar_nfs_client_v2_t *nfs) -{ - return sigar_nfs_v2_get(PROC_FS_ROOT "net/rpc/nfs", - (sigar_nfs_v2_t *)nfs); -} - -int sigar_nfs_server_v2_get(sigar_t *sigar, - sigar_nfs_server_v2_t *nfs) -{ - return sigar_nfs_v2_get(PROC_FS_ROOT "net/rpc/nfsd", - (sigar_nfs_v2_t *)nfs); -} - -static int sigar_nfs_v3_get(char *file, sigar_nfs_v3_t *nfs) -{ - char buffer[BUFSIZ], *ptr=buffer; - int status = - sigar_proc_nfs_gets(file, - "proc3", buffer, sizeof(buffer)); - - if (status != SIGAR_OK) { - return status; - } - - ptr = sigar_skip_multiple_token(ptr, 2); - - nfs->null = sigar_strtoull(ptr); - nfs->getattr = sigar_strtoull(ptr); - nfs->setattr = sigar_strtoull(ptr); - nfs->lookup = sigar_strtoull(ptr); - nfs->access = sigar_strtoull(ptr); - nfs->readlink = sigar_strtoull(ptr); - nfs->read = sigar_strtoull(ptr); - nfs->write = sigar_strtoull(ptr); - nfs->create = sigar_strtoull(ptr); - nfs->mkdir = sigar_strtoull(ptr); - nfs->symlink = sigar_strtoull(ptr); - nfs->mknod = sigar_strtoull(ptr); - nfs->remove = sigar_strtoull(ptr); - nfs->rmdir = sigar_strtoull(ptr); - nfs->rename = sigar_strtoull(ptr); - nfs->link = sigar_strtoull(ptr); - nfs->readdir = sigar_strtoull(ptr); - nfs->readdirplus = sigar_strtoull(ptr); - nfs->fsstat = sigar_strtoull(ptr); - nfs->fsinfo = sigar_strtoull(ptr); - nfs->pathconf = sigar_strtoull(ptr); - nfs->commit = sigar_strtoull(ptr); - - return SIGAR_OK; -} - -int sigar_nfs_client_v3_get(sigar_t *sigar, - sigar_nfs_client_v3_t *nfs) -{ - return sigar_nfs_v3_get(PROC_FS_ROOT "net/rpc/nfs", - (sigar_nfs_v3_t *)nfs); -} - -int sigar_nfs_server_v3_get(sigar_t *sigar, - sigar_nfs_server_v3_t *nfs) -{ - return sigar_nfs_v3_get(PROC_FS_ROOT "net/rpc/nfsd", - (sigar_nfs_v3_t *)nfs); -} - -#include - -static char *get_hw_type(int type) -{ - switch (type) { - case ARPHRD_AX25: - return "ax25"; - case ARPHRD_ECONET: - return "ec"; - case ARPHRD_ETHER: - return "ether"; - case ARPHRD_FDDI: - return "fddi"; - case ARPHRD_DLCI: - return "dlci"; - case ARPHRD_FRAD: - return "frad"; - case ARPHRD_HDLC: - return "hdlc"; - case ARPHRD_LAPB: - return "lapb"; - case ARPHRD_HIPPI: - return "hippi"; - case ARPHRD_IRDA: - return "irda"; - case ARPHRD_LOOPBACK: - return "loop"; - case ARPHRD_NETROM: - return "netrom"; - case ARPHRD_PPP: - return "ppp"; - case ARPHRD_ROSE: - return "rose"; - case ARPHRD_SIT: - return "sit"; - case ARPHRD_SLIP: - return "slip"; - case ARPHRD_CSLIP: - return "cslip"; - case ARPHRD_SLIP6: - return "slip6"; - case ARPHRD_CSLIP6: - return "cslip6"; - case ARPHRD_ADAPT: - return "adaptive"; - case ARPHRD_IEEE802: - return "tr"; - case ARPHRD_IEEE802_TR: - return "tr"; - case ARPHRD_TUNNEL: - return "tunnel"; - case ARPHRD_X25: - return "x25"; - default: - return "unknown"; - } -} - -int sigar_arp_list_get(sigar_t *sigar, - sigar_arp_list_t *arplist) -{ - FILE *fp; - char buffer[1024]; - char net_addr[128], hwaddr[128], mask_addr[128]; - int flags, type, status; - sigar_arp_t *arp; - - arplist->size = arplist->number = 0; - - if (!(fp = fopen(PROC_FS_ROOT "net/arp", "r"))) { - return errno; - } - - sigar_arp_list_create(arplist); - - (void)fgets(buffer, sizeof(buffer), fp); /* skip header */ - while (fgets(buffer, sizeof(buffer), fp)) { - int num; - - SIGAR_ARP_LIST_GROW(arplist); - arp = &arplist->data[arplist->number++]; - - /* XXX rid sscanf */ - num = sscanf(buffer, "%128s 0x%x 0x%x %128s %128s %16s", - net_addr, &type, &flags, - hwaddr, mask_addr, arp->ifname); - - if (num < 6) { - --arplist->number; - continue; - } - - arp->flags = flags; - status = inet_pton(AF_INET, net_addr, &arp->address.addr); - if (status > 0) { - arp->address.family = SIGAR_AF_INET; - } - else if ((status = inet_pton(AF_INET6, net_addr, &arp->address.addr)) > 0) { - arp->address.family = SIGAR_AF_INET6; - } - else { - sigar_log_printf(sigar, SIGAR_LOG_WARN, - "[arp] failed to parse address='%s' (%s)\n", net_addr, - ((status == 0) ? "Invalid format" : sigar_strerror(sigar, errno))); - --arplist->number; - continue; - } - - num = sscanf(hwaddr, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", - &arp->hwaddr.addr.mac[0], - &arp->hwaddr.addr.mac[1], - &arp->hwaddr.addr.mac[2], - &arp->hwaddr.addr.mac[3], - &arp->hwaddr.addr.mac[4], - &arp->hwaddr.addr.mac[5]); - if (num < 6) { - sigar_log_printf(sigar, SIGAR_LOG_WARN, - "[arp] failed to parse hwaddr='%s' (%s)\n", hwaddr); - --arplist->number; - continue; - } - arp->hwaddr.family = SIGAR_AF_LINK; - - SIGAR_SSTRCPY(arp->type, get_hw_type(type)); - } - - fclose(fp); - - return SIGAR_OK; -} - -int sigar_proc_port_get(sigar_t *sigar, int protocol, - unsigned long port, sigar_pid_t *pid) -{ - int status; - sigar_net_connection_t netconn; - DIR *dirp; - struct dirent *ent, dbuf; - - SIGAR_ZERO(&netconn); - *pid = 0; - - status = sigar_net_connection_get(sigar, &netconn, port, - SIGAR_NETCONN_SERVER|protocol); - - if (status != SIGAR_OK) { - return status; - } - - if (netconn.local_port != port) { - return SIGAR_OK; /* XXX or ENOENT? */ - } - - if (!(dirp = opendir(PROCP_FS_ROOT))) { - return errno; - } - - while (readdir_r(dirp, &dbuf, &ent) == 0) { - DIR *fd_dirp; - struct dirent *fd_ent, fd_dbuf; - struct stat sb; - char fd_name[BUFSIZ], pid_name[BUFSIZ]; - int len, slen; - - if (ent == NULL) { - break; - } - - if (!sigar_isdigit(*ent->d_name)) { - continue; - } - - /* sprintf(pid_name, "/proc/%s", ent->d_name) */ - memcpy(&pid_name[0], PROCP_FS_ROOT, SSTRLEN(PROCP_FS_ROOT)); - len = SSTRLEN(PROCP_FS_ROOT); - pid_name[len++] = '/'; - - slen = strlen(ent->d_name); - memcpy(&pid_name[len], ent->d_name, slen); - len += slen; - pid_name[len] = '\0'; - - if (stat(pid_name, &sb) < 0) { - continue; - } - if (sb.st_uid != netconn.uid) { - continue; - } - - /* sprintf(fd_name, "%s/fd", pid_name) */ - memcpy(&fd_name[0], pid_name, len); - memcpy(&fd_name[len], "/fd", 3); - fd_name[len+=3] = '\0'; - - if (!(fd_dirp = opendir(fd_name))) { - continue; - } - - while (readdir_r(fd_dirp, &fd_dbuf, &fd_ent) == 0) { - char fd_ent_name[BUFSIZ]; - - if (fd_ent == NULL) { - break; - } - - if (!sigar_isdigit(*fd_ent->d_name)) { - continue; - } - - /* sprintf(fd_ent_name, "%s/%s", fd_name, fd_ent->d_name) */ - slen = strlen(fd_ent->d_name); - memcpy(&fd_ent_name[0], fd_name, len); - fd_ent_name[len] = '/'; - memcpy(&fd_ent_name[len+1], fd_ent->d_name, slen); - fd_ent_name[len+1+slen] = '\0'; - - if (stat(fd_ent_name, &sb) < 0) { - continue; - } - - if (sb.st_ino == netconn.inode) { - closedir(fd_dirp); - closedir(dirp); - *pid = strtoul(ent->d_name, NULL, 10); - return SIGAR_OK; - } - - } - - closedir(fd_dirp); - } - - closedir(dirp); - - return SIGAR_OK; -} - -static void generic_vendor_parse(char *line, sigar_sys_info_t *info) -{ - char *ptr; - int len = 0; - - while (*line) { - SIGAR_SKIP_SPACE(line); - if (!isdigit(*line)) { - ++line; - continue; - } - - ptr = line; - while ((isdigit(*ptr) || (*ptr == '.'))) { - ++ptr; - ++len; - } - - if (len) { - /* sanity check */ - if (len > sizeof(info->vendor_version)) { - continue; - } - memcpy(info->vendor_version, line, len);/*XXX*/ - info->vendor_version[len] = '\0'; - return; - } - } -} - -static void redhat_vendor_parse(char *line, sigar_sys_info_t *info) -{ - char *start, *end; - - generic_vendor_parse(line, info); /* super.parse */ - - if ((start = strchr(line, '('))) { - ++start; - if ((end = strchr(start, ')'))) { - int len = end-start; - memcpy(info->vendor_code_name, start, len);/*XXX*/ - info->vendor_code_name[len] = '\0'; - } - } - -#define RHEL_PREFIX "Red Hat Enterprise Linux " -#define CENTOS_VENDOR "CentOS" -#define SL_VENDOR "Scientific Linux" - - if (strnEQ(line, RHEL_PREFIX, sizeof(RHEL_PREFIX)-1)) { - snprintf(info->vendor_version, - sizeof(info->vendor_version), - "Enterprise Linux %c", - info->vendor_version[0]); - } - else if (strnEQ(line, CENTOS_VENDOR, sizeof(CENTOS_VENDOR)-1)) { - SIGAR_SSTRCPY(info->vendor, CENTOS_VENDOR); - } - else if (strnEQ(line, SL_VENDOR, sizeof(SL_VENDOR)-1)) { - SIGAR_SSTRCPY(info->vendor, SL_VENDOR); - } -} - -#define is_quote(c) ((c == '\'') || (c == '"')) - -static void kv_parse(char *data, sigar_sys_info_t *info, - void (*func)(sigar_sys_info_t *, char *, char *)) -{ - char *ptr = data; - int len = strlen(data); - char *end = data+len; - - while (ptr < end) { - char *val = strchr(ptr, '='); - int klen, vlen; - char key[256], *ix; - - if (!val) { - continue; - } - klen = val - ptr; - SIGAR_SSTRCPY(key, ptr); - key[klen] = '\0'; - ++val; - - if ((ix = strchr(val, '\n'))) { - *ix = '\0'; - } - vlen = strlen(val); - if (is_quote(*val)) { - if (is_quote(val[vlen-1])) { - val[vlen-1] = '\0'; - } - ++val; - } - - func(info, key, val); - - ptr += (klen + 1 + vlen + 1); - } -} - -static void lsb_parse(sigar_sys_info_t *info, - char *key, char *val) -{ - if (strEQ(key, "DISTRIB_ID")) { - SIGAR_SSTRCPY(info->vendor, val); - } - else if (strEQ(key, "DISTRIB_RELEASE")) { - SIGAR_SSTRCPY(info->vendor_version, val); - } - else if (strEQ(key, "DISTRIB_CODENAME")) { - SIGAR_SSTRCPY(info->vendor_code_name, val); - } -} - -static void lsb_vendor_parse(char *data, sigar_sys_info_t *info) -{ - kv_parse(data, info, lsb_parse); -} - -static void xen_parse(sigar_sys_info_t *info, - char *key, char *val) -{ - if (strEQ(key, "PRODUCT_VERSION")) { - SIGAR_SSTRCPY(info->vendor_version, val); - } - else if (strEQ(key, "KERNEL_VERSION")) { - SIGAR_SSTRCPY(info->version, val); - } -} - -static void xen_vendor_parse(char *data, sigar_sys_info_t *info) -{ - kv_parse(data, info, xen_parse); - - snprintf(info->description, - sizeof(info->description), - "XenServer %s", - info->vendor_version); -} - -typedef struct { - const char *name; - const char *file; - void (*parse)(char *, sigar_sys_info_t *); -} linux_vendor_info_t; - -static linux_vendor_info_t linux_vendors[] = { - { "Fedora", "/etc/fedora-release", NULL }, - { "SuSE", "/etc/SuSE-release", NULL }, - { "Gentoo", "/etc/gentoo-release", NULL }, - { "Slackware", "/etc/slackware-version", NULL }, - { "Mandrake", "/etc/mandrake-release", NULL }, - { "VMware", "/proc/vmware/version", NULL }, - { "XenSource", "/etc/xensource-inventory", xen_vendor_parse }, - { "Red Hat", "/etc/redhat-release", redhat_vendor_parse }, - { "lsb", "/etc/lsb-release", lsb_vendor_parse }, - { "Debian", "/etc/debian_version", NULL }, - { NULL } -}; - -static int get_linux_vendor_info(sigar_sys_info_t *info) -{ - int i, status = ENOENT; - /* env vars for testing */ - const char *release_file = getenv("SIGAR_OS_RELEASE_FILE"); - const char *vendor_name = getenv("SIGAR_OS_VENDOR_NAME"); - char buffer[8192], *data; - linux_vendor_info_t *vendor = NULL; - - for (i=0; linux_vendors[i].name; i++) { - struct stat sb; - vendor = &linux_vendors[i]; - - if (release_file && vendor_name) { - if (!strEQ(vendor->name, vendor_name)) { - continue; - } - } - else { - if (stat(vendor->file, &sb) < 0) { - continue; - } - release_file = vendor->file; - } - - status = - sigar_file2str(release_file, buffer, sizeof(buffer)-1); - - break; - } - - if (status != SIGAR_OK) { - return status; - } - - data = buffer; - - SIGAR_SSTRCPY(info->vendor, vendor->name); - - if (vendor->parse) { - vendor->parse(data, info); - } - else { - generic_vendor_parse(data, info); - } - - if (info->description[0] == '\0') { - snprintf(info->description, - sizeof(info->description), - "%s %s", - info->vendor, info->vendor_version); - } - - return SIGAR_OK; -} - -int sigar_os_sys_info_get(sigar_t *sigar, - sigar_sys_info_t *sysinfo) -{ - - get_linux_vendor_info(sysinfo); - - return SIGAR_OK; -} diff --git a/vendor/sigar/src/os/linux/sigar_os.h b/vendor/sigar/src/os/linux/sigar_os.h deleted file mode 100644 index 29a2ba3..0000000 --- a/vendor/sigar/src/os/linux/sigar_os.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2004-2008 Hyperic, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SIGAR_OS_H -#define SIGAR_OS_H - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -typedef struct { - sigar_pid_t pid; - time_t mtime; - sigar_uint64_t vsize; - sigar_uint64_t rss; - sigar_uint64_t minor_faults; - sigar_uint64_t major_faults; - sigar_uint64_t ppid; - int tty; - int priority; - int nice; - sigar_uint64_t start_time; - sigar_uint64_t utime; - sigar_uint64_t stime; - char name[SIGAR_PROC_NAME_LEN]; - char state; - int processor; -} linux_proc_stat_t; - -typedef enum { - IOSTAT_NONE, - IOSTAT_PARTITIONS, /* 2.4 */ - IOSTAT_DISKSTATS, /* 2.6 */ - IOSTAT_SYS /* 2.6 */ -} linux_iostat_e; - -struct sigar_t { - SIGAR_T_BASE; - int pagesize; - int ram; - int proc_signal_offset; - linux_proc_stat_t last_proc_stat; - int lcpu; - linux_iostat_e iostat; - char *proc_net; - /* Native POSIX Thread Library 2.6+ kernel */ - int has_nptl; -}; - -#define HAVE_STRERROR_R -#ifndef __USE_XOPEN2K -/* use gnu version of strerror_r */ -#define HAVE_STRERROR_R_GLIBC -#endif -#define HAVE_READDIR_R -#define HAVE_GETPWNAM_R -#define HAVE_GETPWUID_R -#define HAVE_GETGRGID_R - -#endif /* SIGAR_OS_H */ diff --git a/vendor/sigar/src/os/solaris/get_mib2.c b/vendor/sigar/src/os/solaris/get_mib2.c deleted file mode 100644 index fbcadc6..0000000 --- a/vendor/sigar/src/os/solaris/get_mib2.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * get_mib2() -- get MIB2 information from Solaris 2.[3-7] kernel - * - * V. Abell - * Purdue University Computing Center - */ - - -/* - * Copyright 1995 Purdue Research Foundation, West Lafayette, Indiana - * 47907. All rights reserved. - * - * Written by Victor A. Abell - * - * This software is not subject to any license of the American Telephone - * and Telegraph Company or the Regents of the University of California. - * - * Permission is granted to anyone to use this software for any purpose on - * any computer system, and to alter it and redistribute it freely, subject - * to the following restrictions: - * - * 1. Neither Victor A Abell nor Purdue University are responsible for - * any consequences of the use of this software. - * - * 2. The origin of this software must not be misrepresented, either by - * explicit claim or by omission. Credit to Victor A. Abell and Purdue - * University must appear in documentation and sources. - * - * 3. Altered versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 4. This notice may not be removed or altered. - */ - -/* - * Altered for sigar: - * - remove static stuff to make thread-safe by Doug MacEachern (3/11/05) - */ - -#if 0 /*ndef lint -Wall -Werror*/ -static char copyright[] = -"@(#) Copyright 1995 Purdue Research Foundation.\nAll rights reserved.\n"; -#endif - -#include "get_mib2.h" - -#include -#include -#include -#include -#include -#include - -#ifdef DMALLOC -#include -#endif - -/* - * close_mib2() - close MIB2 access - * - * return: - * - * exit = GET_MIB2_OK if close succeeded - * GET_MIB2_* is the error code. - */ - -int -close_mib2(solaris_mib2_t *mib2) -{ - if (mib2->sd < 0) { - (void) strcpy(mib2->errmsg, "close_mib2: socket not open"); - return(GET_MIB2_ERR_NOTOPEN); - } - if (close(mib2->sd)) { - (void) sprintf(mib2->errmsg, "close_mib2: %s", strerror(errno)); - return(GET_MIB2_ERR_CLOSE); - } - mib2->sd = -1; - if (mib2->db_len && mib2->db) { - mib2->db_len = 0; - free((void *)mib2->db); - mib2->db = NULL; - } - if (mib2->smb_len && mib2->smb) { - mib2->smb_len = 0; - free((void *)mib2->smb); - mib2->smb = NULL; - } - return(GET_MIB2_OK); -} - - -/* - * get_mib2() - get MIB2 data - * - * return: - * - * exit = GET_MIB2_OK if get succeeded, and: - * *opt = opthdr structure address - * *data = data buffer address - * *datalen = size of data buffer - * GET_MIB2_* is the error code for failure. - */ - -int -get_mib2(solaris_mib2_t *mib2, - struct opthdr **opt, - char **data, - int *datalen) -{ - struct strbuf d; /* streams data buffer */ - int err; /* error code */ - int f; /* flags */ - int rc; /* reply code */ - - /* - * If MIB2 access isn't open, open it and issue the preliminary stream - * messages. - */ - if (mib2->sd < 0) { - /* - * Open access. Return on error. - */ - if ((err = open_mib2(mib2))) { - return(err); - } - /* - * Set up message request and option. - */ - mib2->req = (struct T_optmgmt_req *)mib2->smb; - mib2->op = (struct opthdr *)&mib2->smb[sizeof(struct T_optmgmt_req)]; - mib2->req->PRIM_type = T_OPTMGMT_REQ; - mib2->req->OPT_offset = sizeof(struct T_optmgmt_req); - mib2->req->OPT_length = sizeof(struct opthdr); - -#if defined(MI_T_CURRENT) - mib2->req->MGMT_flags = MI_T_CURRENT; -#else /* !defined(MI_T_CURRENT) */ -# if defined(T_CURRENT) - mib2->req->MGMT_flags = T_CURRENT; -# else /* !defined(T_CURRENT) */ -#error "Neither MI_T_CURRENT nor T_CURRENT are defined." -# endif /* defined(T_CURRENT) */ -#endif /* defined(MI_T_CURRENT) */ - - mib2->op->level = MIB2_IP; - mib2->op->name = mib2->op->len = 0; - mib2->ctlbuf.buf = mib2->smb; - mib2->ctlbuf.len = mib2->req->OPT_offset + mib2->req->OPT_length; - /* - * Put the message. - */ - if (putmsg(mib2->sd, &mib2->ctlbuf, (struct strbuf *)NULL, 0) == -1) { - (void) sprintf(mib2->errmsg, - "get_mib2: putmsg request: %s", strerror(errno)); - return(GET_MIB2_ERR_PUTMSG); - } - /* - * Set up to process replies. - */ - mib2->op_ack = (struct T_optmgmt_ack *)mib2->smb; - mib2->ctlbuf.maxlen = mib2->smb_len; - mib2->err_ack = (struct T_error_ack *)mib2->smb; - mib2->op = (struct opthdr *)&mib2->smb[sizeof(struct T_optmgmt_ack)]; - } - /* - * Get the next (first) reply message. - */ - f = 0; - if ((rc = getmsg(mib2->sd, &mib2->ctlbuf, NULL, &f)) < 0) { - (void) sprintf(mib2->errmsg, "get_mib2: getmsg(reply): %s", - strerror(errno)); - return(GET_MIB2_ERR_GETMSGR); - } - /* - * Check for end of data. - */ - if (rc == 0 - && mib2->ctlbuf.len >= sizeof(struct T_optmgmt_ack) - && mib2->op_ack->PRIM_type == T_OPTMGMT_ACK - && mib2->op_ack->MGMT_flags == T_SUCCESS - && mib2->op->len == 0) - { - err = close_mib2(mib2); - if (err) { - return(err); - } - return(GET_MIB2_EOD); - } - /* - * Check for error. - */ - if (mib2->ctlbuf.len >= sizeof(struct T_error_ack) - && mib2->err_ack->PRIM_type == T_ERROR_ACK) - { - (void) sprintf(mib2->errmsg, - "get_mib2: T_ERROR_ACK: len=%d, TLI=%#x, UNIX=%#x", - mib2->ctlbuf.len, - (int)mib2->err_ack->TLI_error, - (int)mib2->err_ack->UNIX_error); - return(GET_MIB2_ERR_ACK); - } - /* - * Check for no data. - */ - if (rc != MOREDATA - || mib2->ctlbuf.len < sizeof(struct T_optmgmt_ack) - || mib2->op_ack->PRIM_type != T_OPTMGMT_ACK - || mib2->op_ack->MGMT_flags != T_SUCCESS) - { - (void) sprintf(mib2->errmsg, - "get_mib2: T_OPTMGMT_ACK: " - "rc=%d len=%d type=%#x flags=%#x", - rc, mib2->ctlbuf.len, - (int)mib2->op_ack->PRIM_type, - (int)mib2->op_ack->MGMT_flags); - return(GET_MIB2_ERR_NODATA); - } - /* - * Allocate (or enlarge) the data buffer. - */ - if (mib2->op->len >= mib2->db_len) { - mib2->db_len = mib2->op->len; - if (mib2->db == NULL) { - mib2->db = (char *)malloc(mib2->db_len); - } - else { - mib2->db = (char *)realloc(mib2->db, mib2->db_len); - } - if (mib2->db == NULL) { - (void) sprintf(mib2->errmsg, - "get_mib2: no space for %d byte data buffer", - mib2->db_len); - return(GET_MIB2_ERR_NOSPC); - } - } - /* - * Get the data part of the message -- the MIB2 part. - */ - d.maxlen = mib2->op->len; - d.buf = mib2->db; - d.len = 0; - f = 0; - if ((rc = getmsg(mib2->sd, NULL, &d, &f)) < 0) { - (void) sprintf(mib2->errmsg, "get_mib2: getmsg(data): %s", - strerror(errno)); - return(GET_MIB2_ERR_GETMSGD); - } - if (rc) { - (void) sprintf(mib2->errmsg, - "get_mib2: getmsg(data): rc=%d maxlen=%d len=%d: %s", - rc, d.maxlen, d.len, strerror(errno)); - return(GET_MIB2_ERR_GETMSGD); - } - /* - * Compose a successful return. - */ - *opt = mib2->op; - *data = mib2->db; - *datalen = d.len; - return(GET_MIB2_OK); -} - - -/* - * open_mib2() - open access to MIB2 data - * - * return: - * - * exit = GET_MIB2_OK if open succeeded - * GET_MIB2_* is the error code for failure. - */ - -int -open_mib2(solaris_mib2_t *mib2) -{ - /* - * It's an error if the stream device is already open. - */ - if (mib2->sd >= 0) { - (void) strcpy(mib2->errmsg, "open_mib2: MIB2 access already open"); - return(GET_MIB2_ERR_OPEN); - } - /* - * Open the ARP stream device, push TCP and UDP on it. - */ - if ((mib2->sd = open(GET_MIB2_ARPDEV, O_RDWR, 0600)) < 0) { - (void) sprintf(mib2->errmsg, "open_mib2: %s: %s", GET_MIB2_ARPDEV, - strerror(errno)); - return(GET_MIB2_ERR_ARPOPEN); - } - if (ioctl(mib2->sd, I_PUSH, GET_MIB2_TCPSTREAM) == -1) { - (void) sprintf(mib2->errmsg, "open_mib2: push %s: %s", - GET_MIB2_TCPSTREAM, strerror(errno)); - return(GET_MIB2_ERR_TCPPUSH); - } - if (ioctl(mib2->sd, I_PUSH, GET_MIB2_UDPSTREAM) == -1) { - (void) sprintf(mib2->errmsg, "open_mib2: push %s: %s", - GET_MIB2_UDPSTREAM, strerror(errno)); - return(GET_MIB2_ERR_UDPPUSH); - } - /* - * Allocate a stream message buffer. - */ - mib2->smb_len = sizeof(struct opthdr) + sizeof(struct T_optmgmt_req); - if (mib2->smb_len < (sizeof (struct opthdr) + sizeof(struct T_optmgmt_ack))) { - mib2->smb_len = sizeof (struct opthdr) + sizeof(struct T_optmgmt_ack); - } - if (mib2->smb_len < sizeof(struct T_error_ack)) { - mib2->smb_len = sizeof(struct T_error_ack); - } - if ((mib2->smb = (char *)malloc(mib2->smb_len)) == NULL) { - (void) strcpy(mib2->errmsg, - "open_mib2: no space for stream message buffer"); - return(GET_MIB2_ERR_NOSPC); - } - /* - * All is OK. Return that indication. - */ - return(GET_MIB2_OK); -} diff --git a/vendor/sigar/src/os/solaris/get_mib2.h b/vendor/sigar/src/os/solaris/get_mib2.h deleted file mode 100644 index 53116c5..0000000 --- a/vendor/sigar/src/os/solaris/get_mib2.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * get_mib2.h -- definitions for the get_mib2() function - * - * V. Abell - * Purdue University Computing Center - */ - - -/* - * Copyright 1995 Purdue Research Foundation, West Lafayette, Indiana - * 47907. All rights reserved. - * - * Written by Victor A. Abell - * - * This software is not subject to any license of the American Telephone - * and Telegraph Company or the Regents of the University of California. - * - * Permission is granted to anyone to use this software for any purpose on - * any computer system, and to alter it and redistribute it freely, subject - * to the following restrictions: - * - * 1. Neither Victor A Abell nor Purdue University are responsible for - * any consequences of the use of this software. - * - * 2. The origin of this software must not be misrepresented, either by - * explicit claim or by omission. Credit to Victor A. Abell and Purdue - * University must appear in documentation and sources. - * - * 3. Altered versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 4. This notice may not be removed or altered. - */ - -/* - * Altered for sigar: - * - remove static stuff to make thread-safe by Doug MacEachern (3/11/05) - */ - -#if !defined(GET_MIB2_H) -#define GET_MIB2_H - - -/* - * Required header files - */ - -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * Miscellaneous definitions - */ - -#define GET_MIB2_ARPDEV "/dev/arp" /* ARP stream devi9ce */ -#define GET_MIB2_ERRMSGL 1024 /* ErrMsg buffer length */ -#define GET_MIB2_TCPSTREAM "tcp" /* TCP stream name */ -#define GET_MIB2_UDPSTREAM "udp" /* UDP stream name */ - - -/* - * get_mib2() response codes - * - * -1 End of MIB2 information - * 0 Next MIB2 structure returned - * >0 Error code - */ - -#define GET_MIB2_EOD -1 /* end of data */ -#define GET_MIB2_OK 0 /* function succeeded */ -#define GET_MIB2_ERR_ACK 1 /* getmsg() ACK error received */ -#define GET_MIB2_ERR_ARPOPEN 2 /* error opening ARPDEV */ -#define GET_MIB2_ERR_CLOSE 3 /* MIB2 access close error */ -#define GET_MIB2_ERR_GETMSGD 4 /* error getting message data */ -#define GET_MIB2_ERR_GETMSGR 5 /* error getting message reply */ -#define GET_MIB2_ERR_NODATA 6 /* data expected; not received */ -#define GET_MIB2_ERR_NOSPC 7 /* no malloc() space */ -#define GET_MIB2_ERR_NOTOPEN 8 /* MIB2 access not open */ -#define GET_MIB2_ERR_OPEN 9 /* MIB2 access open error */ -#define GET_MIB2_ERR_PUTMSG 10 /* error putting request message */ -#define GET_MIB2_ERR_TCPPUSH 11 /* error pushing TCPSTREAM */ -#define GET_MIB2_ERR_UDPPUSH 12 /* error pushing UDPSTREAM */ - -#define GET_MIB2_ERR_MAX 13 /* maximum error number + 1 */ - - -typedef struct { - char *db; /* data buffer */ - int db_len; /* data buffer length */ - char *smb; /* stream message buffer */ - size_t smb_len; /* size of Smb[] */ - int sd; /* stream device descriptor */ - char errmsg[GET_MIB2_ERRMSGL]; /* error message buffer */ - struct T_optmgmt_ack *op_ack; /* message ACK pointer */ - struct strbuf ctlbuf; /* streams control buffer */ - struct T_error_ack *err_ack; /* message error pointer */ - struct opthdr *op; /* message option pointer */ - struct T_optmgmt_req *req; /* message request pointer */ -} solaris_mib2_t; - -/* - * Function prototypes - */ - -int close_mib2( /* close acccess to MIB2 information */ - solaris_mib2_t *mib2 - ); -int get_mib2( /* get MIB2 information */ - solaris_mib2_t *mib2, - struct opthdr **opt, /* opthdr pointer return (see - * */ - char **data, /* data buffer return address */ - int *datalen /* data buffer length return - * address */ - ); -int open_mib2( /* open acccess to MIB2 information */ - solaris_mib2_t *mib2 - ); - -#endif /* !defined(GET_MIB2_H) */ diff --git a/vendor/sigar/src/os/solaris/kstats.c b/vendor/sigar/src/os/solaris/kstats.c deleted file mode 100644 index a04ff09..0000000 --- a/vendor/sigar/src/os/solaris/kstats.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2004-2007 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sigar.h" -#include "sigar_private.h" -#include "sigar_util.h" -#include "sigar_os.h" - -int sigar_get_kstats(sigar_t *sigar) -{ - kstat_ctl_t *kc = sigar->kc; - unsigned int i, id, ncpu = sysconf(_SC_NPROCESSORS_CONF); - int is_debug = SIGAR_LOG_IS_DEBUG(sigar); - - if (ncpu != sigar->ncpu) { - if (!sigar->ks.lcpu) { - /* init */ - sigar->ks.lcpu = ncpu; - sigar->ks.cpu = malloc(sizeof(*(sigar->ks.cpu)) * ncpu); - sigar->ks.cpu_info = malloc(sizeof(*(sigar->ks.cpu_info)) * ncpu); - sigar->ks.cpuid = malloc(sizeof(*(sigar->ks.cpuid)) * ncpu); - } - else { - sigar_log_printf(sigar, SIGAR_LOG_INFO, - "ncpu changed from %d to %d", - sigar->ncpu, ncpu); - if (ncpu > sigar->ks.lcpu) { - /* one or more cpus have been added */ - sigar->ks.cpu = realloc(sigar->ks.cpu, - sizeof(*(sigar->ks.cpu)) * ncpu); - sigar->ks.cpu_info = realloc(sigar->ks.cpu_info, - sizeof(*(sigar->ks.cpu_info)) * ncpu); - sigar->ks.cpuid = realloc(sigar->ks.cpuid, - sizeof(*(sigar->ks.cpuid)) * ncpu); - sigar->ks.lcpu = ncpu; - } - /* else or more cpus have been removed */ - } - - sigar->ncpu = ncpu; - - /* from man p_online: - * ``Processor numbers are integers, - * greater than or equal to 0, - * and are defined by the hardware platform. - * Processor numbers are not necessarily contiguous, - * but "not too sparse."`` - * so we maintain our own mapping in ks.cpuid[] - */ - - /* lookup in order, which kstat chain may not be in */ - for (i=0, id=0; iks.cpu_info[i] = cpu_info; - sigar->ks.cpu[i] = cpu_stat; - sigar->ks.cpuid[i] = id; - - if (is_debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "cpu %d id=%d", i, sigar->ks.cpuid[i]); - } - i++; - } - } - - sigar->ks.system = kstat_lookup(kc, "unix", -1, "system_misc"); - sigar->ks.syspages = kstat_lookup(kc, "unix", -1, "system_pages"); - sigar->ks.mempages = kstat_lookup(kc, "bunyip", -1, "mempages"); - - return SIGAR_OK; -} - -SIGAR_INLINE kid_t sigar_kstat_update(sigar_t *sigar) -{ - kid_t id = kstat_chain_update(sigar->kc); - - switch (id) { - case -1: - sigar_log_printf(sigar, SIGAR_LOG_ERROR, - "kstat_chain_update error: %s", - sigar_strerror(sigar, errno)); - break; - case 0: - /* up-to-date */ - break; - default: - sigar_get_kstats(sigar); - sigar_log(sigar, SIGAR_LOG_DEBUG, - "kstat chain updated"); - break; - } - - return id; -} - -/* - * bincompat is not possible with certain kstat data structures between - * solaris 2.6, 2.7, 2.8, etc. alternative is to use kstat_data_lookup() - * which means everytime we want a stat, must do a linear search - * of ksp->ks_data. eek. so we meet half way and do the search for - * each key once per sigar_t instance. once the initial search has - * been done, we have a table of offsets to quickly access the stats via - * ksp->ks_data + offset. this gives us bincompat without the overhead - * of many kstat_data_lookup calls. - */ -static SIGAR_INLINE int kstat_named_offset(kstat_t *ksp, const char *name) -{ - unsigned int i; - kstat_named_t *kn; - - for (i=0, kn=ksp->ks_data; - iks_ndata; - i++, kn++) - { - if (strEQ(kn->name, name)) { - return i; - } - } - - return -2; /* not found */ -} - -static char *kstat_keys_system[] = { - "boot_time", - "avenrun_1min", - "avenrun_5min", - "avenrun_15min", - NULL -}; - -static char *kstat_keys_mempages[] = { - "pages_anon", - "pages_exec", - "pages_vnode", - NULL -}; - -static char *kstat_keys_syspages[] = { - "pagesfree", - NULL -}; - -static char **kstat_keys[] = { - kstat_keys_system, - kstat_keys_mempages, - kstat_keys_syspages, -}; - -void sigar_koffsets_lookup(kstat_t *ksp, int *offsets, int kidx) -{ - int i; - char **keys = kstat_keys[kidx]; - - for (i=0; keys[i]; i++) { - offsets[i] = kstat_named_offset(ksp, keys[i]); - } -} - diff --git a/vendor/sigar/src/os/solaris/procfs.c b/vendor/sigar/src/os/solaris/procfs.c deleted file mode 100644 index 743bd5b..0000000 --- a/vendor/sigar/src/os/solaris/procfs.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2004, 2006 Hyperic, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sigar.h" -#include "sigar_private.h" -#include "sigar_util.h" -#include "sigar_os.h" - -#define my_pread(fd, ptr, type, offset) \ - (pread(fd, ptr, sizeof(type), offset) == sizeof(type)) - -int sigar_proc_psinfo_get(sigar_t *sigar, sigar_pid_t pid) -{ - int fd, retval = SIGAR_OK; - char buffer[BUFSIZ]; - time_t timenow = time(NULL); - - if (sigar->pinfo == NULL) { - sigar->pinfo = malloc(sizeof(*sigar->pinfo)); - } - - if (sigar->last_pid == pid) { - if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) { - return SIGAR_OK; - } - } - - sigar->last_pid = pid; - sigar->last_getprocs = timenow; - - (void)SIGAR_PROC_FILENAME(buffer, pid, "/psinfo"); - - if ((fd = open(buffer, O_RDONLY)) < 0) { - return ESRCH; - } - - if (!my_pread(fd, sigar->pinfo, psinfo_t, 0)) { - retval = errno; - } - - close(fd); - - return retval; -} - -int sigar_proc_usage_get(sigar_t *sigar, prusage_t *prusage, sigar_pid_t pid) -{ - int fd, retval = SIGAR_OK; - char buffer[BUFSIZ]; - - (void)SIGAR_PROC_FILENAME(buffer, pid, "/usage"); - - if ((fd = open(buffer, O_RDONLY)) < 0) { - return ESRCH; - } - - if (!my_pread(fd, prusage, prusage_t, 0)) { - retval = errno; - } - - close(fd); - - return retval; -} - -int sigar_proc_status_get(sigar_t *sigar, pstatus_t *pstatus, sigar_pid_t pid) -{ - int fd, retval = SIGAR_OK; - char buffer[BUFSIZ]; - - (void)SIGAR_PROC_FILENAME(buffer, pid, "/status"); - - if ((fd = open(buffer, O_RDONLY)) < 0) { - return ESRCH; - } - - if (!my_pread(fd, pstatus, pstatus_t, 0)) { - retval = errno; - } - - close(fd); - - return retval; -} diff --git a/vendor/sigar/src/os/solaris/sigar_os.h b/vendor/sigar/src/os/solaris/sigar_os.h deleted file mode 100644 index 73115d8..0000000 --- a/vendor/sigar/src/os/solaris/sigar_os.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2004-2007 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SIGAR_OS_H -#define SIGAR_OS_H - -#ifndef _POSIX_PTHREAD_SEMANTICS -#define _POSIX_PTHREAD_SEMANTICS -#endif - -typedef unsigned long long int u_int64_t; - -#include -#include -#ifndef DMALLOC -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "get_mib2.h" - -/* avoid -Wall warning since solaris doesnt have a prototype for this */ -int getdomainname(char *, int); - -typedef struct { - kstat_t **ks; - int num; - char *name; - int nlen; -} kstat_list_t; - -SIGAR_INLINE kid_t sigar_kstat_update(sigar_t *sigar); - -int sigar_get_kstats(sigar_t *sigar); - -void sigar_init_multi_kstats(sigar_t *sigar); - -void sigar_free_multi_kstats(sigar_t *sigar); - -int sigar_get_multi_kstats(sigar_t *sigar, - kstat_list_t *kl, - const char *name, - kstat_t **retval); - -void sigar_koffsets_lookup(kstat_t *ksp, int *offsets, int kidx); - -int sigar_proc_psinfo_get(sigar_t *sigar, sigar_pid_t pid); - -int sigar_proc_usage_get(sigar_t *sigar, prusage_t *prusage, sigar_pid_t pid); - -int sigar_proc_status_get(sigar_t *sigar, pstatus_t *pstatus, sigar_pid_t pid); - -#define CPU_ONLINE(n) \ - (p_online(n, P_STATUS) == P_ONLINE) - -typedef enum { - KSTAT_SYSTEM_BOOT_TIME, - KSTAT_SYSTEM_LOADAVG_1, - KSTAT_SYSTEM_LOADAVG_2, - KSTAT_SYSTEM_LOADAVG_3, - KSTAT_SYSTEM_MAX -} kstat_system_off_e; - -typedef enum { - KSTAT_MEMPAGES_ANON, - KSTAT_MEMPAGES_EXEC, - KSTAT_MEMPAGES_VNODE, - KSTAT_MEMPAGES_MAX -} kstat_mempages_off_e; - -typedef enum { - KSTAT_SYSPAGES_FREE, - KSTAT_SYSPAGES_MAX -} kstat_syspages_off_e; - -enum { - KSTAT_KEYS_system, - KSTAT_KEYS_mempages, - KSTAT_KEYS_syspages, -} kstat_keys_e; - -typedef struct ps_prochandle * (*proc_grab_func_t)(pid_t, int, int *); - -typedef void (*proc_free_func_t)(struct ps_prochandle *); - -typedef int (*proc_create_agent_func_t)(struct ps_prochandle *); - -typedef void (*proc_destroy_agent_func_t)(struct ps_prochandle *); - -typedef void (*proc_objname_func_t)(struct ps_prochandle *, - uintptr_t, const char *, size_t); - -typedef char * (*proc_dirname_func_t)(const char *, char *, size_t); - -typedef char * (*proc_exename_func_t)(struct ps_prochandle *, char *, size_t); - -typedef int (*proc_fstat64_func_t)(struct ps_prochandle *, int, void *); - -typedef int (*proc_getsockopt_func_t)(struct ps_prochandle *, - int, int, int, void *, int *); - -typedef int (*proc_getsockname_func_t)(struct ps_prochandle *, - int, struct sockaddr *, socklen_t *); - -struct sigar_t { - SIGAR_T_BASE; - - int solaris_version; - int use_ucb_ps; - - kstat_ctl_t *kc; - - /* kstat_lookup() as needed */ - struct { - kstat_t **cpu; - kstat_t **cpu_info; - processorid_t *cpuid; - unsigned int lcpu; /* number malloced slots in the cpu array above */ - kstat_t *system; - kstat_t *syspages; - kstat_t *mempages; - } ks; - - struct { - int system[KSTAT_SYSTEM_MAX]; - int mempages[KSTAT_MEMPAGES_MAX]; - int syspages[KSTAT_SYSPAGES_MAX]; - } koffsets; - - int pagesize; - - time_t last_getprocs; - sigar_pid_t last_pid; - psinfo_t *pinfo; - sigar_cpu_list_t cpulist; - - /* libproc.so interface */ - void *plib; - proc_grab_func_t pgrab; - proc_free_func_t pfree; - proc_create_agent_func_t pcreate_agent; - proc_destroy_agent_func_t pdestroy_agent; - proc_objname_func_t pobjname; - proc_dirname_func_t pdirname; - proc_exename_func_t pexename; - proc_fstat64_func_t pfstat64; - proc_getsockopt_func_t pgetsockopt; - proc_getsockname_func_t pgetsockname; - - sigar_cache_t *pargs; - - solaris_mib2_t mib2; -}; - -#ifdef SIGAR_64BIT -#define KSTAT_UINT ui64 -#else -#define KSTAT_UINT ui32 -#endif - -#define kSTAT_exists(v, type) \ - (sigar->koffsets.type[v] != -2) - -#define kSTAT_ptr(v, type) \ - ((kstat_named_t *)ksp->ks_data + sigar->koffsets.type[v]) - -#define kSTAT_uint(v, type) \ - (kSTAT_exists(v, type) ? kSTAT_ptr(v, type)->value.KSTAT_UINT : 0) - -#define kSTAT_ui32(v, type) \ - (kSTAT_exists(v, type) ? kSTAT_ptr(v, type)->value.ui32 : 0) - -#define kSYSTEM(v) kSTAT_ui32(v, system) - -#define kMEMPAGES(v) kSTAT_uint(v, mempages) - -#define kSYSPAGES(v) kSTAT_uint(v, syspages) - -#define sigar_koffsets_init(sigar, ksp, type) \ - if (sigar->koffsets.type[0] == -1) \ - sigar_koffsets_lookup(ksp, sigar->koffsets.type, KSTAT_KEYS_##type) - -#define sigar_koffsets_init_system(sigar, ksp) \ - sigar_koffsets_init(sigar, ksp, system) - -#define sigar_koffsets_init_mempages(sigar, ksp) \ - sigar_koffsets_init(sigar, ksp, mempages) - -#define sigar_koffsets_init_syspages(sigar, ksp) \ - sigar_koffsets_init(sigar, ksp, syspages) - -#define HAVE_READDIR_R -#define HAVE_GETPWNAM_R -#define HAVE_GETPWUID_R - -#define SIGAR_EMIB2 (SIGAR_OS_START_ERROR+1) - -#endif /* SIGAR_OS_H */ - diff --git a/vendor/sigar/src/os/solaris/solaris_sigar.c b/vendor/sigar/src/os/solaris/solaris_sigar.c deleted file mode 100644 index da9a2b6..0000000 --- a/vendor/sigar/src/os/solaris/solaris_sigar.c +++ /dev/null @@ -1,2717 +0,0 @@ -/* - * Copyright (c) 2004-2008 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * Copyright (c) 2009-2010 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sigar.h" -#include "sigar_private.h" -#include "sigar_util.h" -#include "sigar_os.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PROC_ERRNO ((errno == ENOENT) ? ESRCH : errno) -#define SIGAR_USR_UCB_PS "/usr/ucb/ps" - - -/* like kstat_lookup but start w/ ksp->ks_next instead of kc->kc_chain */ -static kstat_t * -kstat_next(kstat_t *ksp, char *ks_module, int ks_instance, char *ks_name) -{ - if (ksp) { - ksp = ksp->ks_next; - } - for (; ksp; ksp = ksp->ks_next) { - if ((ks_module == NULL || - strcmp(ksp->ks_module, ks_module) == 0) && - (ks_instance == -1 || ksp->ks_instance == ks_instance) && - (ks_name == NULL || strcmp(ksp->ks_name, ks_name) == 0)) - return ksp; - } - - errno = ENOENT; - return NULL; -} - -int sigar_os_open(sigar_t **sig) -{ - kstat_ctl_t *kc; - kstat_t *ksp; - sigar_t *sigar; - int i, status; - struct utsname name; - char *ptr; - - sigar = malloc(sizeof(*sigar)); - *sig = sigar; - - sigar->log_level = -1; /* log nothing by default */ - sigar->log_impl = NULL; - sigar->log_data = NULL; - - uname(&name); - if ((ptr = strchr(name.release, '.'))) { - ptr++; - sigar->solaris_version = atoi(ptr); - } - else { - sigar->solaris_version = 6; - } - - if ((ptr = getenv("SIGAR_USE_UCB_PS"))) { - sigar->use_ucb_ps = strEQ(ptr, "true"); - } - else { - struct stat sb; - if (stat(SIGAR_USR_UCB_PS, &sb) < 0) { - sigar->use_ucb_ps = 0; - } - else { - sigar->use_ucb_ps = 1; - } - } - - sigar->pagesize = 0; - i = sysconf(_SC_PAGESIZE); - while ((i >>= 1) > 0) { - sigar->pagesize++; - } - - sigar->ticks = sysconf(_SC_CLK_TCK); - sigar->kc = kc = kstat_open(); - - if (!kc) { - return errno; - } - - sigar->cpulist.size = 0; - sigar->ncpu = 0; - sigar->ks.cpu = NULL; - sigar->ks.cpu_info = NULL; - sigar->ks.cpuid = NULL; - sigar->ks.lcpu = 0; - - sigar->koffsets.system[0] = -1; - sigar->koffsets.mempages[0] = -1; - sigar->koffsets.syspages[0] = -1; - - if ((status = sigar_get_kstats(sigar)) != SIGAR_OK) { - fprintf(stderr, "status=%d\n", status); - } - - sigar->boot_time = 0; - - if ((ksp = sigar->ks.system) && - (kstat_read(kc, ksp, NULL) >= 0)) - { - sigar_koffsets_init_system(sigar, ksp); - - sigar->boot_time = kSYSTEM(KSTAT_SYSTEM_BOOT_TIME); - } - - sigar->last_pid = -1; - sigar->pinfo = NULL; - - sigar->plib = NULL; - sigar->pgrab = NULL; - sigar->pfree = NULL; - sigar->pobjname = NULL; - - sigar->pargs = NULL; - - SIGAR_ZERO(&sigar->mib2); - sigar->mib2.sd = -1; - - return SIGAR_OK; -} - -int sigar_os_close(sigar_t *sigar) -{ - kstat_close(sigar->kc); - if (sigar->mib2.sd != -1) { - close_mib2(&sigar->mib2); - } - - if (sigar->ks.lcpu) { - free(sigar->ks.cpu); - free(sigar->ks.cpu_info); - free(sigar->ks.cpuid); - } - if (sigar->pinfo) { - free(sigar->pinfo); - } - if (sigar->cpulist.size != 0) { - sigar_cpu_list_destroy(sigar, &sigar->cpulist); - } - if (sigar->plib) { - dlclose(sigar->plib); - } - if (sigar->pargs) { - sigar_cache_destroy(sigar->pargs); - } - free(sigar); - return SIGAR_OK; -} - -char *sigar_os_error_string(sigar_t *sigar, int err) -{ - switch (err) { - case SIGAR_EMIB2: - return sigar->mib2.errmsg; - default: - return NULL; - } -} - -int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem) -{ - kstat_ctl_t *kc = sigar->kc; - kstat_t *ksp; - sigar_uint64_t kern = 0; - - SIGAR_ZERO(mem); - - /* XXX: is mem hot swappable or can we just do this during open ? */ - mem->total = sysconf(_SC_PHYS_PAGES); - mem->total <<= sigar->pagesize; - - if (sigar_kstat_update(sigar) == -1) { - return errno; - } - - if ((ksp = sigar->ks.syspages) && kstat_read(kc, ksp, NULL) >= 0) { - sigar_koffsets_init_syspages(sigar, ksp); - - mem->free = kSYSPAGES(KSTAT_SYSPAGES_FREE); - mem->free <<= sigar->pagesize; - - mem->used = mem->total - mem->free; - } - - if ((ksp = sigar->ks.mempages) && kstat_read(kc, ksp, NULL) >= 0) { - sigar_koffsets_init_mempages(sigar, ksp); - } - - /* XXX mdb ::memstat cachelist/freelist not available to kstat, see: */ - /* http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=6821980 */ - - /* ZFS ARC cache. see: http://opensolaris.org/jive/thread.jspa?messageID=393695 */ - if ((ksp = kstat_lookup(sigar->kc, "zfs", 0, "arcstats")) && - (kstat_read(sigar->kc, ksp, NULL) != -1)) - { - kstat_named_t *kn; - - if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "size"))) { - kern = kn->value.i64; - } - if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "c_min"))) { - /* c_min cannot be reclaimed they say */ - if (kern > kn->value.i64) { - kern -= kn->value.i64; - } - } - } - - mem->actual_free = mem->free + kern; - mem->actual_used = mem->used - kern; - - sigar_mem_calc_ram(sigar, mem); - - return SIGAR_OK; -} - -int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap) -{ - kstat_t *ksp; - kstat_named_t *kn; - swaptbl_t *stab; - int num, i; - char path[PATH_MAX+1]; /* {un,re}used */ - - /* see: man swapctl(2) */ - if ((num = swapctl(SC_GETNSWP, NULL)) == -1) { - return errno; - } - - stab = malloc(num * sizeof(stab->swt_ent[0]) + sizeof(*stab)); - - stab->swt_n = num; - for (i=0; iswt_ent[i].ste_path = path; - } - - if ((num = swapctl(SC_LIST, stab)) == -1) { - free(stab); - return errno; - } - - num = num < stab->swt_n ? num : stab->swt_n; - swap->total = swap->free = 0; - for (i=0; iswt_ent[i].ste_flags & ST_INDEL) { - continue; /* swap file is being deleted */ - } - swap->total += stab->swt_ent[i].ste_pages; - swap->free += stab->swt_ent[i].ste_free; - } - free(stab); - - swap->total <<= sigar->pagesize; - swap->free <<= sigar->pagesize; - swap->used = swap->total - swap->free; - - if (sigar_kstat_update(sigar) == -1) { - return errno; - } - if (!(ksp = kstat_lookup(sigar->kc, "cpu", -1, "vm"))) { - swap->page_in = swap->page_out = SIGAR_FIELD_NOTIMPL; - return SIGAR_OK; - } - - swap->page_in = swap->page_out = 0; - - /* XXX: these stats do not exist in this form on solaris 8 or 9. - * they are in the raw cpu_stat struct, but thats not - * binary compatible - */ - do { - if (kstat_read(sigar->kc, ksp, NULL) < 0) { - break; - } - - if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "pgin"))) { - swap->page_in += kn->value.i64; /* vmstat -s | grep "page ins" */ - } - if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "pgout"))) { - swap->page_out += kn->value.i64; /* vmstat -s | grep "page outs" */ - } - } while ((ksp = kstat_next(ksp, "cpu", -1, "vm"))); - - return SIGAR_OK; -} - -#ifndef KSTAT_NAMED_STR_PTR -/* same offset as KSTAT_NAMED_STR_PTR(brand) */ -#define KSTAT_NAMED_STR_PTR(n) (char *)((n)->value.i32) -#endif - -static int get_chip_brand(sigar_t *sigar, int processor, - sigar_cpu_info_t *info) -{ - kstat_t *ksp = sigar->ks.cpu_info[processor]; - kstat_named_t *brand; - - if (sigar->solaris_version < 10) { - /* don't bother; doesn't exist. */ - return 0; - } - - if (ksp && - (kstat_read(sigar->kc, ksp, NULL) != -1) && - (brand = (kstat_named_t *)kstat_data_lookup(ksp, "brand"))) - { - char *name = KSTAT_NAMED_STR_PTR(brand); - - char *vendor = "Sun"; - char *vendors[] = { - "Intel", "AMD", NULL - }; - int i; - - if (!name) { - return 0; - } - - for (i=0; vendors[i]; i++) { - if (strstr(name, vendors[i])) { - vendor = vendors[i]; - break; - } - } - - SIGAR_SSTRCPY(info->vendor, vendor); -#if 0 - SIGAR_SSTRCPY(info->model, name); - sigar_cpu_model_adjust(sigar, info); -#endif - return 1; - } - else { - return 0; - } -} - -static void free_chip_id(void *ptr) -{ - /*noop*/ -} - -static int get_chip_id(sigar_t *sigar, int processor) -{ - kstat_t *ksp = sigar->ks.cpu_info[processor]; - kstat_named_t *chipid; - - if (ksp && - (kstat_read(sigar->kc, ksp, NULL) != -1) && - (chipid = (kstat_named_t *)kstat_data_lookup(ksp, "chip_id"))) - { - return chipid->value.i32; - } - else { - return -1; - } -} - -int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu) -{ - int status, i; - - status = sigar_cpu_list_get(sigar, &sigar->cpulist); - - if (status != SIGAR_OK) { - return status; - } - - SIGAR_ZERO(cpu); - - for (i=0; icpulist.number; i++) { - sigar_cpu_t *xcpu = &sigar->cpulist.data[i]; - - cpu->user += xcpu->user; - cpu->sys += xcpu->sys; - cpu->idle += xcpu->idle; - cpu->nice += xcpu->nice; - cpu->wait += xcpu->wait; - cpu->total = xcpu->total; - } - - return SIGAR_OK; -} - -int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist) -{ - kstat_ctl_t *kc = sigar->kc; - kstat_t *ksp; - uint_t cpuinfo[CPU_STATES]; - unsigned int i; - int is_debug = SIGAR_LOG_IS_DEBUG(sigar); - sigar_cache_t *chips; - - if (sigar_kstat_update(sigar) == -1) { - return errno; - } - - if (cpulist == &sigar->cpulist) { - if (sigar->cpulist.size == 0) { - /* create once */ - sigar_cpu_list_create(cpulist); - } - else { - /* reset, re-using cpulist.data */ - sigar->cpulist.number = 0; - } - } - else { - sigar_cpu_list_create(cpulist); - } - - if (is_debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[cpu_list] OS reports %d CPUs", - sigar->ncpu); - } - - chips = sigar_cache_new(16); - chips->free_value = free_chip_id; - - for (i=0; incpu; i++) { - sigar_cpu_t *cpu; - char *buf; - int chip_id; - sigar_cache_entry_t *ent; - - if (!CPU_ONLINE(sigar->ks.cpuid[i])) { - sigar_log_printf(sigar, SIGAR_LOG_INFO, - "cpu %d (id=%d) is offline", - i, sigar->ks.cpuid[i]); - continue; - } - - if (!(ksp = sigar->ks.cpu[i])) { - sigar_log_printf(sigar, SIGAR_LOG_ERROR, - "NULL ksp for cpu %d (id=%d)", - i, sigar->ks.cpuid[i]); - continue; /* shouldnot happen */ - } - - if (kstat_read(kc, ksp, NULL) < 0) { - sigar_log_printf(sigar, SIGAR_LOG_ERROR, - "kstat_read failed for cpu %d (id=%d): %s", - i, sigar->ks.cpuid[i], - sigar_strerror(sigar, errno)); - continue; /* shouldnot happen */ - } - - /* - * cpu_stat_t is not binary compatible between solaris versions. - * since cpu_stat is a 'raw' kstat and not 'named' we cannot - * use name based lookups as we do for others. - * the start of the cpu_stat_t structure is binary compatible, - * which looks like so: - * typedef struct cpu_stat { - * kmutex_t cpu_stat_lock; - * cpu_sysinfo_t cpu_sysinfo; - * ... - * typedef struct cpu_sysinfo { - * ulong cpu[CPU_STATES]; - * ... - * we just copy the piece we need below: - */ - buf = ksp->ks_data; - buf += sizeof(kmutex_t); - memcpy(&cpuinfo[0], buf, sizeof(cpuinfo)); - chip_id = sigar->cpu_list_cores ? -1 : get_chip_id(sigar, i); - - if (chip_id == -1) { - SIGAR_CPU_LIST_GROW(cpulist); - cpu = &cpulist->data[cpulist->number++]; - SIGAR_ZERO(cpu); - } - else { - /* merge times of logical processors */ - ent = sigar_cache_get(chips, chip_id); - if (ent->value) { - cpu = &cpulist->data[(long)ent->value-1]; - } - else { - SIGAR_CPU_LIST_GROW(cpulist); - cpu = &cpulist->data[cpulist->number++]; - ent->value = (void *)(long)cpulist->number; - SIGAR_ZERO(cpu); - - if (is_debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[cpu_list] Merging times of" - " logical processors for chip_id=%d", - chip_id); - } - } - } - - cpu->user += SIGAR_TICK2MSEC(cpuinfo[CPU_USER]); - cpu->sys += SIGAR_TICK2MSEC(cpuinfo[CPU_KERNEL]); - cpu->idle += SIGAR_TICK2MSEC(cpuinfo[CPU_IDLE]); - cpu->wait += SIGAR_TICK2MSEC(cpuinfo[CPU_WAIT]); - cpu->nice += 0; /* no cpu->nice */ - cpu->total = cpu->user + cpu->sys + cpu->idle + cpu->wait; - } - - sigar_cache_destroy(chips); - - return SIGAR_OK; -} - -int sigar_uptime_get(sigar_t *sigar, - sigar_uptime_t *uptime) -{ - if (sigar->boot_time) { - uptime->uptime = time(NULL) - sigar->boot_time; - } - else { - uptime->uptime = 0; /* XXX: shouldn't happen */ - } - - return SIGAR_OK; -} - -static int loadavg_keys[] = { - KSTAT_SYSTEM_LOADAVG_1, - KSTAT_SYSTEM_LOADAVG_2, - KSTAT_SYSTEM_LOADAVG_3 -}; - -int sigar_loadavg_get(sigar_t *sigar, - sigar_loadavg_t *loadavg) -{ - kstat_t *ksp; - int i; - - if (sigar_kstat_update(sigar) == -1) { - return errno; - } - - if (!(ksp = sigar->ks.system)) { - return -1; - } - - if (kstat_read(sigar->kc, ksp, NULL) < 0) { - return -1; - } - - sigar_koffsets_init_system(sigar, ksp); - - for (i=0; i<3; i++) { - loadavg->loadavg[i] = (double)kSYSTEM(loadavg_keys[i]) / FSCALE; - } - - return SIGAR_OK; -} - -#define LIBPROC "/usr/lib/libproc.so" - -#define CHECK_PSYM(s) \ - if (!sigar->s) { \ - sigar_log_printf(sigar, SIGAR_LOG_WARN, \ - "[%s] Symbol not found: %s", \ - SIGAR_FUNC, #s); \ - dlclose(sigar->plib); \ - sigar->plib = NULL; \ - return SIGAR_ENOTIMPL; \ - } - -static char *proc_readlink(const char *name, char *buffer, size_t size) -{ - int len; - - if ((len = readlink(name, buffer, size-1)) < 0) { - return NULL; - } - - buffer[len] = '\0'; - return buffer; -} - -static int sigar_init_libproc(sigar_t *sigar) -{ - if (sigar->plib) { - return SIGAR_OK; - } - - /* libproc.so ships with 5.8+ */ - /* interface is undocumented, see libproc.h in the sun jdk sources */ - sigar->plib = dlopen(LIBPROC, RTLD_LAZY); - - if (!sigar->plib) { - sigar_log_printf(sigar, SIGAR_LOG_WARN, - "[%s] dlopen(%s) = %s", - SIGAR_FUNC, LIBPROC, dlerror()); - return SIGAR_ENOTIMPL; - } - - sigar->pgrab = (proc_grab_func_t)dlsym(sigar->plib, "Pgrab"); - sigar->pfree = (proc_free_func_t)dlsym(sigar->plib, "Pfree"); - sigar->pcreate_agent = (proc_create_agent_func_t)dlsym(sigar->plib, "Pcreate_agent"); - sigar->pdestroy_agent = (proc_destroy_agent_func_t)dlsym(sigar->plib, "Pdestroy_agent"); - sigar->pobjname = (proc_objname_func_t)dlsym(sigar->plib, "Pobjname"); - sigar->pexename = (proc_exename_func_t)dlsym(sigar->plib, "Pexecname"); - sigar->pdirname = (proc_dirname_func_t)dlsym(sigar->plib, "proc_dirname"); - sigar->pfstat64 = (proc_fstat64_func_t)dlsym(sigar->plib, "pr_fstat64"); - sigar->pgetsockopt = (proc_getsockopt_func_t)dlsym(sigar->plib, "pr_getsockopt"); - sigar->pgetsockname = (proc_getsockname_func_t)dlsym(sigar->plib, "pr_getsockname"); - - CHECK_PSYM(pgrab); - CHECK_PSYM(pfree); - CHECK_PSYM(pobjname); - - return SIGAR_OK; -} - -/* from libproc.h, not included w/ solaris distro */ -/* Error codes from Pgrab(), Pfgrab_core(), and Pgrab_core() */ -#define G_STRANGE -1 /* Unanticipated error, errno is meaningful */ -#define G_NOPROC 1 /* No such process */ -#define G_NOCORE 2 /* No such core file */ -#define G_NOPROCORCORE 3 /* No such proc or core (for proc_arg_grab) */ -#define G_NOEXEC 4 /* Cannot locate executable file */ -#define G_ZOMB 5 /* Zombie process */ -#define G_PERM 6 /* No permission */ -#define G_BUSY 7 /* Another process has control */ -#define G_SYS 8 /* System process */ -#define G_SELF 9 /* Process is self */ -#define G_INTR 10 /* Interrupt received while grabbing */ -#define G_LP64 11 /* Process is _LP64, self is ILP32 */ -#define G_FORMAT 12 /* File is not an ELF format core file */ -#define G_ELF 13 /* Libelf error, elf_errno() is meaningful */ -#define G_NOTE 14 /* Required PT_NOTE Phdr not present in core */ - -static int sigar_pgrab(sigar_t *sigar, sigar_pid_t pid, - const char *func, - struct ps_prochandle **phandle) -{ - int pstatus; - - if (!(*phandle = sigar->pgrab(pid, 0x01, &pstatus))) { - switch (pstatus) { - case G_NOPROC: - return ESRCH; - case G_PERM: - return EACCES; - default: - sigar_log_printf(sigar, SIGAR_LOG_ERROR, - "[%s] Pgrab error=%d", - func, pstatus); - return ENOTSUP; /*XXX*/ - } - } - - return SIGAR_OK; -} - -int sigar_os_proc_list_get(sigar_t *sigar, - sigar_proc_list_t *proclist) -{ - return sigar_proc_list_procfs_get(sigar, proclist); -} - -int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_mem_t *procmem) -{ - int status = sigar_proc_psinfo_get(sigar, pid); - psinfo_t *pinfo = sigar->pinfo; - prusage_t usage; - - if (status != SIGAR_OK) { - return status; - } - - procmem->size = pinfo->pr_size << 10; - procmem->resident = pinfo->pr_rssize << 10; - procmem->share = SIGAR_FIELD_NOTIMPL; - - if (sigar_proc_usage_get(sigar, &usage, pid) == SIGAR_OK) { - procmem->minor_faults = usage.pr_minf; - procmem->major_faults = usage.pr_majf; - procmem->page_faults = - procmem->minor_faults + - procmem->major_faults; - } - else { - procmem->minor_faults = SIGAR_FIELD_NOTIMPL; - procmem->major_faults = SIGAR_FIELD_NOTIMPL; - procmem->page_faults = SIGAR_FIELD_NOTIMPL; - } - - return SIGAR_OK; -} - -int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_cred_t *proccred) -{ - int status = sigar_proc_psinfo_get(sigar, pid); - psinfo_t *pinfo = sigar->pinfo; - - if (status != SIGAR_OK) { - return status; - } - - proccred->uid = pinfo->pr_uid; - proccred->gid = pinfo->pr_gid; - proccred->euid = pinfo->pr_euid; - proccred->egid = pinfo->pr_egid; - - return SIGAR_OK; -} - -#define TIMESTRUCT_2MSEC(t) \ - ((t.tv_sec * MILLISEC) + (t.tv_nsec / (NANOSEC/MILLISEC))) - -int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_time_t *proctime) -{ - prusage_t usage; - int status; - - if ((status = sigar_proc_usage_get(sigar, &usage, pid)) != SIGAR_OK) { - return status; - } - - proctime->start_time = usage.pr_create.tv_sec + sigar->boot_time; - proctime->start_time *= MILLISEC; - - if (usage.pr_utime.tv_sec < 0) { - /* XXX wtf? seen on solaris 10, only for the self process */ - pstatus_t pstatus; - - status = sigar_proc_status_get(sigar, &pstatus, pid); - if (status != SIGAR_OK) { - return status; - } - - usage.pr_utime.tv_sec = pstatus.pr_utime.tv_sec; - usage.pr_utime.tv_nsec = pstatus.pr_utime.tv_nsec; - usage.pr_stime.tv_sec = pstatus.pr_stime.tv_sec; - usage.pr_stime.tv_nsec = pstatus.pr_stime.tv_nsec; - } - - proctime->user = TIMESTRUCT_2MSEC(usage.pr_utime); - proctime->sys = TIMESTRUCT_2MSEC(usage.pr_stime); - proctime->total = proctime->user + proctime->sys; - - return SIGAR_OK; -} - -int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_state_t *procstate) -{ - int status = sigar_proc_psinfo_get(sigar, pid); - psinfo_t *pinfo = sigar->pinfo; - - if (status != SIGAR_OK) { - return status; - } - - SIGAR_SSTRCPY(procstate->name, pinfo->pr_fname); - procstate->ppid = pinfo->pr_ppid; - procstate->tty = pinfo->pr_ttydev; - procstate->priority = pinfo->pr_lwp.pr_pri; - procstate->nice = pinfo->pr_lwp.pr_nice - NZERO; - procstate->threads = pinfo->pr_nlwp; - procstate->processor = pinfo->pr_lwp.pr_onpro; - - switch (pinfo->pr_lwp.pr_state) { - case SONPROC: - case SRUN: - procstate->state = 'R'; - break; - case SZOMB: - procstate->state = 'Z'; - break; - case SSLEEP: - procstate->state = 'S'; - break; - case SSTOP: - procstate->state = 'T'; - break; - case SIDL: - procstate->state = 'D'; - break; - } - - return SIGAR_OK; -} - -typedef struct { - int timestamp; - char *args; -} pargs_t; - -static void pargs_free(void *value) -{ - pargs_t *pargs = (pargs_t *)value; - if (pargs->args != NULL) { - free(pargs->args); - } - free(pargs); -} - -static int ucb_ps_args_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_args_t *procargs, - int timestamp) -{ - char buffer[9086], *args=NULL, *arg; - sigar_cache_entry_t *ent; - FILE *fp; - pargs_t *pargs; - - if (!sigar->pargs) { - sigar->pargs = sigar_cache_new(15); - sigar->pargs->free_value = pargs_free; - } - - ent = sigar_cache_get(sigar->pargs, pid); - if (ent->value) { - pargs = (pargs_t *)ent->value; - if (pargs->timestamp != timestamp) { - if (pargs->args) { - free(pargs->args); - pargs->args = NULL; - } - } - } - else { - pargs = malloc(sizeof(*pargs)); - pargs->args = NULL; - ent->value = pargs; - } - - pargs->timestamp = timestamp; - - if (pargs->args) { - args = pargs->args; - } - else { - snprintf(buffer, sizeof(buffer), - SIGAR_USR_UCB_PS " -ww %ld", (long)pid); - - if (!(fp = popen(buffer, "r"))) { - return errno; - } - /* skip header */ - (void)fgets(buffer, sizeof(buffer), fp); - if ((args = fgets(buffer, sizeof(buffer), fp))) { - int len; - - /* skip PID,TT,S,TIME */ - args = sigar_skip_multiple_token(args, 4); - SIGAR_SKIP_SPACE(args); - len = strlen(args); - if (len > 0) { - args[len-1] = '\0'; /* chop \n */ - } - - pargs->args = malloc(len+1); - memcpy(pargs->args, args, len); - } - - pclose(fp); - - if (!args) { - return ESRCH; - } - } - - while (*args && (arg = sigar_getword(&args, ' '))) { - SIGAR_PROC_ARGS_GROW(procargs); - procargs->data[procargs->number++] = arg; - } - - return SIGAR_OK; -} - -int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_args_t *procargs) -{ - psinfo_t *pinfo; - int fd, status; - char buffer[9086]; - char *argvb[56]; - char **argvp = argvb; - - int n; - size_t nread = 0; - unsigned int argv_size; - - if ((status = sigar_proc_psinfo_get(sigar, pid)) != SIGAR_OK) { - return status; - } - pinfo = sigar->pinfo; - - if (pinfo->pr_argc == 0) { - procargs->number = 0; - return SIGAR_OK; - } - else if (pinfo->pr_dmodel != PR_MODEL_NATIVE) { - /* we are compiled in 32bit mode - * punt any 64bit native process, - * sizeof our structures can't handle. - */ - if (sigar->use_ucb_ps) { - return ucb_ps_args_get(sigar, pid, procargs, - pinfo->pr_start.tv_sec); - } - else { - return ENOTSUP; - } - } - - argv_size = sizeof(*argvp) * pinfo->pr_argc; - - (void)SIGAR_PROC_FILENAME(buffer, pid, "/as"); - - if ((fd = open(buffer, O_RDONLY)) < 0) { - if ((errno == EACCES) && sigar->use_ucb_ps) { - return ucb_ps_args_get(sigar, pid, procargs, - pinfo->pr_start.tv_sec); - } - else { - return PROC_ERRNO; - } - } - - if (argv_size > sizeof(argvb)) { - argvp = malloc(argv_size); - } - - if ((nread = pread(fd, argvp, argv_size, pinfo->pr_argv)) <= 0) { - close(fd); - if (argvp != argvb) { - free(argvp); - } - return errno; - } - - for (n = 0; n < pinfo->pr_argc; n++) { - int alen; - char *arg; - - if ((nread = pread(fd, buffer, sizeof(buffer)-1, (off_t)argvp[n])) <= 0) { - close(fd); - if (argvp != argvb) { - free(argvp); - } - return errno; - } - - buffer[nread] = '\0'; - alen = strlen(buffer)+1; - arg = malloc(alen); - memcpy(arg, buffer, alen); - - SIGAR_PROC_ARGS_GROW(procargs); - procargs->data[procargs->number++] = arg; - } - - if (argvp != argvb) { - free(argvp); - } - - close(fd); - - return SIGAR_OK; -} - -int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_env_t *procenv) -{ - psinfo_t *pinfo; - int fd, status; - char buffer[BUFSIZ], *offsets[512]; - size_t nread; - int n=0, max=sizeof(offsets)/sizeof(char *); - - if ((status = sigar_proc_psinfo_get(sigar, pid)) != SIGAR_OK) { - return status; - } - pinfo = sigar->pinfo; - - (void)SIGAR_PROC_FILENAME(buffer, pid, "/as"); - - if ((fd = open(buffer, O_RDONLY)) < 0) { - return PROC_ERRNO; - } - - if ((nread = pread(fd, offsets, sizeof(offsets), - pinfo->pr_envp)) <= 0) - { - close(fd); - return errno; - } - - while ((n < max) && offsets[n]) { - char *val; - int klen, vlen, status; - char key[128]; /* XXX is there a max key size? */ - - if ((nread = pread(fd, buffer, sizeof(buffer), - (off_t)offsets[n++])) <= 0) - { - close(fd); - return errno; - } - - val = strchr(buffer, '='); - - if (val == NULL) { - break; /*XXX*/ - } - - klen = val - buffer; - SIGAR_SSTRCPY(key, buffer); - key[klen] = '\0'; - ++val; - - vlen = strlen(val); - - status = procenv->env_getter(procenv->data, - key, klen, val, vlen); - - if (status != SIGAR_OK) { - /* not an error; just stop iterating */ - break; - } - } - - close(fd); - - return SIGAR_OK; -} - -int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_fd_t *procfd) -{ - int status = - sigar_proc_fd_count(sigar, pid, &procfd->total); - - return status; -} - -static int sigar_proc_path_exe_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_exe_t *procexe) -{ - /* solaris 10+ */ - char buffer[BUFSIZ]; - - (void)SIGAR_PROC_FILENAME(buffer, pid, "/path/a.out"); - if (!proc_readlink(buffer, procexe->name, sizeof(procexe->name))) { - procexe->name[0] = '\0'; - } - - (void)SIGAR_PROC_FILENAME(buffer, pid, "/path/cwd"); - if (!proc_readlink(buffer, procexe->cwd, sizeof(procexe->cwd))) { - procexe->cwd[0] = '\0'; - } - - (void)SIGAR_PROC_FILENAME(buffer, pid, "/path/root"); - if (!proc_readlink(buffer, procexe->root, sizeof(procexe->root))) { - procexe->root[0] = '\0'; - } - - return SIGAR_OK; -} - -static int proc_module_get_exe(void *data, char *name, int len) -{ - sigar_proc_exe_t *procexe = (sigar_proc_exe_t *)data; - SIGAR_STRNCPY(procexe->name, name, sizeof(procexe->name)); - return !SIGAR_OK; /* break loop */ -} - -static int sigar_which_exe_get(sigar_t *sigar, sigar_proc_exe_t *procexe) -{ - char *path = getenv("PATH"); - char exe[PATH_MAX]; - if (path == NULL) { - return EINVAL; - } - - while (path) { - char *ptr = strchr(path, ':'); - if (!ptr) { - break; - } - exe[0] = '\0'; - strncat(exe, path, ptr-path); - strncat(exe, "/", 1); - strcat(exe, procexe->name); - if (access(exe, X_OK) == 0) { - SIGAR_STRNCPY(procexe->name, exe, sizeof(procexe->name)); - break; - } - path = ptr+1; - } - - return ENOENT; -} - -int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_exe_t *procexe) -{ - int status; - char buffer[BUFSIZ]; - struct ps_prochandle *phandle; - - if (sigar->solaris_version >= 10) { - return sigar_proc_path_exe_get(sigar, pid, procexe); - } - - if ((status = sigar_init_libproc(sigar)) != SIGAR_OK) { - return status; - } - - procexe->name[0] = '\0'; - - /* Pgrab would return G_SELF error */ - if (pid == sigar_pid_get(sigar)) { - sigar_proc_modules_t procmods; - procmods.module_getter = proc_module_get_exe; - procmods.data = procexe; - - status = - sigar_dlinfo_modules(sigar, &procmods); - if (status == SIGAR_OK) { - if (procexe->name[0] != '/') { - sigar_which_exe_get(sigar, procexe); - } - } - } - else { - status = sigar_pgrab(sigar, pid, SIGAR_FUNC, &phandle); - - if (status == SIGAR_OK) { - sigar->pexename(phandle, procexe->name, sizeof(procexe->name)); - sigar->pfree(phandle); - } - } - - if (procexe->name[0] == '\0') { - /*XXX*/ - } - - (void)SIGAR_PROC_FILENAME(buffer, pid, "/cwd"); - - if (!sigar->pdirname(buffer, procexe->cwd, sizeof(procexe->cwd))) { - procexe->cwd[0] = '\0'; - } - - (void)SIGAR_PROC_FILENAME(buffer, pid, "/root"); - - if (!(sigar->pdirname(buffer, procexe->root, sizeof(procexe->root)))) { - procexe->root[0] = '\0'; - } - - return SIGAR_OK; -} - -static int sigar_read_xmaps(sigar_t *sigar, - prxmap_t *xmaps, int total, - unsigned long *last_inode, - struct ps_prochandle *phandle, - sigar_proc_modules_t *procmods) -{ - int status, i; - unsigned long inode; - char buffer[BUFSIZ]; - - for (i=0; ipobjname(phandle, xmaps[i].pr_vaddr, buffer, sizeof(buffer)); - - status = - procmods->module_getter(procmods->data, buffer, strlen(buffer)); - - if (status != SIGAR_OK) { - /* not an error; just stop iterating */ - return status; - } - } - - return SIGAR_OK; -} - -static int sigar_pgrab_modules(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_modules_t *procmods) -{ - int fd, pstatus; - off_t map_size, nread; - unsigned long last_inode = 0; - prxmap_t xmaps[15]; /* ~2K */ - struct ps_prochandle *phandle; - struct stat statbuf; - char buffer[BUFSIZ]; - - (void)SIGAR_PROC_FILENAME(buffer, pid, "/xmap"); - - if ((fd = open(buffer, O_RDONLY)) < 0) { - return errno; - } - - if (fstat(fd, &statbuf) < 0) { - close(fd); - return errno; - } - - map_size = statbuf.st_size; - - if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[%s] pid=%d, size=%d", - SIGAR_FUNC, pid, map_size); - } - - if ((pstatus = sigar_init_libproc(sigar)) != SIGAR_OK) { - close(fd); - return pstatus; - } - - pstatus = sigar_pgrab(sigar, pid, SIGAR_FUNC, &phandle); - - if (pstatus != SIGAR_OK) { - close(fd); - return pstatus; - } - - for (nread=0; nread sizeof(xmaps) ? sizeof(xmaps) : map_size; - int total = wanted / sizeof(prxmap_t); - - if (pread(fd, xmaps, wanted, nread) != wanted) { - close(fd); - sigar->pfree(phandle); - return errno; - } - - if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[%s] nread=%d, map_size=%d, wanted=%d, total=%d", - SIGAR_FUNC, - nread, map_size, wanted, total); - } - - if (sigar_read_xmaps(sigar, xmaps, total, - &last_inode, - phandle, procmods) != SIGAR_OK) - { - break; - } - - nread += wanted; - map_size -= wanted; - } - - close(fd); - - sigar->pfree(phandle); - - return SIGAR_OK; -} - -int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_modules_t *procmods) -{ - if (pid == sigar_pid_get(sigar)) { - /* Pgrab would return G_SELF, this is faster anyhow */ - /* XXX one difference to Pgrab, first entry is not the exe name */ - return sigar_dlinfo_modules(sigar, procmods); - } - else { - return sigar_pgrab_modules(sigar, pid, procmods); - } -} - -#define TIME_NSEC(t) \ - (SIGAR_SEC2NANO((t).tv_sec) + (sigar_uint64_t)(t).tv_nsec) - -int sigar_thread_cpu_get(sigar_t *sigar, - sigar_uint64_t id, - sigar_thread_cpu_t *cpu) -{ - struct lwpinfo info; - - if (id != 0) { - return SIGAR_ENOTIMPL; - } - - _lwp_info(&info); - - cpu->user = TIME_NSEC(info.lwp_utime); - cpu->sys = TIME_NSEC(info.lwp_stime); - cpu->total = TIME_NSEC(info.lwp_utime) + TIME_NSEC(info.lwp_stime); - - return SIGAR_OK; -} - -#include - -int sigar_os_fs_type_get(sigar_file_system_t *fsp) -{ - char *type = fsp->sys_type_name; - - switch (*type) { - case 'u': - if (strEQ(type, "ufs")) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - /* XXX */ - } - - return fsp->type; -} - -int sigar_file_system_list_get(sigar_t *sigar, - sigar_file_system_list_t *fslist) -{ - struct mnttab ent; - sigar_file_system_t *fsp; - FILE *fp = fopen(MNTTAB, "r"); - - if (!fp) { - return errno; - } - - sigar_file_system_list_create(fslist); - - while (getmntent(fp, &ent) == 0) { - if (strstr(ent.mnt_mntopts, "ignore")) { - continue; /* e.g. vold */ - } - - SIGAR_FILE_SYSTEM_LIST_GROW(fslist); - - fsp = &fslist->data[fslist->number++]; - - SIGAR_SSTRCPY(fsp->dir_name, ent.mnt_mountp); - SIGAR_SSTRCPY(fsp->dev_name, ent.mnt_special); - SIGAR_SSTRCPY(fsp->sys_type_name, ent.mnt_fstype); - SIGAR_SSTRCPY(fsp->options, ent.mnt_mntopts); - sigar_fs_type_init(fsp); - } - - fclose(fp); - - return SIGAR_OK; -} - -typedef struct { - char device[PATH_MAX]; - char name[8]; - int instance; -} fsdev_path_t; - -typedef struct { - char name[256]; - int is_partition; - sigar_disk_usage_t disk; -} iodev_t; - -static fsdev_path_t *get_fsdev_paths(sigar_t *sigar, - sigar_file_system_list_t *fslist) -{ - int i, ndisk, size; - char buffer[BUFSIZ], *ptr; - char *dev, *inst, *drv; - fsdev_path_t *paths, *mapping; - FILE *fp = fopen("/etc/path_to_inst", "r"); - - if (!fp) { - return NULL; - } - - for (i=0, ndisk=0; inumber; i++) { - sigar_file_system_t *fsp = &fslist->data[i]; - if (fsp->type == SIGAR_FSTYPE_LOCAL_DISK) { - ndisk++; - } - } - - size = sizeof(*paths) * (ndisk+1); - mapping = paths = malloc(size); - memset(mapping, '\0', size); - - while ((ptr = fgets(buffer, sizeof(buffer), fp))) { - /* eat dust java */ - char *q; - - SIGAR_SKIP_SPACE(ptr); - if (*ptr == '#') { - continue; - } - if (*ptr == '"') { - ptr++; - } - dev = ptr; - if (!(q = strchr(ptr, '"'))) { - continue; - } - ptr = q+1; - *q = '\0'; - SIGAR_SKIP_SPACE(ptr); - inst = ptr; - while (sigar_isdigit(*ptr)) { - ptr++; - } - *ptr = '\0'; - ptr++; - SIGAR_SKIP_SPACE(ptr); - if (*ptr == '"') { - ptr++; - } - drv = ptr; - if (!(q = strchr(ptr, '"'))) { - continue; - } - *q = '\0'; - - if (!(strEQ(drv, "sd") || - strEQ(drv, "ssd") || - strEQ(drv, "st") || - strEQ(drv, "dad") || - strEQ(drv, "cmdk"))) - { - continue; - } - - paths->instance = atoi(inst); - if (!kstat_lookup(sigar->kc, drv, paths->instance, NULL)) { - continue; - } - - SIGAR_SSTRCPY(paths->device, dev); - SIGAR_SSTRCPY(paths->name, drv); - - if (--ndisk < 0) { - /* XXX prevent overflow */ - break; - } - paths++; - } - fclose(fp); - - return mapping; -} - -static int create_fsdev_cache(sigar_t *sigar) -{ - fsdev_path_t *paths, *mapping; - sigar_file_system_list_t fslist; - int i, j; - int status; - int debug = SIGAR_LOG_IS_DEBUG(sigar); - - sigar->fsdev = sigar_cache_new(15); - - status = sigar_file_system_list_get(sigar, &fslist); - - if (status != SIGAR_OK) { - return status; - } - - if (!(mapping = get_fsdev_paths(sigar, &fslist))) { - sigar_file_system_list_destroy(sigar, &fslist); - return ENOENT; - } - - for (i=0; itype == SIGAR_FSTYPE_LOCAL_DISK) { - char device[PATH_MAX+1], *ptr=device; - int len = readlink(fsp->dev_name, device, sizeof(device)-1); - char *s; - char partition; - - if (len < 0) { - continue; - } - device[len] = '\0'; - - if (debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[fsdev] name=%s, dev=%s", - fsp->dev_name, device); - } - - while (strnEQ(ptr, "../", 3)) { - ptr += 3; - } - if (strnEQ(ptr, "devices", 7)) { - ptr += 7; - } - if ((s = strchr(ptr, ':'))) { - partition = *(s+1); - } - else { - continue; - } - - for (j=0, paths=mapping; paths->name[0]; j++) { - if (strnEQ(paths->device, ptr, strlen(paths->device))) { - sigar_cache_entry_t *ent; - struct stat sb; - int retval = stat(fsp->dir_name, &sb); - iodev_t *iodev; - - if (retval == 0) { - iodev = malloc(sizeof(*iodev)); - - SIGAR_DISK_STATS_INIT(&iodev->disk); - /* e.g. sd9,g - * module == sd - * instance == 9 - * partition == 8 - */ - snprintf(iodev->name, sizeof(iodev->name), "%s%d,%c", - paths->name, paths->instance, partition); - - ent = sigar_cache_get(sigar->fsdev, SIGAR_FSDEV_ID(sb)); - ent->value = iodev; - - if (debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[fsdev] map %s -> %s", - fsp->dir_name, iodev->name); - } - } - break; - } - paths++; - } - } - } - - free(mapping); - sigar_file_system_list_destroy(sigar, &fslist); - - return SIGAR_OK; -} - -static int io_kstat_read(sigar_t *sigar, - sigar_disk_usage_t *disk, - kstat_t *ksp) -{ - kstat_io_t *io; - - kstat_read(sigar->kc, ksp, NULL); - - io = (kstat_io_t *)ksp->ks_data; - - disk->reads = io->reads; - disk->writes = io->writes; - disk->read_bytes = io->nread; - disk->write_bytes = io->nwritten; - disk->qtime = io->wlentime; - disk->rtime = io->rlentime; - disk->wtime = io->wlentime; - disk->time = disk->rtime + disk->wtime; - disk->snaptime = ksp->ks_snaptime; - - return SIGAR_OK; -} - - -static int sigar_kstat_disk_usage_get(sigar_t *sigar, const char *name, - sigar_disk_usage_t *disk, - kstat_t **kio) -{ - kstat_t *ksp; - - if (sigar_kstat_update(sigar) == -1) { - return errno; - } - - for (ksp = sigar->kc->kc_chain; - ksp; - ksp = ksp->ks_next) - { - if (ksp->ks_type != KSTAT_TYPE_IO) { - continue; - } - if (strEQ(ksp->ks_name, name)) { - int status = io_kstat_read(sigar, disk, ksp); - *kio = ksp; - return status; - } - } - - return ENXIO; -} - -static int simple_hash(const char *s) -{ - int hash = 0; - while (*s) { - hash = 31*hash + *s++; - } - return hash; -} - -int sigar_disk_usage_get(sigar_t *sigar, const char *name, - sigar_disk_usage_t *disk) -{ - kstat_t *ksp; - int status; - iodev_t *iodev = NULL; - sigar_cache_entry_t *ent; - sigar_uint64_t id; - - SIGAR_DISK_STATS_INIT(disk); - - if (!sigar->fsdev) { - if (create_fsdev_cache(sigar) != SIGAR_OK) { - return SIGAR_OK; - } - } - - if (*name == '/') { - struct stat sb; - - if (stat(name, &sb) < 0) { - return errno; - } - - id = SIGAR_FSDEV_ID(sb); - ent = sigar_cache_get(sigar->fsdev, id); - if (ent->value == NULL) { - return ENXIO; - } - iodev = (iodev_t *)ent->value; - - status = sigar_kstat_disk_usage_get(sigar, iodev->name, disk, &ksp); - } - else { - status = sigar_kstat_disk_usage_get(sigar, name, disk, &ksp); - if (status != SIGAR_OK) { - return status; - } - id = simple_hash(name); /*XXX*/ - ent = sigar_cache_get(sigar->fsdev, id); - if (ent->value) { - iodev = (iodev_t *)ent->value; - } - else { - ent->value = iodev = malloc(sizeof(*iodev)); - SIGAR_SSTRCPY(iodev->name, name); - SIGAR_DISK_STATS_INIT(&iodev->disk); - } - } - - /* service_time formula derived from opensolaris.org:iostat.c */ - if ((status == SIGAR_OK) && iodev) { - sigar_uint64_t delta; - double avw, avr, tps, mtps; - double etime, hr_etime; - - if (iodev->disk.snaptime) { - delta = disk->snaptime - iodev->disk.snaptime; - } - else { - delta = ksp->ks_crtime - ksp->ks_snaptime; - } - - hr_etime = (double)delta; - if (hr_etime == 0.0) { - hr_etime = (double)NANOSEC; - } - etime = hr_etime / (double)NANOSEC; - - tps = - (((double)(disk->reads - iodev->disk.reads)) / etime) + - (((double)(disk->writes - iodev->disk.writes)) / etime); - - delta = disk->wtime - iodev->disk.wtime; - if (delta) { - avw = (double)delta; - avw /= hr_etime; - } - else { - avw = 0.0; - } - - delta = disk->rtime - iodev->disk.rtime; - if (delta) { - avr = (double)delta; - avr /= hr_etime; - } - else { - avr = 0.0; - } - - disk->queue = avw; - disk->service_time = 0.0; - - if (tps && (avw != 0.0 || avr != 0.0)) { - mtps = 1000.0 / tps; - if (avw != 0.0) { - disk->service_time += avw * mtps; - } - if (avr != 0.0) { - disk->service_time += avr * mtps; - } - } - - memcpy(&iodev->disk, disk, sizeof(iodev->disk)); - } - - return status; -} - -int sigar_file_system_usage_get(sigar_t *sigar, - const char *dirname, - sigar_file_system_usage_t *fsusage) -{ - int status = sigar_statvfs(sigar, dirname, fsusage); - - if (status != SIGAR_OK) { - return status; - } - - fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage); - - sigar_disk_usage_get(sigar, dirname, &fsusage->disk); - - return SIGAR_OK; -} - -int sigar_cpu_info_list_get(sigar_t *sigar, - sigar_cpu_info_list_t *cpu_infos) -{ - processor_info_t stats; - unsigned int i; - int status = SIGAR_OK; - int brand = -1; - sigar_cache_t *chips; - int is_debug = SIGAR_LOG_IS_DEBUG(sigar); - int nsockets = 0; - - if (sigar_kstat_update(sigar) == -1) { /* for sigar->ncpu */ - return errno; - } - - /* - * stats we care about will be the same for each - * online processor, so just grab the first. - */ - for (i=0; incpu; i++) { - processorid_t id = sigar->ks.cpuid[i]; - - if ((status = processor_info(id, &stats)) < 0) { - continue; - } - else { - status = SIGAR_OK; - break; - } - } - - if (status != SIGAR_OK) { - /* should never happen */ - return ENOENT; - } - - sigar_cpu_info_list_create(cpu_infos); - chips = sigar_cache_new(16); - chips->free_value = free_chip_id; - - for (i=0; incpu; i++) { - sigar_cpu_info_t *info; - int chip_id = get_chip_id(sigar, i); - - if (chip_id != -1) { - sigar_cache_entry_t *ent = - sigar_cache_get(chips, chip_id); - - if (ent->value) { - if (!sigar->cpu_list_cores) { - continue; - } - } - else { - ++nsockets; - ent->value = chips; /*anything non-NULL*/ - if (is_debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[cpu_list] Merging info of" - " logical processors for chip_id=%d", - chip_id); - } - } - } - else { - ++nsockets; - } - - SIGAR_CPU_INFO_LIST_GROW(cpu_infos); - - info = &cpu_infos->data[cpu_infos->number++]; - - SIGAR_SSTRCPY(info->model, stats.pi_processor_type); - - if (brand == -1) { - brand = get_chip_brand(sigar, i, info); - } - - if (strEQ(info->model, "i386")) { - if (!brand) { - /* assume Intel on x86 */ - SIGAR_SSTRCPY(info->vendor, "Intel"); - } - SIGAR_SSTRCPY(info->model, "x86"); - } - else { - if (!brand) { - /* assume Sun */ - SIGAR_SSTRCPY(info->vendor, "Sun"); - } - /* s/sparc/Sparc/ */ - info->model[0] = toupper(info->model[0]); - } - - if (brand) { - SIGAR_SSTRCPY(info->vendor, cpu_infos->data[0].vendor); - } - - info->mhz = stats.pi_clock; - info->cache_size = SIGAR_FIELD_NOTIMPL; /*XXX*/ - } - - sigar_cache_destroy(chips); - - for (i=0; inumber; i++) { - sigar_cpu_info_t *info = &cpu_infos->data[i]; - info->total_sockets = nsockets; - info->total_cores = sigar->ncpu; - info->cores_per_socket = sigar->ncpu / nsockets; - } - - return SIGAR_OK; -} - -int sigar_net_route_list_get(sigar_t *sigar, - sigar_net_route_list_t *routelist) - -{ - char *data; - int len, rc; - struct opthdr *op; - size_t nread=0, size=0; - const char *size_from; - - sigar_net_route_list_create(routelist); - - while ((rc = get_mib2(&sigar->mib2, &op, &data, &len)) == GET_MIB2_OK) { - mib2_ipRouteEntry_t *entry; - char *end; - - if (op->level != MIB2_IP) { - continue; - } - - if (op->name == 0) { - /* we want to use this size for bincompat */ - size = ((mib2_ip_t *)data)->ipRouteEntrySize; - continue; - } - else if (op->name != MIB2_IP_21) { - continue; - } - - if (size == 0) { - size_from = "sizeof"; - size = sizeof(*entry); - } - else { - size_from = "mib2_ip"; - } - - if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[route_list] ipRouteEntrySize=%d (from %s)", - size, size_from); - } - - for (entry = (mib2_ipRouteEntry_t *)data, end = data + len; - (char *)entry < end; - nread+=size, entry = (mib2_ipRouteEntry_t *)((char *)data+nread)) - { - sigar_net_route_t *route; - int type = entry->ipRouteInfo.re_ire_type; - - /* filter same as netstat -r */ - if ((type == IRE_CACHE) || - (type == IRE_BROADCAST) || - (type == IRE_LOCAL)) - { - continue; - } - - SIGAR_NET_ROUTE_LIST_GROW(routelist); - route = &routelist->data[routelist->number++]; - - sigar_net_address_set(route->destination, - entry->ipRouteDest); - - sigar_net_address_set(route->gateway, - entry->ipRouteNextHop); - - sigar_net_address_set(route->mask, - entry->ipRouteMask); - - route->refcnt = entry->ipRouteInfo.re_ref; - route->irtt = entry->ipRouteInfo.re_rtt; - route->metric = entry->ipRouteMetric1; - - SIGAR_SSTRCPY(route->ifname, entry->ipRouteIfIndex.o_bytes); - - route->flags = RTF_UP; - if ((route->destination.addr.in == 0) && - (route->mask.addr.in == 0)) - { - route->flags |= RTF_GATEWAY; - } - - route->use = route->window = route->mtu = - SIGAR_FIELD_NOTIMPL; /*XXX*/ - } - } - - if (rc != GET_MIB2_EOD) { - close_mib2(&sigar->mib2); - return SIGAR_EMIB2; - } - - return SIGAR_OK; -} - -static void ifstat_kstat_common(sigar_net_interface_stat_t *ifstat, - kstat_named_t *data, int ndata) -{ - int i; - - for (i=0; itx_collisions = value; - } - break; - case 'd': - if (strEQ(ptr, "drop")) { - ifstat->rx_dropped = value; - ifstat->tx_dropped = value; - } - break; - case 'i': - if (strEQ(ptr, "ipackets")) { - if (ifstat->rx_packets == 0) { - ifstat->rx_packets = value; - } - } - else if (strEQ(ptr, "ipackets64")) { - ifstat->rx_packets = data[i].value.ui64; - } - else if (strEQ(ptr, "ierrors")) { - ifstat->rx_errors = value; - } - else if (strEQ(ptr, "ifspeed")) { - ifstat->speed = value; - } - break; - case 'f': - if (strEQ(ptr, "framing")) { - ifstat->rx_frame = value; - } - break; - case 'm': - if (strEQ(ptr, "missed")) { - ifstat->rx_dropped = value; - ifstat->tx_dropped = value; - } - break; - case 'n': - if (strEQ(ptr, "nocarrier")) { - ifstat->tx_carrier = value; - } - break; - case 'o': - if (strEQ(ptr, "obytes")) { - if (ifstat->tx_bytes == 0) { - ifstat->tx_bytes = value; - } - } - else if (strEQ(ptr, "obytes64")) { - ifstat->tx_bytes = data[i].value.ui64; - } - else if (strEQ(ptr, "oerrors")) { - ifstat->tx_errors = value; - } - else if (strEQ(ptr, "oflo")) { - ifstat->tx_overruns = value; - } - else if (strEQ(ptr, "opackets")) { - if (ifstat->tx_packets == 0) { - ifstat->tx_packets = value; - } - } - else if (strEQ(ptr, "opackets64")) { - ifstat->tx_packets = data[i].value.ui64; - } - else if (strEQ(ptr, "toolong_errors")) { - ifstat->tx_overruns = value; - } - break; - case 'r': - if (strEQ(ptr, "rbytes")) { - if (ifstat->rx_bytes == 0) { - ifstat->rx_bytes = value; - } - } - else if (strEQ(ptr, "rbytes64")) { - ifstat->rx_bytes = data[i].value.ui64; - } - else if (strEQ(ptr, "rx_overflow")) { - ifstat->rx_overruns = value; - } - break; - default: - break; - } - } -} - -static int sigar_net_ifstat_get_any(sigar_t *sigar, const char *name, - sigar_net_interface_stat_t *ifstat) -{ - kstat_ctl_t *kc = sigar->kc; - kstat_t *ksp; - kstat_named_t *data; - - if (sigar_kstat_update(sigar) == -1) { - return errno; - } - - if (!(ksp = kstat_lookup(kc, NULL, -1, (char *)name))) { - return ENXIO; - } - - if (kstat_read(kc, ksp, NULL) < 0) { - return ENOENT; - } - - data = (kstat_named_t *)ksp->ks_data; - - ifstat_kstat_common(ifstat, data, ksp->ks_ndata); - - return SIGAR_OK; -} - -/* loopback interface only has rx/tx packets */ -static int sigar_net_ifstat_get_lo(sigar_t *sigar, const char *name, - sigar_net_interface_stat_t *ifstat) -{ - ifstat->rx_packets = 0; - ifstat->rx_bytes = SIGAR_FIELD_NOTIMPL; - ifstat->rx_errors = SIGAR_FIELD_NOTIMPL; - ifstat->rx_dropped = SIGAR_FIELD_NOTIMPL; - ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL; - ifstat->rx_frame = SIGAR_FIELD_NOTIMPL; - - ifstat->tx_packets = 0; - ifstat->tx_bytes = SIGAR_FIELD_NOTIMPL; - ifstat->tx_errors = SIGAR_FIELD_NOTIMPL; - ifstat->tx_dropped = SIGAR_FIELD_NOTIMPL; - ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL; - ifstat->tx_collisions = SIGAR_FIELD_NOTIMPL; - ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL; - - ifstat->speed = SIGAR_FIELD_NOTIMPL; - - return sigar_net_ifstat_get_any(sigar, name, ifstat); -} - -int sigar_net_interface_stat_get(sigar_t *sigar, const char *name, - sigar_net_interface_stat_t *ifstat) -{ - ifstat->speed = SIGAR_FIELD_NOTIMPL; - - if (strnEQ(name, "lo", 2)) { - return sigar_net_ifstat_get_lo(sigar, name, ifstat); - } - else { - SIGAR_ZERO(ifstat); - return sigar_net_ifstat_get_any(sigar, name, ifstat); - } -} - -int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, - sigar_net_interface_config_t *ifconfig) -{ - int sock; - struct lifreq lifr; - - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { - return errno; - } - - SIGAR_SSTRCPY(lifr.lifr_name, name); - - if (ioctl(sock, SIOCGLIFADDR, &lifr) == 0) { - struct in6_addr *addr = SIGAR_SIN6_ADDR(&lifr.lifr_addr); - - sigar_net_address6_set(ifconfig->address6, addr); - sigar_net_interface_scope6_set(ifconfig, addr); - ifconfig->prefix6_length = lifr.lifr_addrlen; - } - - close(sock); - return SIGAR_OK; -} - -#define TCPQ_SIZE(s) ((s) >= 0 ? (s) : 0) - -static int tcp_connection_get(sigar_net_connection_walker_t *walker, - struct mib2_tcpConnEntry *entry, - int len) -{ - int flags = walker->flags; - int status; - char *end = (char *)entry + len; - - while ((char *)entry < end) { - int state = entry->tcpConnEntryInfo.ce_state; - - if (((flags & SIGAR_NETCONN_SERVER) && (state == TCPS_LISTEN)) || - ((flags & SIGAR_NETCONN_CLIENT) && (state != TCPS_LISTEN))) - { - sigar_net_connection_t conn; - - SIGAR_ZERO(&conn); - - sigar_net_address_set(conn.local_address, entry->tcpConnLocalAddress); - sigar_net_address_set(conn.remote_address, entry->tcpConnRemAddress); - - conn.local_port = entry->tcpConnLocalPort; - conn.remote_port = entry->tcpConnRemPort; - conn.type = SIGAR_NETCONN_TCP; - conn.send_queue = - TCPQ_SIZE(entry->tcpConnEntryInfo.ce_snxt - - entry->tcpConnEntryInfo.ce_suna - 1); - conn.receive_queue = - TCPQ_SIZE(entry->tcpConnEntryInfo.ce_rnxt - - entry->tcpConnEntryInfo.ce_rack); - - switch (state) { - case TCPS_CLOSED: - conn.state = SIGAR_TCP_CLOSE; - break; - case TCPS_IDLE: - conn.state = SIGAR_TCP_IDLE; - break; - case TCPS_BOUND: - conn.state = SIGAR_TCP_BOUND; - break; - case TCPS_LISTEN: - conn.state = SIGAR_TCP_LISTEN; - break; - case TCPS_SYN_SENT: - conn.state = SIGAR_TCP_SYN_SENT; - break; - case TCPS_SYN_RCVD: - conn.state = SIGAR_TCP_SYN_RECV; - break; - case TCPS_ESTABLISHED: - conn.state = SIGAR_TCP_ESTABLISHED; - break; - case TCPS_CLOSE_WAIT: - conn.state = SIGAR_TCP_CLOSE_WAIT; - break; - case TCPS_FIN_WAIT_1: - conn.state = SIGAR_TCP_FIN_WAIT1; - break; - case TCPS_CLOSING: - conn.state = SIGAR_TCP_CLOSING; - break; - case TCPS_LAST_ACK: - conn.state = SIGAR_TCP_LAST_ACK; - break; - case TCPS_FIN_WAIT_2: - conn.state = SIGAR_TCP_FIN_WAIT2; - break; - case TCPS_TIME_WAIT: - conn.state = SIGAR_TCP_TIME_WAIT; - break; - default: - conn.state = SIGAR_TCP_UNKNOWN; - break; - } - - status = walker->add_connection(walker, &conn); - if (status != SIGAR_OK) { - return status; - } - } - - entry++; - } - - return SIGAR_OK; -} - -static int udp_connection_get(sigar_net_connection_walker_t *walker, - struct mib2_udpEntry *entry, - int len) -{ - int flags = walker->flags; - int status; - char *end = (char *)entry + len; - - while ((char *)entry < end) { - int state = entry->udpEntryInfo.ue_state; - - /* XXX dunno if this state check is right */ - if (((flags & SIGAR_NETCONN_SERVER) && (state == MIB2_UDP_idle)) || - ((flags & SIGAR_NETCONN_CLIENT) && (state != MIB2_UDP_idle))) - { - sigar_net_connection_t conn; - - SIGAR_ZERO(&conn); - - sigar_net_address_set(conn.local_address, entry->udpLocalAddress); - sigar_net_address_set(conn.remote_address, 0); - - conn.local_port = entry->udpLocalPort; - conn.remote_port = 0; - conn.type = SIGAR_NETCONN_UDP; - - status = walker->add_connection(walker, &conn); - if (status != SIGAR_OK) { - return status; - } - } - - entry++; - } - - return SIGAR_OK; -} - -int sigar_net_connection_walk(sigar_net_connection_walker_t *walker) -{ - sigar_t *sigar = walker->sigar; - int flags = walker->flags; - int status; - int want_tcp = flags & SIGAR_NETCONN_TCP; - int want_udp = flags & SIGAR_NETCONN_UDP; - char *data; - int len; - int rc; - struct opthdr *op; - - while ((rc = get_mib2(&sigar->mib2, &op, &data, &len)) == GET_MIB2_OK) { - if ((op->level == MIB2_TCP) && - (op->name == MIB2_TCP_13) && - want_tcp) - { - status = - tcp_connection_get(walker, - (struct mib2_tcpConnEntry *)data, - len); - } - else if ((op->level == MIB2_UDP) && - (op->name == MIB2_UDP_5) && - want_udp) - { - status = - udp_connection_get(walker, - (struct mib2_udpEntry *)data, - len); - } - else { - status = SIGAR_OK; - } - - if (status != SIGAR_OK) { - break; - } - } - - if (rc != GET_MIB2_EOD) { - close_mib2(&sigar->mib2); - return SIGAR_EMIB2; - } - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) -sigar_tcp_get(sigar_t *sigar, - sigar_tcp_t *tcp) -{ - char *data; - int len; - int rc; - struct opthdr *op; - mib2_tcp_t *mib = NULL; - - while ((rc = get_mib2(&sigar->mib2, &op, &data, &len)) == GET_MIB2_OK) { - if ((op->level == MIB2_TCP) && (op->name == 0)) { - mib = (mib2_tcp_t *)data; - break; - } - } - - if (mib) { - tcp->active_opens = mib->tcpActiveOpens; - tcp->passive_opens = mib->tcpPassiveOpens; - tcp->attempt_fails = mib->tcpAttemptFails; - tcp->estab_resets = mib->tcpEstabResets; - tcp->curr_estab = mib->tcpCurrEstab; - tcp->in_segs = mib->tcpInSegs; - tcp->out_segs = mib->tcpOutSegs; - tcp->retrans_segs = mib->tcpRetransSegs; - tcp->in_errs = SIGAR_FIELD_NOTIMPL; /* XXX mib2_ip_t.tcpInErrs */ - tcp->out_rsts = mib->tcpOutRsts; - return SIGAR_OK; - } - else { - return SIGAR_ENOTIMPL; - } -} - -static int sigar_nfs_get(sigar_t *sigar, - char *type, - char **names, - char *nfs) -{ - size_t offset; - kstat_t *ksp; - int i; - - if (sigar_kstat_update(sigar) == -1) { - return errno; - } - - if (!(ksp = kstat_lookup(sigar->kc, "nfs", 0, type))) { - return SIGAR_ENOTIMPL; - } - - if (kstat_read(sigar->kc, ksp, NULL) < 0) { - return errno; - } - - for (i=0, offset=0; - names[i]; - i++, offset+=sizeof(sigar_uint64_t)) - { - sigar_uint64_t val; - kstat_named_t *kv = - kstat_data_lookup(ksp, names[i]); - - if (kv) { - val = kv->value.ui64; - } - else { - val = -1; - } - - *(sigar_uint64_t *)((char *)nfs + offset) = val; - } - - return SIGAR_OK; -} - -static char *nfs_v2_names[] = { - "null", - "getattr", - "setattr", - "root", - "lookup", - "readlink", - "read", - "wrcache", - "write", - "create", - "remove", - "rename", - "link", - "symlink", - "mkdir", - "rmdir", - "readdir", - "statfs", - NULL -}; - -int sigar_nfs_client_v2_get(sigar_t *sigar, - sigar_nfs_client_v2_t *nfs) -{ - return sigar_nfs_get(sigar, "rfsreqcnt_v2", nfs_v2_names, (char *)nfs); -} - -int sigar_nfs_server_v2_get(sigar_t *sigar, - sigar_nfs_server_v2_t *nfs) -{ - return sigar_nfs_get(sigar, "rfsproccnt_v2", nfs_v2_names, (char *)nfs); -} - -static char *nfs_v3_names[] = { - "null", - "getattr", - "setattr", - "lookup", - "access", - "readlink", - "read", - "write", - "create", - "mkdir", - "symlink", - "mknod", - "remove", - "rmdir", - "rename", - "link", - "readdir", - "readdirplus", - "fsstat", - "fsinfo", - "pathconf", - "commit", - NULL -}; - -int sigar_nfs_client_v3_get(sigar_t *sigar, - sigar_nfs_client_v3_t *nfs) -{ - return sigar_nfs_get(sigar, "rfsreqcnt_v3", nfs_v3_names, (char *)nfs); -} - -int sigar_nfs_server_v3_get(sigar_t *sigar, - sigar_nfs_server_v3_t *nfs) -{ - return sigar_nfs_get(sigar, "rfsproccnt_v3", nfs_v3_names, (char *)nfs); -} - -int sigar_arp_list_get(sigar_t *sigar, - sigar_arp_list_t *arplist) -{ - char *data; - int len, rc; - struct opthdr *op; - size_t nread=0, size=0; - const char *size_from; - - sigar_arp_list_create(arplist); - - while ((rc = get_mib2(&sigar->mib2, &op, &data, &len)) == GET_MIB2_OK) { - mib2_ipNetToMediaEntry_t *entry; - char *end; - - if (op->level != MIB2_IP) { - continue; - } - - if (op->name == 0) { - /* we want to use this size for bincompat */ - size = ((mib2_ip_t *)data)->ipNetToMediaEntrySize; - continue; - } - else if (op->name != MIB2_IP_MEDIA) { - continue; - } - - if (size == 0) { - size_from = "sizeof"; - size = sizeof(*entry); - } - else { - size_from = "mib2_ip"; - } - - if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[arp_list] ipNetToMediaEntrySize=%d (from %s)", - size, size_from); - } - - for (entry = (mib2_ipNetToMediaEntry_t *)data, end = data + len; - (char *)entry < end; - nread+=size, entry = (mib2_ipNetToMediaEntry_t *)((char *)data+nread)) - { - sigar_arp_t *arp; - - SIGAR_ARP_LIST_GROW(arplist); - arp = &arplist->data[arplist->number++]; - - sigar_net_address_set(arp->address, - entry->ipNetToMediaNetAddress); - - sigar_net_address_mac_set(arp->hwaddr, - entry->ipNetToMediaPhysAddress.o_bytes, - entry->ipNetToMediaPhysAddress.o_length); - - SIGAR_SSTRCPY(arp->ifname, entry->ipNetToMediaIfIndex.o_bytes); - - arp->flags = entry->ipNetToMediaInfo.ntm_flags; - SIGAR_SSTRCPY(arp->type, "ether"); /*XXX*/ - } - } - - if (rc != GET_MIB2_EOD) { - close_mib2(&sigar->mib2); - return SIGAR_EMIB2; - } - - return SIGAR_OK; -} - -static int find_port(sigar_t *sigar, struct ps_prochandle *phandle, - sigar_pid_t pid, unsigned long port) -{ - DIR *dirp; - struct dirent *ent; - char pname[PATH_MAX]; - struct stat64 statb; - int found=0; - - sprintf(pname, "/proc/%d/fd", (int)pid); - - if (!(dirp = opendir(pname))) { - return 0; - } - - while ((ent = readdir(dirp))) { - int fd; - - if (!sigar_isdigit(ent->d_name[0])) { - continue; - } - fd = atoi(ent->d_name); - - if (sigar->pfstat64(phandle, fd, &statb) == -1) { - continue; - } - - if ((statb.st_mode & S_IFMT) == S_IFSOCK) { - struct sockaddr_in sin; - struct sockaddr *sa = (struct sockaddr *)&sin; - socklen_t len = sizeof(sin); - int opt, optsz, rc; - - optsz = sizeof(opt); - rc = sigar->pgetsockopt(phandle, fd, SOL_SOCKET, SO_TYPE, &opt, &optsz); - if (rc != 0) { - continue; - } - if (opt != SOCK_STREAM) { - continue; - } - optsz = sizeof(opt); - rc = sigar->pgetsockopt(phandle, fd, SOL_SOCKET, SO_ACCEPTCONN, &opt, &optsz); - if (rc != 0) { - continue; - } - if (opt != SO_ACCEPTCONN) { - continue; - } - - rc = sigar->pgetsockname(phandle, fd, sa, &len); - if (rc != 0) { - continue; - } - - if ((sa->sa_family == AF_INET) || - (sa->sa_family == AF_INET6)) - { - if (ntohs(sin.sin_port) == port) { - found = 1; - break; - } - } - } - } - - closedir(dirp); - - return found; -} - -/* derived from /usr/bin/pfiles.c */ -int sigar_proc_port_get(sigar_t *sigar, int protocol, - unsigned long port, sigar_pid_t *pid) -{ - sigar_proc_list_t pids; - int i, status, found=0; - - if (sigar->solaris_version < 10) { - return SIGAR_ENOTIMPL; - } - - if ((status = sigar_init_libproc(sigar)) != SIGAR_OK) { - return SIGAR_ENOTIMPL; - } - status = sigar_proc_list_get(sigar, &pids); - if (status != SIGAR_OK) { - return status; - } - - for (i=0; ipcreate_agent(phandle) == 0) { - found = find_port(sigar, phandle, ps_id, port); - sigar->pdestroy_agent(phandle); - } - - sigar->pfree(phandle); - if (found) { - *pid = ps_id; - break; - } - } - - sigar_proc_list_destroy(sigar, &pids); - - return found ? SIGAR_OK : ENOENT; -} - -int sigar_os_sys_info_get(sigar_t *sigar, - sigar_sys_info_t *sys_info) -{ - char *vendor_version; - - sysinfo(SI_ARCHITECTURE, sys_info->arch, sizeof(sys_info->arch)); - - SIGAR_SSTRCPY(sys_info->name, "Solaris"); - SIGAR_SSTRCPY(sys_info->vendor, "Sun Microsystems"); - - if (strEQ(sys_info->version, "5.6")) { - vendor_version = "2.6"; - } - else { - if ((vendor_version = strchr(sys_info->version, '.'))) { - ++vendor_version; - } - else { - vendor_version = sys_info->version; - } - } - - SIGAR_SSTRCPY(sys_info->vendor_version, vendor_version); - - snprintf(sys_info->description, - sizeof(sys_info->description), - "%s %s", - sys_info->name, sys_info->vendor_version); - - return SIGAR_OK; -} diff --git a/vendor/sigar/src/os/win32/peb.c b/vendor/sigar/src/os/win32/peb.c deleted file mode 100644 index d8b2eca..0000000 --- a/vendor/sigar/src/os/win32/peb.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2004, 2006-2008 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * Copyright (c) 2009 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * functions for getting info from the Process Environment Block - */ -#define UNICODE -#define _UNICODE - -#include "sigar.h" -#include "sigar_private.h" -#include "sigar_os.h" -#include - -void dllmod_init_ntdll(sigar_t *sigar); - -#define sigar_NtQueryInformationProcess \ - sigar->ntdll.query_proc_info.func - -static int sigar_pbi_get(sigar_t *sigar, HANDLE proc, PEB *peb) -{ - int status; - PROCESS_BASIC_INFORMATION pbi; - DWORD size=sizeof(pbi); - - dllmod_init_ntdll(sigar); - - if (!sigar_NtQueryInformationProcess) { - return SIGAR_ENOTIMPL; - } - - SIGAR_ZERO(&pbi); - status = - sigar_NtQueryInformationProcess(proc, - ProcessBasicInformation, - &pbi, - size, NULL); - if (status != ERROR_SUCCESS) { - return status; - } - - if (!pbi.PebBaseAddress) { - /* likely we are 32-bit, pid process is 64-bit */ - return ERROR_DATATYPE_MISMATCH; - } - - size = sizeof(*peb); - - if (ReadProcessMemory(proc, pbi.PebBaseAddress, peb, size, NULL)) { - return SIGAR_OK; - } - else { - return GetLastError(); - } -} - -static int sigar_rtl_get(sigar_t *sigar, HANDLE proc, - RTL_USER_PROCESS_PARAMETERS *rtl) -{ - PEB peb; - int status = sigar_pbi_get(sigar, proc, &peb); - DWORD size=sizeof(*rtl); - - if (status != SIGAR_OK) { - return status; - } - - if (ReadProcessMemory(proc, peb.ProcessParameters, rtl, size, NULL)) { - return SIGAR_OK; - } - else { - return GetLastError(); - } -} - -#define rtl_bufsize(buf, uc) \ - ((sizeof(buf) < uc.Length) ? sizeof(buf) : uc.Length) - -int sigar_proc_exe_peb_get(sigar_t *sigar, HANDLE proc, - sigar_proc_exe_t *procexe) -{ - int status; - WCHAR buf[MAX_PATH+1]; - RTL_USER_PROCESS_PARAMETERS rtl; - DWORD size; - - procexe->name[0] = '\0'; - procexe->cwd[0] = '\0'; - - if ((status = sigar_rtl_get(sigar, proc, &rtl)) != SIGAR_OK) { - return status; - } - - size = rtl_bufsize(buf, rtl.ImagePathName); - memset(buf, '\0', sizeof(buf)); - - if ((size > 0) && - ReadProcessMemory(proc, rtl.ImagePathName.Buffer, buf, size, NULL)) - { - SIGAR_W2A(buf, procexe->name, sizeof(procexe->name)); - } - - size = rtl_bufsize(buf, rtl.CurrentDirectoryName); - memset(buf, '\0', sizeof(buf)); - - if ((size > 0) && - ReadProcessMemory(proc, rtl.CurrentDirectoryName.Buffer, buf, size, NULL)) - { - SIGAR_W2A(buf, procexe->cwd, sizeof(procexe->cwd)); - } - - return SIGAR_OK; -} - -int sigar_parse_proc_args(sigar_t *sigar, WCHAR *buf, - sigar_proc_args_t *procargs) -{ - char arg[SIGAR_CMDLINE_MAX]; - LPWSTR *args; - int num, i; - - if (!buf) { - buf = GetCommandLine(); - } - - args = CommandLineToArgvW(buf, &num); - - if (args == NULL) { - return SIGAR_OK; - } - - for (i=0; idata[procargs->number++] = sigar_strdup(arg); - } - - GlobalFree(args); - - return SIGAR_OK; -} - -int sigar_proc_args_peb_get(sigar_t *sigar, HANDLE proc, - sigar_proc_args_t *procargs) -{ - int status; - WCHAR buf[SIGAR_CMDLINE_MAX]; - RTL_USER_PROCESS_PARAMETERS rtl; - DWORD size; - - if ((status = sigar_rtl_get(sigar, proc, &rtl)) != SIGAR_OK) { - return status; - } - - size = rtl_bufsize(buf, rtl.CommandLine); - if (size <= 0) { - return ERROR_DATATYPE_MISMATCH; /* fallback to wmi */ - } - memset(buf, '\0', sizeof(buf)); - - if (ReadProcessMemory(proc, rtl.CommandLine.Buffer, buf, size, NULL)) { - return sigar_parse_proc_args(sigar, buf, procargs); - } - else { - return GetLastError(); - } -} - -int sigar_proc_env_peb_get(sigar_t *sigar, HANDLE proc, - WCHAR *buf, DWORD size) -{ - int status; - RTL_USER_PROCESS_PARAMETERS rtl; - MEMORY_BASIC_INFORMATION info; - - if ((status = sigar_rtl_get(sigar, proc, &rtl)) != SIGAR_OK) { - return status; - } - - memset(buf, '\0', size); - /* -2 to ensure \0\0 terminator */ - size -= 2; - - if (VirtualQueryEx(proc, rtl.Environment, &info, sizeof(info))) { - if (size > info.RegionSize) { - /* ReadProcessMemory beyond region would fail */ - size = info.RegionSize; - } - } - - if (ReadProcessMemory(proc, rtl.Environment, buf, size, NULL)) { - return SIGAR_OK; - } - else { - return GetLastError(); - } -} diff --git a/vendor/sigar/src/os/win32/sigar_os.h b/vendor/sigar/src/os/win32/sigar_os.h deleted file mode 100755 index cf61c25..0000000 --- a/vendor/sigar/src/os/win32/sigar_os.h +++ /dev/null @@ -1,676 +0,0 @@ -/* - * Copyright (c) 2004-2009 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * Copyright (c) 2009-2010 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SIGAR_OS_H -#define SIGAR_OS_H - -#if !defined(MSVC) && defined(_MSC_VER) -#define MSVC -#endif - -#ifdef MSVC -#define WIN32_LEAN_AND_MEAN -#define snprintf _snprintf -#if _MSC_VER <= 1200 -#define SIGAR_USING_MSC6 /* Visual Studio version 6 */ -#define HAVE_MIB_IPADDRROW_WTYPE 0 -#else -#define HAVE_MIB_IPADDRROW_WTYPE 1 -#endif -#else -/* Cross compiling */ -#define _WIN32_WINNT 0x0501 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sigar_util.h" - -#ifdef MSVC -# define INT64_C(val) val##i64 -# define SIGAR_DLLFUNC(api, name) \ - struct { \ - const char *name; \ - ##api##_##name func; \ - } ##name -#else -/* The GCC compiler doesn't require/accept the ## prefix */ -# define INT64_C(val) val##L -# define SIGAR_DLLFUNC(api, name) \ - struct { \ - const char *name; \ - api##_##name func; \ - } name -#endif - -/* see apr/include/arch/win32/atime.h */ -#define EPOCH_DELTA INT64_C(11644473600000000) - -#define SIGAR_CMDLINE_MAX 4096<<2 - -/* XXX: support CP_UTF8 ? */ - -#define SIGAR_A2W(lpa, lpw, bytes) \ - (lpw[0] = 0, MultiByteToWideChar(CP_ACP, 0, \ - lpa, -1, lpw, (bytes/sizeof(WCHAR)))) - -#define SIGAR_W2A(lpw, lpa, chars) \ - (lpa[0] = '\0', WideCharToMultiByte(CP_ACP, 0, \ - lpw, -1, (LPSTR)lpa, chars, \ - NULL, NULL)) - -/* iptypes.h from vc7, not available in vc6 */ -/* copy from PSDK if using vc6 */ -#include "iptypes.h" - -/* from wtsapi32.h not in vs6.0 */ -typedef enum { - WTSInitialProgram, - WTSApplicationName, - WTSWorkingDirectory, - WTSOEMId, - WTSSessionId, - WTSUserName, - WTSWinStationName, - WTSDomainName, - WTSConnectState, - WTSClientBuildNumber, - WTSClientName, - WTSClientDirectory, - WTSClientProductId, - WTSClientHardwareId, - WTSClientAddress, - WTSClientDisplay, - WTSClientProtocolType, -} WTS_INFO_CLASS; - -typedef enum _WTS_CONNECTSTATE_CLASS { - WTSActive, - WTSConnected, - WTSConnectQuery, - WTSShadow, - WTSDisconnected, - WTSIdle, - WTSListen, - WTSReset, - WTSDown, - WTSInit -} WTS_CONNECTSTATE_CLASS; - -#define WTS_PROTOCOL_TYPE_CONSOLE 0 -#define WTS_PROTOCOL_TYPE_ICA 1 -#define WTS_PROTOCOL_TYPE_RDP 2 - -typedef struct _WTS_SESSION_INFO { - DWORD SessionId; - LPTSTR pWinStationName; - DWORD State; -} WTS_SESSION_INFO, *PWTS_SESSION_INFO; - -typedef struct _WTS_PROCESS_INFO { - DWORD SessionId; - DWORD ProcessId; - LPSTR pProcessName; - PSID pUserSid; -} WTS_PROCESS_INFO, *PWTS_PROCESS_INFO; - -typedef struct _WTS_CLIENT_ADDRESS { - DWORD AddressFamily; - BYTE Address[20]; -} WTS_CLIENT_ADDRESS, *PWTS_CLIENT_ADDRESS; - -/* the WINSTATION_INFO stuff here is undocumented - * got the howto from google groups: - * http://redirx.com/?31gy - */ -typedef enum _WINSTATION_INFO_CLASS { - WinStationInformation = 8 -} WINSTATION_INFO_CLASS; - -typedef struct _WINSTATION_INFO { - BYTE Reserved1[72]; - ULONG SessionId; - BYTE Reserved2[4]; - FILETIME ConnectTime; - FILETIME DisconnectTime; - FILETIME LastInputTime; - FILETIME LoginTime; - BYTE Reserved3[1096]; - FILETIME CurrentTime; -} WINSTATION_INFO, *PWINSTATION_INFO; - -/* end wtsapi32.h */ - -#ifdef SIGAR_USING_MSC6 - -/* from winbase.h not in vs6.0 */ -typedef struct { - DWORD dwLength; - DWORD dwMemoryLoad; - DWORDLONG ullTotalPhys; - DWORDLONG ullAvailPhys; - DWORDLONG ullTotalPageFile; - DWORDLONG ullAvailPageFile; - DWORDLONG ullTotalVirtual; - DWORDLONG ullAvailVirtual; - DWORDLONG ullAvailExtendedVirtual; -} MEMORYSTATUSEX; - -/* service manager stuff not in vs6.0 */ -typedef struct _SERVICE_STATUS_PROCESS { - DWORD dwServiceType; - DWORD dwCurrentState; - DWORD dwControlsAccepted; - DWORD dwWin32ExitCode; - DWORD dwServiceSpecificExitCode; - DWORD dwCheckPoint; - DWORD dwWaitHint; - DWORD dwProcessId; - DWORD dwServiceFlags; -} SERVICE_STATUS_PROCESS; - -typedef enum { - SC_STATUS_PROCESS_INFO = 0 -} SC_STATUS_TYPE; - -#ifndef ERROR_DATATYPE_MISMATCH -#define ERROR_DATATYPE_MISMATCH 1629L -#endif - -#endif /* _MSC_VER */ - -#include - -/* undocumented structures */ -typedef struct { - DWORD dwState; - DWORD dwLocalAddr; - DWORD dwLocalPort; - DWORD dwRemoteAddr; - DWORD dwRemotePort; - DWORD dwProcessId; -} MIB_TCPEXROW, *PMIB_TCPEXROW; - -typedef struct { - DWORD dwNumEntries; - MIB_TCPEXROW table[ANY_SIZE]; -} MIB_TCPEXTABLE, *PMIB_TCPEXTABLE; - -typedef struct { - DWORD dwLocalAddr; - DWORD dwLocalPort; - DWORD dwProcessId; -} MIB_UDPEXROW, *PMIB_UDPEXROW; - -typedef struct { - DWORD dwNumEntries; - MIB_UDPEXROW table[ANY_SIZE]; -} MIB_UDPEXTABLE, *PMIB_UDPEXTABLE; - -/* end undocumented structures */ - -/* no longer in the standard header files */ -typedef struct { - LARGE_INTEGER IdleTime; - LARGE_INTEGER KernelTime; - LARGE_INTEGER UserTime; - LARGE_INTEGER DpcTime; - LARGE_INTEGER InterruptTime; - ULONG InterruptCount; -} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; - -#define SystemProcessorPerformanceInformation 8 - -/* PEB decls from msdn docs w/ slight mods */ -#define ProcessBasicInformation 0 - -typedef struct _UNICODE_STRING { - USHORT Length; - USHORT MaximumLength; - PWSTR Buffer; -} UNICODE_STRING, *PUNICODE_STRING; - -typedef struct _PEB_LDR_DATA { - BYTE Reserved1[8]; - PVOID Reserved2[3]; - LIST_ENTRY InMemoryOrderModuleList; -} PEB_LDR_DATA, *PPEB_LDR_DATA; - -typedef struct RTL_DRIVE_LETTER_CURDIR { - USHORT Flags; - USHORT Length; - ULONG TimeStamp; - UNICODE_STRING DosPath; -} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; - -/* from: http://source.winehq.org/source/include/winternl.h */ -typedef struct _RTL_USER_PROCESS_PARAMETERS { - ULONG AllocationSize; - ULONG Size; - ULONG Flags; - ULONG DebugFlags; - HANDLE hConsole; - ULONG ProcessGroup; - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; - UNICODE_STRING CurrentDirectoryName; - HANDLE CurrentDirectoryHandle; - UNICODE_STRING DllPath; - UNICODE_STRING ImagePathName; - UNICODE_STRING CommandLine; - PWSTR Environment; - ULONG dwX; - ULONG dwY; - ULONG dwXSize; - ULONG dwYSize; - ULONG dwXCountChars; - ULONG dwYCountChars; - ULONG dwFillAttribute; - ULONG dwFlags; - ULONG wShowWindow; - UNICODE_STRING WindowTitle; - UNICODE_STRING Desktop; - UNICODE_STRING ShellInfo; - UNICODE_STRING RuntimeInfo; - RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; -} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; - -/* from msdn docs -typedef struct _RTL_USER_PROCESS_PARAMETERS { - BYTE Reserved1[16]; - PVOID Reserved2[10]; - UNICODE_STRING ImagePathName; - UNICODE_STRING CommandLine; -} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; -*/ - -typedef struct _PEB { - BYTE Reserved1[2]; - BYTE BeingDebugged; - BYTE Reserved2[1]; - PVOID Reserved3[2]; - PPEB_LDR_DATA Ldr; - PRTL_USER_PROCESS_PARAMETERS ProcessParameters; - BYTE Reserved4[104]; - PVOID Reserved5[52]; - /*PPS_POST_PROCESS_INIT_ROUTINE*/ PVOID PostProcessInitRoutine; - BYTE Reserved6[128]; - PVOID Reserved7[1]; - ULONG SessionId; -} PEB, *PPEB; - -typedef struct _PROCESS_BASIC_INFORMATION { - PVOID Reserved1; - PPEB PebBaseAddress; - PVOID Reserved2[2]; - /*ULONG_PTR*/ UINT_PTR UniqueProcessId; - PVOID Reserved3; -} PROCESS_BASIC_INFORMATION; - -typedef struct { - sigar_pid_t pid; - int ppid; - int priority; - time_t mtime; - sigar_uint64_t size; - sigar_uint64_t resident; - char name[SIGAR_PROC_NAME_LEN]; - char state; - sigar_uint64_t handles; - sigar_uint64_t threads; - sigar_uint64_t page_faults; -} sigar_win32_pinfo_t; - -typedef struct { - const char *name; - HINSTANCE handle; -} sigar_dll_handle_t; - -typedef struct { - const char *name; - FARPROC func; -} sigar_dll_func_t; - -typedef struct { - const char *name; - HINSTANCE handle; - sigar_dll_func_t funcs[12]; -} sigar_dll_module_t; - -/* wtsapi.dll */ -typedef BOOL (CALLBACK *wtsapi_enum_sessions)(HANDLE, - DWORD, - DWORD, - PWTS_SESSION_INFO *, - DWORD *); - -typedef void (CALLBACK *wtsapi_free_mem)(PVOID); - -typedef BOOL (CALLBACK *wtsapi_query_session)(HANDLE, - DWORD, - WTS_INFO_CLASS, - LPSTR *, DWORD *); -/* iphlpapi.dll */ - -typedef DWORD (CALLBACK *iphlpapi_get_ipforward_table)(PMIB_IPFORWARDTABLE, - PULONG, - BOOL); - -typedef DWORD (CALLBACK *iphlpapi_get_ipaddr_table)(PMIB_IPADDRTABLE, - PULONG, - BOOL); - -typedef DWORD (CALLBACK *iphlpapi_get_if_table)(PMIB_IFTABLE, - PULONG, - BOOL); - -typedef DWORD (CALLBACK *iphlpapi_get_if_entry)(PMIB_IFROW); - -typedef DWORD (CALLBACK *iphlpapi_get_num_if)(PDWORD); - -typedef DWORD (CALLBACK *iphlpapi_get_tcp_table)(PMIB_TCPTABLE, - PDWORD, - BOOL); - -typedef DWORD (CALLBACK *iphlpapi_get_udp_table)(PMIB_UDPTABLE, - PDWORD, - BOOL); - -typedef DWORD (CALLBACK *iphlpapi_get_tcpx_table)(PMIB_TCPEXTABLE *, - BOOL, - HANDLE, - DWORD, - DWORD); - -typedef DWORD (CALLBACK *iphlpapi_get_udpx_table)(PMIB_UDPEXTABLE *, - BOOL, - HANDLE, - DWORD, - DWORD); - -typedef DWORD (CALLBACK *iphlpapi_get_tcp_stats)(PMIB_TCPSTATS); - -typedef DWORD (CALLBACK *iphlpapi_get_net_params)(PFIXED_INFO, - PULONG); - -typedef DWORD (CALLBACK *iphlpapi_get_adapters_info)(PIP_ADAPTER_INFO, - PULONG); - -typedef ULONG (CALLBACK *iphlpapi_get_adapters_addrs)(ULONG, - ULONG, - PVOID, - PIP_ADAPTER_ADDRESSES, - PULONG); - -/* advapi32.dll */ -typedef BOOL (CALLBACK *advapi_convert_string_sid)(LPCSTR, - PSID *); - -typedef BOOL (CALLBACK *advapi_query_service_status)(SC_HANDLE, - SC_STATUS_TYPE, - LPBYTE, - DWORD, - LPDWORD); - -typedef DWORD (CALLBACK *iphlpapi_get_ipnet_table)(PMIB_IPNETTABLE, - PDWORD, - BOOL); - -/* ntdll.dll */ -typedef DWORD (CALLBACK *ntdll_query_sys_info)(DWORD, - PVOID, - ULONG, - PULONG); - -typedef DWORD (CALLBACK *ntdll_query_proc_info)(HANDLE, - DWORD, - PVOID, - ULONG, - PULONG); - -/* psapi.dll */ -typedef BOOL (CALLBACK *psapi_enum_modules)(HANDLE, - HMODULE *, - DWORD, - LPDWORD); - -typedef DWORD (CALLBACK *psapi_get_module_name)(HANDLE, - HMODULE, - LPTSTR, - DWORD); - -typedef BOOL (CALLBACK *psapi_enum_processes)(DWORD *, - DWORD, - DWORD *); - -/* winsta.dll */ -typedef BOOLEAN (CALLBACK *winsta_query_info)(HANDLE, - ULONG, - WINSTATION_INFO_CLASS, - PVOID, - ULONG, - PULONG); - -/* kernel32.dll */ -typedef BOOL (CALLBACK *kernel_memory_status)(MEMORYSTATUSEX *); - -/* mpr.dll */ -typedef BOOL (CALLBACK *mpr_get_net_connection)(LPCTSTR, - LPTSTR, - LPDWORD); - -typedef struct { - sigar_dll_handle_t handle; - - SIGAR_DLLFUNC(wtsapi, enum_sessions); - SIGAR_DLLFUNC(wtsapi, free_mem); - SIGAR_DLLFUNC(wtsapi, query_session); - - sigar_dll_func_t end; -} sigar_wtsapi_t; - -typedef struct { - sigar_dll_handle_t handle; - - SIGAR_DLLFUNC(iphlpapi, get_ipforward_table); - SIGAR_DLLFUNC(iphlpapi, get_ipaddr_table); - SIGAR_DLLFUNC(iphlpapi, get_if_table); - SIGAR_DLLFUNC(iphlpapi, get_if_entry); - SIGAR_DLLFUNC(iphlpapi, get_num_if); - SIGAR_DLLFUNC(iphlpapi, get_tcp_table); - SIGAR_DLLFUNC(iphlpapi, get_udp_table); - SIGAR_DLLFUNC(iphlpapi, get_tcpx_table); - SIGAR_DLLFUNC(iphlpapi, get_udpx_table); - SIGAR_DLLFUNC(iphlpapi, get_tcp_stats); - SIGAR_DLLFUNC(iphlpapi, get_net_params); - SIGAR_DLLFUNC(iphlpapi, get_adapters_info); - SIGAR_DLLFUNC(iphlpapi, get_adapters_addrs); - SIGAR_DLLFUNC(iphlpapi, get_ipnet_table); - - sigar_dll_func_t end; -} sigar_iphlpapi_t; - -typedef struct { - sigar_dll_handle_t handle; - - SIGAR_DLLFUNC(advapi, convert_string_sid); - SIGAR_DLLFUNC(advapi, query_service_status); - - sigar_dll_func_t end; -} sigar_advapi_t; - -typedef struct { - sigar_dll_handle_t handle; - - SIGAR_DLLFUNC(ntdll, query_sys_info); - SIGAR_DLLFUNC(ntdll, query_proc_info); - - sigar_dll_func_t end; -} sigar_ntdll_t; - -typedef struct { - sigar_dll_handle_t handle; - - SIGAR_DLLFUNC(psapi, enum_modules); - SIGAR_DLLFUNC(psapi, enum_processes); - SIGAR_DLLFUNC(psapi, get_module_name); - - sigar_dll_func_t end; -} sigar_psapi_t; - -typedef struct { - sigar_dll_handle_t handle; - - SIGAR_DLLFUNC(winsta, query_info); - - sigar_dll_func_t end; -} sigar_winsta_t; - -typedef struct { - sigar_dll_handle_t handle; - - SIGAR_DLLFUNC(kernel, memory_status); - - sigar_dll_func_t end; -} sigar_kernel_t; - -typedef struct { - sigar_dll_handle_t handle; - - SIGAR_DLLFUNC(mpr, get_net_connection); - - sigar_dll_func_t end; -} sigar_mpr_t; - -struct sigar_t { - SIGAR_T_BASE; - char *machine; - int using_wide; - long pagesize; - HKEY handle; - char *perfbuf; - DWORD perfbuf_size; - sigar_wtsapi_t wtsapi; - sigar_iphlpapi_t iphlpapi; - sigar_advapi_t advapi; - sigar_ntdll_t ntdll; - sigar_psapi_t psapi; - sigar_winsta_t winsta; - sigar_kernel_t kernel; - sigar_mpr_t mpr; - sigar_win32_pinfo_t pinfo; - sigar_cache_t *netif_adapters; - sigar_cache_t *netif_mib_rows; - sigar_cache_t *netif_addr_rows; - sigar_cache_t *netif_names; /* dwIndex -> net_interface_config.name */ - int netif_name_short; - - WORD ws_version; - int ws_error; - int ht_enabled; - int lcpu; //number of logical cpus - int winnt; -}; - -#ifdef __cplusplus -extern "C" { -#endif - -sigar_uint64_t sigar_FileTimeToTime(FILETIME *ft); - -int sigar_wsa_init(sigar_t *sigar); - -int sigar_proc_exe_peb_get(sigar_t *sigar, HANDLE proc, - sigar_proc_exe_t *procexe); - -int sigar_proc_args_peb_get(sigar_t *sigar, HANDLE proc, - sigar_proc_args_t *procargs); - -int sigar_proc_env_peb_get(sigar_t *sigar, HANDLE proc, - WCHAR *env, DWORD envlen); - -int sigar_proc_args_wmi_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_args_t *procargs); - -int sigar_proc_exe_wmi_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_exe_t *procexe); - -int sigar_parse_proc_args(sigar_t *sigar, WCHAR *buf, - sigar_proc_args_t *procargs); - -int sigar_service_pid_get(sigar_t *sigar, char *name, sigar_pid_t *pid); - -typedef struct { - DWORD size; - DWORD count; - ENUM_SERVICE_STATUS *services; - SC_HANDLE handle; -} sigar_services_status_t; - -int sigar_services_status_get(sigar_services_status_t *ss, DWORD state); - -void sigar_services_status_close(sigar_services_status_t *ss); - -typedef struct sigar_services_walker_t sigar_services_walker_t; - -struct sigar_services_walker_t { - sigar_t *sigar; - int flags; - void *data; /* user data */ - int (*add_service)(sigar_services_walker_t *walker, char *name); -}; - -int sigar_services_query(char *ptql, - sigar_ptql_error_t *error, - sigar_services_walker_t *walker); - -char *sigar_service_exe_get(char *path, char *buffer, int basename); - -typedef struct { - WORD product_major; - WORD product_minor; - WORD product_build; - WORD product_revision; - WORD file_major; - WORD file_minor; - WORD file_build; - WORD file_revision; -} sigar_file_version_t; - -int sigar_file_version_get(sigar_file_version_t *version, - char *name, - sigar_proc_env_t *infocb); - -#ifdef __cplusplus -} -#endif - -#define SIGAR_NO_SUCH_PROCESS (SIGAR_OS_START_ERROR+1) - -#endif /* SIGAR_OS_H */ diff --git a/vendor/sigar/src/os/win32/sigar_pdh.h b/vendor/sigar/src/os/win32/sigar_pdh.h deleted file mode 100644 index 86a481a..0000000 --- a/vendor/sigar/src/os/win32/sigar_pdh.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2004, 2006 Hyperic, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SIGAR_PDH_H -#define SIGAR_PDH_H - -/* performance data helpers */ - -#define PdhFirstObject(block) \ - ((PERF_OBJECT_TYPE *)((BYTE *) block + block->HeaderLength)) - -#define PdhNextObject(object) \ - ((PERF_OBJECT_TYPE *)((BYTE *) object + object->TotalByteLength)) - -#define PdhFirstCounter(object) \ - ((PERF_COUNTER_DEFINITION *)((BYTE *) object + object->HeaderLength)) - -#define PdhNextCounter(counter) \ - ((PERF_COUNTER_DEFINITION *)((BYTE *) counter + counter->ByteLength)) - -#define PdhGetCounterBlock(inst) \ - ((PERF_COUNTER_BLOCK *)((BYTE *) inst + inst->ByteLength)) - -#define PdhFirstInstance(object) \ - ((PERF_INSTANCE_DEFINITION *)((BYTE *) object + object->DefinitionLength)) - -#define PdhNextInstance(inst) \ - ((PERF_INSTANCE_DEFINITION *)((BYTE *)inst + inst->ByteLength + \ - PdhGetCounterBlock(inst)->ByteLength)) - -#define PdhInstanceName(inst) \ - ((wchar_t *)((BYTE *)inst + inst->NameOffset)) - -#endif /* SIGAR_PDH_H */ diff --git a/vendor/sigar/src/os/win32/win32_sigar.c b/vendor/sigar/src/os/win32/win32_sigar.c deleted file mode 100755 index 4288f08..0000000 --- a/vendor/sigar/src/os/win32/win32_sigar.c +++ /dev/null @@ -1,3992 +0,0 @@ -/* - * Copyright (c) 2004-2009 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * Copyright (c) 2009-2010 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sigar.h" -#include "sigar_private.h" -#include "sigar_pdh.h" -#include "sigar_os.h" -#include "sigar_util.h" -#include "sigar_format.h" -#include -#ifndef MSVC -#include -#endif - -#define USING_WIDE_S(s) (s)->using_wide -#define USING_WIDE() USING_WIDE_S(sigar) - -#define PERFBUF_SIZE 8192 - -#define PERF_TITLE_PROC 230 -#define PERF_TITLE_SYS_KEY "2" -#define PERF_TITLE_MEM_KEY "4" -#define PERF_TITLE_PROC_KEY "230" -#define PERF_TITLE_CPU_KEY "238" -#define PERF_TITLE_DISK_KEY "236" - -#define PERF_TITLE_CPU_USER 142 -#define PERF_TITLE_CPU_IDLE 1746 -#define PERF_TITLE_CPU_SYS 144 -#define PERF_TITLE_CPU_IRQ 698 - -typedef enum { - PERF_IX_CPU_USER, - PERF_IX_CPU_IDLE, - PERF_IX_CPU_SYS, - PERF_IX_CPU_IRQ, - PERF_IX_CPU_MAX -} perf_cpu_offsets_t; - -#define PERF_TITLE_CPUTIME 6 -#define PERF_TITLE_PAGE_FAULTS 28 -#define PERF_TITLE_MEM_VSIZE 174 -#define PERF_TITLE_MEM_SIZE 180 -#define PERF_TITLE_THREAD_CNT 680 -#define PERF_TITLE_HANDLE_CNT 952 -#define PERF_TITLE_PID 784 -#define PERF_TITLE_PPID 1410 -#define PERF_TITLE_PRIORITY 682 -#define PERF_TITLE_START_TIME 684 - -typedef enum { - PERF_IX_CPUTIME, - PERF_IX_PAGE_FAULTS, - PERF_IX_MEM_VSIZE, - PERF_IX_MEM_SIZE, - PERF_IX_THREAD_CNT, - PERF_IX_HANDLE_CNT, - PERF_IX_PID, - PERF_IX_PPID, - PERF_IX_PRIORITY, - PERF_IX_START_TIME, - PERF_IX_MAX -} perf_proc_offsets_t; - -typedef enum { - PERF_IX_DISK_TIME, - PERF_IX_DISK_READ_TIME, - PERF_IX_DISK_WRITE_TIME, - PERF_IX_DISK_READ, - PERF_IX_DISK_WRITE, - PERF_IX_DISK_READ_BYTES, - PERF_IX_DISK_WRITE_BYTES, - PERF_IX_DISK_QUEUE, - PERF_IX_DISK_MAX -} perf_disk_offsets_t; - -#define PERF_TITLE_DISK_TIME 200 /* % Disk Time */ -#define PERF_TITLE_DISK_READ_TIME 202 /* % Disk Read Time */ -#define PERF_TITLE_DISK_WRITE_TIME 204 /* % Disk Write Time */ -#define PERF_TITLE_DISK_READ 214 /* Disk Reads/sec */ -#define PERF_TITLE_DISK_WRITE 216 /* Disk Writes/sec */ -#define PERF_TITLE_DISK_READ_BYTES 220 /* Disk Read Bytes/sec */ -#define PERF_TITLE_DISK_WRITE_BYTES 222 /* Disk Write Bytes/sec */ -#define PERF_TITLE_DISK_QUEUE 198 /* Current Disk Queue Length */ - -/* - * diff is: - * ExW -> ExA - * wcounter -> counter - */ -#define MyRegQueryValue() \ - (USING_WIDE() ? \ - RegQueryValueExW(sigar->handle, \ - wcounter_key, NULL, &type, \ - sigar->perfbuf, \ - &bytes) : \ - RegQueryValueExA(sigar->handle, \ - counter_key, NULL, &type, \ - sigar->perfbuf, \ - &bytes)) - -#define PERF_VAL(ix) \ - perf_offsets[ix] ? \ - *((DWORD *)((BYTE *)counter_block + perf_offsets[ix])) : 0 - -/* 1/100ns units to milliseconds */ -#define NS100_2MSEC(t) ((t) / 10000) - -#define PERF_VAL_CPU(ix) \ - NS100_2MSEC(PERF_VAL(ix)) - -#define MS_LOOPBACK_ADAPTER "Microsoft Loopback Adapter" -#define NETIF_LA "la" - -static int get_proc_info(sigar_t *sigar, sigar_pid_t pid); -static int netif_hash(char *s); - -sigar_uint64_t sigar_FileTimeToTime(FILETIME *ft) -{ - sigar_uint64_t time; - time = ft->dwHighDateTime; - time = time << 32; - time |= ft->dwLowDateTime; - time /= 10; - time -= EPOCH_DELTA; - return time; -} - -static DWORD perfbuf_init(sigar_t *sigar) -{ - if (!sigar->perfbuf) { - sigar->perfbuf = malloc(PERFBUF_SIZE); - sigar->perfbuf_size = PERFBUF_SIZE; - } - - return sigar->perfbuf_size; -} - -static DWORD perfbuf_grow(sigar_t *sigar) -{ - sigar->perfbuf_size += PERFBUF_SIZE; - - sigar->perfbuf = - realloc(sigar->perfbuf, sigar->perfbuf_size); - - return sigar->perfbuf_size; -} - -static char *get_counter_name(char *key) -{ - if (strEQ(key, PERF_TITLE_MEM_KEY)) { - return "Memory"; - } - else if (strEQ(key, PERF_TITLE_PROC_KEY)) { - return "Process"; - } - else if (strEQ(key, PERF_TITLE_CPU_KEY)) { - return "Processor"; - } - else if (strEQ(key, PERF_TITLE_DISK_KEY)) { - return "LogicalDisk"; - } - else { - return key; - } -} - -static PERF_OBJECT_TYPE *get_perf_object_inst(sigar_t *sigar, - char *counter_key, - DWORD inst, DWORD *err) -{ - DWORD retval, type, bytes; - WCHAR wcounter_key[MAX_PATH+1]; - PERF_DATA_BLOCK *block; - PERF_OBJECT_TYPE *object; - - *err = SIGAR_OK; - - if (USING_WIDE()) { - SIGAR_A2W(counter_key, wcounter_key, sizeof(wcounter_key)); - } - - bytes = perfbuf_init(sigar); - - while ((retval = MyRegQueryValue()) != ERROR_SUCCESS) { - if (retval == ERROR_MORE_DATA) { - bytes = perfbuf_grow(sigar); - } - else { - *err = retval; - return NULL; - } - } - - block = (PERF_DATA_BLOCK *)sigar->perfbuf; - if (block->NumObjectTypes == 0) { - counter_key = get_counter_name(counter_key); - sigar_strerror_printf(sigar, "No %s counters defined (disabled?)", - counter_key); - *err = -1; - return NULL; - } - object = PdhFirstObject(block); - - /* - * only seen on windows 2003 server when pdh.dll - * functions are in use by the same process. - * confucius say what the fuck. - */ - if (inst && (object->NumInstances == PERF_NO_INSTANCES)) { - int i; - - for (i=0; iNumObjectTypes; i++) { - if (object->NumInstances != PERF_NO_INSTANCES) { - return object; - } - object = PdhNextObject(object); - } - return NULL; - } - else { - return object; - } -} - -#define get_perf_object(sigar, counter_key, err) \ - get_perf_object_inst(sigar, counter_key, 1, err) - -static int get_mem_counters(sigar_t *sigar, sigar_swap_t *swap, sigar_mem_t *mem) -{ - int status; - PERF_OBJECT_TYPE *object = - get_perf_object_inst(sigar, PERF_TITLE_MEM_KEY, 0, &status); - PERF_INSTANCE_DEFINITION *inst; - PERF_COUNTER_DEFINITION *counter; - BYTE *data; - DWORD i; - - if (!object) { - return status; - } - - data = (BYTE *)((BYTE *)object + object->DefinitionLength); - - for (i=0, counter = PdhFirstCounter(object); - iNumCounters; - i++, counter = PdhNextCounter(counter)) - { - DWORD offset = counter->CounterOffset; - - switch (counter->CounterNameTitleIndex) { - case 48: /* "Pages Output/sec" */ - if (swap) swap->page_out = *((DWORD *)(data + offset)); - break; - case 76: /* "System Cache Resident Bytes" aka file cache */ - if (mem) { - sigar_uint64_t kern = *((DWORD *)(data + offset)); - mem->actual_free = mem->free + kern; - mem->actual_used = mem->used - kern; - return SIGAR_OK; - } - case 822: /* "Pages Input/sec" */ - if (swap) swap->page_in = *((DWORD *)(data + offset)); - break; - default: - continue; - } - } - - return SIGAR_OK; -} - -static void get_sysinfo(sigar_t *sigar) -{ - SYSTEM_INFO sysinfo; - - GetSystemInfo(&sysinfo); - - sigar->ncpu = sysinfo.dwNumberOfProcessors; - sigar->pagesize = sysinfo.dwPageSize; -} - -/* for C# bindings */ -SIGAR_DECLARE(sigar_t *) sigar_new(void) -{ - sigar_t *sigar; - if (sigar_open(&sigar) != SIGAR_OK) { - return NULL; - } - return sigar; -} - -static sigar_wtsapi_t sigar_wtsapi = { - "wtsapi32.dll", - NULL, - { "WTSEnumerateSessionsA", NULL }, - { "WTSFreeMemory", NULL }, - { "WTSQuerySessionInformationA", NULL }, - { NULL, NULL } -}; - -static sigar_iphlpapi_t sigar_iphlpapi = { - "iphlpapi.dll", - NULL, - { "GetIpForwardTable", NULL }, - { "GetIpAddrTable", NULL }, - { "GetIfTable", NULL }, - { "GetIfEntry", NULL }, - { "GetNumberOfInterfaces", NULL }, - { "GetTcpTable", NULL }, - { "GetUdpTable", NULL }, - { "AllocateAndGetTcpExTableFromStack", NULL }, - { "AllocateAndGetUdpExTableFromStack", NULL }, - { "GetTcpStatistics", NULL }, - { "GetNetworkParams", NULL }, - { "GetAdaptersInfo", NULL }, - { "GetAdaptersAddresses", NULL }, - { "GetIpNetTable", NULL }, - { NULL, NULL } -}; - -static sigar_advapi_t sigar_advapi = { - "advapi32.dll", - NULL, - { "ConvertStringSidToSidA", NULL }, - { "QueryServiceStatusEx", NULL }, - { NULL, NULL } -}; - -static sigar_ntdll_t sigar_ntdll = { - "ntdll.dll", - NULL, - { "NtQuerySystemInformation", NULL }, - { "NtQueryInformationProcess", NULL }, - { NULL, NULL } -}; - -static sigar_psapi_t sigar_psapi = { - "psapi.dll", - NULL, - { "EnumProcessModules", NULL }, - { "EnumProcesses", NULL }, - { "GetModuleFileNameExA", NULL }, - { NULL, NULL } -}; - -static sigar_psapi_t sigar_winsta = { - "winsta.dll", - NULL, - { "WinStationQueryInformationW", NULL }, - { NULL, NULL } -}; - -static sigar_psapi_t sigar_kernel = { - "kernel32.dll", - NULL, - { "GlobalMemoryStatusEx", NULL }, - { NULL, NULL } -}; - -static sigar_mpr_t sigar_mpr = { - "mpr.dll", - NULL, - { "WNetGetConnectionA", NULL }, - { NULL, NULL } -}; - -#define DLLMOD_COPY(name) \ - memcpy(&(sigar->name), &sigar_##name, sizeof(sigar_##name)) - -#define DLLMOD_INIT(name, all) \ - sigar_dllmod_init(sigar, (sigar_dll_module_t *)&(sigar->name), all) - -#define DLLMOD_FREE(name) \ - sigar_dllmod_free((sigar_dll_module_t *)&(sigar->name)) - -static void sigar_dllmod_free(sigar_dll_module_t *module) -{ - if (module->handle) { - FreeLibrary(module->handle); - module->handle = NULL; - } -} - -static int sigar_dllmod_init(sigar_t *sigar, - sigar_dll_module_t *module, - int all) -{ - sigar_dll_func_t *funcs = &module->funcs[0]; - int is_debug = SIGAR_LOG_IS_DEBUG(sigar); - int rc, success; - - if (module->handle == INVALID_HANDLE_VALUE) { - return ENOENT; /* XXX better rc */ - } - - if (module->handle) { - return SIGAR_OK; - } - - module->handle = LoadLibrary(module->name); - if (!(success = (module->handle ? TRUE : FALSE))) { - rc = GetLastError(); - /* dont try again */ - module->handle = INVALID_HANDLE_VALUE; - } - - if (is_debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "LoadLibrary(%s): %s", - module->name, - success ? - "OK" : - sigar_strerror(sigar, rc)); - } - - if (!success) { - return rc; - } - - while (funcs->name) { - funcs->func = GetProcAddress(module->handle, funcs->name); - - if (!(success = (funcs->func ? TRUE : FALSE))) { - rc = GetLastError(); - } - - if (is_debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "GetProcAddress(%s:%s): %s", - module->name, funcs->name, - success ? - "OK" : - sigar_strerror(sigar, rc)); - } - - if (all && !success) { - return rc; - } - - funcs++; - } - - return SIGAR_OK; -} - -int sigar_wsa_init(sigar_t *sigar) -{ - if (sigar->ws_version == 0) { - WSADATA data; - - if (WSAStartup(MAKEWORD(2, 0), &data)) { - sigar->ws_error = WSAGetLastError(); - WSACleanup(); - return sigar->ws_error; - } - - sigar->ws_version = data.wVersion; - } - - return SIGAR_OK; -} - -static int sigar_enable_privilege(char *name) -{ - int status; - HANDLE handle; - TOKEN_PRIVILEGES tok; - - SIGAR_ZERO(&tok); - - if (!OpenProcessToken(GetCurrentProcess(), - TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, - &handle)) - { - return GetLastError(); - } - - if (LookupPrivilegeValue(NULL, name, - &tok.Privileges[0].Luid)) - { - tok.PrivilegeCount = 1; - tok.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - - if (AdjustTokenPrivileges(handle, FALSE, &tok, 0, NULL, 0)) { - status = SIGAR_OK; - } - else { - status = GetLastError(); - } - } - else { - status = GetLastError(); - } - - CloseHandle(handle); - - return status; -} - -static int netif_name_short(void) -{ - char value[32767]; /* max size from msdn docs */ - DWORD retval = - GetEnvironmentVariable("SIGAR_NETIF_NAME_SHORT", value, sizeof(value)); - if ((retval > 0) && (strEQ(value, "1") || (strEQ(value, "true")))) { - return 1; - } - else { - return 0; - } -} - -int sigar_os_open(sigar_t **sigar_ptr) -{ - LONG result; - HINSTANCE h; - OSVERSIONINFO version; - int i; - sigar_t *sigar; - - *sigar_ptr = sigar = malloc(sizeof(*sigar)); - sigar->machine = ""; /* local machine */ - sigar->using_wide = 0; /*XXX*/ - - sigar->perfbuf = NULL; - sigar->perfbuf_size = 0; - - version.dwOSVersionInfoSize = sizeof(version); - GetVersionEx(&version); - - /* - * 4 == NT 4.0 - * 5 == 2000, XP, 2003 Server - */ - sigar->winnt = (version.dwMajorVersion == 4); - - if (USING_WIDE_S(sigar)) { - WCHAR wmachine[MAX_PATH+1]; - - SIGAR_A2W(sigar->machine, wmachine, sizeof(wmachine)); - - result = RegConnectRegistryW(wmachine, - HKEY_PERFORMANCE_DATA, - &sigar->handle); - } - else { - result = RegConnectRegistryA(sigar->machine, - HKEY_PERFORMANCE_DATA, - &sigar->handle); - } - - get_sysinfo(sigar); - - DLLMOD_COPY(wtsapi); - DLLMOD_COPY(iphlpapi); - DLLMOD_COPY(advapi); - DLLMOD_COPY(ntdll); - DLLMOD_COPY(psapi); - DLLMOD_COPY(winsta); - DLLMOD_COPY(kernel); - DLLMOD_COPY(mpr); - - sigar->log_level = -1; /* else below segfaults */ - /* XXX init early for use by javasigar.c */ - sigar_dllmod_init(sigar, - (sigar_dll_module_t *)&sigar->advapi, - FALSE); - - sigar->netif_mib_rows = NULL; - sigar->netif_addr_rows = NULL; - sigar->netif_adapters = NULL; - sigar->netif_names = NULL; - sigar->netif_name_short = netif_name_short(); - - sigar->pinfo.pid = -1; - sigar->ws_version = 0; - sigar->lcpu = -1; - - /* increase process visibility */ - sigar_enable_privilege(SE_DEBUG_NAME); - - return result; -} - -void dllmod_init_ntdll(sigar_t *sigar) -{ - DLLMOD_INIT(ntdll, FALSE); -} - -int sigar_os_close(sigar_t *sigar) -{ - int retval; - - DLLMOD_FREE(wtsapi); - DLLMOD_FREE(iphlpapi); - DLLMOD_FREE(advapi); - DLLMOD_FREE(ntdll); - DLLMOD_FREE(psapi); - DLLMOD_FREE(winsta); - DLLMOD_FREE(kernel); - DLLMOD_FREE(mpr); - - if (sigar->perfbuf) { - free(sigar->perfbuf); - } - - retval = RegCloseKey(sigar->handle); - - if (sigar->ws_version != 0) { - WSACleanup(); - } - - if (sigar->netif_mib_rows) { - sigar_cache_destroy(sigar->netif_mib_rows); - } - - if (sigar->netif_addr_rows) { - sigar_cache_destroy(sigar->netif_addr_rows); - } - - if (sigar->netif_adapters) { - sigar_cache_destroy(sigar->netif_adapters); - } - - if (sigar->netif_names) { - sigar_cache_destroy(sigar->netif_names); - } - - free(sigar); - - return retval; -} - -char *sigar_os_error_string(sigar_t *sigar, int err) -{ - switch (err) { - case SIGAR_NO_SUCH_PROCESS: - return "No such process"; - break; - } - return NULL; -} - -#define sigar_GlobalMemoryStatusEx \ - sigar->kernel.memory_status.func - -SIGAR_DECLARE(int) sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem) -{ - DLLMOD_INIT(kernel, TRUE); - - if (sigar_GlobalMemoryStatusEx) { - MEMORYSTATUSEX memstat; - - memstat.dwLength = sizeof(memstat); - - if (!sigar_GlobalMemoryStatusEx(&memstat)) { - return GetLastError(); - } - - mem->total = memstat.ullTotalPhys; - mem->free = memstat.ullAvailPhys; - } - else { - MEMORYSTATUS memstat; - GlobalMemoryStatus(&memstat); - mem->total = memstat.dwTotalPhys; - mem->free = memstat.dwAvailPhys; - } - - mem->used = mem->total - mem->free; - - mem->actual_free = mem->free; - mem->actual_used = mem->used; - /* set actual_{free,used} */ - get_mem_counters(sigar, NULL, mem); - - sigar_mem_calc_ram(sigar, mem); - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap) -{ - int status; - DLLMOD_INIT(kernel, TRUE); - - if (sigar_GlobalMemoryStatusEx) { - MEMORYSTATUSEX memstat; - - memstat.dwLength = sizeof(memstat); - - if (!sigar_GlobalMemoryStatusEx(&memstat)) { - return GetLastError(); - } - - swap->total = memstat.ullTotalPageFile; - swap->free = memstat.ullAvailPageFile; - } - else { - MEMORYSTATUS memstat; - GlobalMemoryStatus(&memstat); - swap->total = memstat.dwTotalPageFile; - swap->free = memstat.dwAvailPageFile; - } - - swap->used = swap->total - swap->free; - - if (get_mem_counters(sigar, swap, NULL) != SIGAR_OK) { - swap->page_in = SIGAR_FIELD_NOTIMPL; - swap->page_out = SIGAR_FIELD_NOTIMPL; - } - - return SIGAR_OK; -} - -static PERF_INSTANCE_DEFINITION *get_cpu_instance(sigar_t *sigar, - DWORD *perf_offsets, - DWORD *num, DWORD *err) -{ - PERF_OBJECT_TYPE *object = get_perf_object(sigar, PERF_TITLE_CPU_KEY, err); - PERF_INSTANCE_DEFINITION *inst; - PERF_COUNTER_DEFINITION *counter; - DWORD i; - - if (!object) { - return NULL; - } - - for (i=0, counter = PdhFirstCounter(object); - iNumCounters; - i++, counter = PdhNextCounter(counter)) - { - DWORD offset = counter->CounterOffset; - - switch (counter->CounterNameTitleIndex) { - case PERF_TITLE_CPU_SYS: - perf_offsets[PERF_IX_CPU_SYS] = offset; - break; - case PERF_TITLE_CPU_USER: - perf_offsets[PERF_IX_CPU_USER] = offset; - break; - case PERF_TITLE_CPU_IDLE: - perf_offsets[PERF_IX_CPU_IDLE] = offset; - break; - case PERF_TITLE_CPU_IRQ: - perf_offsets[PERF_IX_CPU_IRQ] = offset; - break; - } - } - - if (num) { - *num = object->NumInstances; - } - - return PdhFirstInstance(object); -} - -#define SPPI_MAX 128 /* XXX unhardcode; should move off this api anyhow */ - -#define sigar_NtQuerySystemInformation \ - sigar->ntdll.query_sys_info.func - -static int get_idle_cpu(sigar_t *sigar, sigar_cpu_t *cpu, - DWORD idx, - PERF_COUNTER_BLOCK *counter_block, - DWORD *perf_offsets) -{ - cpu->idle = 0; - - if (perf_offsets[PERF_IX_CPU_IDLE]) { - cpu->idle = PERF_VAL_CPU(PERF_IX_CPU_IDLE); - } - else { - /* windows NT and 2000 do not have an Idle counter */ - DLLMOD_INIT(ntdll, FALSE); - if (sigar_NtQuerySystemInformation) { - DWORD retval, num; - SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[SPPI_MAX]; - /* into the lungs of hell */ - sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation, - &info, sizeof(info), &retval); - - if (!retval) { - return GetLastError(); - } - num = retval/sizeof(info[0]); - - if (idx == -1) { - int i; - for (i=0; iidle += NS100_2MSEC(info[i].IdleTime.QuadPart); - } - } - else if (idx < num) { - cpu->idle = NS100_2MSEC(info[idx].IdleTime.QuadPart); - } - else { - return ERROR_INVALID_DATA; - } - } - else { - return ERROR_INVALID_FUNCTION; - } - } - - return SIGAR_OK; -} - -static int sigar_cpu_perflib_get(sigar_t *sigar, sigar_cpu_t *cpu) -{ - int status; - PERF_INSTANCE_DEFINITION *inst; - PERF_COUNTER_BLOCK *counter_block; - DWORD perf_offsets[PERF_IX_CPU_MAX], err; - - SIGAR_ZERO(cpu); - memset(&perf_offsets, 0, sizeof(perf_offsets)); - - inst = get_cpu_instance(sigar, (DWORD*)&perf_offsets, 0, &err); - - if (!inst) { - return err; - } - - /* first instance is total, rest are per-cpu */ - counter_block = PdhGetCounterBlock(inst); - - cpu->sys = PERF_VAL_CPU(PERF_IX_CPU_SYS); - cpu->user = PERF_VAL_CPU(PERF_IX_CPU_USER); - status = get_idle_cpu(sigar, cpu, -1, counter_block, perf_offsets); - cpu->irq = PERF_VAL_CPU(PERF_IX_CPU_IRQ); - cpu->nice = 0; /* no nice here */ - cpu->wait = 0; /*N/A?*/ - cpu->total = cpu->sys + cpu->user + cpu->idle + cpu->wait + cpu->irq; - - if (status != SIGAR_OK) { - sigar_log_printf(sigar, SIGAR_LOG_WARN, - "unable to determine idle cpu time: %s", - sigar_strerror(sigar, status)); - } - - return SIGAR_OK; -} - -static int sigar_cpu_ntsys_get(sigar_t *sigar, sigar_cpu_t *cpu) -{ - DWORD retval, num; - int i; - SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[SPPI_MAX]; - /* into the lungs of hell */ - sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation, - &info, sizeof(info), &retval); - - if (!retval) { - return GetLastError(); - } - num = retval/sizeof(info[0]); - SIGAR_ZERO(cpu); - - for (i=0; iidle += NS100_2MSEC(info[i].IdleTime.QuadPart); - cpu->user += NS100_2MSEC(info[i].UserTime.QuadPart); - cpu->sys += NS100_2MSEC(info[i].KernelTime.QuadPart - - info[i].IdleTime.QuadPart); - cpu->irq += NS100_2MSEC(info[i].InterruptTime.QuadPart); - cpu->total += cpu->idle + cpu->user + cpu->sys; - } - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu) -{ - DLLMOD_INIT(ntdll, FALSE); - if (sigar_NtQuerySystemInformation) { - return sigar_cpu_ntsys_get(sigar, cpu); - } - else { - return sigar_cpu_perflib_get(sigar, cpu); - } -} - -static int sigar_cpu_list_perflib_get(sigar_t *sigar, - sigar_cpu_list_t *cpulist) -{ - int status, i, j; - PERF_INSTANCE_DEFINITION *inst; - DWORD perf_offsets[PERF_IX_CPU_MAX], num, err; - int core_rollup = sigar_cpu_core_rollup(sigar); - - memset(&perf_offsets, 0, sizeof(perf_offsets)); - - /* first instance is total, rest are per-cpu */ - inst = get_cpu_instance(sigar, (DWORD*)&perf_offsets, &num, &err); - - if (!inst) { - return err; - } - - if (!sigar->winnt) { - /* skip Processor _Total instance (NT doesnt have one) */ - --num; - inst = PdhNextInstance(inst); - } - - sigar_cpu_list_create(cpulist); - - /* verify there's a counter for each logical cpu */ - if (core_rollup && (sigar->ncpu != num)) { - core_rollup = 0; - } - - for (i=0; ilcpu)) { - /* merge times of logical processors */ - cpu = &cpulist->data[cpulist->number-1]; - } - else { - SIGAR_CPU_LIST_GROW(cpulist); - cpu = &cpulist->data[cpulist->number++]; - SIGAR_ZERO(cpu); - } - - counter_block = PdhGetCounterBlock(inst); - - cpu->sys += PERF_VAL_CPU(PERF_IX_CPU_SYS); - cpu->user += PERF_VAL_CPU(PERF_IX_CPU_USER); - cpu->irq += PERF_VAL_CPU(PERF_IX_CPU_IRQ); - get_idle_cpu(sigar, cpu, i, counter_block, perf_offsets); - cpu->nice = cpu->wait = 0; /*N/A*/ - - /*XXX adding up too much here if xeon, but not using this atm*/ - cpu->total += cpu->sys + cpu->user + cpu->idle + cpu->irq; - - inst = PdhNextInstance(inst); - } - - return SIGAR_OK; -} - -static int sigar_cpu_list_ntsys_get(sigar_t *sigar, - sigar_cpu_list_t *cpulist) -{ - DWORD retval, num; - int status, i, j; - int core_rollup = sigar_cpu_core_rollup(sigar); - - SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[SPPI_MAX]; - /* into the lungs of hell */ - sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation, - &info, sizeof(info), &retval); - - if (!retval) { - return GetLastError(); - } - num = retval/sizeof(info[0]); - - sigar_cpu_list_create(cpulist); - - /* verify there's a counter for each logical cpu */ - if (core_rollup && (sigar->ncpu != num)) { - core_rollup = 0; - } - - for (i=0; ilcpu)) { - /* merge times of logical processors */ - cpu = &cpulist->data[cpulist->number-1]; - } - else { - SIGAR_CPU_LIST_GROW(cpulist); - cpu = &cpulist->data[cpulist->number++]; - SIGAR_ZERO(cpu); - } - - idle = NS100_2MSEC(info[i].IdleTime.QuadPart); - user = NS100_2MSEC(info[i].UserTime.QuadPart); - sys = NS100_2MSEC(info[i].KernelTime.QuadPart - - info[i].IdleTime.QuadPart); - cpu->idle += idle; - cpu->user += user; - cpu->sys += sys; - cpu->nice = cpu->wait = 0; /*N/A*/ - cpu->total += idle + user + sys; - } - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_cpu_list_get(sigar_t *sigar, - sigar_cpu_list_t *cpulist) -{ - DLLMOD_INIT(ntdll, FALSE); - if (sigar_NtQuerySystemInformation) { - return sigar_cpu_list_ntsys_get(sigar, cpulist); - } - else { - return sigar_cpu_list_perflib_get(sigar, cpulist); - } -} - -#define PERF_TITLE_UPTIME_KEY 674 /* System Up Time */ - -SIGAR_DECLARE(int) sigar_uptime_get(sigar_t *sigar, - sigar_uptime_t *uptime) -{ - int status; - PERF_OBJECT_TYPE *object = - get_perf_object_inst(sigar, PERF_TITLE_SYS_KEY, 0, &status); - PERF_INSTANCE_DEFINITION *inst; - PERF_COUNTER_DEFINITION *counter; - BYTE *data; - DWORD i; - - if (!object) { - return status; - } - - data = (BYTE *)((BYTE *)object + object->DefinitionLength); - - for (i=0, counter = PdhFirstCounter(object); - iNumCounters; - i++, counter = PdhNextCounter(counter)) - { - if (counter->CounterNameTitleIndex == PERF_TITLE_UPTIME_KEY) { - DWORD offset = counter->CounterOffset; - LONGLONG time = object->PerfTime.QuadPart; - LONGLONG freq = object->PerfFreq.QuadPart; - LONGLONG counter = *((LONGLONG *)(data + offset)); - uptime->uptime = (time - counter) / freq; - return SIGAR_OK; - } - } - - /* http://msdn.microsoft.com/en-us/library/ms724408.aspx */ - return GetTickCount() / 1000; -} - -/* - * there is no api for this info. - * closest i've seen is enumerating the entire process table - * and calculating an average based on process times. - */ -SIGAR_DECLARE(int) sigar_loadavg_get(sigar_t *sigar, - sigar_loadavg_t *loadavg) -{ - return SIGAR_ENOTIMPL; -} - -#define get_process_object(sigar, err) \ - get_perf_object(sigar, PERF_TITLE_PROC_KEY, err) - -static int sigar_proc_list_get_perf(sigar_t *sigar, - sigar_proc_list_t *proclist) -{ - - PERF_OBJECT_TYPE *object; - PERF_INSTANCE_DEFINITION *inst; - PERF_COUNTER_DEFINITION *counter; - DWORD i, err; - DWORD perf_offsets[PERF_IX_MAX]; - - perf_offsets[PERF_IX_PID] = 0; - - object = get_process_object(sigar, &err); - - if (!object) { - return err; - } - - /* - * note we assume here: - * block->NumObjectTypes == 1 - * object->ObjectNameTitleIndex == PERF_TITLE_PROC - * - * which should always be the case. - */ - - for (i=0, counter = PdhFirstCounter(object); - iNumCounters; - i++, counter = PdhNextCounter(counter)) - { - DWORD offset = counter->CounterOffset; - - switch (counter->CounterNameTitleIndex) { - case PERF_TITLE_PID: - perf_offsets[PERF_IX_PID] = offset; - break; - } - } - - for (i=0, inst = PdhFirstInstance(object); - iNumInstances; - i++, inst = PdhNextInstance(inst)) - { - PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst); - DWORD pid = PERF_VAL(PERF_IX_PID); - - if (pid == 0) { - continue; /* dont include the system Idle process */ - } - - SIGAR_PROC_LIST_GROW(proclist); - - proclist->data[proclist->number++] = pid; - } - - return SIGAR_OK; -} - -#define sigar_EnumProcesses \ - sigar->psapi.enum_processes.func - -int sigar_os_proc_list_get(sigar_t *sigar, - sigar_proc_list_t *proclist) -{ - DLLMOD_INIT(psapi, FALSE); - - if (sigar_EnumProcesses) { - DWORD retval, *pids; - DWORD size = 0, i; - - do { - /* re-use the perfbuf */ - if (size == 0) { - size = perfbuf_init(sigar); - } - else { - size = perfbuf_grow(sigar); - } - - if (!sigar_EnumProcesses((DWORD *)sigar->perfbuf, - sigar->perfbuf_size, - &retval)) - { - return GetLastError(); - } - } while (retval == sigar->perfbuf_size); //unlikely - - pids = (DWORD *)sigar->perfbuf; - - size = retval / sizeof(DWORD); - - for (i=0; idata[proclist->number++] = pid; - } - - return SIGAR_OK; - } - else { - return sigar_proc_list_get_perf(sigar, proclist); - } -} - -#define PROCESS_DAC (PROCESS_QUERY_INFORMATION|PROCESS_VM_READ) - -static HANDLE open_process(sigar_pid_t pid) -{ - return OpenProcess(PROCESS_DAC, 0, (DWORD)pid); -} - -/* - * Pretty good explanation of counters: - * http://www.semack.net/wiki/default.asp?db=SemackNetWiki&o=VirtualMemory - */ -SIGAR_DECLARE(int) sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_mem_t *procmem) -{ - int status = get_proc_info(sigar, pid); - sigar_win32_pinfo_t *pinfo = &sigar->pinfo; - - if (status != SIGAR_OK) { - return status; - } - - procmem->size = pinfo->size; /* "Virtual Bytes" */ - procmem->resident = pinfo->resident; /* "Working Set" */ - procmem->share = SIGAR_FIELD_NOTIMPL; - procmem->page_faults = pinfo->page_faults; - procmem->minor_faults = SIGAR_FIELD_NOTIMPL; - procmem->major_faults = SIGAR_FIELD_NOTIMPL; - - return SIGAR_OK; -} - -#define TOKEN_DAC (STANDARD_RIGHTS_READ | READ_CONTROL | TOKEN_QUERY) - -SIGAR_DECLARE(int) -sigar_proc_cred_name_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_cred_name_t *proccredname) -{ - HANDLE proc, token; - DWORD len; - int success; - TOKEN_USER *user = NULL; - TOKEN_PRIMARY_GROUP *group = NULL; - SID_NAME_USE type; - char domain[SIGAR_CRED_NAME_MAX]; - - /* XXX cache lookup */ - - if (!(proc = open_process(pid))) { - return GetLastError(); - } - - if (!OpenProcessToken(proc, TOKEN_DAC, &token)) { - CloseHandle(proc); - return GetLastError(); - } - - CloseHandle(proc); - - success = - !GetTokenInformation(token, TokenUser, NULL, 0, &len) && - (GetLastError() == ERROR_INSUFFICIENT_BUFFER) && - (user = malloc(len)) && - GetTokenInformation(token, TokenUser, user, len, &len); - - if (success) { - DWORD domain_len = sizeof(domain); - DWORD user_len = sizeof(proccredname->user); - - success = LookupAccountSid(NULL, user->User.Sid, - proccredname->user, &user_len, - domain, &domain_len, &type); - } - - if (user != NULL) { - free(user); - } - if (!success) { - CloseHandle(token); - return GetLastError(); - } - - success = - !GetTokenInformation(token, TokenPrimaryGroup, NULL, 0, &len) && - (GetLastError() == ERROR_INSUFFICIENT_BUFFER) && - (group = malloc(len)) && - GetTokenInformation(token, TokenPrimaryGroup, group, len, &len); - - if (success) { - DWORD domain_len = sizeof(domain); - DWORD group_len = sizeof(proccredname->group); - - success = LookupAccountSid(NULL, group->PrimaryGroup, - proccredname->group, &group_len, - domain, &domain_len, &type); - } - - if (group != NULL) { - free(group); - } - - CloseHandle(token); - - if (!success) { - return GetLastError(); - } - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_cred_t *proccred) -{ - return SIGAR_ENOTIMPL; -} - -#define FILETIME2MSEC(ft) \ - NS100_2MSEC(((ft.dwHighDateTime << 32) | ft.dwLowDateTime)) - -sigar_int64_t sigar_time_now_millis(void) -{ - SYSTEMTIME st; - FILETIME time; - - GetSystemTime(&st); - SystemTimeToFileTime(&st, &time); - - return sigar_FileTimeToTime(&time) / 1000; -} - -SIGAR_DECLARE(int) sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_time_t *proctime) -{ - HANDLE proc = open_process(pid); - FILETIME start_time, exit_time, system_time, user_time; - int status = ERROR_SUCCESS; - - if (!proc) { - return GetLastError(); - } - - if (!GetProcessTimes(proc, - &start_time, &exit_time, - &system_time, &user_time)) - { - status = GetLastError(); - } - - CloseHandle(proc); - - if (status != ERROR_SUCCESS) { - return status; - } - - if (start_time.dwHighDateTime) { - proctime->start_time = - sigar_FileTimeToTime(&start_time) / 1000; - } - else { - proctime->start_time = 0; - } - - proctime->user = FILETIME2MSEC(user_time); - proctime->sys = FILETIME2MSEC(system_time); - proctime->total = proctime->user + proctime->sys; - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_state_t *procstate) -{ - int status = get_proc_info(sigar, pid); - sigar_win32_pinfo_t *pinfo = &sigar->pinfo; - - if (status != SIGAR_OK) { - return status; - } - - memcpy(procstate->name, pinfo->name, sizeof(procstate->name)); - procstate->state = pinfo->state; - procstate->ppid = pinfo->ppid; - procstate->priority = pinfo->priority; - procstate->nice = SIGAR_FIELD_NOTIMPL; - procstate->tty = SIGAR_FIELD_NOTIMPL; - procstate->threads = pinfo->threads; - procstate->processor = SIGAR_FIELD_NOTIMPL; - - return SIGAR_OK; -} - -static int get_proc_info(sigar_t *sigar, sigar_pid_t pid) -{ - PERF_OBJECT_TYPE *object; - PERF_INSTANCE_DEFINITION *inst; - PERF_COUNTER_DEFINITION *counter; - DWORD i, err; - DWORD perf_offsets[PERF_IX_MAX]; - sigar_win32_pinfo_t *pinfo = &sigar->pinfo; - time_t timenow = time(NULL); - - if (pinfo->pid == pid) { - if ((timenow - pinfo->mtime) < SIGAR_LAST_PROC_EXPIRE) { - return SIGAR_OK; - } - } - - memset(&perf_offsets, 0, sizeof(perf_offsets)); - - object = get_process_object(sigar, &err); - - if (object == NULL) { - return err; - } - - pinfo->pid = pid; - pinfo->mtime = timenow; - - /* - * note we assume here: - * block->NumObjectTypes == 1 - * object->ObjectNameTitleIndex == PERF_TITLE_PROC - * - * which should always be the case. - */ - - for (i=0, counter = PdhFirstCounter(object); - iNumCounters; - i++, counter = PdhNextCounter(counter)) - { - DWORD offset = counter->CounterOffset; - - switch (counter->CounterNameTitleIndex) { - case PERF_TITLE_CPUTIME: - perf_offsets[PERF_IX_CPUTIME] = offset; - break; - case PERF_TITLE_PAGE_FAULTS: - perf_offsets[PERF_IX_PAGE_FAULTS] = offset; - break; - case PERF_TITLE_MEM_VSIZE: - perf_offsets[PERF_IX_MEM_VSIZE] = offset; - break; - case PERF_TITLE_MEM_SIZE: - perf_offsets[PERF_IX_MEM_SIZE] = offset; - break; - case PERF_TITLE_THREAD_CNT: - perf_offsets[PERF_IX_THREAD_CNT] = offset; - break; - case PERF_TITLE_HANDLE_CNT: - perf_offsets[PERF_IX_HANDLE_CNT] = offset; - break; - case PERF_TITLE_PID: - perf_offsets[PERF_IX_PID] = offset; - break; - case PERF_TITLE_PPID: - perf_offsets[PERF_IX_PPID] = offset; - break; - case PERF_TITLE_PRIORITY: - perf_offsets[PERF_IX_PRIORITY] = offset; - break; - case PERF_TITLE_START_TIME: - perf_offsets[PERF_IX_START_TIME] = offset; - break; - } - } - - for (i=0, inst = PdhFirstInstance(object); - iNumInstances; - i++, inst = PdhNextInstance(inst)) - { - PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst); - sigar_pid_t this_pid = PERF_VAL(PERF_IX_PID); - - if (this_pid != pid) { - continue; - } - - pinfo->state = 'R'; /* XXX? */ - SIGAR_W2A(PdhInstanceName(inst), - pinfo->name, sizeof(pinfo->name)); - - pinfo->size = PERF_VAL(PERF_IX_MEM_VSIZE); - pinfo->resident = PERF_VAL(PERF_IX_MEM_SIZE); - pinfo->ppid = PERF_VAL(PERF_IX_PPID); - pinfo->priority = PERF_VAL(PERF_IX_PRIORITY); - pinfo->handles = PERF_VAL(PERF_IX_HANDLE_CNT); - pinfo->threads = PERF_VAL(PERF_IX_THREAD_CNT); - pinfo->page_faults = PERF_VAL(PERF_IX_PAGE_FAULTS); - - return SIGAR_OK; - } - - return SIGAR_NO_SUCH_PROCESS; -} - -static int sigar_remote_proc_args_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_args_t *procargs) -{ - int status; - char cmdline[SIGAR_CMDLINE_MAX], *ptr = cmdline, *arg; - HANDLE proc = open_process(pid); - - if (proc) { - status = sigar_proc_args_peb_get(sigar, proc, procargs); - - CloseHandle(proc); - - if (status == SIGAR_OK) { - return status; - } - } - - /* likely we are 32-bit, pid process is 64-bit */ -#ifdef MSVC - status = sigar_proc_args_wmi_get(sigar, pid, procargs); -#endif - if (status == ERROR_NOT_FOUND) { - status = SIGAR_NO_SUCH_PROCESS; - } - return status; -} - -int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_args_t *procargs) -{ - if (pid == sigar->pid) { - return sigar_parse_proc_args(sigar, NULL, procargs); - } - else { - return sigar_remote_proc_args_get(sigar, pid, procargs); - } -} - -static int sigar_proc_env_parse(UCHAR *ptr, sigar_proc_env_t *procenv, - int multi) -{ - while (*ptr) { - char *val; - int klen, vlen, status; - char key[128]; /* XXX is there a max key size? */ - - if (*ptr == '=') { - ptr += strlen(ptr)+1; - continue; - } - - val = strchr(ptr, '='); - - if (val == NULL) { - break; /*XXX*/ - } - - klen = val - (char*)ptr; - SIGAR_SSTRCPY(key, ptr); - key[klen] = '\0'; - ++val; - - vlen = strlen(val); - - status = procenv->env_getter(procenv->data, - key, klen, val, vlen); - - if (status != SIGAR_OK) { - /* not an error; just stop iterating */ - return status; - } - - if (!multi) { - break; /* caller only provided 1 key=val pair */ - } - - ptr += klen + 1 + vlen + 1; - } - - return SIGAR_OK; -} - -static int sigar_local_proc_env_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_env_t *procenv) -{ - UCHAR *env = (UCHAR*)GetEnvironmentStrings(); - - sigar_proc_env_parse(env, procenv, TRUE); - - FreeEnvironmentStrings(env); - - return SIGAR_OK; -} - -static int sigar_remote_proc_env_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_env_t *procenv) -{ - int status; - HANDLE proc = open_process(pid); - WCHAR env[4096]; - - if (!proc) { - return GetLastError(); - } - - status = sigar_proc_env_peb_get(sigar, proc, env, sizeof(env)); - - CloseHandle(proc); - - if (status == SIGAR_OK) { - LPBYTE ptr = (LPBYTE)env; - DWORD size = sizeof(env); - UCHAR ent[4096]; - - while ((size > 0) && (*ptr != L'\0')) { - DWORD len = (wcslen((LPWSTR)ptr) + 1) * sizeof(WCHAR); - /* multi=FALSE so no need to: memset(ent, '\0', sizeof(ent)) */ - SIGAR_W2A((WCHAR *)ptr, ent, sizeof(ent)); - if (sigar_proc_env_parse(ent, procenv, FALSE) != SIGAR_OK) { - break; - } - size -= len; - ptr += len; - } - } - - return status; -} - -SIGAR_DECLARE(int) sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_env_t *procenv) -{ - if (pid == sigar->pid) { - if (procenv->type == SIGAR_PROC_ENV_KEY) { - char value[32767]; /* max size from msdn docs */ - DWORD retval = - GetEnvironmentVariable(procenv->key, value, sizeof(value)); - - if (retval == 0) { - if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) { - return SIGAR_OK; - } - return GetLastError(); - } - else if (retval > sizeof(value)) { - /* XXX shouldnt happen */ - return GetLastError(); - } - - procenv->env_getter(procenv->data, - procenv->key, procenv->klen, - value, retval); - return SIGAR_OK; - } - else { - return sigar_local_proc_env_get(sigar, pid, procenv); - } - } - else { - return sigar_remote_proc_env_get(sigar, pid, procenv); - } -} - -SIGAR_DECLARE(int) sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_fd_t *procfd) -{ - int status; - sigar_win32_pinfo_t *pinfo = &sigar->pinfo; - - pinfo->pid = -1; /* force update */ - if ((status = get_proc_info(sigar, pid)) != SIGAR_OK) { - return status; - } - - procfd->total = pinfo->handles; - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_exe_t *procexe) -{ - int status = SIGAR_OK; - HANDLE proc = open_process(pid); - - if (!proc) { - return GetLastError(); - } - - status = sigar_proc_exe_peb_get(sigar, proc, procexe); -#ifdef MSVC - if (procexe->name[0] == '\0') { - /* likely we are 32-bit, pid process is 64-bit */ - /* procexe->cwd[0] = XXX where else can we try? */ - status = sigar_proc_exe_wmi_get(sigar, pid, procexe); - if (status == ERROR_NOT_FOUND) { - status = SIGAR_NO_SUCH_PROCESS; - } - } -#endif - if (procexe->cwd[0] != '\0') { - /* strip trailing '\' */ - int len = strlen(procexe->cwd); - if (procexe->cwd[len-1] == '\\') { - procexe->cwd[len-1] = '\0'; - } - /* uppercase driver letter */ - procexe->cwd[0] = toupper(procexe->cwd[0]); - /* e.g. C:\ */ - strncpy(procexe->root, procexe->cwd, 3); - procexe->root[3] = '\0'; - } - else { - procexe->root[0] = '\0'; - } - - if (procexe->name[0] != '\0') { - /* uppercase driver letter */ - procexe->name[0] = toupper(procexe->name[0]); - } - - CloseHandle(proc); - - return status; -} - -#define sigar_EnumProcessModules \ - sigar->psapi.enum_modules.func - -#define sigar_GetModuleFileNameEx \ - sigar->psapi.get_module_name.func - -SIGAR_DECLARE(int) sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_modules_t *procmods) -{ - HANDLE proc; - HMODULE modules[1024]; - DWORD size = 0; - unsigned int i; - - if (DLLMOD_INIT(psapi, TRUE) != SIGAR_OK) { - return SIGAR_ENOTIMPL; - } - - if (!(proc = open_process(pid))) { - return GetLastError(); - } - - if (!sigar_EnumProcessModules(proc, modules, sizeof(modules), &size)) { - CloseHandle(proc); - return GetLastError(); - } - - for (i=0; i<(size/sizeof(HMODULE)); i++) { - int status; - char name[MAX_PATH]; - - if (!sigar_GetModuleFileNameEx(proc, modules[i], - name, sizeof(name))) - { - continue; - } - - status = procmods->module_getter(procmods->data, - name, strlen(name)); - - if (status != SIGAR_OK) { - /* not an error; just stop iterating */ - break; - } - } - - CloseHandle(proc); - - return SIGAR_OK; -} - -#define FT2INT64(ft) \ - ((__int64)((__int64)(ft).dwHighDateTime << 32 | \ - (__int64)(ft).dwLowDateTime)) - -SIGAR_DECLARE(int) sigar_thread_cpu_get(sigar_t *sigar, - sigar_uint64_t id, - sigar_thread_cpu_t *cpu) -{ - FILETIME start, exit, sys, user; - DWORD retval; - - if (id != 0) { - return SIGAR_ENOTIMPL; - } - - retval = GetThreadTimes(GetCurrentThread(), - &start, &exit, &sys, &user); - - if (retval == 0) { - return GetLastError(); - } - - cpu->user = FT2INT64(user) * 100; - cpu->sys = FT2INT64(sys) * 100; - cpu->total = (FT2INT64(user) + FT2INT64(sys)) * 100; - - return SIGAR_OK; -} - -int sigar_os_fs_type_get(sigar_file_system_t *fsp) -{ - return fsp->type; -} - -#ifndef FILE_READ_ONLY_VOLUME -#define FILE_READ_ONLY_VOLUME 0x00080000 -#endif -#ifndef FILE_NAMED_STREAMS -#define FILE_NAMED_STREAMS 0x00040000 -#endif -#ifndef FILE_SEQUENTIAL_WRITE_ONCE -#define FILE_SEQUENTIAL_WRITE_ONCE 0x00100000 -#endif -#ifndef FILE_SUPPORTS_TRANSACTIONS -#define FILE_SUPPORTS_TRANSACTIONS 0x00200000 -#endif - -static void get_fs_options(char *opts, int osize, long flags) -{ - *opts = '\0'; - if (flags & FILE_READ_ONLY_VOLUME) strncat(opts, "ro", osize); - else strncat(opts, "rw", osize); -#if 0 /*XXX*/ - if (flags & FILE_CASE_PRESERVED_NAMES) strncat(opts, ",casepn", osize); - if (flags & FILE_CASE_SENSITIVE_SEARCH) strncat(opts, ",casess", osize); - if (flags & FILE_FILE_COMPRESSION) strncat(opts, ",fcomp", osize); - if (flags & FILE_NAMED_STREAMS) strncat(opts, ",streams", osize); - if (flags & FILE_PERSISTENT_ACLS) strncat(opts, ",acls", osize); - if (flags & FILE_SEQUENTIAL_WRITE_ONCE) strncat(opts, ",wronce", osize); - if (flags & FILE_SUPPORTS_ENCRYPTION) strncat(opts, ",efs", osize); - if (flags & FILE_SUPPORTS_OBJECT_IDS) strncat(opts, ",oids", osize); - if (flags & FILE_SUPPORTS_REPARSE_POINTS) strncat(opts, ",reparse", osize); - if (flags & FILE_SUPPORTS_SPARSE_FILES) strncat(opts, ",sparse", osize); - if (flags & FILE_SUPPORTS_TRANSACTIONS) strncat(opts, ",trans", osize); - if (flags & FILE_UNICODE_ON_DISK) strncat(opts, ",unicode", osize); - if (flags & FILE_VOLUME_IS_COMPRESSED) strncat(opts, ",vcomp", osize); - if (flags & FILE_VOLUME_QUOTAS) strncat(opts, ",quota", osize); -#endif -} - -#define sigar_WNetGetConnection \ - sigar->mpr.get_net_connection.func - -SIGAR_DECLARE(int) sigar_file_system_list_get(sigar_t *sigar, - sigar_file_system_list_t *fslist) -{ - char name[256]; - char *ptr = name; - /* XXX: hmm, Find{First,Next}Volume not available in my sdk */ - DWORD len = GetLogicalDriveStringsA(sizeof(name), name); - - DLLMOD_INIT(mpr, TRUE); - - if (len == 0) { - return GetLastError(); - } - - sigar_file_system_list_create(fslist); - - while (*ptr) { - sigar_file_system_t *fsp; - DWORD flags, serialnum=0; - char fsname[1024]; - UINT drive_type = GetDriveType(ptr); - int type; - - switch (drive_type) { - case DRIVE_FIXED: - type = SIGAR_FSTYPE_LOCAL_DISK; - break; - case DRIVE_REMOTE: - type = SIGAR_FSTYPE_NETWORK; - break; - case DRIVE_CDROM: - type = SIGAR_FSTYPE_CDROM; - break; - case DRIVE_RAMDISK: - type = SIGAR_FSTYPE_RAM_DISK; - break; - case DRIVE_REMOVABLE: - /* skip floppy, usb, etc. drives */ - ptr += strlen(ptr)+1; - continue; - default: - type = SIGAR_FSTYPE_NONE; - break; - } - - fsname[0] = '\0'; - - GetVolumeInformation(ptr, NULL, 0, &serialnum, NULL, - &flags, fsname, sizeof(fsname)); - - if (!serialnum && (drive_type == DRIVE_FIXED)) { - ptr += strlen(ptr)+1; - continue; /* ignore unformatted partitions */ - } - - SIGAR_FILE_SYSTEM_LIST_GROW(fslist); - - fsp = &fslist->data[fslist->number++]; - - fsp->type = type; - SIGAR_SSTRCPY(fsp->dir_name, ptr); - SIGAR_SSTRCPY(fsp->dev_name, ptr); - - if ((drive_type == DRIVE_REMOTE) && sigar_WNetGetConnection) { - DWORD len = sizeof(fsp->dev_name); - char drive[3] = {'\0', ':', '\0'}; /* e.g. "X:" w/o trailing "\" */ - drive[0] = fsp->dir_name[0]; - sigar_WNetGetConnection(drive, fsp->dev_name, &len); - /* ignoring failure, leaving dev_name as dir_name */ - } - - /* we set fsp->type, just looking up sigar.c:fstype_names[type] */ - sigar_fs_type_get(fsp); - - if (*fsname == '\0') { - SIGAR_SSTRCPY(fsp->sys_type_name, fsp->type_name); - } - else { - SIGAR_SSTRCPY(fsp->sys_type_name, fsname); /* CDFS, NTFS, etc */ - } - - get_fs_options(fsp->options, sizeof(fsp->options)-1, flags); - - ptr += strlen(ptr)+1; - } - - return SIGAR_OK; -} - -static PERF_INSTANCE_DEFINITION *get_disk_instance(sigar_t *sigar, - DWORD *perf_offsets, - DWORD *num, DWORD *err) -{ - PERF_OBJECT_TYPE *object = - get_perf_object(sigar, PERF_TITLE_DISK_KEY, err); - PERF_INSTANCE_DEFINITION *inst; - PERF_COUNTER_DEFINITION *counter; - DWORD i, found=0; - - if (!object) { - return NULL; - } - - for (i=0, counter = PdhFirstCounter(object); - iNumCounters; - i++, counter = PdhNextCounter(counter)) - { - DWORD offset = counter->CounterOffset; - - switch (counter->CounterNameTitleIndex) { - case PERF_TITLE_DISK_TIME: - perf_offsets[PERF_IX_DISK_TIME] = offset; - found = 1; - break; - case PERF_TITLE_DISK_READ_TIME: - perf_offsets[PERF_IX_DISK_READ_TIME] = offset; - found = 1; - break; - case PERF_TITLE_DISK_WRITE_TIME: - perf_offsets[PERF_IX_DISK_WRITE_TIME] = offset; - found = 1; - break; - case PERF_TITLE_DISK_READ: - perf_offsets[PERF_IX_DISK_READ] = offset; - found = 1; - break; - case PERF_TITLE_DISK_WRITE: - perf_offsets[PERF_IX_DISK_WRITE] = offset; - found = 1; - break; - case PERF_TITLE_DISK_READ_BYTES: - perf_offsets[PERF_IX_DISK_READ_BYTES] = offset; - found = 1; - break; - case PERF_TITLE_DISK_WRITE_BYTES: - perf_offsets[PERF_IX_DISK_WRITE_BYTES] = offset; - found = 1; - break; - case PERF_TITLE_DISK_QUEUE: - perf_offsets[PERF_IX_DISK_QUEUE] = offset; - found = 1; - break; - } - } - - if (!found) { - *err = ENOENT; - return NULL; - } - - if (num) { - *num = object->NumInstances; - } - - return PdhFirstInstance(object); -} - -SIGAR_DECLARE(int) sigar_disk_usage_get(sigar_t *sigar, - const char *dirname, - sigar_disk_usage_t *disk) -{ - DWORD i, err; - PERF_OBJECT_TYPE *object = - get_perf_object(sigar, PERF_TITLE_DISK_KEY, &err); - PERF_INSTANCE_DEFINITION *inst; - PERF_COUNTER_DEFINITION *counter; - DWORD perf_offsets[PERF_IX_DISK_MAX]; - - SIGAR_DISK_STATS_INIT(disk); - - if (!object) { - return err; - } - - memset(&perf_offsets, 0, sizeof(perf_offsets)); - inst = get_disk_instance(sigar, (DWORD*)&perf_offsets, 0, &err); - - if (!inst) { - return err; - } - - for (i=0, inst = PdhFirstInstance(object); - iNumInstances; - i++, inst = PdhNextInstance(inst)) - { - char drive[MAX_PATH]; - PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst); - wchar_t *name = (wchar_t *)((BYTE *)inst + inst->NameOffset); - - SIGAR_W2A(name, drive, sizeof(drive)); - - if (sigar_isdigit(*name)) { - char *ptr = strchr(drive, ' '); /* 2000 Server "0 C:" */ - - if (ptr) { - ++ptr; - SIGAR_SSTRCPY(drive, ptr); - } - else { - /* XXX NT is a number only "0", how to map? */ - } - } - - if (strnEQ(drive, dirname, 2)) { - disk->time = PERF_VAL(PERF_IX_DISK_TIME); - disk->rtime = PERF_VAL(PERF_IX_DISK_READ_TIME); - disk->wtime = PERF_VAL(PERF_IX_DISK_WRITE_TIME); - disk->reads = PERF_VAL(PERF_IX_DISK_READ); - disk->writes = PERF_VAL(PERF_IX_DISK_WRITE); - disk->read_bytes = PERF_VAL(PERF_IX_DISK_READ_BYTES); - disk->write_bytes = PERF_VAL(PERF_IX_DISK_WRITE_BYTES); - disk->queue = PERF_VAL(PERF_IX_DISK_QUEUE); - return SIGAR_OK; - } - } - - return ENXIO; -} - -SIGAR_DECLARE(int) -sigar_file_system_usage_get(sigar_t *sigar, - const char *dirname, - sigar_file_system_usage_t *fsusage) -{ - BOOL retval; - ULARGE_INTEGER avail, total, free; - int status; - - /* prevent dialog box if A:\ drive is empty */ - UINT errmode = SetErrorMode(SEM_FAILCRITICALERRORS); - - retval = GetDiskFreeSpaceEx(dirname, - &avail, &total, &free); - - /* restore previous error mode */ - SetErrorMode(errmode); - - if (!retval) { - return GetLastError(); - } - - fsusage->total = total.QuadPart / 1024; - fsusage->free = free.QuadPart / 1024; - fsusage->avail = avail.QuadPart / 1024; - fsusage->used = fsusage->total - fsusage->free; - fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage); - - /* N/A */ - fsusage->files = SIGAR_FIELD_NOTIMPL; - fsusage->free_files = SIGAR_FIELD_NOTIMPL; - - status = sigar_disk_usage_get(sigar, dirname, &fsusage->disk); - - return SIGAR_OK; -} - -static int sigar_cpu_info_get(sigar_t *sigar, sigar_cpu_info_t *info) -{ - HKEY key, cpu; - int i = 0; - char id[MAX_PATH + 1]; - DWORD size = 0, rc; - - RegOpenKey(HKEY_LOCAL_MACHINE, - "HARDWARE\\DESCRIPTION\\System\\CentralProcessor", &key); - - //just lookup the first id, then assume all cpus are the same. - rc = RegEnumKey(key, 0, id, sizeof(id)); - if (rc != ERROR_SUCCESS) { - RegCloseKey(key); - return rc; - } - - rc = RegOpenKey(key, id, &cpu); - if (rc != ERROR_SUCCESS) { - RegCloseKey(key); - return rc; - } - - size = sizeof(info->vendor); - if (RegQueryValueEx(cpu, "VendorIdentifier", NULL, NULL, - (LPVOID)&info->vendor, &size) || - strEQ(info->vendor, "GenuineIntel")) - { - SIGAR_SSTRCPY(info->vendor, "Intel"); - } - else { - if (strEQ(info->vendor, "AuthenticAMD")) { - SIGAR_SSTRCPY(info->vendor, "AMD"); - } - } - - size = sizeof(info->model); - if (RegQueryValueEx(cpu, "ProcessorNameString", NULL, NULL, - (LPVOID)&info->model, &size)) - { - size = sizeof(info->model); - if (RegQueryValueEx(cpu, "Identifier", NULL, NULL, - (LPVOID)&info->model, &size)) - { - SIGAR_SSTRCPY(info->model, "x86"); - } - } - else { - sigar_cpu_model_adjust(sigar, info); - } - - size = sizeof(info->mhz); // == sizeof(DWORD) - if (RegQueryValueEx(cpu, "~MHz", NULL, NULL, - (LPVOID)&info->mhz, &size)) - { - info->mhz = -1; - } - - info->cache_size = -1; //XXX - RegCloseKey(key); - RegCloseKey(cpu); - - info->total_cores = sigar->ncpu; - info->cores_per_socket = sigar->lcpu; - info->total_sockets = sigar_cpu_socket_count(sigar); - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_cpu_info_list_get(sigar_t *sigar, - sigar_cpu_info_list_t *cpu_infos) -{ - int i, status; - sigar_cpu_info_t info; - int core_rollup = sigar_cpu_core_rollup(sigar); - - sigar_cpu_info_list_create(cpu_infos); - - status = sigar_cpu_info_get(sigar, &info); - - if (status != SIGAR_OK) { - return status; - } - - for (i=0; incpu; i++) { - SIGAR_CPU_INFO_LIST_GROW(cpu_infos); - - if (core_rollup && (i % sigar->lcpu)) { - continue; /* fold logical processors */ - } - - memcpy(&cpu_infos->data[cpu_infos->number++], - &info, sizeof(info)); - } - - return SIGAR_OK; -} - -#define sigar_GetNetworkParams \ - sigar->iphlpapi.get_net_params.func - -#define sigar_GetAdaptersInfo \ - sigar->iphlpapi.get_adapters_info.func - -#define sigar_GetAdaptersAddresses \ - sigar->iphlpapi.get_adapters_addrs.func - -#define sigar_GetNumberOfInterfaces \ - sigar->iphlpapi.get_num_if.func - -static sigar_cache_t *sigar_netif_cache_new(sigar_t *sigar) -{ - DWORD num = 0; - - DLLMOD_INIT(iphlpapi, FALSE); - - if (sigar_GetNumberOfInterfaces) { - DWORD rc = sigar_GetNumberOfInterfaces(&num); - - if (rc == NO_ERROR) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "GetNumberOfInterfaces=%d", - num); - } - else { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "GetNumberOfInterfaces failed: %s", - sigar_strerror(sigar, rc)); - } - } - - if (num == 0) { - num = 10; /* reasonable default */ - } - - return sigar_cache_new(num); -} - -static int sigar_get_adapters_info(sigar_t *sigar, - PIP_ADAPTER_INFO *adapter) -{ - ULONG size = sigar->ifconf_len; - DWORD rc; - - DLLMOD_INIT(iphlpapi, FALSE); - - if (!sigar_GetAdaptersInfo) { - return SIGAR_ENOTIMPL; - } - - *adapter = (PIP_ADAPTER_INFO)sigar->ifconf_buf; - rc = sigar_GetAdaptersInfo(*adapter, &size); - - if (rc == ERROR_BUFFER_OVERFLOW) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "GetAdaptersInfo " - "realloc ifconf_buf old=%d, new=%d", - sigar->ifconf_len, size); - sigar->ifconf_len = size; - sigar->ifconf_buf = realloc(sigar->ifconf_buf, - sigar->ifconf_len); - - *adapter = (PIP_ADAPTER_INFO)sigar->ifconf_buf; - rc = sigar_GetAdaptersInfo(*adapter, &size); - } - - if (rc != NO_ERROR) { - return rc; - } - else { - return SIGAR_OK; - } -} - -static int sigar_get_adapter_info(sigar_t *sigar, - DWORD index, - IP_ADAPTER_INFO **adapter) -{ - sigar_cache_entry_t *entry; - *adapter = NULL; - - if (sigar->netif_adapters) { - entry = sigar_cache_get(sigar->netif_adapters, index); - if (entry->value) { - *adapter = (IP_ADAPTER_INFO *)entry->value; - } - } - else { - int status; - IP_ADAPTER_INFO *info; - - sigar->netif_adapters = - sigar_netif_cache_new(sigar); - - status = sigar_get_adapters_info(sigar, &info); - if (status != SIGAR_OK) { - return status; - } - - while (info) { - entry = sigar_cache_get(sigar->netif_adapters, - info->Index); - if (!entry->value) { - entry->value = malloc(sizeof(*info)); - } - memcpy(entry->value, info, sizeof(*info)); - if (info->Index == index) { - *adapter = info; - } - - info = info->Next; - } - } - - if (*adapter) { - return SIGAR_OK; - } - else { - return ENOENT; - } -} - -static int sigar_get_adapters_addresses(sigar_t *sigar, - ULONG family, ULONG flags, - PIP_ADAPTER_ADDRESSES *addrs, - ULONG *size) -{ - ULONG rc; - - DLLMOD_INIT(iphlpapi, FALSE); - - if (!sigar_GetAdaptersAddresses) { - return SIGAR_ENOTIMPL; - } - - rc = sigar_GetAdaptersAddresses(family, - flags, - NULL, - *addrs, - size); - - if (rc == ERROR_BUFFER_OVERFLOW) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "GetAdaptersAddresses realloc to %d", size); - - *addrs = realloc(*addrs, *size); - - rc = sigar_GetAdaptersAddresses(family, - flags, - NULL, - (PIP_ADAPTER_ADDRESSES)*addrs, - size); - } - - if (rc != ERROR_SUCCESS) { - return rc; - } - else { - return SIGAR_OK; - } -} - -#define sigar_GetIpAddrTable \ - sigar->iphlpapi.get_ipaddr_table.func - -static int sigar_get_ipaddr_table(sigar_t *sigar, - PMIB_IPADDRTABLE *ipaddr) -{ - ULONG size = sigar->ifconf_len; - DWORD rc; - - DLLMOD_INIT(iphlpapi, FALSE); - - if (!sigar_GetIpAddrTable) { - return SIGAR_ENOTIMPL; - } - - *ipaddr = (PMIB_IPADDRTABLE)sigar->ifconf_buf; - rc = sigar_GetIpAddrTable(*ipaddr, &size, FALSE); - - if (rc == ERROR_INSUFFICIENT_BUFFER) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "GetIpAddrTable " - "realloc ifconf_buf old=%d, new=%d", - sigar->ifconf_len, size); - sigar->ifconf_len = size; - sigar->ifconf_buf = realloc(sigar->ifconf_buf, - sigar->ifconf_len); - - *ipaddr = (PMIB_IPADDRTABLE)sigar->ifconf_buf; - rc = sigar_GetIpAddrTable(*ipaddr, &size, FALSE); - } - - if (rc != NO_ERROR) { - return rc; - } - else { - return SIGAR_OK; - } -} - -#ifndef MIB_IPADDR_PRIMARY -#define MIB_IPADDR_PRIMARY 0x0001 -#endif - -static int sigar_get_netif_ipaddr(sigar_t *sigar, - DWORD index, - MIB_IPADDRROW **ipaddr) -{ - sigar_cache_entry_t *entry; - *ipaddr = NULL; - - if (sigar->netif_addr_rows) { - entry = sigar_cache_get(sigar->netif_addr_rows, index); - if (entry->value) { - *ipaddr = (MIB_IPADDRROW *)entry->value; - } - } - else { - int status, i; - MIB_IPADDRTABLE *mib; - - sigar->netif_addr_rows = - sigar_netif_cache_new(sigar); - - status = sigar_get_ipaddr_table(sigar, &mib); - if (status != SIGAR_OK) { - return status; - } - - for (i=0; idwNumEntries; i++) { - MIB_IPADDRROW *row = &mib->table[i]; - short type; - -#if HAVE_MIB_IPADDRROW_WTYPE - type = row->wType; -#else - type = row->unused2; -#endif - if (!(type & MIB_IPADDR_PRIMARY)) { - continue; - } - - entry = sigar_cache_get(sigar->netif_addr_rows, - row->dwIndex); - if (!entry->value) { - entry->value = malloc(sizeof(*row)); - } - memcpy(entry->value, row, sizeof(*row)); - - if (row->dwIndex == index) { - *ipaddr = row; - } - } - } - - if (*ipaddr) { - return SIGAR_OK; - } - else { - return ENOENT; - } -} - -SIGAR_DECLARE(int) sigar_net_info_get(sigar_t *sigar, - sigar_net_info_t *netinfo) -{ - PIP_ADAPTER_INFO adapter; - FIXED_INFO *info; - ULONG len = 0; - IP_ADDR_STRING *ip; - DWORD rc; - - DLLMOD_INIT(iphlpapi, FALSE); - - if (!sigar_GetNetworkParams) { - return SIGAR_ENOTIMPL; - } - - SIGAR_ZERO(netinfo); - - rc = sigar_GetNetworkParams(NULL, &len); - if (rc != ERROR_BUFFER_OVERFLOW) { - return rc; - } - - info = malloc(len); - rc = sigar_GetNetworkParams(info, &len); - if (rc != NO_ERROR) { - free(info); - return rc; - } - - SIGAR_SSTRCPY(netinfo->host_name, info->HostName); - SIGAR_SSTRCPY(netinfo->domain_name, info->DomainName); - SIGAR_SSTRCPY(netinfo->primary_dns, - info->DnsServerList.IpAddress.String); - - if ((ip = info->DnsServerList.Next)) { - SIGAR_SSTRCPY(netinfo->secondary_dns, - ip->IpAddress.String); - } - - free(info); - - if (sigar_get_adapters_info(sigar, &adapter) != SIGAR_OK) { - return SIGAR_OK; - } - - while (adapter) { - /* should only be 1 */ - if (adapter->GatewayList.IpAddress.String[0]) { - SIGAR_SSTRCPY(netinfo->default_gateway, - adapter->GatewayList.IpAddress.String); - } -#if 0 - if (apapters->DhcpEnabled) { - SIGAR_SSTRCPY(netinfo->dhcp_server, - apdaters->DhcpServer.IpAddress.String); - } -#endif - adapter = adapter->Next; - } - - return SIGAR_OK; -} - -#define sigar_GetIpForwardTable \ - sigar->iphlpapi.get_ipforward_table.func - -SIGAR_DECLARE(int) sigar_net_route_list_get(sigar_t *sigar, - sigar_net_route_list_t *routelist) -{ - PMIB_IPFORWARDTABLE buffer = NULL; - ULONG bufsize = 0; - DWORD rc, i; - MIB_IPFORWARDTABLE *ipt; - sigar_net_route_t *route; - - DLLMOD_INIT(iphlpapi, FALSE); - if (!sigar_GetIpForwardTable) { - return SIGAR_ENOTIMPL; - } - - rc = sigar_GetIpForwardTable(buffer, &bufsize, FALSE); - if (rc != ERROR_INSUFFICIENT_BUFFER) { - return GetLastError(); - } - - buffer = malloc(bufsize); - rc = sigar_GetIpForwardTable(buffer, &bufsize, FALSE); - if (rc != NO_ERROR) { - free(buffer); - return GetLastError(); - } - - if (!sigar->netif_names) { - sigar_net_interface_list_get(sigar, NULL); - } - - sigar_net_route_list_create(routelist); - routelist->size = routelist->number = 0; - - ipt = buffer; - - for (i=0; idwNumEntries; i++) { - MIB_IPFORWARDROW *ipr = ipt->table + i; - sigar_cache_entry_t *entry; - - SIGAR_NET_ROUTE_LIST_GROW(routelist); - - route = &routelist->data[routelist->number++]; - SIGAR_ZERO(route); /* XXX: other fields */ - - sigar_net_address_set(route->destination, - ipr->dwForwardDest); - - sigar_net_address_set(route->mask, - ipr->dwForwardMask); - - sigar_net_address_set(route->gateway, - ipr->dwForwardNextHop); - - route->metric = ipr->dwForwardMetric1; - - route->flags = SIGAR_RTF_UP; - if ((ipr->dwForwardDest == 0) && - (ipr->dwForwardMask == 0)) - { - route->flags |= SIGAR_RTF_GATEWAY; - } - - entry = sigar_cache_get(sigar->netif_names, ipr->dwForwardIfIndex); - if (entry->value) { - SIGAR_SSTRCPY(route->ifname, (char *)entry->value); - } - } - - free(buffer); - - return SIGAR_OK; -} - -#define sigar_GetIfTable \ - sigar->iphlpapi.get_if_table.func - -#define sigar_GetIfEntry \ - sigar->iphlpapi.get_if_entry.func - -static int sigar_get_if_table(sigar_t *sigar, PMIB_IFTABLE *iftable) -{ - ULONG size = sigar->ifconf_len; - DWORD rc; - - DLLMOD_INIT(iphlpapi, FALSE); - - if (!sigar_GetIfTable) { - return SIGAR_ENOTIMPL; - } - - *iftable = (PMIB_IFTABLE)sigar->ifconf_buf; - rc = sigar_GetIfTable(*iftable, &size, FALSE); - - if (rc == ERROR_INSUFFICIENT_BUFFER) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "GetIfTable " - "realloc ifconf_buf old=%d, new=%d", - sigar->ifconf_len, size); - sigar->ifconf_len = size; - sigar->ifconf_buf = realloc(sigar->ifconf_buf, - sigar->ifconf_len); - - *iftable = (PMIB_IFTABLE)sigar->ifconf_buf; - rc = sigar_GetIfTable(*iftable, &size, FALSE); - } - - if (rc != NO_ERROR) { - return rc; - } - else { - return SIGAR_OK; - } -} - -static int get_mib_ifrow(sigar_t *sigar, - const char *name, - MIB_IFROW **ifrp) -{ - int status, key, cached=0; - sigar_cache_entry_t *entry; - - if (sigar->netif_mib_rows) { - cached = 1; - } - else { - status = sigar_net_interface_list_get(sigar, NULL); - if (status != SIGAR_OK) { - return status; - } - } - key = netif_hash(name); - entry = sigar_cache_get(sigar->netif_mib_rows, key); - if (!entry->value) { - return ENOENT; - } - - *ifrp = (MIB_IFROW *)entry->value; - if (cached) { - /* refresh */ - if ((status = sigar_GetIfEntry(*ifrp)) != NO_ERROR) { - return status; - } - } - - return SIGAR_OK; -} - -static int netif_hash(char *s) -{ - int hash = 0; - while (*s) { - hash = 31*hash + *s++; - } - return hash; -} - -/* Vista and later, wireless network cards are reported as IF_TYPE_IEEE80211 */ -#ifndef IF_TYPE_IEEE80211 -#define IF_TYPE_IEEE80211 71 -#endif - -static int -sigar_net_interface_name_get(sigar_t *sigar, MIB_IFROW *ifr, PIP_ADAPTER_ADDRESSES address_list, char *name) -{ - PIP_ADAPTER_ADDRESSES iter; - int lpc = 0; - - if (address_list == NULL) { - return SIGAR_ENOTIMPL; - } - - for (iter = address_list; iter != NULL; iter = iter->Next) { - for (lpc = 0; lpc < iter->PhysicalAddressLength; lpc++) { - if (iter->PhysicalAddress[lpc] != ifr->bPhysAddr[lpc]) { - break; - } - } - - if (lpc == iter->PhysicalAddressLength) { - wcstombs(name, iter->FriendlyName, MAX_INTERFACE_NAME_LEN); - name[MAX_INTERFACE_NAME_LEN-1] = '\0'; - return SIGAR_OK; - } - } - - return SIGAR_ENOENT; -} - -SIGAR_DECLARE(int) -sigar_net_interface_list_get(sigar_t *sigar, - sigar_net_interface_list_t *iflist) -{ - MIB_IFTABLE *ift; - int i, status; - int lo=0, eth=0, la=0; - PIP_ADAPTER_ADDRESSES address_list = NULL; - ULONG size = 0; - - status = sigar_get_adapters_addresses(sigar, AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, &address_list, &size); - - if (status != SIGAR_OK) { - address_list = NULL; - } - - if (!sigar->netif_mib_rows) { - sigar->netif_mib_rows = - sigar_netif_cache_new(sigar); - } - - if (!sigar->netif_names) { - sigar->netif_names = - sigar_netif_cache_new(sigar); - } - - if ((status = sigar_get_if_table(sigar, &ift)) != SIGAR_OK) { - if (address_list) { - free(address_list); - } - return status; - } - - if (iflist) { - iflist->number = 0; - iflist->size = ift->dwNumEntries; - iflist->data = - malloc(sizeof(*(iflist->data)) * iflist->size); - } - - for (i=0; idwNumEntries; i++) { - char name[MAX_INTERFACE_NAME_LEN]; - int key; - MIB_IFROW *ifr = ift->table + i; - sigar_cache_entry_t *entry; - - status = SIGAR_ENOENT; - - if (strEQ(ifr->bDescr, MS_LOOPBACK_ADAPTER)) { - /* special-case */ - sprintf(name, NETIF_LA "%d", la++); - } - else if (ifr->dwType == MIB_IF_TYPE_LOOPBACK) { - if (!sigar->netif_name_short) { - status = sigar_net_interface_name_get(sigar, ifr, address_list, name); - } - if (status != SIGAR_OK) { - sprintf(name, "lo%d", lo++); - } - } - else if ((ifr->dwType == MIB_IF_TYPE_ETHERNET) || - (ifr->dwType == IF_TYPE_IEEE80211)) - { - if (!sigar->netif_name_short && - (strstr(ifr->bDescr, "Scheduler") == NULL) && - (strstr(ifr->bDescr, "Filter") == NULL)) - { - status = sigar_net_interface_name_get(sigar, ifr, address_list, name); - } - - if (status != SIGAR_OK) { - if (sigar->netif_name_short) { - sprintf(name, "eth%d", eth++); - } - else { - snprintf(name, ifr->dwDescrLen, "%s", ifr->bDescr); - } - } - } - else { - continue; /*XXX*/ - } - - if (iflist) { - iflist->data[iflist->number++] = sigar_strdup(name); - } - - key = netif_hash(name); - entry = sigar_cache_get(sigar->netif_mib_rows, key); - if (!entry->value) { - entry->value = malloc(sizeof(*ifr)); - } - memcpy(entry->value, ifr, sizeof(*ifr)); - - /* save dwIndex -> name mapping for use by route_list */ - entry = sigar_cache_get(sigar->netif_names, ifr->dwIndex); - if (!entry->value) { - entry->value = sigar_strdup(name); - } - } - - if (address_list != NULL) { - free(address_list); - } - - return SIGAR_OK; -} - -static int sigar_net_interface_ipv6_config_find(sigar_t *sigar, int index, - sigar_net_interface_config_t *ifconfig) -{ -#ifdef SIGAR_USING_MSC6 - return SIGAR_ENOTIMPL; -#else - int status; - PIP_ADAPTER_ADDRESSES aa = (PIP_ADAPTER_ADDRESSES)sigar->ifconf_buf, addrs; - ULONG flags = GAA_FLAG_INCLUDE_PREFIX; - status = sigar_get_adapters_addresses(sigar, AF_UNSPEC, flags, &aa, &sigar->ifconf_len); - - if (status != SIGAR_OK) { - return status; - } - - for (addrs = aa; addrs; addrs = addrs->Next) { - PIP_ADAPTER_UNICAST_ADDRESS addr; - if (addrs->IfIndex != index) { - continue; - } - for (addr = addrs->FirstUnicastAddress; addr; addr = addr->Next) { - struct sockaddr *sa = addr->Address.lpSockaddr; - - if (sa->sa_family == AF_INET6) { - struct in6_addr *inet6 = SIGAR_SIN6_ADDR(sa); - - sigar_net_address6_set(ifconfig->address6, inet6); - sigar_net_interface_scope6_set(ifconfig, inet6); - if (addrs->FirstPrefix) { - ifconfig->prefix6_length = addrs->FirstPrefix->PrefixLength; - } - return SIGAR_OK; - } - } - } - return SIGAR_ENOENT; -#endif -} - -SIGAR_DECLARE(int) -sigar_net_interface_config_get(sigar_t *sigar, - const char *name, - sigar_net_interface_config_t *ifconfig) -{ - MIB_IFROW *ifr; - MIB_IPADDRROW *ipaddr; - int status; - - if (!name) { - return sigar_net_interface_config_primary_get(sigar, ifconfig); - } - - status = get_mib_ifrow(sigar, name, &ifr); - if (status != SIGAR_OK) { - return status; - } - - SIGAR_ZERO(ifconfig); - - SIGAR_SSTRCPY(ifconfig->name, name); - - ifconfig->mtu = ifr->dwMtu; - - sigar_net_address_mac_set(ifconfig->hwaddr, - ifr->bPhysAddr, - SIGAR_IFHWADDRLEN); - - SIGAR_SSTRCPY(ifconfig->description, - ifr->bDescr); - - if (ifr->dwOperStatus & MIB_IF_OPER_STATUS_OPERATIONAL) { - ifconfig->flags |= SIGAR_IFF_UP|SIGAR_IFF_RUNNING; - } - - status = sigar_get_netif_ipaddr(sigar, - ifr->dwIndex, - &ipaddr); - - if (status == SIGAR_OK) { - sigar_net_address_set(ifconfig->address, - ipaddr->dwAddr); - - sigar_net_address_set(ifconfig->netmask, - ipaddr->dwMask); - - if (ifr->dwType != MIB_IF_TYPE_LOOPBACK) { - if (ipaddr->dwBCastAddr) { - long bcast = - ipaddr->dwAddr & ipaddr->dwMask; - - bcast |= ~ipaddr->dwMask; - ifconfig->flags |= SIGAR_IFF_BROADCAST; - - sigar_net_address_set(ifconfig->broadcast, - bcast); - } - } - } - - /* hack for MS_LOOPBACK_ADAPTER */ - if (strnEQ(name, NETIF_LA, sizeof(NETIF_LA)-1)) { - ifr->dwType = MIB_IF_TYPE_LOOPBACK; - } - - if (ifr->dwType == MIB_IF_TYPE_LOOPBACK) { - ifconfig->flags |= SIGAR_IFF_LOOPBACK; - - SIGAR_SSTRCPY(ifconfig->type, - SIGAR_NIC_LOOPBACK); - } - else { - if (ipaddr) { - ifconfig->flags |= SIGAR_IFF_MULTICAST; - } - - SIGAR_SSTRCPY(ifconfig->type, - SIGAR_NIC_ETHERNET); - } - - sigar_net_interface_ipv6_config_init(ifconfig); - sigar_net_interface_ipv6_config_find(sigar, ifr->dwIndex, ifconfig); - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) -sigar_net_interface_stat_get(sigar_t *sigar, const char *name, - sigar_net_interface_stat_t *ifstat) -{ - MIB_IFROW *ifr; - int status; - - status = get_mib_ifrow(sigar, name, &ifr); - if (status != SIGAR_OK) { - return status; - } - - ifstat->rx_bytes = ifr->dwInOctets; - ifstat->rx_packets = ifr->dwInUcastPkts + ifr->dwInNUcastPkts; - ifstat->rx_errors = ifr->dwInErrors; - ifstat->rx_dropped = ifr->dwInDiscards; - ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL; - ifstat->rx_frame = SIGAR_FIELD_NOTIMPL; - - ifstat->tx_bytes = ifr->dwOutOctets; - ifstat->tx_packets = ifr->dwOutUcastPkts + ifr->dwOutNUcastPkts; - ifstat->tx_errors = ifr->dwOutErrors; - ifstat->tx_dropped = ifr->dwOutDiscards; - ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL; - ifstat->tx_collisions = SIGAR_FIELD_NOTIMPL; - ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL; - - ifstat->speed = ifr->dwSpeed; - - return SIGAR_OK; -} - -#define IS_TCP_SERVER(state, flags) \ - ((flags & SIGAR_NETCONN_SERVER) && (state == MIB_TCP_STATE_LISTEN)) - -#define IS_TCP_CLIENT(state, flags) \ - ((flags & SIGAR_NETCONN_CLIENT) && (state != MIB_TCP_STATE_LISTEN)) - -#define sigar_GetTcpTable \ - sigar->iphlpapi.get_tcp_table.func - -static int net_conn_get_tcp(sigar_net_connection_walker_t *walker) -{ - sigar_t *sigar = walker->sigar; - int flags = walker->flags; - int status, i; - DWORD rc, size=0; - PMIB_TCPTABLE tcp; - - DLLMOD_INIT(iphlpapi, FALSE); - - if (!sigar_GetTcpTable) { - return SIGAR_ENOTIMPL; - } - - rc = sigar_GetTcpTable(NULL, &size, FALSE); - if (rc != ERROR_INSUFFICIENT_BUFFER) { - return GetLastError(); - } - tcp = malloc(size); - rc = sigar_GetTcpTable(tcp, &size, FALSE); - if (rc) { - free(tcp); - return GetLastError(); - } - - /* go in reverse to get LISTEN states first */ - for (i = (tcp->dwNumEntries-1); i >= 0; i--) { - sigar_net_connection_t conn; - DWORD state = tcp->table[i].dwState; - - if (!(IS_TCP_SERVER(state, flags) || - IS_TCP_CLIENT(state, flags))) - { - continue; - } - - conn.local_port = htons((WORD)tcp->table[i].dwLocalPort); - conn.remote_port = htons((WORD)tcp->table[i].dwRemotePort); - - conn.type = SIGAR_NETCONN_TCP; - - sigar_net_address_set(conn.local_address, - tcp->table[i].dwLocalAddr); - - sigar_net_address_set(conn.remote_address, - tcp->table[i].dwRemoteAddr); - - conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL; - - switch (state) { - case MIB_TCP_STATE_CLOSED: - conn.state = SIGAR_TCP_CLOSE; - break; - case MIB_TCP_STATE_LISTEN: - conn.state = SIGAR_TCP_LISTEN; - break; - case MIB_TCP_STATE_SYN_SENT: - conn.state = SIGAR_TCP_SYN_SENT; - break; - case MIB_TCP_STATE_SYN_RCVD: - conn.state = SIGAR_TCP_SYN_RECV; - break; - case MIB_TCP_STATE_ESTAB: - conn.state = SIGAR_TCP_ESTABLISHED; - break; - case MIB_TCP_STATE_FIN_WAIT1: - conn.state = SIGAR_TCP_FIN_WAIT1; - break; - case MIB_TCP_STATE_FIN_WAIT2: - conn.state = SIGAR_TCP_FIN_WAIT2; - break; - case MIB_TCP_STATE_CLOSE_WAIT: - conn.state = SIGAR_TCP_CLOSE_WAIT; - break; - case MIB_TCP_STATE_CLOSING: - conn.state = SIGAR_TCP_CLOSING; - break; - case MIB_TCP_STATE_LAST_ACK: - conn.state = SIGAR_TCP_LAST_ACK; - break; - case MIB_TCP_STATE_TIME_WAIT: - conn.state = SIGAR_TCP_TIME_WAIT; - break; - case MIB_TCP_STATE_DELETE_TCB: - default: - conn.state = SIGAR_TCP_UNKNOWN; - break; - } - - if (walker->add_connection(walker, &conn) != SIGAR_OK) { - break; - } - } - - free(tcp); - return SIGAR_OK; -} - -#define IS_UDP_SERVER(conn, flags) \ - ((flags & SIGAR_NETCONN_SERVER) && !conn.remote_port) - -#define IS_UDP_CLIENT(state, flags) \ - ((flags & SIGAR_NETCONN_CLIENT) && conn.remote_port) - -#define sigar_GetUdpTable \ - sigar->iphlpapi.get_udp_table.func - -static int net_conn_get_udp(sigar_net_connection_walker_t *walker) -{ - sigar_t *sigar = walker->sigar; - int flags = walker->flags; - int status; - DWORD rc, size=0, i; - PMIB_UDPTABLE udp; - - DLLMOD_INIT(iphlpapi, FALSE); - - if (!sigar_GetUdpTable) { - return SIGAR_ENOTIMPL; - } - - rc = sigar_GetUdpTable(NULL, &size, FALSE); - if (rc != ERROR_INSUFFICIENT_BUFFER) { - return GetLastError(); - } - udp = malloc(size); - rc = sigar_GetUdpTable(udp, &size, FALSE); - if (rc) { - free(udp); - return GetLastError(); - } - - for (i = 0; i < udp->dwNumEntries; i++) { - sigar_net_connection_t conn; - - if (!(IS_UDP_SERVER(conn, flags) || - IS_UDP_CLIENT(conn, flags))) - { - continue; - } - - conn.local_port = htons((WORD)udp->table[i].dwLocalPort); - conn.remote_port = 0; - - conn.type = SIGAR_NETCONN_UDP; - - sigar_net_address_set(conn.local_address, - udp->table[i].dwLocalAddr); - - sigar_net_address_set(conn.remote_address, 0); - - conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL; - - if (walker->add_connection(walker, &conn) != SIGAR_OK) { - break; - } - } - - free(udp); - return SIGAR_OK; -} - -SIGAR_DECLARE(int) -sigar_net_connection_walk(sigar_net_connection_walker_t *walker) -{ - int status; - - if (walker->flags & SIGAR_NETCONN_TCP) { - status = net_conn_get_tcp(walker); - - if (status != SIGAR_OK) { - return status; - } - } - - if (walker->flags & SIGAR_NETCONN_UDP) { - status = net_conn_get_udp(walker); - - if (status != SIGAR_OK) { - return status; - } - } - - return SIGAR_OK; -} - -#define sigar_GetTcpStatistics \ - sigar->iphlpapi.get_tcp_stats.func - -SIGAR_DECLARE(int) -sigar_tcp_get(sigar_t *sigar, - sigar_tcp_t *tcp) -{ - MIB_TCPSTATS mib; - int status; - - DLLMOD_INIT(iphlpapi, FALSE); - - if (!sigar_GetTcpStatistics) { - return SIGAR_ENOTIMPL; - } - - status = sigar_GetTcpStatistics(&mib); - - if (status != NO_ERROR) { - return status; - } - - tcp->active_opens = mib.dwActiveOpens; - tcp->passive_opens = mib.dwPassiveOpens; - tcp->attempt_fails = mib.dwAttemptFails; - tcp->estab_resets = mib.dwEstabResets; - tcp->curr_estab = mib.dwCurrEstab; - tcp->in_segs = mib.dwInSegs; - tcp->out_segs = mib.dwOutSegs; - tcp->retrans_segs = mib.dwRetransSegs; - tcp->in_errs = mib.dwInErrs; - tcp->out_rsts = mib.dwOutRsts; - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) -sigar_nfs_client_v2_get(sigar_t *sigar, - sigar_nfs_client_v2_t *nfs) -{ - return SIGAR_ENOTIMPL; -} - -SIGAR_DECLARE(int) -sigar_nfs_server_v2_get(sigar_t *sigar, - sigar_nfs_server_v2_t *nfs) -{ - return SIGAR_ENOTIMPL; -} - -SIGAR_DECLARE(int) -sigar_nfs_client_v3_get(sigar_t *sigar, - sigar_nfs_client_v3_t *nfs) -{ - return SIGAR_ENOTIMPL; -} - -SIGAR_DECLARE(int) -sigar_nfs_server_v3_get(sigar_t *sigar, - sigar_nfs_server_v3_t *nfs) -{ - return SIGAR_ENOTIMPL; -} - -#define sigar_GetTcpExTable \ - sigar->iphlpapi.get_tcpx_table.func - -#define sigar_GetUdpExTable \ - sigar->iphlpapi.get_udpx_table.func - -SIGAR_DECLARE(int) sigar_proc_port_get(sigar_t *sigar, - int protocol, - unsigned long port, - sigar_pid_t *pid) -{ - DWORD rc, i; - - DLLMOD_INIT(iphlpapi, FALSE); - - if (protocol == SIGAR_NETCONN_TCP) { - PMIB_TCPEXTABLE tcp; - - if (!sigar_GetTcpExTable) { - return SIGAR_ENOTIMPL; - } - - rc = sigar_GetTcpExTable(&tcp, FALSE, GetProcessHeap(), - 2, 2); - - if (rc) { - return GetLastError(); - } - - for (i=0; idwNumEntries; i++) { - if (tcp->table[i].dwState != MIB_TCP_STATE_LISTEN) { - continue; - } - - if (htons((WORD)tcp->table[i].dwLocalPort) != port) { - continue; - } - - *pid = tcp->table[i].dwProcessId; - - return SIGAR_OK; - } - } - else if (protocol == SIGAR_NETCONN_UDP) { - PMIB_UDPEXTABLE udp; - - if (!sigar_GetUdpExTable) { - return SIGAR_ENOTIMPL; - } - - rc = sigar_GetUdpExTable(&udp, FALSE, GetProcessHeap(), - 2, 2); - - if (rc) { - return GetLastError(); - } - - for (i=0; idwNumEntries; i++) { - if (htons((WORD)udp->table[i].dwLocalPort) != port) { - continue; - } - - *pid = udp->table[i].dwProcessId; - - return SIGAR_OK; - } - } - else { - return SIGAR_ENOTIMPL; - } - - return ENOENT; -} - -#define sigar_GetIpNetTable \ - sigar->iphlpapi.get_ipnet_table.func - -SIGAR_DECLARE(int) sigar_arp_list_get(sigar_t *sigar, - sigar_arp_list_t *arplist) -{ - int status; - DWORD rc, size=0, i; - PMIB_IPNETTABLE ipnet; - - DLLMOD_INIT(iphlpapi, FALSE); - - if (!sigar_GetIpNetTable) { - return SIGAR_ENOTIMPL; - } - - rc = sigar_GetIpNetTable(NULL, &size, FALSE); - if (rc != ERROR_INSUFFICIENT_BUFFER) { - return GetLastError(); - } - ipnet = malloc(size); - rc = sigar_GetIpNetTable(ipnet, &size, FALSE); - if (rc) { - free(ipnet); - return GetLastError(); - } - - sigar_arp_list_create(arplist); - - if (!sigar->netif_names) { - /* dwIndex -> name map */ - sigar_net_interface_list_get(sigar, NULL); - } - - for (i = 0; i < ipnet->dwNumEntries; i++) { - sigar_arp_t *arp; - PMIB_IPNETROW entry; - sigar_cache_entry_t *ifname; - - entry = &ipnet->table[i]; - SIGAR_ARP_LIST_GROW(arplist); - arp = &arplist->data[arplist->number++]; - - sigar_net_address_set(arp->address, - entry->dwAddr); - - sigar_net_address_mac_set(arp->hwaddr, - entry->bPhysAddr, - entry->dwPhysAddrLen); - - ifname = sigar_cache_get(sigar->netif_names, entry->dwIndex); - if (ifname->value) { - SIGAR_SSTRCPY(arp->ifname, (char *)ifname->value); - } - - arp->flags = 0; /*XXX*/ - SIGAR_SSTRCPY(arp->type, "ether"); /*XXX*/ - } - - free(ipnet); - - return SIGAR_OK; -} - -#include - -static int sigar_who_net_sessions(sigar_t *sigar, - sigar_who_list_t *wholist) -{ - NET_API_STATUS status; - LPSESSION_INFO_10 buffer=NULL, ptr; - DWORD entries=0, total_entries=0; - DWORD resume_handle=0; - DWORD i; - - do { - status = NetSessionEnum(NULL, /* server name */ - NULL, /* client name */ - NULL, /* user name */ - 10, /* level */ - (LPBYTE*)&buffer, - MAX_PREFERRED_LENGTH, - &entries, - &total_entries, - &resume_handle); - - if ((status == NERR_Success) || (status == ERROR_MORE_DATA)) { - if ((ptr = buffer)) { - for (i=0; idata[wholist->number++]; - - who->time = (time(NULL) - ptr->sesi10_time); - SIGAR_W2A((LPCWSTR)ptr->sesi10_username, - who->user, sizeof(who->user)); - SIGAR_W2A((LPCWSTR)ptr->sesi10_cname, - who->host, sizeof(who->host)); - SIGAR_SSTRCPY(who->device, "network share"); - - ptr++; - } - } - } - else { - break; - } - - if (buffer) { - NetApiBufferFree(buffer); - buffer = NULL; - } - } while (status == ERROR_MORE_DATA); - - if (buffer) { - NetApiBufferFree(buffer); - } - - return SIGAR_OK; -} - -static int get_logon_info(HKEY users, - char *username, - sigar_who_t *who) -{ - DWORD status, size, type; - HKEY key; - char key_name[MAX_PATH]; - char value[256]; - FILETIME wtime; - - who->time = 0; - - sprintf(key_name, "%s\\Volatile Environment", username); - if (RegOpenKey(users, key_name, &key) != ERROR_SUCCESS) { - return ENOENT; - } - - status = RegQueryInfoKey(key, - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, - &wtime); - - if (status == ERROR_SUCCESS) { - FileTimeToLocalFileTime(&wtime, &wtime); - who->time = sigar_FileTimeToTime(&wtime) / 1000000; - } - - size = sizeof(value); - status = RegQueryValueEx(key, "CLIENTNAME", - NULL, &type, value, &size); - if (status == ERROR_SUCCESS) { - if ((value[0] != '\0') && !strEQ(value, "Console")) { - SIGAR_SSTRCPY(who->host, value); - } - } - - size = sizeof(value); - status = RegQueryValueEx(key, "SESSIONNAME", - NULL, &type, value, &size); - if (status == ERROR_SUCCESS) { - SIGAR_SSTRCPY(who->device, value); - } - - RegCloseKey(key); - - return SIGAR_OK; -} - -#define sigar_ConvertStringSidToSid \ - sigar->advapi.convert_string_sid.func - -static int sigar_who_registry(sigar_t *sigar, - sigar_who_list_t *wholist) -{ - HKEY users; - DWORD index=0, status; - - if (!sigar_ConvertStringSidToSid) { - return ENOENT; - } - - status = RegOpenKey(HKEY_USERS, NULL, &users); - if (status != ERROR_SUCCESS) { - return status; - } - - while (1) { - char subkey[MAX_PATH]; - char username[SIGAR_CRED_NAME_MAX]; - char domain[SIGAR_CRED_NAME_MAX]; - DWORD subkey_len = sizeof(subkey); - DWORD username_len = sizeof(username); - DWORD domain_len = sizeof(domain); - PSID sid; - SID_NAME_USE type; - - status = RegEnumKeyEx(users, index, subkey, &subkey_len, - NULL, NULL, NULL, NULL); - - if (status != ERROR_SUCCESS) { - break; - } - - index++; - - if ((subkey[0] == '.') || strstr(subkey, "_Classes")) { - continue; - } - - if (!sigar_ConvertStringSidToSid(subkey, &sid)) { - continue; - } - - if (LookupAccountSid(NULL, /* server */ - sid, - username, &username_len, - domain, &domain_len, - &type)) - { - sigar_who_t *who; - - SIGAR_WHO_LIST_GROW(wholist); - who = &wholist->data[wholist->number++]; - - SIGAR_SSTRCPY(who->user, username); - SIGAR_SSTRCPY(who->host, domain); - SIGAR_SSTRCPY(who->device, "console"); - - get_logon_info(users, subkey, who); - } - - LocalFree(sid); - } - - RegCloseKey(users); - - return SIGAR_OK; -} - -#define sigar_WTSEnumerateSessions \ - sigar->wtsapi.enum_sessions.func - -#define sigar_WTSFreeMemory \ - sigar->wtsapi.free_mem.func - -#define sigar_WTSQuerySessionInformation \ - sigar->wtsapi.query_session.func - -#define sigar_WinStationQueryInformation \ - sigar->winsta.query_info.func - -static int sigar_who_wts(sigar_t *sigar, - sigar_who_list_t *wholist) -{ - DWORD count=0, i; - WTS_SESSION_INFO *sessions = NULL; - - if (DLLMOD_INIT(wtsapi, TRUE) != SIGAR_OK) { - sigar_log(sigar, SIGAR_LOG_DEBUG, - "Terminal Services api functions not available"); - return ENOENT; - } - - DLLMOD_INIT(winsta, FALSE); - - if (!sigar_WTSEnumerateSessions(0, 0, 1, &sessions, &count)) { - return GetLastError(); - } - - for (i=0; idata[wholist->number++]; - - SIGAR_SSTRCPY(who->device, sessions[i].pWinStationName); - - buffer = NULL; - bytes = 0; - if (sigar_WTSQuerySessionInformation(0, - sessionId, - WTSClientAddress, - &buffer, - &bytes)) - { - PWTS_CLIENT_ADDRESS client = - (PWTS_CLIENT_ADDRESS)buffer; - - sprintf(who->host, "%u.%u.%u.%u", - client->Address[2], - client->Address[3], - client->Address[4], - client->Address[5]); - - sigar_WTSFreeMemory(buffer); - } - else { - SIGAR_SSTRCPY(who->host, "unknown"); - } - - buffer = NULL; - bytes = 0; - if (sigar_WTSQuerySessionInformation(0, - sessionId, - WTSUserName, - &buffer, - &bytes)) - { - SIGAR_SSTRCPY(who->user, buffer); - sigar_WTSFreeMemory(buffer); - } - else { - SIGAR_SSTRCPY(who->user, "unknown"); - } - - buffer = NULL; - bytes = 0; - if (sigar_WinStationQueryInformation && - sigar_WinStationQueryInformation(0, - sessionId, - WinStationInformation, - &station_info, - sizeof(station_info), - &bytes)) - { - who->time = - sigar_FileTimeToTime(&station_info.ConnectTime) / 1000000; - } - else { - who->time = 0; - } - } - - sigar_WTSFreeMemory(sessions); - - return SIGAR_OK; -} - -int sigar_who_list_get_win32(sigar_t *sigar, - sigar_who_list_t *wholist) -{ - sigar_who_net_sessions(sigar, wholist); - - sigar_who_registry(sigar, wholist); - - sigar_who_wts(sigar, wholist); - - return SIGAR_OK; -} - -/* see: http://msdn2.microsoft.com/en-us/library/ms724833.aspx */ -#ifndef VER_NT_WORKSTATION -#define VER_NT_WORKSTATION 0x0000001 -#endif - -#ifdef SIGAR_USING_MSC6 -#define sigar_wProductType wReserved[1] -#else -#define sigar_wProductType wProductType -#endif -#ifdef _M_X64 -#define SIGAR_ARCH "x64" -#else -#define SIGAR_ARCH "x86" -#endif - -int sigar_os_sys_info_get(sigar_t *sigar, - sigar_sys_info_t *sysinfo) -{ - OSVERSIONINFOEX version; - char *vendor_name, *vendor_version, *code_name=NULL; - - version.dwOSVersionInfoSize = sizeof(version); - GetVersionEx((OSVERSIONINFO *)&version); - - if (version.dwMajorVersion == 4) { - vendor_name = "Windows NT"; - vendor_version = "NT"; - } - else if (version.dwMajorVersion == 5) { - switch (version.dwMinorVersion) { - case 0: - vendor_name = "Windows 2000"; - vendor_version = "2000"; - break; - case 1: - vendor_name = "Windows XP"; - vendor_version = "XP"; - code_name = "Whistler"; - break; - case 2: - vendor_name = "Windows 2003"; - vendor_version = "2003"; - code_name = "Whistler Server"; - break; - default: - vendor_name = "Windows Unknown"; - break; - } - } - else if (version.dwMajorVersion == 6) { - if (version.sigar_wProductType == VER_NT_WORKSTATION) { - if (version.dwMinorVersion == 0) { - vendor_name = "Windows Vista"; - vendor_version = "Vista"; - code_name = "Longhorn"; - } - else { - vendor_name = "Windows 7"; - vendor_version = "7"; - code_name = "Vienna"; - } - } - else { - vendor_name = "Windows 2008"; - vendor_version = "2008"; - code_name = "Longhorn Server"; - } - } - - SIGAR_SSTRCPY(sysinfo->name, "Win32"); - SIGAR_SSTRCPY(sysinfo->vendor, "Microsoft"); - SIGAR_SSTRCPY(sysinfo->vendor_name, vendor_name); - SIGAR_SSTRCPY(sysinfo->vendor_version, vendor_version); - if (code_name) { - SIGAR_SSTRCPY(sysinfo->vendor_code_name, code_name); - } - - SIGAR_SSTRCPY(sysinfo->arch, SIGAR_ARCH); - - sprintf(sysinfo->version, "%d.%d", - version.dwMajorVersion, - version.dwMinorVersion); - - SIGAR_SSTRCPY(sysinfo->patch_level, - version.szCSDVersion); - - sprintf(sysinfo->description, "%s %s", - sysinfo->vendor, sysinfo->vendor_name); - - return SIGAR_OK; -} - -#define sigar_QueryServiceStatusEx \ - sigar->advapi.query_service_status.func - -int sigar_service_pid_get(sigar_t *sigar, char *name, sigar_pid_t *pid) -{ - DWORD rc = ERROR_SUCCESS, len; - SC_HANDLE mgr; - HANDLE svc; - SERVICE_STATUS_PROCESS status; - - if (!sigar_QueryServiceStatusEx) { - return SIGAR_ENOTIMPL; - } - - mgr = OpenSCManager(NULL, - SERVICES_ACTIVE_DATABASE, - SC_MANAGER_ALL_ACCESS); - - if (!mgr) { - return GetLastError(); - } - - if (!(svc = OpenService(mgr, name, SERVICE_ALL_ACCESS))) { - CloseServiceHandle(mgr); - return GetLastError(); - } - - if (sigar_QueryServiceStatusEx(svc, - SC_STATUS_PROCESS_INFO, - (LPBYTE)&status, - sizeof(status), &len)) - { - *pid = status.dwProcessId; - } - else { - *pid = -1; - rc = GetLastError(); - } - - CloseServiceHandle(svc); - CloseServiceHandle(mgr); - - return rc; -} - -int sigar_services_status_get(sigar_services_status_t *ss, DWORD state) -{ - DWORD bytes, resume=0; - BOOL retval; - - if (!ss->handle) { - ss->handle = - OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); - if (!ss->handle) { - return GetLastError(); - } - } - - retval = EnumServicesStatus(ss->handle, - SERVICE_WIN32, state, - ss->services, ss->size, - &bytes, &ss->count, &resume); - if (retval == FALSE) { - DWORD err = GetLastError(); - if (err != ERROR_MORE_DATA) { - return err; - } - - ss->services = realloc(ss->services, bytes); - ss->size = bytes; - - retval = EnumServicesStatus(ss->handle, - SERVICE_WIN32, state, - ss->services, ss->size, - &bytes, &ss->count, &resume); - - if (retval == FALSE) { - return GetLastError(); - } - } - - return SIGAR_OK; -} - -void sigar_services_status_close(sigar_services_status_t *ss) -{ - if (ss->handle) { - CloseServiceHandle(ss->handle); - } - if (ss->size) { - free(ss->services); - } - SIGAR_ZERO(ss); -} - -/* extract exe from QUERY_SERVICE_CONFIG.lpBinaryPathName - * leaves behind command-line arguments and quotes (if any) - */ -char *sigar_service_exe_get(char *path, char *buffer, int basename) -{ - char *ptr; - - if (path) { - strncpy(buffer, path, SIGAR_CMDLINE_MAX); - } - path = buffer; - - if (*path == '"') { - ++path; - if ((ptr = strchr(path, '"'))) { - *ptr = '\0'; - } - } - else { - ptr = sigar_strcasestr(path, ".exe"); - - if (ptr) { - *(ptr+4) = '\0'; - } - else { - if ((ptr = strchr(path, ' '))) { - *ptr = '\0'; - } - } - } - - if (basename && (ptr = strrchr(path, '\\'))) { - path = ++ptr; - } - - return path; -} - -static char *string_file_info_keys[] = { - "Comments", - "CompanyName", - "FileDescription", - "FileVersion", - "InternalName", - "LegalCopyright", - "LegalTrademarks", - "OriginalFilename", - "ProductName", - "ProductVersion", - "PrivateBuild", - "SpecialBuild", - NULL -}; - -int sigar_file_version_get(sigar_file_version_t *version, - char *name, - sigar_proc_env_t *infocb) -{ - DWORD handle, len; - LPTSTR data; - VS_FIXEDFILEINFO *info; - int status; - - if (!(len = GetFileVersionInfoSize(name, &handle))) { - return GetLastError(); - } - - if (len == 0) { - return !SIGAR_OK; - } - data = malloc(len); - - if (GetFileVersionInfo(name, handle, len, data)) { - if (VerQueryValue(data, "\\", &info, &len)) { - version->product_major = HIWORD(info->dwProductVersionMS); - version->product_minor = LOWORD(info->dwProductVersionMS); - version->product_build = HIWORD(info->dwProductVersionLS); - version->product_revision = LOWORD(info->dwProductVersionLS); - version->file_major = HIWORD(info->dwFileVersionMS); - version->file_minor = LOWORD(info->dwFileVersionMS); - version->file_build = HIWORD(info->dwFileVersionLS); - version->file_revision = LOWORD(info->dwFileVersionLS); - status = SIGAR_OK; - } - else { - status = GetLastError(); - } - } - else { - status = GetLastError(); - } - - if (infocb && (status == SIGAR_OK)) { - struct { - WORD lang; - WORD code_page; - } *trans; - - if (VerQueryValue(data, "\\VarFileInfo\\Translation", - &trans, &len)) - { - int i; - char buf[1024]; - void *ptr; - - for (i=0; string_file_info_keys[i]; i++) { - char *key = string_file_info_keys[i]; - sprintf(buf, "\\StringFileInfo\\%04x%04x\\%s", - trans[0].lang, trans[0].code_page, - key); - if (VerQueryValue(data, buf, &ptr, &len)) { - if (len == 0) { - continue; - } - infocb->env_getter(infocb->data, - key, strlen(key), - (char *)ptr, len); - } - } - } - } - - free(data); - return status; -} diff --git a/vendor/sigar/src/os/win32/wmi.cpp b/vendor/sigar/src/os/win32/wmi.cpp deleted file mode 100644 index bc1019d..0000000 --- a/vendor/sigar/src/os/win32/wmi.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (c) 2009 SpringSource, Inc. - * Copyright (c) 2009 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define UNICODE -#define _UNICODE -#define _WIN32_DCOM - -#include -#include -#include -#include -#include "sigar.h" - -#pragma comment(lib, "wbemuuid.lib") - -#ifndef SIGAR_CMDLINE_MAX -#define SIGAR_CMDLINE_MAX 4096<<2 -#endif - -class WMI { - - public: - WMI(); - ~WMI(); - HRESULT Open(LPCTSTR machine=NULL, LPCTSTR user=NULL, LPCTSTR pass=NULL); - void Close(); - HRESULT GetProcStringProperty(DWORD pid, TCHAR *name, TCHAR *value, DWORD len); - HRESULT GetProcExecutablePath(DWORD pid, TCHAR *value); - HRESULT GetProcCommandLine(DWORD pid, TCHAR *value); - int GetLastError(); - - private: - IWbemServices *wbem; - HRESULT result; - BSTR GetProcQuery(DWORD pid); -}; - -WMI::WMI() -{ - wbem = NULL; - result = S_OK; - CoInitializeEx(NULL, COINIT_MULTITHREADED); -} - -WMI::~WMI() -{ - Close(); - CoUninitialize(); -} - -/* XXX must be a better way to map HRESULT */ -int WMI::GetLastError() -{ - switch (result) { - case S_OK: - return ERROR_SUCCESS; - case WBEM_E_NOT_FOUND: - return ERROR_NOT_FOUND; - case WBEM_E_ACCESS_DENIED: - return ERROR_ACCESS_DENIED; - case WBEM_E_NOT_SUPPORTED: - return SIGAR_ENOTIMPL; - default: - return ERROR_INVALID_FUNCTION; - } -} - -HRESULT WMI::Open(LPCTSTR machine, LPCTSTR user, LPCTSTR pass) -{ - IWbemLocator *locator; - wchar_t path[MAX_PATH]; - - if (wbem) { - result = S_OK; - return result; - } - - result = - CoInitializeSecurity(NULL, //Security Descriptor - -1, //COM authentication - NULL, //Authentication services - NULL, //Reserved - RPC_C_AUTHN_LEVEL_DEFAULT, //Default authentication - RPC_C_IMP_LEVEL_IMPERSONATE, //Default Impersonation - NULL, //Authentication info - EOAC_NONE, //Additional capabilities - NULL); //Reserved - - result = CoCreateInstance(CLSID_WbemLocator, - NULL, /* IUnknown */ - CLSCTX_INPROC_SERVER, - IID_IWbemLocator, - (LPVOID *)&locator); - - if (FAILED(result)) { - return result; - } - - if (machine == NULL) { - machine = L"."; - } - - wsprintf(path, L"\\\\%S\\ROOT\\CIMV2", machine); - - result = locator->ConnectServer(bstr_t(path), //Object path of WMI namespace - bstr_t(user), //User name. NULL = current user - bstr_t(pass), //User password. NULL = current - NULL, //Locale. NULL indicates current - 0, //Security flags - NULL, //Authority (e.g. Kerberos) - NULL, //Context object - &wbem); //pointer to IWbemServices proxy - - locator->Release(); - - return result; -} - -void WMI::Close() -{ - if (wbem) { - wbem->Release(); - wbem = NULL; - result = S_OK; - } -} - -BSTR WMI::GetProcQuery(DWORD pid) -{ - wchar_t query[56]; - wsprintf(query, L"Win32_Process.Handle=%d", pid); - return bstr_t(query); -} - -HRESULT WMI::GetProcStringProperty(DWORD pid, TCHAR *name, TCHAR *value, DWORD len) -{ - IWbemClassObject *obj; - VARIANT var; - - result = wbem->GetObject(GetProcQuery(pid), 0, 0, &obj, 0); - - if (FAILED(result)) { - return result; - } - - result = obj->Get(name, 0, &var, 0, 0); - - if (SUCCEEDED(result)) { - if (var.vt == VT_NULL) { - result = E_INVALIDARG; - } - else { - lstrcpyn(value, var.bstrVal, len); - } - VariantClear(&var); - } - - obj->Release(); - - return result; -} - -HRESULT WMI::GetProcExecutablePath(DWORD pid, TCHAR *value) -{ - return GetProcStringProperty(pid, L"ExecutablePath", value, MAX_PATH); -} - -HRESULT WMI::GetProcCommandLine(DWORD pid, TCHAR *value) -{ - return GetProcStringProperty(pid, L"CommandLine", value, SIGAR_CMDLINE_MAX); -} - -/* in peb.c */ -extern "C" int sigar_parse_proc_args(sigar_t *sigar, WCHAR *buf, - sigar_proc_args_t *procargs); - -extern "C" int sigar_proc_args_wmi_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_args_t *procargs) -{ - int status; - TCHAR buf[SIGAR_CMDLINE_MAX]; - WMI *wmi = new WMI(); - - if (FAILED(wmi->Open())) { - return wmi->GetLastError(); - } - - if (FAILED(wmi->GetProcCommandLine(pid, buf))) { - status = wmi->GetLastError(); - } - else { - status = sigar_parse_proc_args(sigar, buf, procargs); - } - - wmi->Close(); - delete wmi; - - return status; -} - -extern "C" int sigar_proc_exe_wmi_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_exe_t *procexe) -{ - int status; - TCHAR buf[MAX_PATH+1]; - WMI *wmi = new WMI(); - - if (FAILED(wmi->Open())) { - return wmi->GetLastError(); - } - - procexe->name[0] = '\0'; - - if (FAILED(wmi->GetProcExecutablePath(pid, buf))) { - status = wmi->GetLastError(); - } - else { - status = SIGAR_OK; - /* SIGAR_W2A(buf, procexe->name, sizeof(procexe->name)); */ - WideCharToMultiByte(CP_ACP, 0, buf, -1, - (LPSTR)procexe->name, sizeof(procexe->name), - NULL, NULL); - } - - wmi->Close(); - delete wmi; - - return status; -} diff --git a/vendor/sigar/src/sigar.c b/vendor/sigar/src/sigar.c deleted file mode 100644 index 8bd7e91..0000000 --- a/vendor/sigar/src/sigar.c +++ /dev/null @@ -1,2428 +0,0 @@ -/* - * Copyright (c) 2004-2009 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * Copyright (c) 2009-2010 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#ifndef WIN32 -#include -#include -#include -#endif -#if defined(__OpenBSD__) || defined(__FreeBSD__) -#include -#endif -#ifndef WIN32 -#include -#endif - -#include "sigar.h" -#include "sigar_private.h" -#include "sigar_util.h" -#include "sigar_os.h" -#include "sigar_format.h" - -SIGAR_DECLARE(int) sigar_open(sigar_t **sigar) -{ - int status = sigar_os_open(sigar); - - if (status == SIGAR_OK) { - /* use env to revert to old behavior */ - (*sigar)->cpu_list_cores = getenv("SIGAR_CPU_LIST_SOCKETS") ? 0 : 1; - (*sigar)->pid = 0; - (*sigar)->ifconf_buf = NULL; - (*sigar)->ifconf_len = 0; - (*sigar)->log_level = -1; /* log nothing by default */ - (*sigar)->log_impl = NULL; - (*sigar)->log_data = NULL; - (*sigar)->ptql_re_impl = NULL; - (*sigar)->ptql_re_data = NULL; - (*sigar)->self_path = NULL; - (*sigar)->fsdev = NULL; - (*sigar)->pids = NULL; - (*sigar)->proc_cpu = NULL; - (*sigar)->net_listen = NULL; - (*sigar)->net_services_tcp = NULL; - (*sigar)->net_services_udp = NULL; - } - - return status; -} - -SIGAR_DECLARE(int) sigar_close(sigar_t *sigar) -{ - if (sigar->ifconf_buf) { - free(sigar->ifconf_buf); - } - if (sigar->self_path) { - free(sigar->self_path); - } - if (sigar->pids) { - sigar_proc_list_destroy(sigar, sigar->pids); - free(sigar->pids); - } - if (sigar->fsdev) { - sigar_cache_destroy(sigar->fsdev); - } - if (sigar->proc_cpu) { - sigar_cache_destroy(sigar->proc_cpu); - } - if (sigar->net_listen) { - sigar_cache_destroy(sigar->net_listen); - } - if (sigar->net_services_tcp) { - sigar_cache_destroy(sigar->net_services_tcp); - } - if (sigar->net_services_udp) { - sigar_cache_destroy(sigar->net_services_udp); - } - - return sigar_os_close(sigar); -} - -#ifndef __linux__ /* linux has a special case */ -SIGAR_DECLARE(sigar_pid_t) sigar_pid_get(sigar_t *sigar) -{ - if (!sigar->pid) { - sigar->pid = getpid(); - } - - return sigar->pid; -} -#endif - -/* XXX: add clear() function */ -/* XXX: check for stale-ness using start_time */ -SIGAR_DECLARE(int) sigar_proc_cpu_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_cpu_t *proccpu) -{ - sigar_cache_entry_t *entry; - sigar_proc_cpu_t *prev; - sigar_uint64_t otime, time_now = sigar_time_now_millis(); - sigar_uint64_t time_diff, total_diff; - int status; - - if (!sigar->proc_cpu) { - sigar->proc_cpu = sigar_cache_new(128); - } - - entry = sigar_cache_get(sigar->proc_cpu, pid); - if (entry->value) { - prev = (sigar_proc_cpu_t *)entry->value; - } - else { - prev = entry->value = malloc(sizeof(*prev)); - SIGAR_ZERO(prev); - } - - time_diff = time_now - prev->last_time; - proccpu->last_time = prev->last_time = time_now; - - if (time_diff == 0) { - /* we were just called within < 1 second ago. */ - memcpy(proccpu, prev, sizeof(*proccpu)); - return SIGAR_OK; - } - - otime = prev->total; - - status = - sigar_proc_time_get(sigar, pid, - (sigar_proc_time_t *)proccpu); - - if (status != SIGAR_OK) { - return status; - } - - memcpy(prev, proccpu, sizeof(*prev)); - - if (proccpu->total < otime) { - /* XXX this should not happen */ - otime = 0; - } - - if (otime == 0) { - proccpu->percent = 0.0; - /* first time called */ - return SIGAR_OK; - } - - total_diff = proccpu->total - otime; - proccpu->percent = total_diff / (double)time_diff; - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_proc_stat_get(sigar_t *sigar, - sigar_proc_stat_t *procstat) -{ - int status, i; - sigar_proc_list_t *pids; - - SIGAR_ZERO(procstat); - procstat->threads = SIGAR_FIELD_NOTIMPL; - - if ((status = sigar_proc_list_get(sigar, NULL)) != SIGAR_OK) { - return status; - } - - pids = sigar->pids; - procstat->total = pids->number; - - for (i=0; inumber; i++) { - sigar_proc_state_t state; - - status = sigar_proc_state_get(sigar, pids->data[i], &state); - if (status != SIGAR_OK) { - continue; - } - - if (state.threads != SIGAR_FIELD_NOTIMPL) { - procstat->threads += state.threads; - } - - switch (state.state) { - case SIGAR_PROC_STATE_IDLE: - procstat->idle++; - break; - case SIGAR_PROC_STATE_RUN: - procstat->running++; - break; - case SIGAR_PROC_STATE_SLEEP: - procstat->sleeping++; - break; - case SIGAR_PROC_STATE_STOP: - procstat->stopped++; - break; - case SIGAR_PROC_STATE_ZOMBIE: - procstat->zombie++; - break; - default: - break; - } - } - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_sys_info_get(sigar_t *sigar, - sigar_sys_info_t *sysinfo) -{ - SIGAR_ZERO(sysinfo); - -#ifndef WIN32 - sigar_sys_info_get_uname(sysinfo); -#endif - - sigar_os_sys_info_get(sigar, sysinfo); - - return SIGAR_OK; -} - -#ifndef WIN32 - -#include - -int sigar_sys_info_get_uname(sigar_sys_info_t *sysinfo) -{ - struct utsname name; - - uname(&name); - - SIGAR_SSTRCPY(sysinfo->version, name.release); - SIGAR_SSTRCPY(sysinfo->vendor_name, name.sysname); - SIGAR_SSTRCPY(sysinfo->name, name.sysname); - SIGAR_SSTRCPY(sysinfo->machine, name.machine); - SIGAR_SSTRCPY(sysinfo->arch, name.machine); - SIGAR_SSTRCPY(sysinfo->patch_level, "unknown"); - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) -sigar_proc_cred_name_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_cred_name_t *proccredname) -{ - sigar_proc_cred_t cred; - - int status = sigar_proc_cred_get(sigar, pid, &cred); - - if (status != SIGAR_OK) { - return status; - } - - status = sigar_user_name_get(sigar, cred.uid, - proccredname->user, - sizeof(proccredname->user)); - - if (status != SIGAR_OK) { - return status; - } - - status = sigar_group_name_get(sigar, cred.gid, - proccredname->group, - sizeof(proccredname->group)); - - return status; -} - -#endif /* WIN32 */ - -int sigar_proc_list_create(sigar_proc_list_t *proclist) -{ - proclist->number = 0; - proclist->size = SIGAR_PROC_LIST_MAX; - proclist->data = malloc(sizeof(*(proclist->data)) * - proclist->size); - return SIGAR_OK; -} - -int sigar_proc_list_grow(sigar_proc_list_t *proclist) -{ - proclist->data = realloc(proclist->data, - sizeof(*(proclist->data)) * - (proclist->size + SIGAR_PROC_LIST_MAX)); - proclist->size += SIGAR_PROC_LIST_MAX; - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_proc_list_destroy(sigar_t *sigar, - sigar_proc_list_t *proclist) -{ - if (proclist->size) { - free(proclist->data); - proclist->number = proclist->size = 0; - } - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_proc_list_get(sigar_t *sigar, - sigar_proc_list_t *proclist) -{ - if (proclist == NULL) { - /* internal re-use */ - if (sigar->pids == NULL) { - sigar->pids = malloc(sizeof(*sigar->pids)); - sigar_proc_list_create(sigar->pids); - } - else { - sigar->pids->number = 0; - } - proclist = sigar->pids; - } - else { - sigar_proc_list_create(proclist); - } - - return sigar_os_proc_list_get(sigar, proclist); -} - -int sigar_proc_args_create(sigar_proc_args_t *procargs) -{ - procargs->number = 0; - procargs->size = SIGAR_PROC_ARGS_MAX; - procargs->data = malloc(sizeof(*(procargs->data)) * - procargs->size); - return SIGAR_OK; -} - -int sigar_proc_args_grow(sigar_proc_args_t *procargs) -{ - procargs->data = realloc(procargs->data, - sizeof(*(procargs->data)) * - (procargs->size + SIGAR_PROC_ARGS_MAX)); - procargs->size += SIGAR_PROC_ARGS_MAX; - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_proc_args_destroy(sigar_t *sigar, - sigar_proc_args_t *procargs) -{ - unsigned int i; - - if (procargs->size) { - for (i=0; inumber; i++) { - free(procargs->data[i]); - } - free(procargs->data); - procargs->number = procargs->size = 0; - } - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_proc_args_get(sigar_t *sigar, - sigar_pid_t pid, - sigar_proc_args_t *procargs) -{ - int status; - sigar_proc_args_create(procargs); - status = sigar_os_proc_args_get(sigar, pid, procargs); - if (status != SIGAR_OK) { - sigar_proc_args_destroy(sigar, procargs); - } - return status; -} - -int sigar_file_system_list_create(sigar_file_system_list_t *fslist) -{ - fslist->number = 0; - fslist->size = SIGAR_FS_MAX; - fslist->data = malloc(sizeof(*(fslist->data)) * - fslist->size); - return SIGAR_OK; -} - -int sigar_file_system_list_grow(sigar_file_system_list_t *fslist) -{ - fslist->data = realloc(fslist->data, - sizeof(*(fslist->data)) * - (fslist->size + SIGAR_FS_MAX)); - fslist->size += SIGAR_FS_MAX; - - return SIGAR_OK; -} - -/* indexed with sigar_file_system_type_e */ -static const char *fstype_names[] = { - "unknown", "none", "local", "remote", "ram", "cdrom", "swap" -}; - -static int sigar_common_fs_type_get(sigar_file_system_t *fsp) -{ - char *type = fsp->sys_type_name; - - switch (*type) { - case 'n': - if (strnEQ(type, "nfs", 3)) { - fsp->type = SIGAR_FSTYPE_NETWORK; - } - break; - case 's': - if (strEQ(type, "smbfs")) { /* samba */ - fsp->type = SIGAR_FSTYPE_NETWORK; - } - else if (strEQ(type, "swap")) { - fsp->type = SIGAR_FSTYPE_SWAP; - } - break; - case 'a': - if (strEQ(type, "afs")) { - fsp->type = SIGAR_FSTYPE_NETWORK; - } - break; - case 'i': - if (strEQ(type, "iso9660")) { - fsp->type = SIGAR_FSTYPE_CDROM; - } - break; - case 'c': - if (strEQ(type, "cvfs")) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - else if (strEQ(type, "cifs")) { - fsp->type = SIGAR_FSTYPE_NETWORK; - } - break; - case 'm': - if (strEQ(type, "msdos") || strEQ(type, "minix")) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - case 'h': - if (strEQ(type, "hpfs")) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - case 'v': - if (strEQ(type, "vxfs")) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - else if (strEQ(type, "vfat")) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - case 'z': - if (strEQ(type, "zfs")) { - fsp->type = SIGAR_FSTYPE_LOCAL_DISK; - } - break; - } - - return fsp->type; -} - -void sigar_fs_type_get(sigar_file_system_t *fsp) -{ - if (!(fsp->type || /* already set */ - sigar_os_fs_type_get(fsp) || /* try os specifics first */ - sigar_common_fs_type_get(fsp))) /* try common ones last */ - { - fsp->type = SIGAR_FSTYPE_NONE; - } - - if (fsp->type >= SIGAR_FSTYPE_MAX) { - fsp->type = SIGAR_FSTYPE_NONE; - } - - strcpy(fsp->type_name, fstype_names[fsp->type]); -} - - -SIGAR_DECLARE(int) -sigar_file_system_list_destroy(sigar_t *sigar, - sigar_file_system_list_t *fslist) -{ - if (fslist->size) { - free(fslist->data); - fslist->number = fslist->size = 0; - } - - return SIGAR_OK; -} - -#ifndef NFS_PROGRAM -#define NFS_PROGRAM 100003 -#endif - -#ifndef NFS_VERSION -#define NFS_VERSION 2 -#endif - -SIGAR_DECLARE(int) -sigar_file_system_ping(sigar_t *sigar, - sigar_file_system_t *fs) -{ - int status = SIGAR_OK; -#ifndef WIN32 - char *ptr; - - if ((fs->type == SIGAR_FSTYPE_NETWORK) && - strEQ(fs->sys_type_name, "nfs") && - (ptr = strchr(fs->dev_name, ':'))) - { - *ptr = '\0'; /* "hostname:/mount" -> "hostname" */ - - status = sigar_rpc_ping(fs->dev_name, - SIGAR_NETCONN_UDP, - NFS_PROGRAM, NFS_VERSION); - - if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[fs_ping] %s -> %s: %s", - fs->dir_name, fs->dev_name, - ((status == SIGAR_OK) ? - "OK" : sigar_rpc_strerror(status))); - } - - *ptr = ':'; /* "hostname" -> "hostname:/mount" */ - } -#endif - return status; -} - -int sigar_cpu_info_list_create(sigar_cpu_info_list_t *cpu_infos) -{ - cpu_infos->number = 0; - cpu_infos->size = SIGAR_CPU_INFO_MAX; - cpu_infos->data = malloc(sizeof(*(cpu_infos->data)) * - cpu_infos->size); - return SIGAR_OK; -} - -int sigar_cpu_info_list_grow(sigar_cpu_info_list_t *cpu_infos) -{ - cpu_infos->data = realloc(cpu_infos->data, - sizeof(*(cpu_infos->data)) * - (cpu_infos->size + SIGAR_CPU_INFO_MAX)); - cpu_infos->size += SIGAR_CPU_INFO_MAX; - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) -sigar_cpu_info_list_destroy(sigar_t *sigar, - sigar_cpu_info_list_t *cpu_infos) -{ - if (cpu_infos->size) { - free(cpu_infos->data); - cpu_infos->number = cpu_infos->size = 0; - } - - return SIGAR_OK; -} - -int sigar_cpu_list_create(sigar_cpu_list_t *cpulist) -{ - cpulist->number = 0; - cpulist->size = SIGAR_CPU_INFO_MAX; - cpulist->data = malloc(sizeof(*(cpulist->data)) * - cpulist->size); - return SIGAR_OK; -} - -int sigar_cpu_list_grow(sigar_cpu_list_t *cpulist) -{ - cpulist->data = realloc(cpulist->data, - sizeof(*(cpulist->data)) * - (cpulist->size + SIGAR_CPU_INFO_MAX)); - cpulist->size += SIGAR_CPU_INFO_MAX; - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_cpu_list_destroy(sigar_t *sigar, - sigar_cpu_list_t *cpulist) -{ - if (cpulist->size) { - free(cpulist->data); - cpulist->number = cpulist->size = 0; - } - - return SIGAR_OK; -} - -int sigar_net_route_list_create(sigar_net_route_list_t *routelist) -{ - routelist->number = 0; - routelist->size = SIGAR_NET_ROUTE_LIST_MAX; - routelist->data = malloc(sizeof(*(routelist->data)) * - routelist->size); - return SIGAR_OK; -} - -int sigar_net_route_list_grow(sigar_net_route_list_t *routelist) -{ - routelist->data = - realloc(routelist->data, - sizeof(*(routelist->data)) * - (routelist->size + SIGAR_NET_ROUTE_LIST_MAX)); - routelist->size += SIGAR_NET_ROUTE_LIST_MAX; - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_net_route_list_destroy(sigar_t *sigar, - sigar_net_route_list_t *routelist) -{ - if (routelist->size) { - free(routelist->data); - routelist->number = routelist->size = 0; - } - - return SIGAR_OK; -} - -int sigar_net_interface_list_create(sigar_net_interface_list_t *iflist) -{ - iflist->number = 0; - iflist->size = SIGAR_NET_IFLIST_MAX; - iflist->data = malloc(sizeof(*(iflist->data)) * - iflist->size); - return SIGAR_OK; -} - -int sigar_net_interface_list_grow(sigar_net_interface_list_t *iflist) -{ - iflist->data = realloc(iflist->data, - sizeof(*(iflist->data)) * - (iflist->size + SIGAR_NET_IFLIST_MAX)); - iflist->size += SIGAR_NET_IFLIST_MAX; - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) -sigar_net_interface_list_destroy(sigar_t *sigar, - sigar_net_interface_list_t *iflist) -{ - unsigned int i; - - if (iflist->size) { - for (i=0; inumber; i++) { - free(iflist->data[i]); - } - free(iflist->data); - iflist->number = iflist->size = 0; - } - - return SIGAR_OK; -} - -int sigar_net_connection_list_create(sigar_net_connection_list_t *connlist) -{ - connlist->number = 0; - connlist->size = SIGAR_NET_CONNLIST_MAX; - connlist->data = malloc(sizeof(*(connlist->data)) * - connlist->size); - return SIGAR_OK; -} - -int sigar_net_connection_list_grow(sigar_net_connection_list_t *connlist) -{ - connlist->data = - realloc(connlist->data, - sizeof(*(connlist->data)) * - (connlist->size + SIGAR_NET_CONNLIST_MAX)); - connlist->size += SIGAR_NET_CONNLIST_MAX; - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) -sigar_net_connection_list_destroy(sigar_t *sigar, - sigar_net_connection_list_t *connlist) -{ - if (connlist->size) { - free(connlist->data); - connlist->number = connlist->size = 0; - } - - return SIGAR_OK; -} - -#if !defined(__linux__) -/* - * implement sigar_net_connection_list_get using sigar_net_connection_walk - * linux has its own list_get impl. - */ -static int net_connection_list_walker(sigar_net_connection_walker_t *walker, - sigar_net_connection_t *conn) -{ - sigar_net_connection_list_t *connlist = - (sigar_net_connection_list_t *)walker->data; - - SIGAR_NET_CONNLIST_GROW(connlist); - memcpy(&connlist->data[connlist->number++], - conn, sizeof(*conn)); - - return SIGAR_OK; /* continue loop */ -} - -SIGAR_DECLARE(int) -sigar_net_connection_list_get(sigar_t *sigar, - sigar_net_connection_list_t *connlist, - int flags) -{ - int status; - sigar_net_connection_walker_t walker; - - sigar_net_connection_list_create(connlist); - - walker.sigar = sigar; - walker.flags = flags; - walker.data = connlist; - walker.add_connection = net_connection_list_walker; - - status = sigar_net_connection_walk(&walker); - - if (status != SIGAR_OK) { - sigar_net_connection_list_destroy(sigar, connlist); - } - - return status; -} -#endif - -static void sigar_net_listen_address_add(sigar_t *sigar, - sigar_net_connection_t *conn) -{ - sigar_cache_entry_t *entry = - sigar_cache_get(sigar->net_listen, conn->local_port); - - if (entry->value) { - if (conn->local_address.family == SIGAR_AF_INET6) { - return; /* prefer ipv4 */ - } - } - else { - entry->value = malloc(sizeof(conn->local_address)); - } - - memcpy(entry->value, &conn->local_address, - sizeof(conn->local_address)); -} - -SIGAR_DECLARE(int) -sigar_net_listen_address_get(sigar_t *sigar, - unsigned long port, - sigar_net_address_t *address) -{ - if (!sigar->net_listen || - !sigar_cache_find(sigar->net_listen, port)) - { - sigar_net_stat_t netstat; - int status = - sigar_net_stat_get(sigar, &netstat, - SIGAR_NETCONN_SERVER|SIGAR_NETCONN_TCP); - - if (status != SIGAR_OK) { - return status; - } - } - - if (sigar_cache_find(sigar->net_listen, port)) { - void *value = sigar_cache_get(sigar->net_listen, port)->value; - memcpy(address, value, sizeof(*address)); - return SIGAR_OK; - } - else { - return ENOENT; - } -} - -typedef struct { - sigar_net_stat_t *netstat; - sigar_net_connection_list_t *connlist; -} net_stat_getter_t; - -static int net_stat_walker(sigar_net_connection_walker_t *walker, - sigar_net_connection_t *conn) -{ - int state = conn->state; - sigar_cache_t *listen_ports = walker->sigar->net_listen; - net_stat_getter_t *getter = - (net_stat_getter_t *)walker->data; - - if (conn->type == SIGAR_NETCONN_TCP) { - getter->netstat->tcp_states[state]++; - - /* XXX listen_ports may get stale */ - if (state == SIGAR_TCP_LISTEN) { - sigar_net_listen_address_add(walker->sigar, conn); - } - else { - if (sigar_cache_find(listen_ports, - conn->local_port)) - { - getter->netstat->tcp_inbound_total++; - } - else { - getter->netstat->tcp_outbound_total++; - } - } - } - else if (conn->type == SIGAR_NETCONN_UDP) { - /*XXX*/ - } - - getter->netstat->all_inbound_total = - getter->netstat->tcp_inbound_total; - - getter->netstat->all_outbound_total = - getter->netstat->tcp_outbound_total; - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) -sigar_net_stat_get(sigar_t *sigar, - sigar_net_stat_t *netstat, - int flags) -{ - sigar_net_connection_walker_t walker; - net_stat_getter_t getter; - - if (!sigar->net_listen) { - sigar->net_listen = sigar_cache_new(32); - } - - SIGAR_ZERO(netstat); - - getter.netstat = netstat; - - walker.sigar = sigar; - walker.data = &getter; - walker.add_connection = net_stat_walker; - - walker.flags = flags; - - return sigar_net_connection_walk(&walker); -} - -typedef struct { - sigar_net_stat_t *netstat; - sigar_net_address_t *address; - unsigned long port; -} net_stat_port_getter_t; - -static int net_stat_port_walker(sigar_net_connection_walker_t *walker, - sigar_net_connection_t *conn) -{ - net_stat_port_getter_t *getter = - (net_stat_port_getter_t *)walker->data; - sigar_net_stat_t *netstat = getter->netstat; - - if (conn->type == SIGAR_NETCONN_TCP) { - if (conn->local_port == getter->port) { - netstat->all_inbound_total++; - - if (sigar_net_address_equals(getter->address, - &conn->local_address) == SIGAR_OK) - { - netstat->tcp_inbound_total++; - } - } - else if (conn->remote_port == getter->port) { - netstat->all_outbound_total++; - - if (sigar_net_address_equals(getter->address, - &conn->remote_address) == SIGAR_OK) - { - netstat->tcp_outbound_total++; - } - } - else { - return SIGAR_OK; - } - - netstat->tcp_states[conn->state]++; - } - else if (conn->type == SIGAR_NETCONN_UDP) { - /*XXX*/ - } - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) -sigar_net_stat_port_get(sigar_t *sigar, - sigar_net_stat_t *netstat, - int flags, - sigar_net_address_t *address, - unsigned long port) -{ - sigar_net_connection_walker_t walker; - net_stat_port_getter_t getter; - - SIGAR_ZERO(netstat); - - getter.netstat = netstat; - getter.address = address; - getter.port = port; - - walker.sigar = sigar; - walker.data = &getter; - walker.add_connection = net_stat_port_walker; - - walker.flags = flags; - - if (SIGAR_LOG_IS_DEBUG(sigar)) { - char name[SIGAR_FQDN_LEN]; - sigar_net_address_to_string(sigar, address, name); - - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[net_stat_port] using address '%s:%d'", - name, port); - } - - return sigar_net_connection_walk(&walker); -} - -static int tcp_curr_estab_count(sigar_net_connection_walker_t *walker, - sigar_net_connection_t *conn) -{ - if ((conn->state == SIGAR_TCP_ESTABLISHED) || - (conn->state == SIGAR_TCP_CLOSE_WAIT)) - { - ((sigar_tcp_t *)walker->data)->curr_estab++; - } - - return SIGAR_OK; -} - -/* TCP-MIB::tcpCurrEstab */ -int sigar_tcp_curr_estab(sigar_t *sigar, sigar_tcp_t *tcp) -{ - sigar_net_connection_walker_t walker; - - walker.sigar = sigar; - walker.data = tcp; - walker.add_connection = tcp_curr_estab_count; - walker.flags = SIGAR_NETCONN_CLIENT|SIGAR_NETCONN_TCP; - - tcp->curr_estab = 0; - - return sigar_net_connection_walk(&walker); -} - -int sigar_arp_list_create(sigar_arp_list_t *arplist) -{ - arplist->number = 0; - arplist->size = SIGAR_ARP_LIST_MAX; - arplist->data = malloc(sizeof(*(arplist->data)) * - arplist->size); - return SIGAR_OK; -} - -int sigar_arp_list_grow(sigar_arp_list_t *arplist) -{ - arplist->data = realloc(arplist->data, - sizeof(*(arplist->data)) * - (arplist->size + SIGAR_ARP_LIST_MAX)); - arplist->size += SIGAR_ARP_LIST_MAX; - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_arp_list_destroy(sigar_t *sigar, - sigar_arp_list_t *arplist) -{ - if (arplist->size) { - free(arplist->data); - arplist->number = arplist->size = 0; - } - - return SIGAR_OK; -} - -int sigar_who_list_create(sigar_who_list_t *wholist) -{ - wholist->number = 0; - wholist->size = SIGAR_WHO_LIST_MAX; - wholist->data = malloc(sizeof(*(wholist->data)) * - wholist->size); - return SIGAR_OK; -} - -int sigar_who_list_grow(sigar_who_list_t *wholist) -{ - wholist->data = realloc(wholist->data, - sizeof(*(wholist->data)) * - (wholist->size + SIGAR_WHO_LIST_MAX)); - wholist->size += SIGAR_WHO_LIST_MAX; - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_who_list_destroy(sigar_t *sigar, - sigar_who_list_t *wholist) -{ - if (wholist->size) { - free(wholist->data); - wholist->number = wholist->size = 0; - } - - return SIGAR_OK; -} - -#ifdef DARWIN -#include -#endif -#ifdef MAC_OS_X_VERSION_10_5 -# if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 -# define SIGAR_NO_UTMP -# endif -/* else 10.4 and earlier or compiled with -mmacosx-version-min=10.3 */ -#endif - -#if defined(__sun) -# include -# define SIGAR_UTMP_FILE _UTMPX_FILE -# define ut_time ut_tv.tv_sec -#elif defined(WIN32) -/* XXX may not be the default */ -#define SIGAR_UTMP_FILE "C:\\cygwin\\var\\run\\utmp" -#define UT_LINESIZE 16 -#define UT_NAMESIZE 16 -#define UT_HOSTSIZE 256 -#define UT_IDLEN 2 -#define ut_name ut_user - -struct utmp { - short ut_type; - int ut_pid; - char ut_line[UT_LINESIZE]; - char ut_id[UT_IDLEN]; - time_t ut_time; - char ut_user[UT_NAMESIZE]; - char ut_host[UT_HOSTSIZE]; - long ut_addr; -}; -#elif defined(NETWARE) -static char *getpass(const char *prompt) -{ - static char password[BUFSIZ]; - - fputs(prompt, stderr); - fgets((char *)&password, sizeof(password), stdin); - - return (char *)&password; -} -#elif !defined(SIGAR_NO_UTMP) -# include -# ifdef UTMP_FILE -# define SIGAR_UTMP_FILE UTMP_FILE -# else -# define SIGAR_UTMP_FILE _PATH_UTMP -# endif -#endif - -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(DARWIN) -# define ut_user ut_name -#endif - -#ifdef DARWIN -/* XXX from utmpx.h; sizeof changed in 10.5 */ -/* additionally, utmpx does not work on 10.4 */ -#define SIGAR_HAS_UTMPX -#define _PATH_UTMPX "/var/run/utmpx" -#define _UTX_USERSIZE 256 /* matches MAXLOGNAME */ -#define _UTX_LINESIZE 32 -#define _UTX_IDSIZE 4 -#define _UTX_HOSTSIZE 256 -struct utmpx { - char ut_user[_UTX_USERSIZE]; /* login name */ - char ut_id[_UTX_IDSIZE]; /* id */ - char ut_line[_UTX_LINESIZE]; /* tty name */ - pid_t ut_pid; /* process id creating the entry */ - short ut_type; /* type of this entry */ - struct timeval ut_tv; /* time entry was created */ - char ut_host[_UTX_HOSTSIZE]; /* host name */ - __uint32_t ut_pad[16]; /* reserved for future use */ -}; -#define ut_xtime ut_tv.tv_sec -#define UTMPX_USER_PROCESS 7 -/* end utmpx.h */ -#define SIGAR_UTMPX_FILE _PATH_UTMPX -#endif - -#if !defined(NETWARE) && !defined(_AIX) - -#define WHOCPY(dest, src) \ - SIGAR_SSTRCPY(dest, src); \ - if (sizeof(src) < sizeof(dest)) \ - dest[sizeof(src)] = '\0' - -#ifdef SIGAR_HAS_UTMPX -static int sigar_who_utmpx(sigar_t *sigar, - sigar_who_list_t *wholist) -{ - FILE *fp; - struct utmpx ut; - - if (!(fp = fopen(SIGAR_UTMPX_FILE, "r"))) { - return errno; - } - - while (fread(&ut, sizeof(ut), 1, fp) == 1) { - sigar_who_t *who; - - if (*ut.ut_user == '\0') { - continue; - } - -#ifdef UTMPX_USER_PROCESS - if (ut.ut_type != UTMPX_USER_PROCESS) { - continue; - } -#endif - - SIGAR_WHO_LIST_GROW(wholist); - who = &wholist->data[wholist->number++]; - - WHOCPY(who->user, ut.ut_user); - WHOCPY(who->device, ut.ut_line); - WHOCPY(who->host, ut.ut_host); - - who->time = ut.ut_xtime; - } - - fclose(fp); - - return SIGAR_OK; -} -#endif - -#if defined(SIGAR_NO_UTMP) && defined(SIGAR_HAS_UTMPX) -#define sigar_who_utmp sigar_who_utmpx -#else -static int sigar_who_utmp(sigar_t *sigar, - sigar_who_list_t *wholist) -{ - FILE *fp; -#ifdef __sun - /* use futmpx w/ pid32_t for sparc64 */ - struct futmpx ut; -#else - struct utmp ut; -#endif - if (!(fp = fopen(SIGAR_UTMP_FILE, "r"))) { -#ifdef SIGAR_HAS_UTMPX - /* Darwin 10.5 */ - return sigar_who_utmpx(sigar, wholist); -#endif - return errno; - } - - while (fread(&ut, sizeof(ut), 1, fp) == 1) { - sigar_who_t *who; - - if (*ut.ut_name == '\0') { - continue; - } - -#ifdef USER_PROCESS - if (ut.ut_type != USER_PROCESS) { - continue; - } -#endif - - SIGAR_WHO_LIST_GROW(wholist); - who = &wholist->data[wholist->number++]; - - WHOCPY(who->user, ut.ut_user); - WHOCPY(who->device, ut.ut_line); - WHOCPY(who->host, ut.ut_host); - - who->time = ut.ut_time; - } - - fclose(fp); - - return SIGAR_OK; -} -#endif /* SIGAR_NO_UTMP */ -#endif /* NETWARE */ - -#if defined(WIN32) - -int sigar_who_list_get_win32(sigar_t *sigar, - sigar_who_list_t *wholist); - -SIGAR_DECLARE(int) sigar_who_list_get(sigar_t *sigar, - sigar_who_list_t *wholist) -{ - sigar_who_list_create(wholist); - - /* cygwin ssh */ - sigar_who_utmp(sigar, wholist); - - sigar_who_list_get_win32(sigar, wholist); - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_resource_limit_get(sigar_t *sigar, - sigar_resource_limit_t *rlimit) -{ - MEMORY_BASIC_INFORMATION meminfo; - memset(rlimit, 0x7fffffff, sizeof(*rlimit)); - - if (VirtualQuery((LPCVOID)&meminfo, &meminfo, sizeof(meminfo))) { - rlimit->stack_cur = - (DWORD)&meminfo - (DWORD)meminfo.AllocationBase; - rlimit->stack_max = - ((DWORD)meminfo.BaseAddress + meminfo.RegionSize) - - (DWORD)meminfo.AllocationBase; - } - - rlimit->virtual_memory_max = rlimit->virtual_memory_cur = - 0x80000000UL; - - return SIGAR_OK; -} - -#elif defined(NETWARE) -int sigar_resource_limit_get(sigar_t *sigar, - sigar_resource_limit_t *rlimit) -{ - return SIGAR_ENOTIMPL; -} - -int sigar_who_list_get(sigar_t *sigar, - sigar_who_list_t *wholist) -{ - return SIGAR_ENOTIMPL; -} -#else - -#ifndef _AIX -int sigar_who_list_get(sigar_t *sigar, - sigar_who_list_t *wholist) -{ - int status; - - sigar_who_list_create(wholist); - - status = sigar_who_utmp(sigar, wholist); - if (status != SIGAR_OK) { - sigar_who_list_destroy(sigar, wholist); - return status; - } - - return SIGAR_OK; -} -#endif - -static int sigar_get_default_gateway(sigar_t *sigar, - sigar_net_info_t *netinfo) -{ - int status, i; - sigar_net_route_list_t routelist; - - status = sigar_net_route_list_get(sigar, &routelist); - if (status != SIGAR_OK) { - return status; - } - - for (i=0; idefault_gateway); - - SIGAR_STRNCPY(netinfo->default_gateway_interface, - routelist.data[i].ifname, - sizeof(netinfo->default_gateway_interface)); - break; - } - } - - sigar_net_route_list_destroy(sigar, &routelist); - - return SIGAR_OK; -} - -int sigar_net_info_get(sigar_t *sigar, - sigar_net_info_t *netinfo) -{ - int size; - char buffer[BUFSIZ], *ptr; - FILE *fp; - - SIGAR_ZERO(netinfo); - - if ((fp = fopen("/etc/resolv.conf", "r"))) { - while ((ptr = fgets(buffer, sizeof(buffer), fp))) { - int len; - - SIGAR_SKIP_SPACE(ptr); - if ((*ptr == '#') || - !(ptr = strstr(ptr, "nameserver"))) - { - continue; - } - ptr += 10; - SIGAR_SKIP_SPACE(ptr); - - len = strlen(ptr); - ptr[len-1] = '\0'; /* chop \n */ - - if (!netinfo->primary_dns[0]) { - SIGAR_SSTRCPY(netinfo->primary_dns, ptr); - } - else if (!netinfo->secondary_dns[0]) { - SIGAR_SSTRCPY(netinfo->secondary_dns, ptr); - } - else { - break; - } - } - fclose(fp); - } /* else /etc/resolv.conf may not exist if unplugged (MacOSX) */ - - size = sizeof(netinfo->host_name)-1; - if (gethostname(netinfo->host_name, size) == 0) { - netinfo->host_name[size] = '\0'; - } - else { - netinfo->host_name[0] = '\0'; - } - - size = sizeof(netinfo->domain_name)-1; - if (getdomainname(netinfo->domain_name, size) == 0) { - netinfo->domain_name[size] = '\0'; - } - else { - netinfo->domain_name[0] = '\0'; - } - - sigar_get_default_gateway(sigar, netinfo); - - return SIGAR_OK; -} - -#include - -#define OffsetOf(structure, field) \ - (size_t)(&((structure *)NULL)->field) - -#define RlimitOffsets(field) \ - OffsetOf(sigar_resource_limit_t, field##_cur), \ - OffsetOf(sigar_resource_limit_t, field##_max) - -#define RlimitSet(structure, ptr, val) \ - *(sigar_uint64_t *)((char *)structure + (int)(long)ptr) = val - -typedef struct { - int resource; - int factor; - size_t cur; - size_t max; -} rlimit_field_t; - -#ifndef RLIMIT_RSS -#define RLIMIT_RSS (RLIM_NLIMITS+1) -#endif - -#ifndef RLIMIT_NPROC -#define RLIMIT_NPROC (RLIM_NLIMITS+2) -#endif - -#define RLIMIT_PSIZE (RLIM_NLIMITS+3) - -#ifndef RLIMIT_AS -# if defined(RLIMIT_VMEM) -# define RLIMIT_AS RLIMIT_VMEM -# elif defined(RLIMIT_RSS) -# define RLIMIT_AS RLIMIT_RSS -# endif -#endif - -static rlimit_field_t sigar_rlimits[] = { - { RLIMIT_CPU, 1, RlimitOffsets(cpu) }, - { RLIMIT_FSIZE, 1024, RlimitOffsets(file_size) }, - { RLIMIT_DATA, 1024, RlimitOffsets(data) }, - { RLIMIT_STACK, 1024, RlimitOffsets(stack) }, - { RLIMIT_PSIZE, 512, RlimitOffsets(pipe_size) }, - { RLIMIT_CORE, 1024, RlimitOffsets(core) }, - { RLIMIT_RSS, 1024, RlimitOffsets(memory) }, - { RLIMIT_NPROC, 1, RlimitOffsets(processes) }, - { RLIMIT_NOFILE, 1, RlimitOffsets(open_files) }, - { RLIMIT_AS, 1024, RlimitOffsets(virtual_memory) }, - { -1 } -}; - -#define RlimitScale(val) \ - if (val != RLIM_INFINITY) val /= r->factor - -#define RlimitHS(val) \ - rl.rlim_cur = rl.rlim_max = (val) - -int sigar_resource_limit_get(sigar_t *sigar, - sigar_resource_limit_t *rlimit) -{ - int i; - - for (i=0; sigar_rlimits[i].resource != -1; i++) { - struct rlimit rl; - rlimit_field_t *r = &sigar_rlimits[i]; - - if (r->resource > RLIM_NLIMITS) { - switch (r->resource) { - case RLIMIT_NPROC: - RlimitHS(sysconf(_SC_CHILD_MAX)); - break; - case RLIMIT_PSIZE: - RlimitHS(PIPE_BUF/512); - break; - default: - RlimitHS(RLIM_INFINITY); - break; - } - } - else if (getrlimit(r->resource, &rl) != 0) { - RlimitHS(RLIM_INFINITY); - } - else { - RlimitScale(rl.rlim_cur); - RlimitScale(rl.rlim_max); - } - - RlimitSet(rlimit, r->cur, rl.rlim_cur); - RlimitSet(rlimit, r->max, rl.rlim_max); - } - - return SIGAR_OK; -} -#endif - -#if !defined(WIN32) && !defined(NETWARE) && !defined(DARWIN) && \ - !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) - -/* XXX: prolly will be moving these stuffs into os_net.c */ -#include -#include - -#ifndef SIOCGIFCONF -#include -#endif - -#if defined(_AIX) || defined(__osf__) /* good buddies */ - -#include - -static void hwaddr_aix_lookup(sigar_t *sigar, sigar_net_interface_config_t *ifconfig) -{ - char *ent, *end; - struct ifreq *ifr; - - /* XXX: assumes sigar_net_interface_list_get has been called */ - end = sigar->ifconf_buf + sigar->ifconf_len; - - for (ent = sigar->ifconf_buf; - ent < end; - ent += sizeof(*ifr)) - { - ifr = (struct ifreq *)ent; - - if (ifr->ifr_addr.sa_family != AF_LINK) { - continue; - } - - if (strEQ(ifr->ifr_name, ifconfig->name)) { - struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr; - - sigar_net_address_mac_set(ifconfig->hwaddr, - LLADDR(sdl), - sdl->sdl_alen); - return; - } - } - - sigar_hwaddr_set_null(ifconfig); -} - -#elif !defined(SIOCGIFHWADDR) - -#include - -static void hwaddr_arp_lookup(sigar_net_interface_config_t *ifconfig, int sock) -{ - struct arpreq areq; - struct sockaddr_in *sa; - - memset(&areq, 0, sizeof(areq)); - sa = (struct sockaddr_in *)&areq.arp_pa; - sa->sin_family = AF_INET; - sa->sin_addr.s_addr = ifconfig->address.addr.in; - - if (ioctl(sock, SIOCGARP, &areq) < 0) { - /* ho-hum */ - sigar_hwaddr_set_null(ifconfig); - } - else { - sigar_net_address_mac_set(ifconfig->hwaddr, - areq.arp_ha.sa_data, - SIGAR_IFHWADDRLEN); - } -} - -#endif - -#ifdef __linux__ - -#include - -#ifndef ARPHRD_CISCO /* not in 2.2 kernel headers */ -#define ARPHRD_CISCO 513 /* Cisco HDLC. */ -#endif - -static void get_interface_type(sigar_net_interface_config_t *ifconfig, - int family) -{ - char *type; - - switch (family) { - case ARPHRD_SLIP: - type = SIGAR_NIC_SLIP; - break; - case ARPHRD_CSLIP: - type = SIGAR_NIC_CSLIP; - break; - case ARPHRD_SLIP6: - type = SIGAR_NIC_SLIP6; - break; - case ARPHRD_CSLIP6: - type = SIGAR_NIC_CSLIP6; - break; - case ARPHRD_ADAPT: - type = SIGAR_NIC_ADAPTIVE; - break; - case ARPHRD_ETHER: - type = SIGAR_NIC_ETHERNET; - break; - case ARPHRD_ASH: - type = SIGAR_NIC_ASH; - break; - case ARPHRD_FDDI: - type = SIGAR_NIC_FDDI; - break; - case ARPHRD_HIPPI: - type = SIGAR_NIC_HIPPI; - break; - case ARPHRD_AX25: - type = SIGAR_NIC_AX25; - break; - case ARPHRD_ROSE: - type = SIGAR_NIC_ROSE; - break; - case ARPHRD_NETROM: - type = SIGAR_NIC_NETROM; - break; - case ARPHRD_X25: - type = SIGAR_NIC_X25; - break; - case ARPHRD_TUNNEL: - type = SIGAR_NIC_TUNNEL; - break; - case ARPHRD_PPP: - type = SIGAR_NIC_PPP; - break; - case ARPHRD_CISCO: - type = SIGAR_NIC_HDLC; - break; - case ARPHRD_LAPB: - type = SIGAR_NIC_LAPB; - break; - case ARPHRD_ARCNET: - type = SIGAR_NIC_ARCNET; - break; - case ARPHRD_DLCI: - type = SIGAR_NIC_DLCI; - break; - case ARPHRD_FRAD: - type = SIGAR_NIC_FRAD; - break; - case ARPHRD_SIT: - type = SIGAR_NIC_SIT; - break; - case ARPHRD_IRDA: - type = SIGAR_NIC_IRDA; - break; - case ARPHRD_ECONET: - type = SIGAR_NIC_EC; - break; - default: - type = SIGAR_NIC_UNSPEC; - break; - } - - SIGAR_SSTRCPY(ifconfig->type, type); -} - -#endif - -int sigar_net_interface_config_get(sigar_t *sigar, const char *name, - sigar_net_interface_config_t *ifconfig) -{ - int sock; - struct ifreq ifr; - - if (!name) { - return sigar_net_interface_config_primary_get(sigar, ifconfig); - } - - SIGAR_ZERO(ifconfig); - - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - return errno; - } - - SIGAR_SSTRCPY(ifconfig->name, name); - SIGAR_SSTRCPY(ifr.ifr_name, name); - -#define ifr_s_addr(ifr) \ - ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr - - if (!ioctl(sock, SIOCGIFADDR, &ifr)) { - sigar_net_address_set(ifconfig->address, - ifr_s_addr(ifr)); - } - - if (!ioctl(sock, SIOCGIFNETMASK, &ifr)) { - sigar_net_address_set(ifconfig->netmask, - ifr_s_addr(ifr)); - } - - if (!ioctl(sock, SIOCGIFFLAGS, &ifr)) { - sigar_uint64_t flags = ifr.ifr_flags; -#ifdef __linux__ -# ifndef IFF_DYNAMIC -# define IFF_DYNAMIC 0x8000 /* not in 2.2 kernel */ -# endif /* IFF_DYNAMIC */ - int is_mcast = flags & IFF_MULTICAST; - int is_slave = flags & IFF_SLAVE; - int is_master = flags & IFF_MASTER; - int is_dynamic = flags & IFF_DYNAMIC; - /* - * XXX: should just define SIGAR_IFF_* - * and test IFF_* bits on given platform. - * this is the only diff between solaris/hpux/linux - * for the flags we care about. - * - */ - flags &= ~(IFF_MULTICAST|IFF_SLAVE|IFF_MASTER); - if (is_mcast) { - flags |= SIGAR_IFF_MULTICAST; - } - if (is_slave) { - flags |= SIGAR_IFF_SLAVE; - } - if (is_master) { - flags |= SIGAR_IFF_MASTER; - } - if (is_dynamic) { - flags |= SIGAR_IFF_DYNAMIC; - } -#endif - ifconfig->flags = flags; - } - else { - /* should always be able to get flags for existing device */ - /* other ioctls may fail if device is not enabled: ok */ - close(sock); - return errno; - } - - if (ifconfig->flags & IFF_LOOPBACK) { - sigar_net_address_set(ifconfig->destination, - ifconfig->address.addr.in); - sigar_net_address_set(ifconfig->broadcast, 0); - sigar_hwaddr_set_null(ifconfig); - SIGAR_SSTRCPY(ifconfig->type, - SIGAR_NIC_LOOPBACK); - } - else { - if (!ioctl(sock, SIOCGIFDSTADDR, &ifr)) { - sigar_net_address_set(ifconfig->destination, - ifr_s_addr(ifr)); - } - - if (!ioctl(sock, SIOCGIFBRDADDR, &ifr)) { - sigar_net_address_set(ifconfig->broadcast, - ifr_s_addr(ifr)); - } - -#if defined(SIOCGIFHWADDR) - if (!ioctl(sock, SIOCGIFHWADDR, &ifr)) { - get_interface_type(ifconfig, - ifr.ifr_hwaddr.sa_family); - sigar_net_address_mac_set(ifconfig->hwaddr, - ifr.ifr_hwaddr.sa_data, - IFHWADDRLEN); - } -#elif defined(_AIX) || defined(__osf__) - hwaddr_aix_lookup(sigar, ifconfig); - SIGAR_SSTRCPY(ifconfig->type, - SIGAR_NIC_ETHERNET); -#else - hwaddr_arp_lookup(ifconfig, sock); - SIGAR_SSTRCPY(ifconfig->type, - SIGAR_NIC_ETHERNET); -#endif - } - -#if defined(SIOCGLIFMTU) && !defined(__hpux) - { - struct lifreq lifr; - SIGAR_SSTRCPY(lifr.lifr_name, name); - if(!ioctl(sock, SIOCGLIFMTU, &lifr)) { - ifconfig->mtu = lifr.lifr_mtu; - } - } -#elif defined(SIOCGIFMTU) - if (!ioctl(sock, SIOCGIFMTU, &ifr)) { -# if defined(__hpux) - ifconfig->mtu = ifr.ifr_metric; -# else - ifconfig->mtu = ifr.ifr_mtu; -#endif - } -#else - ifconfig->mtu = 0; /*XXX*/ -#endif - - if (!ioctl(sock, SIOCGIFMETRIC, &ifr)) { - ifconfig->metric = ifr.ifr_metric ? ifr.ifr_metric : 1; - } - -#if defined(SIOCGIFTXQLEN) - if (!ioctl(sock, SIOCGIFTXQLEN, &ifr)) { - ifconfig->tx_queue_len = ifr.ifr_qlen; - } - else { - ifconfig->tx_queue_len = -1; /* net-tools behaviour */ - } -#else - ifconfig->tx_queue_len = -1; -#endif - - close(sock); - - /* XXX can we get a better description like win32? */ - SIGAR_SSTRCPY(ifconfig->description, - ifconfig->name); - - sigar_net_interface_ipv6_config_init(ifconfig); - sigar_net_interface_ipv6_config_get(sigar, name, ifconfig); - - return SIGAR_OK; -} - -#ifdef _AIX -# define MY_SIOCGIFCONF CSIOCGIFCONF -#else -# define MY_SIOCGIFCONF SIOCGIFCONF -#endif - -#ifdef __osf__ -static int sigar_netif_configured(sigar_t *sigar, char *name) -{ - int status; - sigar_net_interface_config_t ifconfig; - - status = sigar_net_interface_config_get(sigar, name, &ifconfig); - - return status == SIGAR_OK; -} -#endif - -#ifdef __linux__ -static SIGAR_INLINE int has_interface(sigar_net_interface_list_t *iflist, - char *name) -{ - register int i; - register int num = iflist->number; - register char **data = iflist->data; - for (i=0; idata[iflist->number++] = - sigar_strdup(dev); - } - - fclose(fp); - - return SIGAR_OK; -} -#endif - -int sigar_net_interface_list_get(sigar_t *sigar, - sigar_net_interface_list_t *iflist) -{ - int n, lastlen=0; - struct ifreq *ifr; - struct ifconf ifc; - int sock = socket(AF_INET, SOCK_DGRAM, 0); - - if (sock < 0) { - return errno; - } - - for (;;) { - if (!sigar->ifconf_buf || lastlen) { - sigar->ifconf_len += sizeof(struct ifreq) * SIGAR_NET_IFLIST_MAX; - sigar->ifconf_buf = realloc(sigar->ifconf_buf, sigar->ifconf_len); - } - - ifc.ifc_len = sigar->ifconf_len; - ifc.ifc_buf = sigar->ifconf_buf; - - if (ioctl(sock, MY_SIOCGIFCONF, &ifc) < 0) { - /* EINVAL should mean num_interfaces > ifc.ifc_len */ - if ((errno != EINVAL) || - (lastlen == ifc.ifc_len)) - { - free(ifc.ifc_buf); - return errno; - } - } - - if (ifc.ifc_len < sigar->ifconf_len) { - break; /* got em all */ - } - - if (ifc.ifc_len != lastlen) { - /* might be more */ - lastlen = ifc.ifc_len; - continue; - } - - break; - } - - close(sock); - - iflist->number = 0; - iflist->size = ifc.ifc_len; - iflist->data = malloc(sizeof(*(iflist->data)) * - iflist->size); - - ifr = ifc.ifc_req; - for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq), ifr++) { -#if defined(_AIX) || defined(__osf__) /* pass the bourbon */ - if (ifr->ifr_addr.sa_family != AF_LINK) { - /* XXX: dunno if this is right. - * otherwise end up with two 'en0' and three 'lo0' - * with the same ip address. - */ - continue; - } -# ifdef __osf__ - /* weed out "sl0", "tun0" and the like */ - /* XXX must be a better way to check this */ - if (!sigar_netif_configured(sigar, ifr->ifr_name)) { - continue; - } -# endif -#endif - iflist->data[iflist->number++] = - sigar_strdup(ifr->ifr_name); - } - -#ifdef __linux__ - proc_net_interface_list_get(sigar, iflist); -#endif - - return SIGAR_OK; -} - -#endif /* WIN32 */ - -SIGAR_DECLARE(int) -sigar_net_interface_config_primary_get(sigar_t *sigar, - sigar_net_interface_config_t *ifconfig) -{ - int i, status, found=0; - sigar_net_interface_list_t iflist; - sigar_net_interface_config_t possible_config; - - possible_config.flags = 0; - - if ((status = sigar_net_interface_list_get(sigar, &iflist)) != SIGAR_OK) { - return status; - } - - for (i=0; iflags & SIGAR_IFF_LOOPBACK) || - !ifconfig->hwaddr.addr.in) /* no mac address */ - { - continue; - } - - if (!possible_config.flags) { - /* save for later for use if we're not connected to the net - * or all interfaces are aliases (e.g. solaris zone) - */ - memcpy(&possible_config, ifconfig, sizeof(*ifconfig)); - } - if (!ifconfig->address.addr.in) { - continue; /* no ip address */ - } - if (strchr(iflist.data[i], ':')) { - continue; /* alias */ - } - - found = 1; - break; - } - - sigar_net_interface_list_destroy(sigar, &iflist); - - if (found) { - return SIGAR_OK; - } - else if (possible_config.flags) { - memcpy(ifconfig, &possible_config, sizeof(*ifconfig)); - return SIGAR_OK; - } - else { - return SIGAR_ENXIO; - } -} - -static int fqdn_ip_get(sigar_t *sigar, char *name) -{ - sigar_net_interface_config_t ifconfig; - int status; - - status = sigar_net_interface_config_primary_get(sigar, &ifconfig); - - if (status != SIGAR_OK) { - return status; - } - if (!ifconfig.address.addr.in) { - return SIGAR_ENXIO; - } - - sigar_net_address_to_string(sigar, &ifconfig.address, name); - - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[fqdn] using ip address '%s' for fqdn", - name); - - return SIGAR_OK; -} - -struct hostent *sigar_gethostbyname(const char *name, - sigar_hostent_t *data) -{ - struct hostent *hp = NULL; - -#if defined(__linux__) - gethostbyname_r(name, &data->hs, - data->buffer, sizeof(data->buffer), - &hp, &data->error); -#elif defined(__sun) - hp = gethostbyname_r(name, &data->hs, - data->buffer, sizeof(data->buffer), - &data->error); -#elif defined(SIGAR_HAS_HOSTENT_DATA) - if (gethostbyname_r(name, &data->hs, &data->hd) == 0) { - hp = &data->hs; - } - else { - data->error = h_errno; - } -#else - hp = gethostbyname(name); -#endif - - return hp; -} - -static struct hostent *sigar_gethostbyaddr(const char *addr, - int len, int type, - sigar_hostent_t *data) -{ - struct hostent *hp = NULL; - -#if defined(__linux__) - gethostbyaddr_r(addr, len, type, - &data->hs, - data->buffer, sizeof(data->buffer), - &hp, &data->error); -#elif defined(__sun) - hp = gethostbyaddr_r(addr, len, type, - &data->hs, - data->buffer, sizeof(data->buffer), - &data->error); -#elif defined(SIGAR_HAS_HOSTENT_DATA) - if (gethostbyaddr_r((char *)addr, len, type, - &data->hs, &data->hd) == 0) - { - hp = &data->hs; - } - else { - data->error = h_errno; - } -#else - if (!(hp = gethostbyaddr(addr, len, type))) { - data->error = h_errno; - } -#endif - - return hp; -} -#define IS_FQDN(name) \ - (name && strchr(name, '.')) - -#define IS_FQDN_MATCH(lookup, name) \ - (IS_FQDN(lookup) && strnEQ(lookup, name, strlen(name))) - -#define FQDN_SET(fqdn) \ - SIGAR_STRNCPY(name, fqdn, namelen) - -SIGAR_DECLARE(int) sigar_fqdn_get(sigar_t *sigar, char *name, int namelen) -{ - register int is_debug = SIGAR_LOG_IS_DEBUG(sigar); - sigar_hostent_t data; - struct hostent *p; - char domain[SIGAR_FQDN_LEN + 1]; -#ifdef WIN32 - int status = sigar_wsa_init(sigar); - - if (status != SIGAR_OK) { - return status; - } -#endif - - if (gethostname(name, namelen - 1) != 0) { - sigar_log_printf(sigar, SIGAR_LOG_ERROR, - "[fqdn] gethostname failed: %s", - sigar_strerror(sigar, errno)); - return errno; - } - else { - if (is_debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[fqdn] gethostname()=='%s'", - name); - } - } - - if (!(p = sigar_gethostbyname(name, &data))) { - if (is_debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[fqdn] gethostbyname(%s) failed: %s", - name, sigar_strerror(sigar, errno)); - } - - if (!IS_FQDN(name)) { - fqdn_ip_get(sigar, name); - } - - return SIGAR_OK; - } - - if (IS_FQDN_MATCH(p->h_name, name)) { - FQDN_SET(p->h_name); - - sigar_log(sigar, SIGAR_LOG_DEBUG, - "[fqdn] resolved using gethostbyname.h_name"); - - return SIGAR_OK; - } - else { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[fqdn] unresolved using gethostbyname.h_name"); - } - - if (p->h_aliases) { - int i; - - for (i=0; p->h_aliases[i]; i++) { - if (IS_FQDN_MATCH(p->h_aliases[i], name)) { - FQDN_SET(p->h_aliases[i]); - - sigar_log(sigar, SIGAR_LOG_DEBUG, - "[fqdn] resolved using gethostbyname.h_aliases"); - - return SIGAR_OK; - } - else if (is_debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[fqdn] gethostbyname(%s).alias[%d]=='%s'", - name, i, p->h_aliases[i]); - } - } - } - - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[fqdn] unresolved using gethostbyname.h_aliases"); - - if (p->h_addr_list) { - int i,j; - - for (i=0; p->h_addr_list[i]; i++) { - char addr[SIGAR_INET6_ADDRSTRLEN]; - struct in_addr *in = - (struct in_addr *)p->h_addr_list[i]; - - struct hostent *q = - sigar_gethostbyaddr(p->h_addr_list[i], - p->h_length, - p->h_addrtype, - &data); - - if (is_debug) { - sigar_inet_ntoa(sigar, in->s_addr, addr); - } - - if (!q) { - if (is_debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[fqdn] gethostbyaddr(%s) failed: %s", - addr, - sigar_strerror(sigar, errno)); - } - continue; - } - - if (IS_FQDN_MATCH(q->h_name, name)) { - FQDN_SET(q->h_name); - - sigar_log(sigar, SIGAR_LOG_DEBUG, - "[fqdn] resolved using gethostbyaddr.h_name"); - - return SIGAR_OK; - } - else { - if (is_debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[fqdn] gethostbyaddr(%s)=='%s'", - addr, q->h_name); - } - - for (j=0; q->h_aliases[j]; j++) { - if (IS_FQDN_MATCH(q->h_aliases[j], name)) { - FQDN_SET(q->h_aliases[j]); - - sigar_log(sigar, SIGAR_LOG_DEBUG, - "[fqdn] resolved using " - "gethostbyaddr.h_aliases"); - - return SIGAR_OK; - } - else if (is_debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[fqdn] gethostbyaddr(%s).alias[%d]=='%s'", - addr, j, q->h_aliases[j]); - } - } - } - } - } - - sigar_log(sigar, SIGAR_LOG_DEBUG, - "[fqdn] unresolved using gethostbyname.h_addr_list"); - -#if !defined(WIN32) && !defined(NETWARE) - if (!IS_FQDN(name) && /* e.g. aix gethostname is already fqdn */ - (getdomainname(domain, sizeof(domain) - 1) == 0) && - (domain[0] != '\0') && - (domain[0] != '(')) /* linux default is "(none)" */ - { - /* sprintf(name, "%s.%s", name, domain); */ - char *ptr = name; - int len = strlen(name); - ptr += len; - *ptr++ = '.'; - namelen -= (len+1); - SIGAR_STRNCPY(ptr, domain, namelen); - - sigar_log(sigar, SIGAR_LOG_DEBUG, - "[fqdn] resolved using getdomainname"); - } - else { - sigar_log(sigar, SIGAR_LOG_DEBUG, - "[fqdn] getdomainname failed"); - } -#endif - - if (!IS_FQDN(name)) { - fqdn_ip_get(sigar, name); - } - - return SIGAR_OK; -} - -#ifndef MAX_STRING_LEN -#define MAX_STRING_LEN 8192 -#endif - -#ifdef WIN32 -/* The windows version of getPasswordNative was lifted from apr */ -SIGAR_DECLARE(char *) sigar_password_get(const char *prompt) -{ - static char password[MAX_STRING_LEN]; - int n = 0; - int ch; - - fputs(prompt, stderr); - fflush(stderr); - - while ((ch = _getch()) != '\r') { - if (ch == EOF) /* EOF */ { - return NULL; - } - else if (ch == 0 || ch == 0xE0) { - /* FN Keys (0 or E0) are a sentinal for a FN code */ - ch = (ch << 4) | _getch(); - /* Catch {DELETE}, {<--}, Num{DEL} and Num{<--} */ - if ((ch == 0xE53 || ch == 0xE4B || ch == 0x053 || ch == 0x04b) && n) { - password[--n] = '\0'; - fputs("\b \b", stderr); - fflush(stderr); - } - else { - fputc('\a', stderr); - fflush(stderr); - } - } - else if ((ch == '\b' || ch == 127) && n) /* BS/DEL */ { - password[--n] = '\0'; - fputs("\b \b", stderr); - fflush(stderr); - } - else if (ch == 3) /* CTRL+C */ { - /* _getch() bypasses Ctrl+C but not Ctrl+Break detection! */ - fputs("^C\n", stderr); - fflush(stderr); - exit(-1); - } - else if (ch == 26) /* CTRL+Z */ { - fputs("^Z\n", stderr); - fflush(stderr); - return NULL; - } - else if (ch == 27) /* ESC */ { - fputc('\n', stderr); - fputs(prompt, stderr); - fflush(stderr); - n = 0; - } - else if ((n < sizeof(password) - 1) && !iscntrl(ch)) { - password[n++] = ch; - fputc(' ', stderr); - fflush(stderr); - } - else { - fputc('\a', stderr); - fflush(stderr); - } - } - - fputc('\n', stderr); - fflush(stderr); - password[n] = '\0'; - - return password; -} - -#else - -/* linux/hpux/solaris getpass() prototype lives here */ -#include - -#include - -/* from apr_getpass.c */ - -#if defined(SIGAR_HPUX) -# define getpass termios_getpass -#elif defined(SIGAR_SOLARIS) -# define getpass getpassphrase -#endif - -#ifdef SIGAR_HPUX -static char *termios_getpass(const char *prompt) -{ - struct termios attr; - static char password[MAX_STRING_LEN]; - unsigned int n=0; - - fputs(prompt, stderr); - fflush(stderr); - - if (tcgetattr(STDIN_FILENO, &attr) != 0) { - return NULL; - } - - attr.c_lflag &= ~(ECHO); - - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) != 0) { - return NULL; - } - - while ((password[n] = getchar()) != '\n') { - if (n < (sizeof(password) - 1) && - (password[n] >= ' ') && - (password[n] <= '~')) - { - n++; - } - else { - fprintf(stderr, "\n"); - fputs(prompt, stderr); - fflush(stderr); - n = 0; - } - } - - password[n] = '\0'; - printf("\n"); - - if (n > (MAX_STRING_LEN - 1)) { - password[MAX_STRING_LEN - 1] = '\0'; - } - - attr.c_lflag |= ECHO; - tcsetattr(STDIN_FILENO, TCSANOW, &attr); - - return (char *)&password; -} -#endif - -SIGAR_DECLARE(char *) sigar_password_get(const char *prompt) -{ - char *buf = NULL; - - /* the linux version of getpass prints the prompt to the tty; ok. - * the solaris version prints the prompt to stderr; not ok. - * so print the prompt to /dev/tty ourselves if possible (always should be) - */ - - FILE *tty = NULL; - - if ((tty = fopen("/dev/tty", "w"))) { - fprintf(tty, "%s", prompt); - fflush(tty); - - buf = getpass(tty ? "" : prompt); - fclose(tty); - } - - return buf; -} - -#endif /* WIN32 */ diff --git a/vendor/sigar/src/sigar_cache.c b/vendor/sigar/src/sigar_cache.c deleted file mode 100644 index 8d64016..0000000 --- a/vendor/sigar/src/sigar_cache.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2004-2006 Hyperic, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sigar.h" -#include "sigar_private.h" -#include "sigar_util.h" -#include -/* - * hash table to cache values where key is a unique number - * such as: - * pid -> some process data - * uid -> user name - * gid -> group name - */ - -#define ENTRIES_SIZE(n) \ - (sizeof(sigar_cache_entry_t *) * (n)) - -/* wrap free() for use w/ dmalloc */ -static void free_value(void *ptr) -{ - free(ptr); -} - -sigar_cache_t *sigar_cache_new(int size) -{ - sigar_cache_t *table = malloc(sizeof(*table)); - table->count = 0; - table->size = size; - table->entries = malloc(ENTRIES_SIZE(size)); - memset(table->entries, '\0', ENTRIES_SIZE(size)); - table->free_value = free_value; - return table; -} - -#ifdef DEBUG_CACHE -/* see how well entries are distributed */ -static void sigar_cache_dump(sigar_cache_t *table) -{ - int i; - sigar_cache_entry_t **entries = table->entries; - - for (i=0; isize; i++) { - sigar_cache_entry_t *entry = *entries++; - - printf("|"); - while (entry) { - printf("%lld", entry->id); - if (entry->next) { - printf(","); - } - entry = entry->next; - } - } - printf("\n"); - fflush(stdout); -} -#endif - -static void sigar_cache_rehash(sigar_cache_t *table) -{ - int i; - unsigned int new_size = table->size * 2 + 1; - sigar_cache_entry_t **entries = table->entries; - sigar_cache_entry_t **new_entries = - malloc(ENTRIES_SIZE(new_size)); - - memset(new_entries, '\0', ENTRIES_SIZE(new_size)); - - for (i=0; isize; i++) { - sigar_cache_entry_t *entry = *entries++; - - while (entry) { - sigar_cache_entry_t *next = entry->next; - sigar_uint64_t hash = entry->id % new_size; - - entry->next = new_entries[hash]; - new_entries[hash] = entry; - entry = next; - } - } - - free(table->entries); - table->entries = new_entries; - table->size = new_size; -} - -#define SIGAR_CACHE_IX(t, k) \ - t->entries + (k % t->size) - -sigar_cache_entry_t *sigar_cache_find(sigar_cache_t *table, - sigar_uint64_t key) -{ - sigar_cache_entry_t *entry, **ptr; - - for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr; - entry; - ptr = &entry->next, entry = *ptr) - { - if (entry->id == key) { - return entry; - } - } - - return NULL; -} - -/* create entry if it does not exist */ -sigar_cache_entry_t *sigar_cache_get(sigar_cache_t *table, - sigar_uint64_t key) -{ - sigar_cache_entry_t *entry, **ptr; - - for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr; - entry; - ptr = &entry->next, entry = *ptr) - { - if (entry->id == key) { - return entry; - } - } - - if (table->count++ > table->size) { - sigar_cache_rehash(table); - - for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr; - entry; - ptr = &entry->next, entry = *ptr) - { - } - } - - *ptr = entry = malloc(sizeof(*entry)); - entry->id = key; - entry->value = NULL; - entry->next = NULL; - - return entry; -} - -void sigar_cache_destroy(sigar_cache_t *table) -{ - int i; - sigar_cache_entry_t **entries = table->entries; - -#ifdef DEBUG_CACHE - sigar_cache_dump(table); -#endif - - for (i=0; isize; i++) { - sigar_cache_entry_t *entry, *ptr; - entry = *entries++; - - while (entry) { - if (entry->value) { - table->free_value(entry->value); - } - ptr = entry->next; - free(entry); - entry = ptr; - } - } - - free(table->entries); - free(table); -} diff --git a/vendor/sigar/src/sigar_fileinfo.c b/vendor/sigar/src/sigar_fileinfo.c deleted file mode 100644 index adde8c0..0000000 --- a/vendor/sigar/src/sigar_fileinfo.c +++ /dev/null @@ -1,815 +0,0 @@ -/* - * Copyright (c) 2004-2005, 2007-2008 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * Copyright (c) 2010 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2003 The Apache Software Foundation. All rights - * reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - */ - -#ifndef WIN32 -# ifdef _AIX -# define _LARGE_FILES -# else -# define _FILE_OFFSET_BITS 64 -# define _LARGEFILE64_SOURCE -# endif -#endif - -#include "sigar.h" - -#ifndef WIN32 -#if defined(__FreeBSD__) || defined(__OpenBSD__) -# include -# include -#else -# include -# define HAVE_STATVFS -#endif -#include - -#define SIGAR_FS_BLOCKS_TO_BYTES(val, bsize) ((val * bsize) >> 1) - -int sigar_statvfs(sigar_t *sigar, - const char *dirname, - sigar_file_system_usage_t *fsusage) -{ - sigar_uint64_t val, bsize; -#ifdef HAVE_STATVFS - struct statvfs buf; - int status = -# if defined(__sun) && !defined(_LP64) - /* http://bugs.opensolaris.org/view_bug.do?bug_id=4462986 */ - statvfs(dirname, (void *)&buf); -# else - statvfs(dirname, &buf); -# endif -#else - struct statfs buf; - int status = statfs(dirname, &buf); -#endif - - if (status != 0) { - return errno; - } - -#ifdef HAVE_STATVFS - bsize = buf.f_frsize / 512; -#else - bsize = buf.f_bsize / 512; -#endif - val = buf.f_blocks; - fsusage->total = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize); - val = buf.f_bfree; - fsusage->free = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize); - val = buf.f_bavail; - fsusage->avail = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize); - fsusage->used = fsusage->total - fsusage->free; - fsusage->files = buf.f_files; - fsusage->free_files = buf.f_ffree; - - return SIGAR_OK; -} -#endif - -/* - * whittled down version of apr/file_info/{unix,win32}/filestat.c - * to fillin sigar_fileattrs_t - */ -#include "sigar_fileinfo.h" -#include "sigar_log.h" - -#ifndef SIGAR_ZERO -#define SIGAR_ZERO(s) \ - memset(s, '\0', sizeof(*(s))) -#endif - -#ifdef WIN32 -#include -sigar_uint64_t sigar_FileTimeToTime(FILETIME *ft); -#else -#include -#endif - -static const char* types[] = { - "none", - "regular", - "directory", - "character device", - "block device", - "pipe", - "symbolic link", - "socket", - "unknown" -}; - -SIGAR_DECLARE(const char *) -sigar_file_attrs_type_string_get(sigar_file_type_e type) -{ - if ((type < SIGAR_FILETYPE_NOFILE) || - (type > SIGAR_FILETYPE_UNKFILE)) - { - type = SIGAR_FILETYPE_UNKFILE; - } - - return types[type]; -} - -static const sigar_uint64_t perm_modes[] = { - SIGAR_UREAD, SIGAR_UWRITE, SIGAR_UEXECUTE, - SIGAR_GREAD, SIGAR_GWRITE, SIGAR_GEXECUTE, - SIGAR_WREAD, SIGAR_WWRITE, SIGAR_WEXECUTE -}; - -static const char perm_chars[] = "rwx"; - -SIGAR_DECLARE(char *) -sigar_file_attrs_permissions_string_get(sigar_uint64_t permissions, - char *str) -{ - char *ptr = str; - int i=0, j=0; - - for (i=0; i<9; i+=3) { - for (j=0; j<3; j++) { - if (permissions & perm_modes[i+j]) { - *ptr = perm_chars[j]; - } - else { - *ptr = '-'; - } - ptr++; - } - } - - *ptr = '\0'; - return str; -} - -static const int perm_int[] = { - 400, 200, 100, - 40, 20, 10, - 4, 2, 1 -}; - -SIGAR_DECLARE(int)sigar_file_attrs_mode_get(sigar_uint64_t permissions) -{ - int i=0; - int perms = 0; - - /* no doubt there is some fancy bitshifting - * to convert, but this works fine. - */ - for (i=0; i<9; i++) { - if (permissions & perm_modes[i]) { - perms += perm_int[i]; - } - } - - return perms; -} - -#define IS_DOTDIR(dir) \ - ((dir[0] == '.') && (!dir[1] || ((dir[1] == '.') && !dir[2]))) - -#define DIR_STAT_WARN() \ - sigar_log_printf(sigar, SIGAR_LOG_WARN, \ - "dir_stat: cannot stat `%s': %s", \ - name, \ - sigar_strerror(sigar, status)) - -#if defined(NETWARE) - -int sigar_dir_stat_get(sigar_t *sigar, - const char *dir, - sigar_dir_stat_t *dirstats) -{ - return SIGAR_ENOTIMPL; -} - -int sigar_file_attrs_get(sigar_t *sigar, - const char *file, - sigar_file_attrs_t *fileattrs) -{ - return SIGAR_ENOTIMPL; -} - -int sigar_link_attrs_get(sigar_t *sigar, - const char *file, - sigar_file_attrs_t *fileattrs) -{ - return SIGAR_ENOTIMPL; -} - -#elif defined(WIN32) - -#include -#include - -static void fillin_fileattrs(sigar_file_attrs_t *finfo, - WIN32_FILE_ATTRIBUTE_DATA *wininfo, - int linkinfo) -{ - DWORD *sizes = &wininfo->nFileSizeHigh; - - finfo->atime = sigar_FileTimeToTime(&wininfo->ftLastAccessTime) / 1000; - finfo->ctime = sigar_FileTimeToTime(&wininfo->ftCreationTime) / 1000; - finfo->mtime = sigar_FileTimeToTime(&wininfo->ftLastWriteTime) / 1000; - - finfo->size = - (sigar_uint64_t)sizes[1] | ((sigar_uint64_t)sizes[0] << 32); - - if (linkinfo && - (wininfo->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { - finfo->type = SIGAR_FILETYPE_LNK; - } - else if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - finfo->type = SIGAR_FILETYPE_DIR; - } - else { - finfo->type = SIGAR_FILETYPE_REG; - } -} - -static sigar_uint64_t convert_perms(ACCESS_MASK acc, sigar_uint64_t scope) -{ - sigar_uint64_t perms = 0; - if (acc & FILE_EXECUTE) { - perms |= SIGAR_WEXECUTE; - } - if (acc & FILE_WRITE_DATA) { - perms |= SIGAR_WWRITE; - } - if (acc & FILE_READ_DATA) { - perms |= SIGAR_WREAD; - } - - return (perms << scope); -} - -static int get_security_info(sigar_t *sigar, - const char *file, - sigar_file_attrs_t *fileattrs) -{ - DWORD retval; - PSID user = NULL, group = NULL, world = NULL; - PACL dacl = NULL; - PSECURITY_DESCRIPTOR pdesc = NULL; - SECURITY_INFORMATION sinfo = - OWNER_SECURITY_INFORMATION | - GROUP_SECURITY_INFORMATION | - DACL_SECURITY_INFORMATION; - TRUSTEE ident = {NULL, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_SID}; - ACCESS_MASK acc; - SID_IDENTIFIER_AUTHORITY auth = SECURITY_WORLD_SID_AUTHORITY; - - retval = GetNamedSecurityInfo((char *)file, - SE_FILE_OBJECT, - sinfo, - &user, - &group, - &dacl, - NULL, - &pdesc); - - if (retval != ERROR_SUCCESS) { - return retval; - } - - if (!AllocateAndInitializeSid(&auth, 1, SECURITY_WORLD_RID, - 0, 0, 0, 0, 0, 0, 0, &world)) - { - world = NULL; - } - - ident.TrusteeType = TRUSTEE_IS_USER; - ident.ptstrName = user; - if (GetEffectiveRightsFromAcl(dacl, &ident, &acc) == ERROR_SUCCESS) { - fileattrs->permissions |= convert_perms(acc, 8); - } - - ident.TrusteeType = TRUSTEE_IS_GROUP; - ident.ptstrName = group; - if (GetEffectiveRightsFromAcl(dacl, &ident, &acc) == ERROR_SUCCESS) { - fileattrs->permissions |= convert_perms(acc, 4); - } - - if (world) { - ident.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; - ident.ptstrName = world; - if (GetEffectiveRightsFromAcl(dacl, &ident, &acc) == ERROR_SUCCESS) { - fileattrs->permissions |= convert_perms(acc, 0); - } - } - - if (world) { - FreeSid(world); - } - - LocalFree(pdesc); - - return SIGAR_OK; -} - -static int fileattrs_get(sigar_t *sigar, - const char *file, - sigar_file_attrs_t *fileattrs, - int linkinfo) -{ - BY_HANDLE_FILE_INFORMATION info; - WIN32_FILE_ATTRIBUTE_DATA attrs; - HANDLE handle; - DWORD flags; - - SIGAR_ZERO(fileattrs); - - if (!GetFileAttributesExA(file, - GetFileExInfoStandard, - &attrs)) - { - return GetLastError(); - } - - fillin_fileattrs(fileattrs, &attrs, linkinfo); - - flags = fileattrs->type == SIGAR_FILETYPE_DIR ? - FILE_FLAG_BACKUP_SEMANTICS : - FILE_ATTRIBUTE_NORMAL; - - /** - * We need to set dwDesiredAccess to 0 to work in cases where GENERIC_READ can fail. - * - * see: http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx - */ - handle = CreateFile(file, - 0, - 0, - NULL, - OPEN_EXISTING, - flags, - NULL); - - if (handle != INVALID_HANDLE_VALUE) { - if (GetFileInformationByHandle(handle, &info)) { - fileattrs->inode = - info.nFileIndexLow | - (info.nFileIndexHigh << 32); - fileattrs->device = info.dwVolumeSerialNumber; - fileattrs->nlink = info.nNumberOfLinks; - } - CloseHandle(handle); - } - - get_security_info(sigar, file, fileattrs); - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_file_attrs_get(sigar_t *sigar, - const char *file, - sigar_file_attrs_t *fileattrs) -{ - return fileattrs_get(sigar, file, fileattrs, 0); -} - -SIGAR_DECLARE(int) sigar_link_attrs_get(sigar_t *sigar, - const char *file, - sigar_file_attrs_t *fileattrs) -{ - return fileattrs_get(sigar, file, fileattrs, 1); -} - -static __inline int file_type(char *file) -{ - WIN32_FILE_ATTRIBUTE_DATA attrs; - - if (!GetFileAttributesExA(file, - GetFileExInfoStandard, - &attrs)) - { - return -1; - } - - if (attrs.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - return SIGAR_FILETYPE_LNK; - } - else if (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - return SIGAR_FILETYPE_DIR; - } - else { - return SIGAR_FILETYPE_REG; - } -} - -static int dir_stat_get(sigar_t *sigar, - const char *dir, - sigar_dir_stat_t *dirstats, - int recurse) -{ - int status; - char name[SIGAR_PATH_MAX+1]; - int len = strlen(dir); - int max = sizeof(name)-len-1; - char *ptr = name; - WIN32_FIND_DATA data; - HANDLE handle; - DWORD error; - char delim; - - if (file_type((char *)dir) != SIGAR_FILETYPE_DIR) { - return ERROR_NO_MORE_FILES; - } - - strncpy(name, dir, sizeof(name)); - ptr += len; - if (strchr(dir, '/')) { - delim = '/'; - } - else { - delim = '\\'; - } - if (name[len] != delim) { - *ptr++ = delim; - len++; - max--; - } - - /* e.g. "C:\sigar\*" */ - name[len] = '*'; - name[len+1] = '\0'; - - handle = FindFirstFile(name, &data); - if (handle == INVALID_HANDLE_VALUE) { - return GetLastError(); - } - - do { - /* skip '.' and '..' */ - if (IS_DOTDIR(data.cFileName)) { - continue; - } - - dirstats->disk_usage += - (data.nFileSizeHigh * (MAXDWORD+1)) + - data.nFileSizeLow; - - /* e.g. "C:\sigar\lib" */ - strncpy(ptr, data.cFileName, max); - ptr[max] = '\0'; - - switch (file_type(name)) { - case -1: - break; - case SIGAR_FILETYPE_REG: - ++dirstats->files; - break; - case SIGAR_FILETYPE_DIR: - ++dirstats->subdirs; - if (recurse) { - status = - dir_stat_get(sigar, name, - dirstats, recurse); - if (status != SIGAR_OK) { - DIR_STAT_WARN(); - } - } - break; - case SIGAR_FILETYPE_LNK: - ++dirstats->symlinks; - break; - case SIGAR_FILETYPE_CHR: - ++dirstats->chrdevs; - break; - case SIGAR_FILETYPE_BLK: - ++dirstats->blkdevs; - break; - case SIGAR_FILETYPE_SOCK: - ++dirstats->sockets; - break; - default: - ++dirstats->total; - } - } while (FindNextFile(handle, &data)); - - error = GetLastError(); - - FindClose(handle); - - if (error != ERROR_NO_MORE_FILES) { - return error; - } - - dirstats->total = - dirstats->files + - dirstats->subdirs + - dirstats->symlinks + - dirstats->chrdevs + - dirstats->blkdevs + - dirstats->sockets; - - return SIGAR_OK; -} - -#else - -#include -#include -#include -#include - -static sigar_file_type_e filetype_from_mode(mode_t mode) -{ - sigar_file_type_e type; - - switch (mode & S_IFMT) { - case S_IFREG: - type = SIGAR_FILETYPE_REG; break; - case S_IFDIR: - type = SIGAR_FILETYPE_DIR; break; - case S_IFLNK: - type = SIGAR_FILETYPE_LNK; break; - case S_IFCHR: - type = SIGAR_FILETYPE_CHR; break; - case S_IFBLK: - type = SIGAR_FILETYPE_BLK; break; -#if defined(S_IFFIFO) - case S_IFFIFO: - type = SIGAR_FILETYPE_PIPE; break; -#endif -#if !defined(BEOS) && defined(S_IFSOCK) - case S_IFSOCK: - type = SIGAR_FILETYPE_SOCK; break; -#endif - - default: - /* Work around missing S_IFxxx values above - * for Linux et al. - */ -#if !defined(S_IFFIFO) && defined(S_ISFIFO) - if (S_ISFIFO(mode)) { - type = SIGAR_FILETYPE_PIPE; - } else -#endif -#if !defined(BEOS) && !defined(S_IFSOCK) && defined(S_ISSOCK) - if (S_ISSOCK(mode)) { - type = SIGAR_FILETYPE_SOCK; - } else -#endif - type = SIGAR_FILETYPE_UNKFILE; - } - return type; -} - -static sigar_uint64_t sigar_unix_mode2perms(mode_t mode) -{ - sigar_uint64_t perms = 0; - - if (mode & S_IRUSR) - perms |= SIGAR_UREAD; - if (mode & S_IWUSR) - perms |= SIGAR_UWRITE; - if (mode & S_IXUSR) - perms |= SIGAR_UEXECUTE; - - if (mode & S_IRGRP) - perms |= SIGAR_GREAD; - if (mode & S_IWGRP) - perms |= SIGAR_GWRITE; - if (mode & S_IXGRP) - perms |= SIGAR_GEXECUTE; - - if (mode & S_IROTH) - perms |= SIGAR_WREAD; - if (mode & S_IWOTH) - perms |= SIGAR_WWRITE; - if (mode & S_IXOTH) - perms |= SIGAR_WEXECUTE; - - return perms; -} - -static void copy_stat_info(sigar_file_attrs_t *fileattrs, - struct stat *info) -{ - fileattrs->permissions = sigar_unix_mode2perms(info->st_mode); - fileattrs->type = filetype_from_mode(info->st_mode); - fileattrs->uid = info->st_uid; - fileattrs->gid = info->st_gid; - fileattrs->size = info->st_size; - fileattrs->inode = info->st_ino; - fileattrs->device = info->st_dev; - fileattrs->nlink = info->st_nlink; - fileattrs->atime = info->st_atime; - fileattrs->mtime = info->st_mtime; - fileattrs->ctime = info->st_ctime; - fileattrs->atime *= 1000; - fileattrs->mtime *= 1000; - fileattrs->ctime *= 1000; -} - -int sigar_file_attrs_get(sigar_t *sigar, - const char *file, - sigar_file_attrs_t *fileattrs) -{ - struct stat info; - - if (stat(file, &info) == 0) { - copy_stat_info(fileattrs, &info); - return SIGAR_OK; - } - else { - return errno; - } -} - -int sigar_link_attrs_get(sigar_t *sigar, - const char *file, - sigar_file_attrs_t *fileattrs) -{ - struct stat info; - - if (lstat(file, &info) == 0) { - copy_stat_info(fileattrs, &info); - return SIGAR_OK; - } - else { - return errno; - } -} - -static int dir_stat_get(sigar_t *sigar, - const char *dir, - sigar_dir_stat_t *dirstats, - int recurse) -{ - int status; - char name[SIGAR_PATH_MAX+1]; - int len = strlen(dir); - int max = sizeof(name)-len-1; - char *ptr = name; - DIR *dirp = opendir(dir); - struct dirent *ent; - struct stat info; -#ifdef HAVE_READDIR_R - struct dirent dbuf; -#endif - - if (!dirp) { - return errno; - } - - strncpy(name, dir, sizeof(name)); - ptr += len; - if (name[len] != '/') { - *ptr++ = '/'; - len++; - max--; - } - -#ifdef HAVE_READDIR_R - while (readdir_r(dirp, &dbuf, &ent) == 0) { - if (ent == NULL) { - break; - } -#else - while ((ent = readdir(dirp))) { -#endif - /* skip '.' and '..' */ - if (IS_DOTDIR(ent->d_name)) { - continue; - } - - strncpy(ptr, ent->d_name, max); - ptr[max] = '\0'; - - if (lstat(name, &info) != 0) { - continue; - } - - dirstats->disk_usage += info.st_size; - - switch (filetype_from_mode(info.st_mode)) { - case SIGAR_FILETYPE_REG: - ++dirstats->files; - break; - case SIGAR_FILETYPE_DIR: - ++dirstats->subdirs; - if (recurse) { - status = - dir_stat_get(sigar, name, - dirstats, recurse); - if (status != SIGAR_OK) { - DIR_STAT_WARN(); - } - } - break; - case SIGAR_FILETYPE_LNK: - ++dirstats->symlinks; - break; - case SIGAR_FILETYPE_CHR: - ++dirstats->chrdevs; - break; - case SIGAR_FILETYPE_BLK: - ++dirstats->blkdevs; - break; - case SIGAR_FILETYPE_SOCK: - ++dirstats->sockets; - break; - default: - ++dirstats->total; - } - } - - dirstats->total = - dirstats->files + - dirstats->subdirs + - dirstats->symlinks + - dirstats->chrdevs + - dirstats->blkdevs + - dirstats->sockets; - - closedir(dirp); - - return SIGAR_OK; -} - -#endif - -SIGAR_DECLARE(int) sigar_dir_stat_get(sigar_t *sigar, - const char *dir, - sigar_dir_stat_t *dirstats) -{ - SIGAR_ZERO(dirstats); - return dir_stat_get(sigar, dir, dirstats, 0); -} - -SIGAR_DECLARE(int) sigar_dir_usage_get(sigar_t *sigar, - const char *dir, - sigar_dir_usage_t *dirusage) -{ - SIGAR_ZERO(dirusage); - return dir_stat_get(sigar, dir, dirusage, 1); -} diff --git a/vendor/sigar/src/sigar_format.c b/vendor/sigar/src/sigar_format.c deleted file mode 100644 index 8062ddd..0000000 --- a/vendor/sigar/src/sigar_format.c +++ /dev/null @@ -1,696 +0,0 @@ -/* - * Copyright (c) 2007-2008 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * Copyright (c) 2010 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Utility functions to provide string formatting of SIGAR data */ - -#include "sigar.h" -#include "sigar_private.h" -#include "sigar_util.h" -#include "sigar_os.h" -#include "sigar_format.h" - -#include -#include - -#ifndef WIN32 -#include -#include -#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(_AIX) -#include -#endif -#include -#include - -/* sysconf(_SC_GET{PW,GR}_R_SIZE_MAX) */ -#define R_SIZE_MAX 2048 - -int sigar_user_name_get(sigar_t *sigar, int uid, char *buf, int buflen) -{ - struct passwd *pw = NULL; - /* XXX cache lookup */ - -# ifdef HAVE_GETPWUID_R - struct passwd pwbuf; - char buffer[R_SIZE_MAX]; - - if (getpwuid_r(uid, &pwbuf, buffer, sizeof(buffer), &pw) != 0) { - return errno; - } - if (!pw) { - return ENOENT; - } -# else - if ((pw = getpwuid(uid)) == NULL) { - return errno; - } -# endif - - strncpy(buf, pw->pw_name, buflen); - buf[buflen-1] = '\0'; - - return SIGAR_OK; -} - -int sigar_group_name_get(sigar_t *sigar, int gid, char *buf, int buflen) -{ - struct group *gr; - /* XXX cache lookup */ - -# ifdef HAVE_GETGRGID_R - struct group grbuf; - char buffer[R_SIZE_MAX]; - - if (getgrgid_r(gid, &grbuf, buffer, sizeof(buffer), &gr) != 0) { - return errno; - } -# else - if ((gr = getgrgid(gid)) == NULL) { - return errno; - } -# endif - - if (gr && gr->gr_name) { - strncpy(buf, gr->gr_name, buflen); - } - else { - /* seen on linux.. apache httpd.conf has: - * Group #-1 - * results in uid == -1 and gr == NULL. - * wtf getgrgid_r doesnt fail instead? - */ - sprintf(buf, "%d", gid); - } - buf[buflen-1] = '\0'; - - return SIGAR_OK; -} - -int sigar_user_id_get(sigar_t *sigar, const char *name, int *uid) -{ - /* XXX cache lookup */ - struct passwd *pw; - -# ifdef HAVE_GETPWNAM_R - struct passwd pwbuf; - char buf[R_SIZE_MAX]; - - if (getpwnam_r(name, &pwbuf, buf, sizeof(buf), &pw) != 0) { - return errno; - } -# else - if (!(pw = getpwnam(name))) { - return errno; - } -# endif - - *uid = (int)pw->pw_uid; - return SIGAR_OK; -} - -#endif /* WIN32 */ - -static char *sigar_error_string(int err) -{ - switch (err) { - case SIGAR_ENOTIMPL: - return "This function has not been implemented on this platform"; - default: - return "Error string not specified yet"; - } -} - -SIGAR_DECLARE(char *) sigar_strerror(sigar_t *sigar, int err) -{ - char *buf; - - if (err < 0) { - return sigar->errbuf; - } - - if (err > SIGAR_OS_START_ERROR) { - if ((buf = sigar_os_error_string(sigar, err)) != NULL) { - return buf; - } - return "Unknown OS Error"; /* should never happen */ - } - - if (err > SIGAR_START_ERROR) { - return sigar_error_string(err); - } - - return sigar_strerror_get(err, sigar->errbuf, sizeof(sigar->errbuf)); -} - -char *sigar_strerror_get(int err, char *errbuf, int buflen) -{ - char *buf = NULL; -#ifdef WIN32 - DWORD len; - - len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - err, - MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), /* force english */ - (LPTSTR)errbuf, - (DWORD)buflen, - NULL); -#else - -#if defined(HAVE_STRERROR_R) && defined(HAVE_STRERROR_R_GLIBC) - /* - * strerror_r man page says: - * "The GNU version may, but need not, use the user supplied buffer" - */ - buf = strerror_r(err, errbuf, buflen); -#elif defined(HAVE_STRERROR_R) - if (strerror_r(err, errbuf, buflen) < 0) { - buf = "Unknown Error"; - } -#else - /* strerror() is thread safe on solaris and hpux */ - buf = strerror(err); -#endif - - if (buf != NULL) { - SIGAR_STRNCPY(errbuf, buf, buflen); - } - -#endif - return errbuf; -} - -void sigar_strerror_set(sigar_t *sigar, char *msg) -{ - SIGAR_SSTRCPY(sigar->errbuf, msg); -} - -#ifdef WIN32 -#define vsnprintf _vsnprintf -#endif - -void sigar_strerror_printf(sigar_t *sigar, const char *format, ...) -{ - va_list args; - - va_start(args, format); - vsnprintf(sigar->errbuf, sizeof(sigar->errbuf), format, args); - va_end(args); -} - -/* copy apr_strfsize */ -SIGAR_DECLARE(char *) sigar_format_size(sigar_uint64_t size, char *buf) -{ - const char ord[] = "KMGTPE"; - const char *o = ord; - int remain; - - if (size == SIGAR_FIELD_NOTIMPL) { - buf[0] = '-'; - buf[1] = '\0'; - return buf; - } - - if (size < 973) { - sprintf(buf, "%3d ", (int) size); - return buf; - } - - do { - remain = (int)(size & 1023); - size >>= 10; - - if (size >= 973) { - ++o; - continue; - } - - if (size < 9 || (size == 9 && remain < 973)) { - if ((remain = ((remain * 5) + 256) / 512) >= 10) { - ++size; - remain = 0; - } - sprintf(buf, "%d.%d%c", (int) size, remain, *o); - return buf; - } - - if (remain >= 512) { - ++size; - } - - sprintf(buf, "%3d%c", (int) size, *o); - - return buf; - } while (1); -} - - -SIGAR_DECLARE(int) sigar_uptime_string(sigar_t *sigar, - sigar_uptime_t *uptime, - char *buffer, - int buflen) -{ - char *ptr = buffer; - int time = (int)uptime->uptime; - int minutes, hours, days, offset = 0; - - /* XXX: get rid of sprintf and/or check for overflow */ - days = time / (60*60*24); - - if (days) { - offset += sprintf(ptr + offset, "%d day%s, ", - days, (days > 1) ? "s" : ""); - } - - minutes = time / 60; - hours = minutes / 60; - hours = hours % 24; - minutes = minutes % 60; - - if (hours) { - offset += sprintf(ptr + offset, "%2d:%02d", - hours, minutes); - } - else { - offset += sprintf(ptr + offset, "%d min", minutes); - } - - return SIGAR_OK; -} - -/* threadsafe alternative to inet_ntoa (inet_ntop4 from apr) */ -int sigar_inet_ntoa(sigar_t *sigar, - sigar_uint32_t address, - char *addr_str) -{ - char *next=addr_str; - int n=0; - const unsigned char *src = - (const unsigned char *)&address; - - do { - unsigned char u = *src++; - if (u > 99) { - *next++ = '0' + u/100; - u %= 100; - *next++ = '0' + u/10; - u %= 10; - } - else if (u > 9) { - *next++ = '0' + u/10; - u %= 10; - } - *next++ = '0' + u; - *next++ = '.'; - n++; - } while (n < 4); - - *--next = 0; - - return SIGAR_OK; -} - -static int sigar_ether_ntoa(char *buff, unsigned char *ptr) -{ - sprintf(buff, "%02X:%02X:%02X:%02X:%02X:%02X", - (ptr[0] & 0xff), (ptr[1] & 0xff), (ptr[2] & 0xff), - (ptr[3] & 0xff), (ptr[4] & 0xff), (ptr[5] & 0xff)); - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_net_address_equals(sigar_net_address_t *addr1, - sigar_net_address_t *addr2) - -{ - if (addr1->family != addr2->family) { - return EINVAL; - } - - switch (addr1->family) { - case SIGAR_AF_INET: - return memcmp(&addr1->addr.in, &addr2->addr.in, sizeof(addr1->addr.in)); - case SIGAR_AF_INET6: - return memcmp(&addr1->addr.in6, &addr2->addr.in6, sizeof(addr1->addr.in6)); - case SIGAR_AF_LINK: - return memcmp(&addr1->addr.mac, &addr2->addr.mac, sizeof(addr1->addr.mac)); - default: - return EINVAL; - } -} - -#if defined(SIGAR_USING_MSC6) -#define sigar_inet_ntop(af, src, dst, size) NULL -#define sigar_inet_ntop_errno SIGAR_ENOTIMPL -#elif defined(WIN32) -static char *sigar_inet_ntop(int af, const void *src, char *dst, int cnt) -{ - struct sockaddr_in6 sa; /* note only using this for AF_INET6 */ - - memset(&sa, '\0', sizeof(sa)); - sa.sin6_family = af; - memcpy(&sa.sin6_addr, src, sizeof(sa.sin6_addr)); - - if (getnameinfo((struct sockaddr *)&sa, sizeof(sa), - dst, cnt, NULL, 0, NI_NUMERICHOST)) - { - return NULL; - } - else { - return dst; - } -} -#define sigar_inet_ntop_errno GetLastError() -#else -#define sigar_inet_ntop inet_ntop -#define sigar_inet_ntop_errno errno -#endif - -SIGAR_DECLARE(int) sigar_net_address_to_string(sigar_t *sigar, - sigar_net_address_t *address, - char *addr_str) -{ - *addr_str = '\0'; - switch (address->family) { - case SIGAR_AF_INET6: - if (sigar_inet_ntop(AF_INET6, (const void *)&address->addr.in6, - addr_str, SIGAR_INET6_ADDRSTRLEN)) - { - return SIGAR_OK; - } - else { - return sigar_inet_ntop_errno; - } - case SIGAR_AF_INET: - return sigar_inet_ntoa(sigar, address->addr.in, addr_str); - case SIGAR_AF_UNSPEC: - return sigar_inet_ntoa(sigar, 0, addr_str); /*XXX*/ - case SIGAR_AF_LINK: - return sigar_ether_ntoa(addr_str, &address->addr.mac[0]); - default: - return EINVAL; - } -} - -SIGAR_DECLARE(const char *)sigar_net_scope_to_string(int type) -{ - switch (type) { - case SIGAR_IPV6_ADDR_ANY: - return "Global"; - case SIGAR_IPV6_ADDR_LOOPBACK: - return "Host"; - case SIGAR_IPV6_ADDR_LINKLOCAL: - return "Link"; - case SIGAR_IPV6_ADDR_SITELOCAL: - return "Site"; - case SIGAR_IPV6_ADDR_COMPATv4: - return "Compat"; - default: - return "Unknown"; - } -} - -SIGAR_DECLARE(sigar_uint32_t) sigar_net_address_hash(sigar_net_address_t *address) -{ - sigar_uint32_t hash = 0; - unsigned char *data; - int i=0, size, elts; - - switch (address->family) { - case SIGAR_AF_UNSPEC: - case SIGAR_AF_INET: - return address->addr.in; - case SIGAR_AF_INET6: - data = (unsigned char *)&address->addr.in6; - size = sizeof(address->addr.in6); - elts = 4; - break; - case SIGAR_AF_LINK: - data = (unsigned char *)&address->addr.mac; - size = sizeof(address->addr.mac); - elts = 2; - break; - default: - return -1; - } - - while (ivalue) { - entry->value = strdup(name); - } - } - - fclose(fp); - return SIGAR_OK; -} - -SIGAR_DECLARE(char *)sigar_net_services_name_get(sigar_t *sigar, - int protocol, unsigned long port) -{ - sigar_cache_entry_t *entry; - sigar_cache_t **names; - char *pname; - - switch (protocol) { - case SIGAR_NETCONN_TCP: - names = &sigar->net_services_tcp; - pname = "tcp"; - break; - case SIGAR_NETCONN_UDP: - names = &sigar->net_services_udp; - pname = "udp"; - break; - default: - return NULL; - } - - if (*names == NULL) { - *names = sigar_cache_new(1024); - net_services_parse(*names, pname); - } - - if ((entry = sigar_cache_find(*names, port))) { - return (char *)entry->value; - } - else { - return NULL; - } -} - -SIGAR_DECLARE(int) sigar_cpu_perc_calculate(sigar_cpu_t *prev, - sigar_cpu_t *curr, - sigar_cpu_perc_t *perc) -{ - double diff_user, diff_sys, diff_nice, diff_idle; - double diff_wait, diff_irq, diff_soft_irq, diff_stolen; - double diff_total; - - diff_user = curr->user - prev->user; - diff_sys = curr->sys - prev->sys; - diff_nice = curr->nice - prev->nice; - diff_idle = curr->idle - prev->idle; - diff_wait = curr->wait - prev->wait; - diff_irq = curr->irq - prev->irq; - diff_soft_irq = curr->soft_irq - prev->soft_irq; - diff_stolen = curr->stolen - prev->stolen; - - diff_user = diff_user < 0 ? 0 : diff_user; - diff_sys = diff_sys < 0 ? 0 : diff_sys; - diff_nice = diff_nice < 0 ? 0 : diff_nice; - diff_idle = diff_idle < 0 ? 0 : diff_idle; - diff_wait = diff_wait < 0 ? 0 : diff_wait; - diff_irq = diff_irq < 0 ? 0 : diff_irq; - diff_soft_irq = diff_soft_irq < 0 ? 0 : diff_soft_irq; - diff_stolen = diff_stolen < 0 ? 0 : diff_stolen; - - diff_total = - diff_user + diff_sys + diff_nice + diff_idle + - diff_wait + diff_irq + diff_soft_irq + - diff_stolen; - - perc->user = diff_user / diff_total; - perc->sys = diff_sys / diff_total; - perc->nice = diff_nice / diff_total; - perc->idle = diff_idle / diff_total; - perc->wait = diff_wait / diff_total; - perc->irq = diff_irq / diff_total; - perc->soft_irq = diff_soft_irq / diff_total; - perc->stolen = diff_stolen / diff_total; - - perc->combined = - perc->user + perc->sys + perc->nice + perc->wait; - - return SIGAR_OK; -} diff --git a/vendor/sigar/src/sigar_getline.c b/vendor/sigar/src/sigar_getline.c deleted file mode 100644 index 0a8946b..0000000 --- a/vendor/sigar/src/sigar_getline.c +++ /dev/null @@ -1,1849 +0,0 @@ -/* - * Copyright (C) 1991, 1992 by Chris Thewalt (thewalt@ce.berkeley.edu) - * - * Permission to use, copy, modify, and distribute this software - * for any purpose and without fee is hereby granted, provided - * that the above copyright notices appear in all copies and that both the - * copyright notice and this permission notice appear in supporting - * documentation. This software is provided "as is" without express or - * implied warranty. - */ -/* -*************************** Motivation ********************************** - -Many interactive programs read input line by line, but would like to -provide line editing and history functionality to the end-user that -runs the program. - -The input-edit package provides that functionality. As far as the -programmer is concerned, the program only asks for the next line -of input. However, until the user presses the RETURN key they can use -emacs-style line editing commands and can traverse the history of lines -previously typed. - -Other packages, such as GNU's readline, have greater capability but are -also substantially larger. Input-edit is small, since it uses neither -stdio nor any termcap features, and is also quite portable. It only uses -\b to backspace and \007 to ring the bell on errors. Since it cannot -edit multiple lines it scrolls long lines left and right on the same line. - -Input edit uses classic (not ANSI) C, and should run on any Unix -system (BSD or SYSV), PC's with the MSC compiler, or Vax/VMS (untested by me). -Porting the package to new systems basicaly requires code to read a -character when it is typed without echoing it, everything else should be OK. - -I have run the package on: - - DECstation 5000, Ultrix 4.2 with cc and gcc - Sun Sparc 2, SunOS 4.1.1, with cc - SGI Iris, IRIX System V.3, with cc - PC, DRDOS 5.0, with MSC 6.0 - -The description below is broken into two parts, the end-user (editing) -interface and the programmer interface. Send bug reports, fixes and -enhancements to: - -Chris Thewalt (thewalt@ce.berkeley.edu) -2/4/92 - -PS: I don't have, and don't want to add, a vi mode, sorry. - -************************** End-User Interface *************************** - -Entering printable keys generally inserts new text into the buffer (unless -in overwrite mode, see below). Other special keys can be used to modify -the text in the buffer. In the description of the keys below, ^n means -Control-n, or holding the CONTROL key down while pressing "n". M-B means -Meta-B (or Alt-B). Errors will ring the terminal bell. - -^A/^E : Move cursor to beginning/end of the line. -^F/^B : Move cursor forward/backward one character. -^D : Delete the character under the cursor. -^H, DEL : Delete the character to the left of the cursor. -^K : Kill from the cursor to the end of line. -^L : Redraw current line. -^O : Toggle overwrite/insert mode. Initially in insert mode. Text - added in overwrite mode (including yanks) overwrite - existing text, while insert mode does not overwrite. -^P/^N : Move to previous/next item on history list. -^R/^S : Perform incremental reverse/forward search for string on - the history list. Typing normal characters adds to the current - search string and searches for a match. Typing ^R/^S marks - the start of a new search, and moves on to the next match. - Typing ^H or DEL deletes the last character from the search - string, and searches from the starting location of the last search. - Therefore, repeated DEL's appear to unwind to the match nearest - the point at which the last ^R or ^S was typed. If DEL is - repeated until the search string is empty the search location - begins from the start of the history list. Typing ESC or - any other editing character accepts the current match and - loads it into the buffer, terminating the search. -^T : Toggle the characters under and to the left of the cursor. -^U : Kill from beginning to the end of the line. -^Y : Yank previously killed text back at current location. Note that - this will overwrite or insert, depending on the current mode. -M-F/M-B : Move cursor forward/backward one word. -M-D : Delete the word under the cursor. -^SPC : Set mark. -^W : Kill from mark to point. -^X : Exchange mark and point. -TAB : By default adds spaces to buffer to get to next TAB stop - (just after every 8th column), although this may be rebound by the - programmer, as described below. -NL, CR : returns current buffer to the program. - -DOS and ANSI terminal arrow key sequences are recognized, and act like: - - up : same as ^P - down : same as ^N - left : same as ^B - right : same as ^F - -************************** Programmer Interface *************************** - -The programmer accesses input-edit through five functions, and optionally -through three additional function pointer hooks. The five functions are: - -char *Getline(char *prompt) - - Prints the prompt and allows the user to edit the current line. A - pointer to the line is returned when the user finishes by - typing a newline or a return. Unlike GNU readline, the returned - pointer points to a static buffer, so it should not be free'd, and - the buffer contains the newline character. The user enters an - end-of-file by typing ^D on an empty line, in which case the - first character of the returned buffer is '\0'. Getline never - returns a NULL pointer. The getline function sets terminal modes - needed to make it work, and resets them before returning to the - caller. The getline function also looks for characters that would - generate a signal, and resets the terminal modes before raising the - signal condition. If the signal handler returns to getline, - the screen is automatically redrawn and editing can continue. - Getline now requires both the input and output stream be connected - to the terminal (not redirected) so the main program should check - to make sure this is true. If input or output have been redirected - the main program should use buffered IO (stdio) rather than - the slow 1 character read()s that getline uses (note: this limitation - has been removed). - -char *Getlinem(int mode, char *prompt) - - mode: -1 = init, 0 = line mode, 1 = one char at a time mode, 2 = cleanup - - More specialized version of the previous function. Depending on - the mode, it behaves differently. Its main use is to allow - character by character input from the input stream (useful when - in an X eventloop). It will return NULL as long as no newline - has been received. Its use is typically as follows: - 1) In the program initialization part one calls: Getlinem(-1,"prompt>") - 2) In the X inputhandler: if ((line = Getlinem(1,NULL))) { - 3) In the termination routine: Getlinem(2,NULL) - With mode=0 the function behaves exactly like the previous function. - -void Gl_config(const char *which, int value) - - Set some config options. Which can be: - "noecho": do not echo characters (used for passwd input) - "erase": do erase line after return (used for text scrollers) - -void Gl_setwidth(int width) - - Set the width of the terminal to the specified width. The default - width is 80 characters, so this function need only be called if the - width of the terminal is not 80. Since horizontal scrolling is - controlled by this parameter it is important to get it right. - -void Gl_histinit(char *file) - - This function reads a history list from file. So lines from a - previous session can be used again. - -void Gl_histadd(char *buf) - - The Gl_histadd function checks to see if the buf is not empty or - whitespace, and also checks to make sure it is different than - the last saved buffer to avoid repeats on the history list. - If the buf is a new non-blank string a copy is made and saved on - the history list, so the caller can re-use the specified buf. - -The main loop in testgl.c, included in this directory, shows how the -input-edit package can be used: - -extern char *Getline(); -extern void Gl_histadd(); -main() -{ - char *p; - Gl_histinit(".hist"); - do { - p = Getline("PROMPT>>>> "); - Gl_histadd(p); - fputs(p, stdout); - } while (*p != 0); -} - -In order to allow the main program to have additional access to the buffer, -to implement things such as completion or auto-indent modes, three -function pointers can be bound to user functions to modify the buffer as -described below. By default gl_in_hook and gl_out_hook are set to NULL, -and gl_tab_hook is bound to a function that inserts spaces until the next -logical tab stop is reached. The user can reassign any of these pointers -to other functions. Each of the functions bound to these hooks receives -the current buffer as the first argument, and must return the location of -the leftmost change made in the buffer. If the buffer isn't modified the -functions should return -1. When the hook function returns the screen is -updated to reflect any changes made by the user function. - -int (*gl_in_hook)(char *buf) - - If gl_in_hook is non-NULL the function is called each time a new - buffer is loaded. It is called when getline is entered, with an - empty buffer, it is called each time a new buffer is loaded from - the history with ^P or ^N, and it is called when an incremental - search string is accepted (when the search is terminated). The - buffer can be modified and will be redrawn upon return to Getline(). - -int (*gl_out_hook)(char *buf) - - If gl_out_hook is non-NULL it is called when a line has been - completed by the user entering a newline or return. The buffer - handed to the hook does not yet have the newline appended. If the - buffer is modified the screen is redrawn before getline returns the - buffer to the caller. - -int (*gl_tab_hook)(char *buf, int prompt_width, int *cursor_loc) - - If gl_tab_hook is non-NULL, it is called whenever a tab is typed. - In addition to receiving the buffer, the current prompt width is - given (needed to do tabbing right) and a pointer to the cursor - offset is given, where a 0 offset means the first character in the - line. Not only does the cursor_loc tell the programmer where the - TAB was received, but it can be reset so that the cursor will end - up at the specified location after the screen is redrawn. -*/ - -/* forward reference needed for gl_tab_hook */ -static int gl_tab(char *buf, int offset, int *loc); - -/********************* exported interface ********************************/ - -static int (*gl_in_hook)(char *buf) = 0; -static int (*gl_out_hook)(char *buf) = 0; -static int (*gl_tab_hook)(char *buf, int prompt_width, int *loc) = gl_tab; - -/******************** imported interface *********************************/ -#ifdef DMALLOC -/* reports leaks, which is the history buffer. dont care */ -#undef DMALLOC -#endif -#include "sigar_getline.h" -#include "sigar_private.h" -#include "sigar_util.h" -#include -#include -#include -#include -#include -#include - -/******************** internal interface *********************************/ - -static char *sigar_getlinem(int mode, char *prompt); /* allows reading char by char */ - -static void sigar_getline_config(const char *which, int value); /* set some options */ - -static void sigar_getline_clear_screen(void); - -#define BUF_SIZE 8096 - -static int gl_init_done = -1; /* terminal mode flag */ -static int gl_notty = 0; /* 1 when not a tty */ -static int gl_eof = 0; /* 1 when not a tty and read() == -1 */ -static int gl_termw = 80; /* actual terminal width */ -static int gl_scroll = 27; /* width of EOL scrolling region */ -static int gl_width = 0; /* net size available for input */ -static int gl_extent = 0; /* how far to redraw, 0 means all */ -static int gl_overwrite = 0; /* overwrite mode */ -static int gl_no_echo = 0; /* do not echo input characters */ -static int gl_passwd = 0; /* do not echo input characters */ -static int gl_erase_line = 0; /* erase line before returning */ -static int gl_pos, gl_cnt = 0; /* position and size of input */ -static char gl_buf[BUF_SIZE]; /* input buffer */ -static char gl_killbuf[BUF_SIZE]=""; /* killed text */ -static char *gl_prompt; /* to save the prompt string */ -static char gl_intrc = 0; /* keyboard SIGINT char */ -static char gl_quitc = 0; /* keyboard SIGQUIT char */ -static char gl_suspc = 0; /* keyboard SIGTSTP char */ -static char gl_dsuspc = 0; /* delayed SIGTSTP char */ -static int gl_search_mode = 0; /* search mode flag */ -static int gl_bell_enabled = 0; /* bell mode */ -static int gl_savehist = 0; /* # of lines to save in hist file */ -static char gl_histfile[256]; /* name of history file */ - -static void gl_init(); /* prepare to edit a line */ -static void gl_bell(); /* ring bell */ -static void gl_cleanup(); /* to undo gl_init */ -static void gl_char_init(); /* get ready for no echo input */ -static void gl_char_cleanup(); /* undo gl_char_init */ - -static void gl_addchar(int c); /* install specified char */ -static void gl_del(int loc); /* del, either left (-1) or cur (0) */ -static void gl_error(char *buf); /* write error msg and die */ -static void gl_fixup(char *p, int c, int cur); /* fixup state variables and screen */ -static int gl_getc(); /* read one char from terminal */ -static void gl_kill(); /* delete to EOL */ -static void gl_newline(); /* handle \n or \r */ -static void gl_putc(int c); /* write one char to terminal */ -static void gl_puts(char *buf); /* write a line to terminal */ -static void gl_transpose(); /* transpose two chars */ -static void gl_yank(); /* yank killed text */ - -static int is_whitespace(char c); /* "whitespace" very loosely interpreted */ -static void gl_back_1_word(); /* move cursor back one word */ -static void gl_kill_1_word(); /* kill to end of word */ -static void gl_kill_region(int i, int j); /* kills from i to j */ -static void gl_fwd_1_word(); /* move cursor forward one word */ -static void gl_set_mark(); /* sets mark to be at point */ -static void gl_exch(); /* exchanges point and mark */ -static void gl_wipe(); /* kills from mark to point */ -static int gl_mark = -1; /* position of mark. gl_mark<0 if not set */ - -static void hist_init(); /* initializes hist pointers */ -static char *hist_next(); /* return ptr to next item */ -static char *hist_prev(); /* return ptr to prev item */ -static char *hist_save(char *p); /* makes copy of a string, without NL */ - -static void search_addchar(int c); /* increment search string */ -static void search_term(); /* reset with current contents */ -static void search_back(int s); /* look back for current string */ -static void search_forw(int s); /* look forw for current string */ - -/************************ nonportable part *********************************/ - -#ifdef MSDOS -#include -#endif - -#ifdef WIN32 -# define MSDOS -# include -# include -#endif /* WIN32 */ - -#ifdef __MWERKS__ -#define R__MWERKS -#endif - -#ifdef R__MWERKS -# include -#endif - -#if defined(_AIX) || defined(__Lynx__) || defined(__APPLE__) -#define unix -#endif - -#if defined(__hpux) || defined(__osf__) /* W.Karig@gsi.de */ -#ifndef unix -#define unix -#endif -#endif - -#ifdef unix -#include -#if !defined(__osf__) && !defined(_AIX) /* W.Karig@gsi.de */ -#include -#endif - -#if defined(__linux__) && defined(__powerpc__) -# define R__MKLINUX // = linux on PowerMac -#endif -#if defined(__linux__) && defined(__alpha__) -# define R__ALPHALINUX // = linux on Alpha -#endif - -#if defined(TIOCGETP) && !defined(__sgi) && !defined(R__MKLINUX) && \ - !defined(R__ALPHALINUX) /* use BSD interface if possible */ -#include -static struct sgttyb new_tty, old_tty; -static struct tchars tch; -static struct ltchars ltch; -#else -#ifdef SIGTSTP /* need POSIX interface to handle SUSP */ -#include -#if defined(__sun) || defined(__sgi) || defined(R__MKLINUX) || \ - defined(R__ALPHALINUX) -#undef TIOCGETP /* Solaris and SGI define TIOCGETP in */ -#undef TIOCSETP -#endif -static struct termios new_termios, old_termios; -#else /* use SYSV interface */ -#include -static struct termio new_termio, old_termio; -#endif -#endif -#endif /* unix */ - -#ifdef VMS -#include -#include -#include -#include -#include -#include unixio - -static int setbuff[2]; /* buffer to set terminal attributes */ -static short chan = -1; /* channel to terminal */ -struct dsc$descriptor_s descrip; /* VMS descriptor */ -#endif - -static void -sigar_getline_config(const char *which, int value) -{ - if (strcmp(which, "noecho") == 0) - gl_no_echo = value; - else if (strcmp(which, "erase") == 0) - gl_erase_line = value; - else - printf("gl_config: %s ?\n", which); -} - -static void -gl_char_init() /* turn off input echo */ -{ - if (gl_notty) return; -#ifdef unix -#ifdef TIOCGETP /* BSD */ - ioctl(0, TIOCGETC, &tch); - ioctl(0, TIOCGLTC, <ch); - gl_intrc = tch.t_intrc; - gl_quitc = tch.t_quitc; - gl_suspc = ltch.t_suspc; - gl_dsuspc = ltch.t_dsuspc; - ioctl(0, TIOCGETP, &old_tty); - new_tty = old_tty; - new_tty.sg_flags |= RAW; - new_tty.sg_flags &= ~ECHO; - ioctl(0, TIOCSETP, &new_tty); -#else -#ifdef SIGTSTP /* POSIX */ - tcgetattr(0, &old_termios); - gl_intrc = old_termios.c_cc[VINTR]; - gl_quitc = old_termios.c_cc[VQUIT]; -#ifdef VSUSP - gl_suspc = old_termios.c_cc[VSUSP]; -#endif -#ifdef VDSUSP - gl_dsuspc = old_termios.c_cc[VDSUSP]; -#endif - new_termios = old_termios; - new_termios.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF); - new_termios.c_iflag |= (IGNBRK|IGNPAR); - new_termios.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO); - new_termios.c_cc[VMIN] = 1; - new_termios.c_cc[VTIME] = 0; - tcsetattr(0, TCSANOW, &new_termios); -#else /* SYSV */ - ioctl(0, TCGETA, &old_termio); - gl_intrc = old_termio.c_cc[VINTR]; - gl_quitc = old_termio.c_cc[VQUIT]; - new_termio = old_termio; - new_termio.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF); - new_termio.c_iflag |= (IGNBRK|IGNPAR); - new_termio.c_lflag &= ~(ICANON|ISIG|ECHO); - new_termio.c_cc[VMIN] = 1; - new_termio.c_cc[VTIME] = 0; - ioctl(0, TCSETA, &new_termio); -#endif -#endif -#endif /* unix */ - -#ifdef MSDOS - gl_intrc = 'C' - '@'; - gl_quitc = 'Q' - '@'; -// gl_suspc = ltch.t_suspc; -#endif /* MSDOS */ - -#ifdef R__MWERKS - gl_intrc = 'C' - '@'; - gl_quitc = 'Q' - '@'; -#endif - -#ifdef vms - descrip.dsc$w_length = strlen("tt:"); - descrip.dsc$b_dtype = DSC$K_DTYPE_T; - descrip.dsc$b_class = DSC$K_CLASS_S; - descrip.dsc$a_pointer = "tt:"; - (void)sys$assign(&descrip,&chan,0,0); - (void)sys$qiow(0,chan,IO$_SENSEMODE,0,0,0,setbuff,8,0,0,0,0); - setbuff[1] |= TT$M_NOECHO; - (void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0); -#endif /* vms */ -} - -static void -gl_char_cleanup() /* undo effects of gl_char_init */ -{ - if (gl_notty) return; -#ifdef unix -#ifdef TIOCSETP /* BSD */ - ioctl(0, TIOCSETP, &old_tty); -#else -#ifdef SIGTSTP /* POSIX */ - tcsetattr(0, TCSANOW, &old_termios); -#else /* SYSV */ - ioctl(0, TCSETA, &old_termio); -#endif -#endif -#endif /* unix */ - -#ifdef vms - setbuff[1] &= ~TT$M_NOECHO; - (void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0); - sys$dassgn(chan); - chan = -1; -#endif -} - -#if defined(MSDOS) && !defined(WIN32) -// +DECK, PAUSE, T=XCC, IF=WINNT. (from KERNDOS.CAR ) -# include - int pause_() - { - int first_char; - first_char = _getch(); - if (first_char == 0 || first_char == 0xE0) first_char = -_getch(); - return first_char; - } -#endif - -#if defined(MSDOS) && defined(WIN32) -//______________________________________________________________________________ -int pause_() -{ - static HANDLE hConsoleInput = NULL; - static iCharCount = 0; - static int chLastChar = 0; - - DWORD cRead; - - INPUT_RECORD pirBuffer; - KEY_EVENT_RECORD *KeyEvent= (KEY_EVENT_RECORD *)&(pirBuffer.Event); - - if (!hConsoleInput) hConsoleInput = GetStdHandle(STD_INPUT_HANDLE); - - if (iCharCount) iCharCount--; // Whether several symbols had been read - else { - chLastChar = 0; - while (chLastChar == 0) { - if (!ReadConsoleInput(hConsoleInput, // handle of a console input buffer - &pirBuffer, // address of the buffer for read data - 1, // number of records to read - &cRead // address of number of records read - )) return 0; - - if (pirBuffer.EventType == KEY_EVENT && KeyEvent->bKeyDown == TRUE){ - iCharCount = KeyEvent->wRepeatCount - 1; - chLastChar = ((int) (KeyEvent->uChar).AsciiChar & 0xffff); - if (chLastChar) - OemToCharBuff((char const *)&chLastChar,(char *)&chLastChar,1); - else - chLastChar = - (KeyEvent->wVirtualScanCode); -// chLastChar = - (KeyEvent->wVirtualKeyCode); - } - } - } - return chLastChar; - -} -#endif - -static int -gl_getc() -/* get a character without echoing it to screen */ -{ -#ifdef MSDOS -# define k_ctrl_C 3 -# define k_ctrl_Z 26 -# define k_ctrl_Q 17 -# define k_ctrl_K 11 -# define k_rt_arr -77 -# define k_lt_arr -75 -# define k_up_arr -72 -# define k_dn_arr -80 -# define k_PGUP -73 -# define k_PGDW -81 -# define k_HOME -71 -# define k_END -79 -# define k_INS -82 -# define k_DEL -83 -# define k_ENTER 13 -# define k_CR 13 -# define k_BS 8 -# define k_ESC 27 -# define k_alt_H -35 -# define k_beep 7 -# ifndef WIN32 - int get_cursor__(int *,int *); - int display_off__(int *); - int display_on__(); - int locate_(int *,int *); - int ixc, iyc; -# endif - int pause_(); -#endif - - int c; - -#if defined(unix) - unsigned char ch; - while ((c = (read(0, &ch, 1) > 0) ? ch : -1) == -1 && errno == EINTR) - errno = 0; -#endif - -#if defined(R__MWERKS) - c = getchar(); -#endif - -#ifdef MSDOS - c = pause_(); - if (c < 0) { - switch (c) { - case k_up_arr: c = 'P' - '@'; /* up -> ^P = 16 */ - break; - case k_dn_arr: c = 'N' - '@'; /* down -> ^N = 14 */ - break; - case k_lt_arr: c = 'B' - '@'; /* left -> ^B =2 */ - break; - case k_rt_arr: c = 'F' - '@'; /* right -> ^F = 6*/ - break; - case k_INS: c = 'O' - '@'; /* right -> ^O = 15*/ - break; - case k_DEL: c = 'D' - '@'; /* Delete character under cursor = 4*/ - break; - case k_END: c = 'E' - '@'; /* Moves cursor to end of line * = 5 */ - break; - case k_HOME: c = 'A' - '@'; /* Moves cursor to beginning of line = 1*/ - break; - default: c = 0; /* make it garbage */ - } - } - else { - switch(c) { - case k_ESC: c = 'U' - '@'; /* Clear full line -> ^U */ - break; - default: - break; - } - } -#endif - -#ifdef vms - if(chan < 0) { - c='\0'; - } - (void)sys$qiow(0,chan,IO$_TTYREADALL,0,0,0,&c,1,0,0,0,0); - c &= 0177; /* get a char */ -#endif - return c; -} - -static void -gl_putc(int c) -{ - char ch = c; - - if (gl_notty) return; - - if ( !gl_passwd || !isgraph(c)) - { -#ifdef WIN32 - CharToOemBuff((char const *)&c,&ch,1); -#endif - - sigar_write(1, &ch, 1); - } -#if defined(unix) || defined(MSDOS) || defined(WIN32) || defined(R__MWERKS) -#ifdef TIOCSETP /* BSD in RAW mode, map NL to NL,CR */ - if (ch == '\n') { - ch = '\r'; - sigar_write(1, &ch, 1); - } -#endif -#endif -} - -/******************** fairly portable part *********************************/ - -static void -gl_puts(char *buf) -{ - int len = strlen(buf); - - if (gl_notty) return; -#ifdef WIN32 - { - char *OemBuf = (char *)malloc(2*len); - CharToOemBuff(buf,OemBuf,len); - sigar_write(1, OemBuf, len); - free(OemBuf); - } -#else - sigar_write(1, buf, len); -#endif -} - -static void -gl_error(char *buf) -{ - int len = strlen(buf); - - gl_cleanup(); -#ifdef WIN32 - { - char *OemBuf = (char *)malloc(2*len); - CharToOemBuff(buf,OemBuf,len); - sigar_write(2, OemBuf, len); - free(OemBuf); - } -#else - sigar_write(2, buf, len); -#endif - exit(1); -} - -static void -gl_init() -/* set up variables and terminal */ -{ - if (gl_init_done < 0) { /* -1 only on startup */ - hist_init(); - } - if (sigar_isatty(0) == 0 || sigar_isatty(1) == 0) - gl_notty = 1; - gl_char_init(); - gl_init_done = 1; -} - -static void -gl_bell() -{ - if (gl_bell_enabled) { - gl_putc('\007'); - } -} - -static void -gl_cleanup() -/* undo effects of gl_init, as necessary */ -{ - if (gl_init_done > 0) - gl_char_cleanup(); - gl_init_done = 0; -} - -SIGAR_DECLARE(void) -sigar_getline_setwidth(int w) -{ - if (w > 20) { - gl_termw = w; - gl_scroll = w / 3; - } else { - gl_error("\n*** Error: minimum screen width is 21\n"); - } -} - -SIGAR_DECLARE(void) -sigar_getline_windowchanged() -{ -#ifdef TIOCGWINSZ - if (sigar_isatty(0)) { - static char lenv[32], cenv[32]; - struct winsize wins; - ioctl(0, TIOCGWINSZ, &wins); - - if (wins.ws_col == 0) wins.ws_col = 80; - if (wins.ws_row == 0) wins.ws_row = 24; - - sigar_getline_setwidth(wins.ws_col); - - sprintf(lenv, "LINES=%d", wins.ws_row); - putenv(lenv); - sprintf(cenv, "COLUMNS=%d", wins.ws_col); - putenv(cenv); - } -#endif -} - -/* -1 = init, 0 = line mode, 1 = one char at a time mode, 2 = cleanup */ - -static char * -sigar_getlinem(int mode, char *prompt) -{ - int c, loc, tmp; - int sig; - - if (mode == 2) { - gl_cleanup(); - return NULL; - } - - if (mode < 1) { - if (mode == -1) { - sigar_getline_config("noecho", 0); - sigar_getline_config("erase", 0); - } - gl_init(); - gl_prompt = (prompt)? prompt : (char*)""; - gl_buf[0] = 0; - if (gl_in_hook) - gl_in_hook(gl_buf); - gl_fixup(gl_prompt, -2, BUF_SIZE); - if (mode == -1) return NULL; - } - while ((c = gl_getc()) >= 0) { - gl_extent = 0; /* reset to full extent */ -#ifndef WIN32 - if (isprint(c)) { -#else - if (c >= ' ') { -#endif - if (gl_search_mode) - search_addchar(c); - else - gl_addchar(c); - } else { - if (gl_search_mode) { - if (c == '\033' || c == '\016' || c == '\020') { - search_term(); - c = 0; /* ignore the character */ - } else if (c == '\010' || c == '\177') { - search_addchar(-1); /* unwind search string */ - c = 0; - } else if (c != '\022' && c != '\023') { - search_term(); /* terminate and handle char */ - } - } - /* NOTE: - * sometimes M-x turns on bit 8 ( M-x --> 'x' + 128 ) - * sometimes M-x prepends an escape character ( M-x --> '\033','x' ) - * both cases are handled ... - */ - switch (c) - { - case 'b'+128: /* M-b */ - case 'B'+128: /* M-B */ - gl_back_1_word(); - break; - case 'd'+128: /* M-d */ - case 'D'+128: /* M-D */ - gl_kill_1_word(); - break; - case 'f'+128: /* M-f */ - case 'F'+128: /* M-F */ - gl_fwd_1_word(); - break; - case '\000': /* ^SPC */ - gl_set_mark(); - break; - case '\027': /* ^W */ - gl_wipe(); - break; - case '\030': /* ^X */ - gl_exch(); - break; - case '\n': /* newline */ - case '\r': - gl_newline(); - gl_cleanup(); - return gl_buf; - /*NOTREACHED*/ - break; - case '\001': gl_fixup(gl_prompt, -1, 0); /* ^A */ - break; - case '\002': gl_fixup(gl_prompt, -1, gl_pos-1); /* ^B */ - break; - case '\004': /* ^D */ - if (gl_cnt == 0) { - gl_buf[0] = 0; - gl_cleanup(); - gl_putc('\n'); - return gl_buf; - } else { - gl_del(0); - } - break; - case '\005': gl_fixup(gl_prompt, -1, gl_cnt); /* ^E */ - break; - case '\006': gl_fixup(gl_prompt, -1, gl_pos+1); /* ^F */ - break; - case '\010': case '\177': gl_del(-1); /* ^H and DEL */ - break; - case '\t': /* TAB */ - if (gl_tab_hook) { - tmp = gl_pos; - loc = gl_tab_hook(gl_buf, strlen(gl_prompt), &tmp); - if (loc >= 0 || tmp != gl_pos || loc == -2) - gl_fixup(gl_prompt, loc, tmp); - } - break; - case '\013': gl_kill(); /* ^K */ - break; - case '\014': sigar_getline_clear_screen(); /* ^L */ - break; - case '\016': /* ^N */ - strcpy(gl_buf, hist_next()); - if (gl_in_hook) - gl_in_hook(gl_buf); - gl_fixup(gl_prompt, 0, BUF_SIZE); - break; - case '\017': gl_overwrite = !gl_overwrite; /* ^O */ - break; - case '\020': /* ^P */ - strcpy(gl_buf, hist_prev()); - if (gl_in_hook) - gl_in_hook(gl_buf); - gl_fixup(gl_prompt, 0, BUF_SIZE); - break; - case '\022': search_back(1); /* ^R */ - break; - case '\023': search_forw(1); /* ^S */ - break; - case '\024': gl_transpose(); /* ^T */ - break; - case '\025': gl_fixup(gl_prompt,-1,0); gl_kill(); /* ^U */ - break; - case '\031': gl_yank(); /* ^Y */ - break; - case '\033': - switch(c = gl_getc()) - { - case 'b': /* M-b */ - case 'B': /* M-B */ - gl_back_1_word(); - break; - case 'd': /* M-d */ - case 'D': /* M-D */ - gl_kill_1_word(); - break; - case 'f': /* M-f */ - case 'F': /* M-F */ - gl_fwd_1_word(); - break; - case '[': /* ansi arrow keys */ - case 'O': /* xterm arrow keys */ - switch(c = gl_getc()) - { - case 'A': /* up */ - strcpy(gl_buf, hist_prev()); - if (gl_in_hook) - gl_in_hook(gl_buf); - gl_fixup(gl_prompt, 0, BUF_SIZE); - break; - case 'B': /* down */ - strcpy(gl_buf, hist_next()); - if (gl_in_hook) - gl_in_hook(gl_buf); - gl_fixup(gl_prompt, 0, BUF_SIZE); - break; - case 'C': gl_fixup(gl_prompt, -1, gl_pos+1); /* right */ - break; - case 'D': gl_fixup(gl_prompt, -1, gl_pos-1); /* left */ - break; - default: /* who knows */ - gl_bell(); - break; - } - break; - default: - gl_bell(); - } - break; - default: /* check for a terminal signal */ - -#if defined(unix) || defined(WIN32) || defined(R__MWERKS) - if (c > 0) { /* ignore 0 (reset above) */ - sig = 0; -#ifdef SIGINT - if (c == gl_intrc) - sig = SIGINT; -#endif -#ifdef SIGQUIT - if (c == gl_quitc) - sig = SIGQUIT; -#endif -#ifdef SIGTSTP - if (c == gl_suspc || c == gl_dsuspc) - sig = SIGTSTP; -#endif - if (sig != 0) { - gl_cleanup(); -#if !defined(WIN32) - raise(sig); -#endif -#ifdef WIN32 - if (sig == SIGINT) GenerateConsoleCtrlEvent(CTRL_C_EVENT,0); - else raise(sig); -#endif - gl_init(); - sigar_getline_redraw(); - c = 0; - } - } -#endif /* unix */ - if (c > 0) - gl_bell(); - break; - } - } - if (mode == 1) return NULL; - } - if (c == -1 && gl_notty) - gl_eof = 1; - else - gl_eof = 0; - - gl_cleanup(); - gl_buf[0] = 0; - return gl_buf; -} - -SIGAR_DECLARE(int) -sigar_getline_eof() -{ - return gl_eof; -} - -SIGAR_DECLARE(char *) -sigar_getline(char *prompt) -{ - return sigar_getlinem(0, prompt); -} - -static void -gl_addchar(int c) -/* adds the character c to the input buffer at current location */ -{ - int i; - - if (gl_cnt >= BUF_SIZE - 1) - gl_error("\n*** Error: sigar_getline(): input buffer overflow\n"); - if (gl_overwrite == 0 || gl_pos == gl_cnt) { - for (i=gl_cnt; i >= gl_pos; i--) - gl_buf[i+1] = gl_buf[i]; - gl_buf[gl_pos] = c; - gl_fixup(gl_prompt, gl_pos, gl_pos+1); - } else { - gl_buf[gl_pos] = c; - gl_extent = 1; - gl_fixup(gl_prompt, gl_pos, gl_pos+1); - } -} - -static void -gl_yank() -/* adds the kill buffer to the input buffer at current location */ -{ - int i, len; - - len = strlen(gl_killbuf); - if (len > 0) { - gl_mark = gl_pos; - if (gl_overwrite == 0) { - if (gl_cnt + len >= BUF_SIZE - 1) - gl_error("\n*** Error: sigar_getline(): input buffer overflow\n"); - for (i=gl_cnt; i >= gl_pos; i--) - gl_buf[i+len] = gl_buf[i]; - for (i=0; i < len; i++) - gl_buf[gl_pos+i] = gl_killbuf[i]; - gl_fixup(gl_prompt, gl_pos, gl_pos+len); - } else { - if (gl_pos + len > gl_cnt) { - if (gl_pos + len >= BUF_SIZE - 1) - gl_error("\n*** Error: sigar_getline(): input buffer overflow\n"); - gl_buf[gl_pos + len] = 0; - } - for (i=0; i < len; i++) - gl_buf[gl_pos+i] = gl_killbuf[i]; - gl_extent = len; - gl_fixup(gl_prompt, gl_pos, gl_pos+len); - } - } else - gl_bell(); -} - -static void -gl_transpose() -/* switch character under cursor and to left of cursor */ -{ - int c; - - if (gl_pos > 0 && gl_cnt > gl_pos) { - c = gl_buf[gl_pos-1]; - gl_buf[gl_pos-1] = gl_buf[gl_pos]; - gl_buf[gl_pos] = c; - gl_extent = 2; - gl_fixup(gl_prompt, gl_pos-1, gl_pos); - } else - gl_bell(); -} - -static void -gl_newline() -/* - * Cleans up entire line before returning to caller. A \n is appended. - * If line longer than screen, we redraw starting at beginning - */ -{ - int change = gl_cnt; - int len = gl_cnt; - int loc = gl_width - 5; /* shifts line back to start position */ - - if (gl_cnt >= BUF_SIZE - 1) - gl_error("\n*** Error: sigar_getline(): input buffer overflow\n"); - if (gl_out_hook) { - change = gl_out_hook(gl_buf); - len = strlen(gl_buf); - } - if (gl_erase_line) { - char gl_buf0 = gl_buf[0]; - gl_buf[0] = '\0'; - gl_fixup("", 0, 0); - gl_buf[0] = gl_buf0; - } - else { - if (loc > len) - loc = len; - gl_fixup(gl_prompt, change, loc); /* must do this before appending \n */ - gl_putc('\n'); - } -#if 0 - gl_buf[len] = '\n'; - gl_buf[len+1] = '\0'; -#endif - gl_mark = -1; -} - -static void -gl_del(int loc) -/* - * Delete a character. The loc variable can be: - * -1 : delete character to left of cursor - * 0 : delete character under cursor - */ -{ - int i; - - if ((loc == -1 && gl_pos > 0) || (loc == 0 && gl_pos < gl_cnt)) { - for (i=gl_pos+loc; i < gl_cnt; i++) - gl_buf[i] = gl_buf[i+1]; - gl_fixup(gl_prompt, gl_pos+loc, gl_pos+loc); - } else - gl_bell(); -} - -static void -gl_kill() -/* delete from current position to the end of line */ -{ - if (gl_pos < gl_cnt) { - strcpy(gl_killbuf, gl_buf + gl_pos); - gl_buf[gl_pos] = '\0'; - gl_fixup(gl_prompt, gl_pos, gl_pos); - } else - gl_bell(); -} - -SIGAR_DECLARE(void) sigar_getline_redraw(void) -/* emit a newline, reset and redraw prompt and current input line */ -{ - if (gl_init_done > 0) { - gl_putc('\n'); - gl_fixup(gl_prompt, -2, gl_pos); - } -} - -#define CLEAR_SCREEN "\033[2J" - -static void sigar_getline_clear_screen(void) -{ - if (gl_init_done > 0) { - gl_putc('\n'); - /* XXX what to do for non-ansi term? */ - gl_puts(CLEAR_SCREEN); - gl_fixup(gl_prompt, -2, gl_pos); - } -} - -SIGAR_DECLARE(void) sigar_getline_reset(void) -{ - gl_fixup(gl_prompt,-1,0); - gl_kill(); -} - -static void -gl_fixup(char *prompt, int change, int cursor) -/* - * This function is used both for redrawing when input changes or for - * moving within the input line. The parameters are: - * prompt: compared to last_prompt[] for changes; - * change : the index of the start of changes in the input buffer, - * with -1 indicating no changes, -2 indicating we're on - * a new line, redraw everything. - * cursor : the desired location of the cursor after the call. - * A value of BUF_SIZE can be used to indicate the cursor should - * move just past the end of the input line. - */ -{ - static int gl_shift; /* index of first on screen character */ - static int off_right; /* true if more text right of screen */ - static int off_left; /* true if more text left of screen */ - static char last_prompt[BUF_SIZE] = ""; - int left = 0, right = -1; /* bounds for redraw */ - int padl; /* how much to erase at end of line */ - int backup; /* how far to backup before fixing */ - int new_shift; /* value of shift based on cursor */ - int extra; /* adjusts when shift (scroll) happens */ - int i; - int new_right = -1; /* alternate right bound, using gl_extent */ - int l1, l2; - - if (change == -2) { /* reset */ - gl_pos = gl_cnt = gl_shift = off_right = off_left = 0; - gl_passwd = 0; - gl_puts(prompt); - gl_passwd = gl_no_echo; - strcpy(last_prompt, prompt); - change = 0; - gl_width = gl_termw - strlen(prompt); - } else if (strcmp(prompt, last_prompt) != 0) { - l1 = strlen(last_prompt); - l2 = strlen(prompt); - gl_cnt = gl_cnt + l1 - l2; - strcpy(last_prompt, prompt); - backup = gl_pos - gl_shift + l1; - for (i=0; i < backup; i++) - gl_putc('\b'); - gl_passwd = 0; - gl_puts(prompt); - gl_passwd = gl_no_echo; - gl_pos = gl_shift; - gl_width = gl_termw - l2; - change = 0; - } - padl = (off_right)? gl_width - 1 : gl_cnt - gl_shift; /* old length */ - backup = gl_pos - gl_shift; - if (change >= 0) { - gl_cnt = strlen(gl_buf); - if (change > gl_cnt) - change = gl_cnt; - } - if (cursor > gl_cnt) { - if (cursor != BUF_SIZE) /* BUF_SIZE means end of line */ - gl_bell(); - cursor = gl_cnt; - } - if (cursor < 0) { - gl_bell(); - cursor = 0; - } - if (off_right || (off_left && cursor < gl_shift + gl_width - gl_scroll / 2)) - extra = 2; /* shift the scrolling boundary */ - else - extra = 0; - new_shift = cursor + extra + gl_scroll - gl_width; - if (new_shift > 0) { - new_shift /= gl_scroll; - new_shift *= gl_scroll; - } else - new_shift = 0; - if (new_shift != gl_shift) { /* scroll occurs */ - gl_shift = new_shift; - off_left = (gl_shift)? 1 : 0; - off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0; - left = gl_shift; - new_right = right = (off_right)? gl_shift + gl_width - 2 : gl_cnt; - } else if (change >= 0) { /* no scroll, but text changed */ - if (change < gl_shift + off_left) { - left = gl_shift; - } else { - left = change; - backup = gl_pos - change; - } - off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0; - right = (off_right)? gl_shift + gl_width - 2 : gl_cnt; - new_right = (gl_extent && (right > left + gl_extent))? - left + gl_extent : right; - } - padl -= (off_right)? gl_width - 1 : gl_cnt - gl_shift; - padl = (padl < 0)? 0 : padl; - if (left <= right) { /* clean up screen */ - for (i=0; i < backup; i++) - gl_putc('\b'); - if (left == gl_shift && off_left) { - gl_putc('$'); - left++; - } - for (i=left; i < new_right; i++) - gl_putc(gl_buf[i]); - gl_pos = new_right; - if (off_right && new_right == right) { - gl_putc('$'); - gl_pos++; - } else { - for (i=0; i < padl; i++) /* erase remains of prev line */ - gl_putc(' '); - gl_pos += padl; - } - } - i = gl_pos - cursor; /* move to final cursor location */ - if (i > 0) { - while (i--) - gl_putc('\b'); - } else { - for (i=gl_pos; i < cursor; i++) - gl_putc(gl_buf[i]); - } - gl_pos = cursor; -} - -static int -gl_tab(char *buf, int offset, int *loc) -/* default tab handler, acts like tabstops every 8 cols */ -{ - int i, count, len; - - len = strlen(buf); - count = 8 - (offset + *loc) % 8; - for (i=len; i >= *loc; i--) - buf[i+count] = buf[i]; - for (i=0; i < count; i++) - buf[*loc+i] = ' '; - i = *loc; - *loc = i + count; - return i; -} - -/******************* History stuff **************************************/ - -#ifndef HIST_SIZE -#define HIST_SIZE 100 -#endif - -static int hist_pos = 0, hist_last = 0; -static char *hist_buf[HIST_SIZE]; - -static void -hist_init() -{ - int i; - - if (gl_savehist) return; - - hist_buf[0] = ""; - for (i=1; i < HIST_SIZE; i++) - hist_buf[i] = (char *)0; -} - -SIGAR_DECLARE(void) sigar_getline_completer_set(sigar_getline_completer_t func) -{ - if (func) { - gl_tab_hook = func; - } - else { - gl_tab_hook = gl_tab; - } -} - -SIGAR_DECLARE(void) -sigar_getline_histinit(char *file) -{ - char line[256]; - FILE *fp; - int nline = 1; /* prevent from becoming 0 */ - - gl_savehist = 0; - - hist_init(); - - if (!strcmp(file, "-")) return; - - sprintf(gl_histfile, "%s", file); - - fp = fopen(gl_histfile, "r"); - if (fp) - while (fgets(line, 256, fp)) { - nline++; - sigar_getline_histadd(line); - } - else - fp = fopen(gl_histfile, "w"); - - if (fp) fclose(fp); - - gl_savehist = nline; -} - -SIGAR_DECLARE(void) -sigar_getline_histadd(char *buf) -{ - static char *prev = 0; - char *p = buf; - int len; - - while (*p == ' ' || *p == '\t' || *p == '\n') - p++; - if (*p) { - len = strlen(buf); - if (strchr(p, '\n')) /* previously line already has NL stripped */ - len--; - if (prev == 0 || strlen(prev) != len || - strncmp(prev, buf, len) != 0) { - hist_buf[hist_last] = hist_save(buf); - prev = hist_buf[hist_last]; - hist_last = (hist_last + 1) % HIST_SIZE; - if (hist_buf[hist_last] && *hist_buf[hist_last]) { - free(hist_buf[hist_last]); - } - hist_buf[hist_last] = ""; - - /* append command to history file */ - if (gl_savehist) { - FILE *fp; - fp = fopen(gl_histfile, "a+"); - if (fp) { - fprintf(fp, "%s\n", prev); - gl_savehist++; - fclose(fp); - } - - /* if more than HIST_SIZE lines, safe last 60 command and delete rest */ - if (gl_savehist > HIST_SIZE) { - FILE *ftmp; - char tname[L_tmpnam]; - char line[BUFSIZ]; - - fp = fopen(gl_histfile, "r"); - tmpnam(tname); - ftmp = fopen(tname, "w"); - if (fp && ftmp) { - int nline = 0; - while (fgets(line, BUFSIZ, fp)) { - nline++; - gl_savehist = 1; /* prevent from becoming 0 */ - if (nline > HIST_SIZE-60) { - gl_savehist++; - fprintf(ftmp, "%s", line); - } - } - } - if (fp) fclose(fp); - if (ftmp) fclose(ftmp); - - /* copy back to history file */ - fp = fopen(gl_histfile, "w"); - ftmp = fopen(tname, "r"); - if (fp && ftmp) - while (fgets(line, BUFSIZ, ftmp)) - fprintf(fp, "%s", line); - - if (fp) fclose(fp); - if (ftmp) fclose(ftmp); - remove(tname); - } - } - } - } - hist_pos = hist_last; -} - -static char * -hist_prev() -/* loads previous hist entry into input buffer, sticks on first */ -{ - char *p = 0; - int next = (hist_pos - 1 + HIST_SIZE) % HIST_SIZE; - - if (hist_buf[hist_pos] != 0 && next != hist_last) { - hist_pos = next; - p = hist_buf[hist_pos]; - } - if (p == 0) { - p = ""; - gl_bell(); - } - return p; -} - -static char * -hist_next() -/* loads next hist entry into input buffer, clears on last */ -{ - char *p = 0; - - if (hist_pos != hist_last) { - hist_pos = (hist_pos+1) % HIST_SIZE; - p = hist_buf[hist_pos]; - } - if (p == 0) { - p = ""; - gl_bell(); - } - return p; -} - -static char * -hist_save(char *p) -/* makes a copy of the string */ -{ - char *s = 0; - int len = strlen(p); - char *nl = strchr(p, '\n'); - - if (nl) { - if ((s = (char *)malloc(len)) != 0) { - strncpy(s, p, len-1); - s[len-1] = 0; - } - } else { - if ((s = (char *)malloc(len+1)) != 0) { - strcpy(s, p); - } - } - if (s == 0) - gl_error("\n*** Error: hist_save() failed on malloc\n"); - return s; -} - -/******************* Search stuff **************************************/ - -static char search_prompt[101]; /* prompt includes search string */ -static char search_string[100]; -static int search_pos = 0; /* current location in search_string */ -static int search_forw_flg = 0; /* search direction flag */ -static int search_last = 0; /* last match found */ - -static void -search_update(int c) -{ - if (c == 0) { - search_pos = 0; - search_string[0] = 0; - search_prompt[0] = '?'; - search_prompt[1] = ' '; - search_prompt[2] = 0; - } else if (c > 0) { - search_string[search_pos] = c; - search_string[search_pos+1] = 0; - search_prompt[search_pos] = c; - search_prompt[search_pos+1] = '?'; - search_prompt[search_pos+2] = ' '; - search_prompt[search_pos+3] = 0; - search_pos++; - } else { - if (search_pos > 0) { - search_pos--; - search_string[search_pos] = 0; - search_prompt[search_pos] = '?'; - search_prompt[search_pos+1] = ' '; - search_prompt[search_pos+2] = 0; - } else { - gl_bell(); - hist_pos = hist_last; - } - } -} - -static void -search_addchar(int c) -{ - char *loc; - - search_update(c); - if (c < 0) { - if (search_pos > 0) { - hist_pos = search_last; - } else { - gl_buf[0] = 0; - hist_pos = hist_last; - } - strcpy(gl_buf, hist_buf[hist_pos]); - } - if ((loc = strstr(gl_buf, search_string)) != 0) { - gl_fixup(search_prompt, 0, loc - gl_buf); - } else if (search_pos > 0) { - if (search_forw_flg) { - search_forw(0); - } else { - search_back(0); - } - } else { - gl_fixup(search_prompt, 0, 0); - } -} - -static void -search_term() -{ - gl_search_mode = 0; - if (gl_buf[0] == 0) /* not found, reset hist list */ - hist_pos = hist_last; - if (gl_in_hook) - gl_in_hook(gl_buf); - gl_fixup(gl_prompt, 0, gl_pos); -} - -static void -search_back(int new_search) -{ - int found = 0; - char *p, *loc; - - search_forw_flg = 0; - if (gl_search_mode == 0) { - search_last = hist_pos = hist_last; - search_update(0); - gl_search_mode = 1; - gl_buf[0] = 0; - gl_fixup(search_prompt, 0, 0); - } else if (search_pos > 0) { - while (!found) { - p = hist_prev(); - if (*p == 0) { /* not found, done looking */ - gl_buf[0] = 0; - gl_fixup(search_prompt, 0, 0); - found = 1; - } else if ((loc = strstr(p, search_string)) != 0) { - strcpy(gl_buf, p); - gl_fixup(search_prompt, 0, loc - p); - if (new_search) - search_last = hist_pos; - found = 1; - } - } - } else { - gl_bell(); - } -} - -static void -search_forw(int new_search) -{ - int found = 0; - char *p, *loc; - - search_forw_flg = 1; - if (gl_search_mode == 0) { - search_last = hist_pos = hist_last; - search_update(0); - gl_search_mode = 1; - gl_buf[0] = 0; - gl_fixup(search_prompt, 0, 0); - } else if (search_pos > 0) { - while (!found) { - p = hist_next(); - if (*p == 0) { /* not found, done looking */ - gl_buf[0] = 0; - gl_fixup(search_prompt, 0, 0); - found = 1; - } else if ((loc = strstr(p, search_string)) != 0) { - strcpy(gl_buf, p); - gl_fixup(search_prompt, 0, loc - p); - if (new_search) - search_last = hist_pos; - found = 1; - } - } - } else { - gl_bell(); - } -} -#if 0 -/*********************************************************************** - * * - * Strip blanks from both sides of a string. Space for the new * - * string is allocated and a pointer to it is returned. * - * * - ***********************************************************************/ -char *strip(char *s) -{ - char *r, *t1, *t2; - int l; - - l = strlen(s); - r = (char *)calloc(l+1, 1); - - if (l == 0) { - *r = '\0'; - return r; - } - - /* get rid of leading blanks */ - t1 = s; - while (*t1 == ' ') - t1++; - - t2 = s + l - 1; - while (*t2 == ' ' && t2 > s) - t2--; - - if (t1 > t2) { - *r = '\0'; - return r; - } - strncpy(r, t1, (size_t) (t2-t1+1)); - - return r; -} -#endif -/*****************************************************************************/ -/* Extra routine provided by Christian Lacunza */ -/*****************************************************************************/ - -/* move cursor back to beginning of _current_ word */ -/* unless it's already at the beginning, */ -/* in which case it moves back to the beginning */ -/* of the _previous_ word. */ -static void gl_back_1_word( void ) -{ - int i = gl_pos; - - /* if we're at the beginning of a word, */ - /* slip back into the preceeding whitespace */ - if( i>0 && is_whitespace(gl_buf[i-1]) ) { - i-=1; - } - - /* now move back over all consecutive whitespace */ - while( i>0 && is_whitespace(gl_buf[i]) ) { - i-=1; - } - - /* now keep moving back over all consecutive non-whitespace */ - /* until we find the beginning of this word. */ - /* ie. stop just before more whitespace shows up. */ - while( i>0 && !is_whitespace(gl_buf[i-1]) ) { - i-=1; - } - - /* move the cursor here */ - gl_fixup(gl_prompt, -1, i); -} - -/* kills from current position to end of word */ -static void gl_kill_1_word( void ) -{ - int i = gl_pos; - int j = gl_pos; - -/* delete this: */ -#if 0 - /* not sure what to do with "punctuation" */ - if( is_whitespace(gl_buf[j]) && gl_buf[j]!=' ' ) { - return; - } - /* first find a word */ - while( j - -#ifdef SIGAR_HAS_PCRE -#include "pcre.h" -#endif - -/* See http://gcc.gnu.org/ml/libstdc++/2002-03/msg00164.html */ -#if defined(WIN32) || (defined(__hpux) && defined(SIGAR_64BIT)) -#define strtoull strtoul -#elif (defined(__hpux) && !defined(SIGAR_64BIT)) -#define strtoull __strtoull -#else -#include -#endif - -#define SIGAR_CLEAR_ERRNO() errno = 0 - -#define strtonum_failed(src, ptr) \ - ((src == ptr) || (errno == ERANGE) || (*ptr != '\0')) - -typedef struct ptql_parse_branch_t ptql_parse_branch_t; -typedef struct ptql_branch_t ptql_branch_t; - -/* adhere to calling convention, else risk stack corruption */ -#ifdef WIN32 -#define SIGAPI WINAPI -#else -#define SIGAPI -#endif - -typedef int (SIGAPI *ptql_get_t)(sigar_t *sigar, sigar_pid_t pid, void *data); -typedef int (*ptql_branch_init_t)(ptql_parse_branch_t *parsed, ptql_branch_t *branch, - sigar_ptql_error_t *error); - -typedef int (*ptql_op_ui64_t)(ptql_branch_t *branch, - sigar_uint64_t haystack, - sigar_uint64_t needle); - -typedef int (*ptql_op_ui32_t)(ptql_branch_t *branch, - sigar_uint32_t haystack, - sigar_uint32_t needle); - -typedef int (*ptql_op_dbl_t)(ptql_branch_t *branch, - double haystack, - double needle); - -typedef int (*ptql_op_str_t)(ptql_branch_t *branch, - char *haystack, - char *needle); - -typedef int (*ptql_op_chr_t)(ptql_branch_t *branch, - char haystack, - char needle); - -typedef enum { - PTQL_VALUE_TYPE_UI64, - PTQL_VALUE_TYPE_UI32, - PTQL_VALUE_TYPE_DBL, - PTQL_VALUE_TYPE_CHR, - PTQL_VALUE_TYPE_STR, - PTQL_VALUE_TYPE_ANY -} ptql_value_type_t; - -typedef enum { - PTQL_OP_EQ, - PTQL_OP_NE, - PTQL_OP_GT, - PTQL_OP_GE, - PTQL_OP_LT, - PTQL_OP_LE, -#define PTQL_OP_MAX_NSTR PTQL_OP_LE - PTQL_OP_EW, /* rest are string only */ - PTQL_OP_SW, - PTQL_OP_RE, - PTQL_OP_CT, - PTQL_OP_MAX -} ptql_op_name_t; - -#define PTQL_OP_FLAG_PARENT 1 -#define PTQL_OP_FLAG_REF 2 -#define PTQL_OP_FLAG_GLOB 4 -#define PTQL_OP_FLAG_PID 8 -#define PTQL_OP_FLAG_ICASE 16 - -struct ptql_parse_branch_t { - char *name; - char *attr; - char *op; - char *value; - unsigned int op_flags; -}; - -typedef struct { - char *name; - ptql_get_t get; - size_t offset; - unsigned int data_size; - ptql_value_type_t type; - ptql_branch_init_t init; -} ptql_lookup_t; - -#define DATA_PTR(branch) \ - ((char *)branch->data.ptr + branch->lookup->offset) - -#define IS_ICASE(branch) \ - (branch->op_flags & PTQL_OP_FLAG_ICASE) - -#define branch_strcmp(branch, s1, s2) \ - (IS_ICASE(branch) ? strcasecmp(s1, s2) : strcmp(s1, s2)) - -#define branch_strncmp(branch, s1, s2, n) \ - (IS_ICASE(branch) ? strncasecmp(s1, s2, n) : strncmp(s1, s2, n)) - -#define branch_strEQ(branch, s1, s2) \ - (branch_strcmp(branch, s1, s2) == 0) - -#define branch_strnEQ(branch, s1, s2, n) \ - (branch_strncmp(branch, s1, s2, n) == 0) - -#define branch_strstr(branch, s1, s2) \ - (IS_ICASE(branch) ? sigar_strcasestr(s1, s2) : strstr(s1, s2)) - -#define IS_PID_SERVICE_QUERY(branch) \ - (branch->flags >= PTQL_PID_SERVICE_NAME) - -static void data_free(void *data) -{ - free(data); -} - -typedef union { - sigar_pid_t pid; - sigar_uint64_t ui64; - sigar_uint32_t ui32; - double dbl; - char chr[4]; - char *str; - void *ptr; -} any_value_t; - -struct ptql_branch_t { - ptql_lookup_t *lookup; - any_value_t data; - unsigned int data_size; - void (*data_free)(void *); - unsigned int flags; - unsigned int op_flags; - ptql_op_name_t op_name; - union { - ptql_op_ui64_t ui64; - ptql_op_ui32_t ui32; - ptql_op_dbl_t dbl; - ptql_op_chr_t chr; - ptql_op_str_t str; - } match; - any_value_t value; - void (*value_free)(void *); -}; - -typedef struct { - char *name; - ptql_lookup_t *members; -} ptql_entry_t; - -typedef struct { - unsigned long number; - unsigned long size; - ptql_branch_t *data; -} ptql_branch_list_t; - -struct sigar_ptql_query_t { - ptql_branch_list_t branches; -#ifdef PTQL_DEBUG - char *ptql; -#endif -}; - -/* XXX optimize */ -static ptql_op_name_t ptql_op_code_get(char *op) -{ - if (strEQ(op, "eq")) { - return PTQL_OP_EQ; - } - else if (strEQ(op, "ne")) { - return PTQL_OP_NE; - } - else if (strEQ(op, "gt")) { - return PTQL_OP_GT; - } - else if (strEQ(op, "ge")) { - return PTQL_OP_GE; - } - else if (strEQ(op, "lt")) { - return PTQL_OP_LT; - } - else if (strEQ(op, "le")) { - return PTQL_OP_LE; - } - else if (strEQ(op, "ew")) { - return PTQL_OP_EW; - } - else if (strEQ(op, "sw")) { - return PTQL_OP_SW; - } - else if (strEQ(op, "re")) { - return PTQL_OP_RE; - } - else if (strEQ(op, "ct")) { - return PTQL_OP_CT; - } - else { - return PTQL_OP_MAX; - } -} - -static int ptql_op_ui64_eq(ptql_branch_t *branch, - sigar_uint64_t haystack, sigar_uint64_t needle) -{ - return haystack == needle; -} - -static int ptql_op_ui64_ne(ptql_branch_t *branch, - sigar_uint64_t haystack, sigar_uint64_t needle) -{ - return haystack != needle; -} - -static int ptql_op_ui64_gt(ptql_branch_t *branch, - sigar_uint64_t haystack, sigar_uint64_t needle) -{ - return haystack > needle; -} - -static int ptql_op_ui64_ge(ptql_branch_t *branch, - sigar_uint64_t haystack, sigar_uint64_t needle) -{ - return haystack >= needle; -} - -static int ptql_op_ui64_lt(ptql_branch_t *branch, - sigar_uint64_t haystack, sigar_uint64_t needle) -{ - return haystack < needle; -} - -static int ptql_op_ui64_le(ptql_branch_t *branch, - sigar_uint64_t haystack, sigar_uint64_t needle) -{ - return haystack <= needle; -} - -static ptql_op_ui64_t ptql_op_ui64[] = { - ptql_op_ui64_eq, - ptql_op_ui64_ne, - ptql_op_ui64_gt, - ptql_op_ui64_ge, - ptql_op_ui64_lt, - ptql_op_ui64_le -}; - -static int ptql_op_ui32_eq(ptql_branch_t *branch, - sigar_uint32_t haystack, sigar_uint32_t needle) -{ - return haystack == needle; -} - -static int ptql_op_ui32_ne(ptql_branch_t *branch, - sigar_uint32_t haystack, sigar_uint32_t needle) -{ - return haystack != needle; -} - -static int ptql_op_ui32_gt(ptql_branch_t *branch, - sigar_uint32_t haystack, sigar_uint32_t needle) -{ - return haystack > needle; -} - -static int ptql_op_ui32_ge(ptql_branch_t *branch, - sigar_uint32_t haystack, sigar_uint32_t needle) -{ - return haystack >= needle; -} - -static int ptql_op_ui32_lt(ptql_branch_t *branch, - sigar_uint32_t haystack, sigar_uint32_t needle) -{ - return haystack < needle; -} - -static int ptql_op_ui32_le(ptql_branch_t *branch, - sigar_uint32_t haystack, sigar_uint32_t needle) -{ - return haystack <= needle; -} - -static ptql_op_ui32_t ptql_op_ui32[] = { - ptql_op_ui32_eq, - ptql_op_ui32_ne, - ptql_op_ui32_gt, - ptql_op_ui32_ge, - ptql_op_ui32_lt, - ptql_op_ui32_le -}; - -static int ptql_op_dbl_eq(ptql_branch_t *branch, - double haystack, double needle) -{ - return haystack == needle; -} - -static int ptql_op_dbl_ne(ptql_branch_t *branch, - double haystack, double needle) -{ - return haystack != needle; -} - -static int ptql_op_dbl_gt(ptql_branch_t *branch, - double haystack, double needle) -{ - return haystack > needle; -} - -static int ptql_op_dbl_ge(ptql_branch_t *branch, - double haystack, double needle) -{ - return haystack >= needle; -} - -static int ptql_op_dbl_lt(ptql_branch_t *branch, - double haystack, double needle) -{ - return haystack < needle; -} - -static int ptql_op_dbl_le(ptql_branch_t *branch, - double haystack, double needle) -{ - return haystack <= needle; -} - -static ptql_op_dbl_t ptql_op_dbl[] = { - ptql_op_dbl_eq, - ptql_op_dbl_ne, - ptql_op_dbl_gt, - ptql_op_dbl_ge, - ptql_op_dbl_lt, - ptql_op_dbl_le -}; - -static int ptql_op_str_eq(ptql_branch_t *branch, - char *haystack, char *needle) -{ - return branch_strEQ(branch, haystack, needle); -} - -static int ptql_op_str_ne(ptql_branch_t *branch, - char *haystack, char *needle) -{ - return !branch_strEQ(branch, haystack, needle); -} - -static int ptql_op_str_gt(ptql_branch_t *branch, - char *haystack, char *needle) -{ - return branch_strcmp(branch, haystack, needle) > 0; -} - -static int ptql_op_str_ge(ptql_branch_t *branch, - char *haystack, char *needle) -{ - return branch_strcmp(branch, haystack, needle) >= 0; -} - -static int ptql_op_str_lt(ptql_branch_t *branch, - char *haystack, char *needle) -{ - return branch_strcmp(branch, haystack, needle) < 0; -} - -static int ptql_op_str_le(ptql_branch_t *branch, - char *haystack, char *needle) -{ - return branch_strcmp(branch, haystack, needle) <= 0; -} - -static int ptql_op_str_ew(ptql_branch_t *branch, - char *haystack, char *needle) -{ - int nlen = strlen(needle); - int hlen = strlen(haystack); - int diff = hlen - nlen; - if (diff < 0) { - return 0; - } - return branch_strnEQ(branch, haystack + diff, needle, nlen); -} - -static int ptql_op_str_sw(ptql_branch_t *branch, - char *haystack, char *needle) -{ - return branch_strnEQ(branch, haystack, needle, strlen(needle)); -} - -static int ptql_op_str_re(ptql_branch_t *branch, - char *haystack, char *needle) -{ -#ifdef SIGAR_HAS_PCRE - pcre *re = (pcre *)branch->value.ptr; - int len = strlen(haystack); - int rc = - pcre_exec(re, NULL, haystack, len, 0, 0, NULL, 0); - return rc >= 0; -#else - return 0; -#endif -} - -static int ptql_op_str_ct(ptql_branch_t *branch, - char *haystack, char *needle) -{ - return branch_strstr(branch, haystack, needle) != NULL; -} - -static ptql_op_str_t ptql_op_str[] = { - ptql_op_str_eq, - ptql_op_str_ne, - ptql_op_str_gt, - ptql_op_str_ge, - ptql_op_str_lt, - ptql_op_str_le, - ptql_op_str_ew, - ptql_op_str_sw, - ptql_op_str_re, - ptql_op_str_ct -}; - -static int ptql_op_chr_eq(ptql_branch_t *branch, - char haystack, char needle) -{ - return haystack == needle; -} - -static int ptql_op_chr_ne(ptql_branch_t *branch, - char haystack, char needle) -{ - return haystack != needle; -} - -static int ptql_op_chr_gt(ptql_branch_t *branch, - char haystack, char needle) -{ - return haystack > needle; -} - -static int ptql_op_chr_ge(ptql_branch_t *branch, - char haystack, char needle) -{ - return haystack >= needle; -} - -static int ptql_op_chr_lt(ptql_branch_t *branch, - char haystack, char needle) -{ - return haystack < needle; -} - -static int ptql_op_chr_le(ptql_branch_t *branch, - char haystack, char needle) -{ - return haystack <= needle; -} - -static ptql_op_chr_t ptql_op_chr[] = { - ptql_op_chr_eq, - ptql_op_chr_ne, - ptql_op_chr_gt, - ptql_op_chr_ge, - ptql_op_chr_lt, - ptql_op_chr_le -}; - -#define PTQL_BRANCH_LIST_MAX 3 - -#define PTQL_BRANCH_LIST_GROW(branches) \ - if ((branches)->number >= (branches)->size) { \ - ptql_branch_list_grow(branches); \ - } - -static int ptql_branch_list_create(ptql_branch_list_t *branches) -{ - branches->number = 0; - branches->size = PTQL_BRANCH_LIST_MAX; - branches->data = malloc(sizeof(*(branches->data)) * - branches->size); - - return SIGAR_OK; -} - -static int ptql_branch_list_grow(ptql_branch_list_t *branches) -{ - branches->data = - realloc(branches->data, - sizeof(*(branches->data)) * - (branches->size + PTQL_BRANCH_LIST_MAX)); - branches->size += PTQL_BRANCH_LIST_MAX; - - return SIGAR_OK; -} - -static int ptql_branch_list_destroy(ptql_branch_list_t *branches) -{ - if (branches->size) { - int i; - - for (i=0; inumber; i++) { - ptql_branch_t *branch = - &branches->data[i]; - - if (branch->data_size && branch->data.ptr) { - branch->data_free(branch->data.ptr); - } - - if (branch->lookup && - ((branch->lookup->type == PTQL_VALUE_TYPE_STR) || - (branch->lookup->type == PTQL_VALUE_TYPE_ANY)) && - !(branch->op_flags & PTQL_OP_FLAG_REF)) - { - if (branch->value.str) { - branch->value_free(branch->value.str); - } - } - } - - free(branches->data); - branches->number = branches->size = 0; - } - - return SIGAR_OK; -} - -#ifdef WIN32 -#define vsnprintf _vsnprintf -#endif - -#define PTQL_ERRNAN \ - ptql_error(error, "Query value '%s' is not a number", parsed->value) - -static int ptql_error(sigar_ptql_error_t *error, const char *format, ...) -{ - va_list args; - - if (error != NULL) { - va_start(args, format); - vsnprintf(error->message, sizeof(error->message), format, args); - va_end(args); - } - - return SIGAR_PTQL_MALFORMED_QUERY; -} - -static int ptql_branch_init_any(ptql_parse_branch_t *parsed, - ptql_branch_t *branch, - sigar_ptql_error_t *error) -{ - branch->data.str = sigar_strdup(parsed->attr); - branch->data_size = strlen(parsed->attr); - return SIGAR_OK; -} - -static int ptql_str_match(sigar_t *sigar, ptql_branch_t *branch, char *value) -{ - if (!branch->value.str) { - return 0; - } -#ifndef SIGAR_HAS_PCRE - if (branch->op_name == PTQL_OP_RE) { - if (sigar->ptql_re_impl) { - return sigar->ptql_re_impl(sigar->ptql_re_data, - value, - branch->value.str); - } - else { - return 0; - } - } -#endif - return branch->match.str(branch, - value, - branch->value.str); -} - -static int ptql_branch_match(ptql_branch_t *branch) -{ - switch (branch->lookup->type) { - case PTQL_VALUE_TYPE_UI64: - return branch->match.ui64(branch, - *(sigar_uint64_t *)DATA_PTR(branch), - branch->value.ui64); - case PTQL_VALUE_TYPE_UI32: - return branch->match.ui32(branch, - *(sigar_uint32_t *)DATA_PTR(branch), - branch->value.ui32); - case PTQL_VALUE_TYPE_DBL: - return branch->match.dbl(branch, - *(double *)DATA_PTR(branch), - branch->value.dbl); - case PTQL_VALUE_TYPE_CHR: - return branch->match.chr(branch, - *(char *)DATA_PTR(branch), - branch->value.chr[0]); - case PTQL_VALUE_TYPE_STR: - case PTQL_VALUE_TYPE_ANY: - if (!branch->value.str) { - return 0; - } - return branch->match.str(branch, - (char *)DATA_PTR(branch), - branch->value.str); - default: - return 0; - } -} - -static int ptql_branch_match_ref(ptql_branch_t *branch, ptql_branch_t *ref) -{ - switch (branch->lookup->type) { - case PTQL_VALUE_TYPE_UI64: - return branch->match.ui64(branch, - *(sigar_uint64_t *)DATA_PTR(branch), - *(sigar_uint64_t *)DATA_PTR(ref)); - case PTQL_VALUE_TYPE_UI32: - return branch->match.ui32(branch, - *(sigar_uint32_t *)DATA_PTR(branch), - *(sigar_uint32_t *)DATA_PTR(ref)); - case PTQL_VALUE_TYPE_DBL: - return branch->match.dbl(branch, - *(double *)DATA_PTR(branch), - *(double *)DATA_PTR(ref)); - case PTQL_VALUE_TYPE_CHR: - return branch->match.chr(branch, - *(char *)DATA_PTR(branch), - *(char *)DATA_PTR(ref)); - case PTQL_VALUE_TYPE_STR: - case PTQL_VALUE_TYPE_ANY: - return branch->match.str(branch, - (char *)DATA_PTR(branch), - (char *)DATA_PTR(ref)); - default: - return 0; - } -} - -enum { - PTQL_PID_PID, - PTQL_PID_FILE, - PTQL_PID_SUDO_FILE, - PTQL_PID_TCP_PORT, - PTQL_PID_UDP_PORT, - PTQL_PID_SERVICE_NAME, - PTQL_PID_SERVICE_DISPLAY, - PTQL_PID_SERVICE_PATH, - PTQL_PID_SERVICE_EXE, - PTQL_PID_SERVICE_PID -}; - -#ifdef SIGAR_64BIT - -#define str2pid(value, ptr) strtoull(value, &ptr, 10) - -#define pid_branch_match(branch, pid, match_pid) \ - ptql_op_ui64[branch->op_name](branch, pid, match_pid) - -#else - -#define str2pid(value, ptr) strtoul(value, &ptr, 10) - -#define pid_branch_match(branch, pid, match_pid) \ - ptql_op_ui32[branch->op_name](branch, pid, match_pid) - -#endif - -#ifndef WIN32 -#include -int sigar_sudo_file2str(const char *fname, char *buffer, int buflen) -{ - FILE *fp; - struct stat sb; - - if (stat(fname, &sb) < 0) { - return errno; - } - if (sb.st_size > buflen) { - return ENOMEM; - } - snprintf(buffer, buflen, "sudo cat %s", fname); - if (!(fp = popen(buffer, "r"))) { - return errno; - } - (void)fgets(buffer, buflen, fp); - pclose(fp); - - return SIGAR_OK; -} -#endif - -static int ptql_branch_init_service(ptql_parse_branch_t *parsed, - ptql_branch_t *branch, - sigar_ptql_error_t *error) -{ - branch->op_flags |= PTQL_OP_FLAG_PID; - - if (strEQ(parsed->attr, "Name")) { - branch->flags = PTQL_PID_SERVICE_NAME; - } - else if (strEQ(parsed->attr, "DisplayName")) { - branch->flags = PTQL_PID_SERVICE_DISPLAY; - } - else if (strEQ(parsed->attr, "Path")) { - branch->flags = PTQL_PID_SERVICE_PATH; - } - else if (strEQ(parsed->attr, "Exe")) { - /* basename of Path */ - branch->flags = PTQL_PID_SERVICE_EXE; - } - else if (strEQ(parsed->attr, "Pid")) { - branch->flags = PTQL_PID_SERVICE_PID; - } - else { - return ptql_error(error, "Unsupported %s attribute: %s", - parsed->name, parsed->attr); - } - -#ifdef WIN32 - branch->data.str = sigar_strdup(parsed->value); - branch->data_size = strlen(parsed->value); -#endif - return SIGAR_OK; -} - -static int ptql_branch_init_pid(ptql_parse_branch_t *parsed, - ptql_branch_t *branch, - sigar_ptql_error_t *error) -{ - int use_sudo = 0; - branch->op_flags |= PTQL_OP_FLAG_PID; - - if (strEQ(parsed->attr, "Pid")) { - branch->flags = PTQL_PID_PID; - if (strEQ(parsed->value, "$$")) { - branch->data.pid = getpid(); - } - else { - char *ptr; - SIGAR_CLEAR_ERRNO(); - branch->data.pid = str2pid(parsed->value, ptr); - if (strtonum_failed(parsed->value, ptr)) { - return PTQL_ERRNAN; - } - } - return SIGAR_OK; - } - else if (strEQ(parsed->attr, "PidFile") || - (use_sudo = strEQ(parsed->attr, "SudoPidFile"))) - { - branch->flags = use_sudo ? PTQL_PID_SUDO_FILE : PTQL_PID_FILE; - branch->data.str = sigar_strdup(parsed->value); - branch->data_size = strlen(parsed->value); - return SIGAR_OK; - } - - return ptql_error(error, "Unsupported %s attribute: %s", - parsed->name, parsed->attr); -} - -#ifdef WIN32 -#define QUERY_SC_SIZE 8192 - -static int ptql_service_query_config(SC_HANDLE scm_handle, - char *name, - LPQUERY_SERVICE_CONFIG config) -{ - int status; - DWORD bytes; - SC_HANDLE handle = - OpenService(scm_handle, name, SERVICE_QUERY_CONFIG); - - if (!handle) { - return GetLastError(); - } - - if (QueryServiceConfig(handle, config, QUERY_SC_SIZE, &bytes)) { - status = SIGAR_OK; - } - else { - status = GetLastError(); - } - - CloseServiceHandle(handle); - return status; -} - -static int sigar_services_walk(sigar_services_walker_t *walker, - ptql_branch_t *branch) -{ - sigar_services_status_t ss; - char buffer[QUERY_SC_SIZE]; - char exe[SIGAR_CMDLINE_MAX]; - LPQUERY_SERVICE_CONFIG config = (LPQUERY_SERVICE_CONFIG)buffer; - DWORD i, status; - - SIGAR_ZERO(&ss); - status = sigar_services_status_get(&ss, walker->flags); - if (status != SIGAR_OK) { - return status; - } - for (i=0; iadd_service(walker, name) != SIGAR_OK) { - break; - } - continue; - } - - switch (branch->flags) { - case PTQL_PID_SERVICE_DISPLAY: - value = ss.services[i].lpDisplayName; - break; - case PTQL_PID_SERVICE_PATH: - case PTQL_PID_SERVICE_EXE: - status = ptql_service_query_config(ss.handle, name, config); - if (status == SIGAR_OK) { - if (branch->flags == PTQL_PID_SERVICE_EXE) { - value = - sigar_service_exe_get(config->lpBinaryPathName, - exe, 1); - } - else { - value = config->lpBinaryPathName; - } - } - else { - continue; - } - break; - case PTQL_PID_SERVICE_PID: - sigar_service_pid_get(walker->sigar, - name, - &service_pid); - break; - case PTQL_PID_SERVICE_NAME: - default: - value = name; - break; - } - - if ((value && ptql_str_match(walker->sigar, branch, value)) || - (service_pid && - pid_branch_match(branch, service_pid, atoi(branch->data.str)))) - { - if (walker->add_service(walker, name) != SIGAR_OK) { - break; - } - } - } - - sigar_services_status_close(&ss); - - return SIGAR_OK; -} - -static int ptql_pid_service_add(sigar_services_walker_t *walker, - char *name) -{ - sigar_pid_t service_pid; - sigar_proc_list_t *proclist = - (sigar_proc_list_t *)walker->data; - int status = - sigar_service_pid_get(walker->sigar, - name, - &service_pid); - - if (status == SIGAR_OK) { - SIGAR_PROC_LIST_GROW(proclist); - proclist->data[proclist->number++] = service_pid; - } - - return SIGAR_OK; -} - -static int ptql_pid_service_list_get(sigar_t *sigar, - ptql_branch_t *branch, - sigar_proc_list_t *proclist) -{ - sigar_services_walker_t walker; - walker.sigar = sigar; - walker.flags = SERVICE_ACTIVE; - walker.data = proclist; - walker.add_service = ptql_pid_service_add; - - return sigar_services_walk(&walker, branch); -} - -int sigar_services_query(char *ptql, - sigar_ptql_error_t *error, - sigar_services_walker_t *walker) -{ - int status; - sigar_ptql_query_t *query; - - if (ptql == NULL) { - return sigar_services_walk(walker, NULL); - } - - status = sigar_ptql_query_create(&query, (char *)ptql, error); - if (status != SIGAR_OK) { - return status; - } - - if (query->branches.number == 1) { - ptql_branch_t *branch = &query->branches.data[0]; - - if (IS_PID_SERVICE_QUERY(branch)) { - status = sigar_services_walk(walker, branch); - } - else { - ptql_error(error, "Invalid Service query: %s", ptql); - status = SIGAR_PTQL_MALFORMED_QUERY; - } - } - else { - ptql_error(error, "Too many queries (%d), must be (1)", - query->branches.number); - status = SIGAR_PTQL_MALFORMED_QUERY; - } - - sigar_ptql_query_destroy(query); - - return status; -} -#endif - -static int ptql_pid_port_get(sigar_t *sigar, - ptql_branch_t *branch, - sigar_pid_t *pid) -{ - unsigned long port = - branch->data.ui32; - int status; - int proto = - branch->flags == PTQL_PID_UDP_PORT ? - SIGAR_NETCONN_UDP : SIGAR_NETCONN_TCP; - - status = - sigar_proc_port_get(sigar, proto, port, pid); - - return status; -} - -static int ptql_pid_get(sigar_t *sigar, - ptql_branch_t *branch, - sigar_pid_t *pid) -{ - if ((branch->flags == PTQL_PID_FILE) || - (branch->flags == PTQL_PID_SUDO_FILE)) - { - char *ptr, buffer[SIGAR_PATH_MAX+1]; - const char *fname = (const char *)branch->data.str; - int status, len = sizeof(buffer)-1; - - if (branch->flags == PTQL_PID_FILE) { - status = sigar_file2str(fname, buffer, len); - } - else { -#ifdef WIN32 - return SIGAR_ENOTIMPL; -#else - status = sigar_sudo_file2str(fname, buffer, len); -#endif - } - if (status != SIGAR_OK) { - return status; - } - SIGAR_CLEAR_ERRNO(); - *pid = str2pid(buffer, ptr); - if ((buffer == ptr) || (errno == ERANGE)) { - return errno; - } - } - else if (branch->flags == PTQL_PID_SERVICE_NAME) { -#ifdef WIN32 - int status = - sigar_service_pid_get(sigar, - branch->data.str, pid); - if (status != SIGAR_OK) { - return status; - } -#else - return SIGAR_ENOTIMPL; -#endif - } - else if ((branch->flags == PTQL_PID_UDP_PORT) || - (branch->flags == PTQL_PID_TCP_PORT)) - { - int status = ptql_pid_port_get(sigar, branch, pid); - if (status != SIGAR_OK) { - return status; - } - } - else { - *pid = branch->data.pid; - } - - return SIGAR_OK; -} - -static int ptql_pid_list_get(sigar_t *sigar, - ptql_branch_t *branch, - sigar_proc_list_t *proclist) -{ - int status, i; - sigar_pid_t match_pid; - - if (IS_PID_SERVICE_QUERY(branch)) { - if ((branch->flags > PTQL_PID_SERVICE_NAME) || - (branch->op_name != PTQL_OP_EQ)) - { -#ifdef WIN32 - return ptql_pid_service_list_get(sigar, branch, proclist); -#else - return SIGAR_OK; /* no matches */ -#endif - } - } - - status = ptql_pid_get(sigar, branch, &match_pid); - - if (status != SIGAR_OK) { - /* XXX treated as non-match but would be nice to propagate */ - return SIGAR_OK; - } - - status = sigar_proc_list_get(sigar, NULL); - if (status != SIGAR_OK) { - return status; - } - for (i=0; ipids->number; i++) { - sigar_pid_t pid = sigar->pids->data[i]; - if (pid_branch_match(branch, pid, match_pid)) { - SIGAR_PROC_LIST_GROW(proclist); - proclist->data[proclist->number++] = pid; - } - } - - return SIGAR_OK; -} - -static int SIGAPI ptql_pid_match(sigar_t *sigar, - sigar_pid_t pid, - void *data) -{ - /* query already used to filter proc_list */ - return SIGAR_OK; -} - -static int ptql_args_branch_init(ptql_parse_branch_t *parsed, - ptql_branch_t *branch, - sigar_ptql_error_t *error) -{ - if (strEQ(parsed->attr, "*")) { - branch->op_flags |= PTQL_OP_FLAG_GLOB; - } - else { - char *end; - - SIGAR_CLEAR_ERRNO(); - branch->data.ui32 = - strtol(parsed->attr, &end, 10); - - if (strtonum_failed(parsed->attr, end)) { - /* conversion failed */ - return ptql_error(error, "%s is not a number", parsed->attr); - } - } - return SIGAR_OK; -} - -static int SIGAPI ptql_args_match(sigar_t *sigar, - sigar_pid_t pid, - void *data) -{ - ptql_branch_t *branch = - (ptql_branch_t *)data; - int status, matched=0; - sigar_proc_args_t args; - - status = sigar_proc_args_get(sigar, pid, &args); - if (status != SIGAR_OK) { - return status; - } - - if (branch->op_flags & PTQL_OP_FLAG_GLOB) { - int i; - for (i=0; idata.ui32; - - /* e.g. find last element of args: Args.-1.eq=weblogic.Server */ - if (num < 0) { - num += args.number; - } - if ((num >= 0) && (num < args.number)) { - matched = - ptql_str_match(sigar, branch, args.data[num]); - } - } - - sigar_proc_args_destroy(sigar, &args); - - return matched ? SIGAR_OK : !SIGAR_OK; -} - -typedef struct { - sigar_t *sigar; - ptql_branch_t *branch; - sigar_uint32_t ix; - int matched; -} proc_modules_match_t; - -static int proc_modules_match(void *data, char *name, int len) -{ - proc_modules_match_t *matcher = - (proc_modules_match_t *)data; - ptql_branch_t *branch = matcher->branch; - - if (branch->op_flags & PTQL_OP_FLAG_GLOB) { /* Modules.*.ct=libc */ - matcher->matched = - ptql_str_match(matcher->sigar, branch, name); - - if (matcher->matched) { - return !SIGAR_OK; /* stop iterating */ - } - } - else { - if (matcher->ix++ == branch->data.ui32) { /* Modules.3.ct=libc */ - matcher->matched = - ptql_str_match(matcher->sigar, branch, name); - return !SIGAR_OK; /* stop iterating */ - } - } - - return SIGAR_OK; -} - -static int SIGAPI ptql_modules_match(sigar_t *sigar, - sigar_pid_t pid, - void *data) -{ - ptql_branch_t *branch = - (ptql_branch_t *)data; - int status; - sigar_proc_modules_t procmods; - proc_modules_match_t matcher; - - matcher.sigar = sigar; - matcher.branch = branch; - matcher.ix = 0; - matcher.matched = 0; - - procmods.module_getter = proc_modules_match; - procmods.data = &matcher; - - status = sigar_proc_modules_get(sigar, pid, &procmods); - - if (status != SIGAR_OK) { - return status; - } - - return matcher.matched ? SIGAR_OK : !SIGAR_OK; -} - -typedef struct { - const char *key; - int klen; - char *val; - int vlen; -} sigar_proc_env_entry_t; - -static int sigar_proc_env_get_key(void *data, - const char *key, int klen, - char *val, int vlen) -{ - sigar_proc_env_entry_t *entry = - (sigar_proc_env_entry_t *)data; - - if ((entry->klen == klen) && - (strcmp(entry->key, key) == 0)) - { - entry->val = val; - entry->vlen = vlen; - return !SIGAR_OK; /* foundit; stop iterating */ - } - - return SIGAR_OK; -} - -static int SIGAPI ptql_env_match(sigar_t *sigar, - sigar_pid_t pid, - void *data) -{ - ptql_branch_t *branch = - (ptql_branch_t *)data; - int status, matched=0; - sigar_proc_env_t procenv; - sigar_proc_env_entry_t entry; - - /* XXX ugh this is klunky */ - entry.key = branch->data.str; - entry.klen = branch->data_size; - entry.val = NULL; - - procenv.type = SIGAR_PROC_ENV_KEY; - procenv.key = branch->data.str; - procenv.klen = branch->data_size; - procenv.env_getter = sigar_proc_env_get_key; - procenv.data = &entry; - - status = sigar_proc_env_get(sigar, pid, &procenv); - if (status != SIGAR_OK) { - return status; - } - else { - if (entry.val) { - matched = - ptql_str_match(sigar, branch, entry.val); - } - } - - return matched ? SIGAR_OK : !SIGAR_OK; -} - -static int ptql_branch_init_port(ptql_parse_branch_t *parsed, - ptql_branch_t *branch, - sigar_ptql_error_t *error) -{ - char *ptr; - - /* only 'eq' is supported here */ - if (branch->op_name != PTQL_OP_EQ) { - return ptql_error(error, "%s requires 'eq' operator", - parsed->name); - } - - if (strEQ(parsed->attr, "tcp")) { - branch->flags = PTQL_PID_TCP_PORT; - } - else if (strEQ(parsed->attr, "udp")) { - branch->flags = PTQL_PID_TCP_PORT; - } - else { - return ptql_error(error, "Unsupported %s protocol: %s", - parsed->name, parsed->attr); - } - - branch->op_flags |= PTQL_OP_FLAG_PID; - SIGAR_CLEAR_ERRNO(); - branch->data.ui32 = strtoul(parsed->value, &ptr, 10); - if (strtonum_failed(parsed->value, ptr)) { - return PTQL_ERRNAN; - } - - return SIGAR_OK; -} - -#define PTQL_LOOKUP_ENTRY(cname, member, type) \ - (ptql_get_t)sigar_##cname##_get, \ - sigar_offsetof(sigar_##cname##_t, member), \ - sizeof(sigar_##cname##_t), \ - PTQL_VALUE_TYPE_##type, \ - NULL - -/* XXX uid/pid can be larger w/ 64bit mode */ -#define PTQL_VALUE_TYPE_PID PTQL_VALUE_TYPE_UI32 -#define PTQL_VALUE_TYPE_UID PTQL_VALUE_TYPE_UI32 - -static ptql_lookup_t PTQL_Time[] = { - { "StartTime", PTQL_LOOKUP_ENTRY(proc_time, start_time, UI64) }, - { "User", PTQL_LOOKUP_ENTRY(proc_time, user, UI64) }, - { "Sys", PTQL_LOOKUP_ENTRY(proc_time, sys, UI64) }, - { "Total", PTQL_LOOKUP_ENTRY(proc_time, total, UI64) }, - { NULL } -}; - -static ptql_lookup_t PTQL_Cpu[] = { - { "StartTime", PTQL_LOOKUP_ENTRY(proc_cpu, start_time, UI64) }, - { "User", PTQL_LOOKUP_ENTRY(proc_cpu, user, UI64) }, - { "Sys", PTQL_LOOKUP_ENTRY(proc_cpu, sys, UI64) }, - { "Total", PTQL_LOOKUP_ENTRY(proc_cpu, total, UI64) }, - { "Percent", PTQL_LOOKUP_ENTRY(proc_cpu, percent, DBL) }, - { NULL } -}; - -static ptql_lookup_t PTQL_CredName[] = { - { "User", PTQL_LOOKUP_ENTRY(proc_cred_name, user, STR) }, - { "Group", PTQL_LOOKUP_ENTRY(proc_cred_name, group, STR) }, - { NULL } -}; - -static ptql_lookup_t PTQL_Mem[] = { - { "Size", PTQL_LOOKUP_ENTRY(proc_mem, size, UI64) }, - { "Resident", PTQL_LOOKUP_ENTRY(proc_mem, resident, UI64) }, - { "Share", PTQL_LOOKUP_ENTRY(proc_mem, share, UI64) }, - { "MinorFaults", PTQL_LOOKUP_ENTRY(proc_mem, minor_faults, UI64) }, - { "MajorFaults", PTQL_LOOKUP_ENTRY(proc_mem, major_faults, UI64) }, - { "PageFaults", PTQL_LOOKUP_ENTRY(proc_mem, page_faults, UI64) }, - { NULL } -}; - -static ptql_lookup_t PTQL_Exe[] = { - { "Name", PTQL_LOOKUP_ENTRY(proc_exe, name, STR) }, - { "Cwd", PTQL_LOOKUP_ENTRY(proc_exe, cwd, STR) }, - { NULL } -}; - -static ptql_lookup_t PTQL_Cred[] = { - { "Uid", PTQL_LOOKUP_ENTRY(proc_cred, uid, UID) }, - { "Gid", PTQL_LOOKUP_ENTRY(proc_cred, gid, UID) }, - { "Euid", PTQL_LOOKUP_ENTRY(proc_cred, euid, UID) }, - { "Egid", PTQL_LOOKUP_ENTRY(proc_cred, egid, UID) }, - { NULL } -}; - -static ptql_lookup_t PTQL_State[] = { - { "State", PTQL_LOOKUP_ENTRY(proc_state, state, CHR) }, - { "Name", PTQL_LOOKUP_ENTRY(proc_state, name, STR) }, - { "Ppid", PTQL_LOOKUP_ENTRY(proc_state, ppid, PID) }, - { "Tty", PTQL_LOOKUP_ENTRY(proc_state, tty, UI32) }, - { "Nice", PTQL_LOOKUP_ENTRY(proc_state, nice, UI32) }, - { "Priority", PTQL_LOOKUP_ENTRY(proc_state, priority, UI32) }, - { "Threads", PTQL_LOOKUP_ENTRY(proc_state, threads, UI64) }, - { "Processor", PTQL_LOOKUP_ENTRY(proc_state, processor, UI32) }, - { NULL } -}; - -static ptql_lookup_t PTQL_Fd[] = { - { "Total", PTQL_LOOKUP_ENTRY(proc_fd, total, UI64) }, - { NULL } -}; - -static ptql_lookup_t PTQL_Args[] = { - { NULL, ptql_args_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_args_branch_init } -}; - -static ptql_lookup_t PTQL_Modules[] = { - { NULL, ptql_modules_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_args_branch_init } -}; - -static ptql_lookup_t PTQL_Env[] = { - { NULL, ptql_env_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_any } -}; - -static ptql_lookup_t PTQL_Port[] = { - { NULL, ptql_pid_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_port } -}; - -static ptql_lookup_t PTQL_Pid[] = { - { NULL, ptql_pid_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_pid } -}; - -static ptql_lookup_t PTQL_Service[] = { - { NULL, ptql_pid_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_service } -}; - -static ptql_entry_t ptql_map[] = { - { "Time", PTQL_Time }, - { "Cpu", PTQL_Cpu }, - { "CredName", PTQL_CredName }, - { "Mem", PTQL_Mem }, - { "Exe", PTQL_Exe }, - { "Cred", PTQL_Cred }, - { "State", PTQL_State }, - { "Fd", PTQL_Fd }, - { "Args", PTQL_Args }, - { "Modules", PTQL_Modules }, - { "Env", PTQL_Env }, - { "Port", PTQL_Port }, - { "Pid", PTQL_Pid }, - { "Service", PTQL_Service }, - { NULL } -}; - -static int ptql_branch_parse(char *query, ptql_parse_branch_t *branch, - sigar_ptql_error_t *error) -{ - char *ptr = strchr(query, '='); - if (!ptr) { - return ptql_error(error, "Missing '='"); - } - - branch->op_flags = 0; - - *ptr = '\0'; - branch->value = ++ptr; - - if ((ptr = strchr(query, '.'))) { - *ptr = '\0'; - branch->name = query; - query = ++ptr; - } - else { - return ptql_error(error, "Missing '.'"); - } - - if ((ptr = strchr(query, '.'))) { - *ptr = '\0'; - branch->attr = query; - query = ++ptr; - } - else { - return ptql_error(error, "Missing '.'"); - } - - if (*query) { - char flag; - - while (sigar_isupper((flag = *query))) { - switch (flag) { - case 'P': - branch->op_flags |= PTQL_OP_FLAG_PARENT; - break; - case 'I': - branch->op_flags |= PTQL_OP_FLAG_ICASE; - break; - default: - return ptql_error(error, "Unsupported modifier: %c", flag); - } - - ++query; - } - - branch->op = query; - } - else { - return ptql_error(error, "Missing query"); - } - - /* Pid.Service -> Service.Name */ - if (strEQ(branch->attr, "Service")) { - branch->name = branch->attr; - branch->attr = "Name"; - } - - return SIGAR_OK; -} - -static int ptql_branch_add(ptql_parse_branch_t *parsed, - ptql_branch_list_t *branches, - sigar_ptql_error_t *error) -{ - ptql_branch_t *branch; - ptql_entry_t *entry = NULL; - ptql_lookup_t *lookup = NULL; - int i, is_set=0; - char *ptr; - - PTQL_BRANCH_LIST_GROW(branches); - - branch = &branches->data[branches->number++]; - SIGAR_ZERO(branch); - branch->data_free = data_free; - branch->value_free = data_free; - branch->op_flags = parsed->op_flags; - - branch->op_name = ptql_op_code_get(parsed->op); - if (branch->op_name == PTQL_OP_MAX) { - return ptql_error(error, "Unsupported operator: %s", parsed->op); - } - - for (i=0; ptql_map[i].name; i++) { - if (strEQ(ptql_map[i].name, parsed->name)) { - entry = &ptql_map[i]; - break; - } - } - - if (!entry) { - return ptql_error(error, "Unsupported method: %s", parsed->name); - } - - for (i=0; entry->members[i].name; i++) { - if (strEQ(entry->members[i].name, parsed->attr)) { - lookup = &entry->members[i]; - break; - } - } - - if (!lookup) { - if (entry->members[0].type == PTQL_VALUE_TYPE_ANY) { - /* Args, Env, etc. */ - lookup = &entry->members[0]; - } - else { - return ptql_error(error, "Unsupported %s attribute: %s", - parsed->name, parsed->attr); - } - } - - if (lookup->init) { - int status = lookup->init(parsed, branch, error); - if (status != SIGAR_OK) { - return status; - } - } - - branch->lookup = lookup; - - if ((lookup->type < PTQL_VALUE_TYPE_STR) && - (branch->op_name > PTQL_OP_MAX_NSTR)) - { - return ptql_error(error, "Unsupported operator '%s' for %s.%s", - parsed->op, parsed->name, parsed->attr); - } - - if (*parsed->value == '$') { - is_set = 1; - - if (branch->op_name == PTQL_OP_RE) { - /* not for use with .re */ - return ptql_error(error, "Unsupported operator '%s' with variable %s", - parsed->op, parsed->value); - } - - if (sigar_isdigit(*(parsed->value+1))) { - branch->op_flags |= PTQL_OP_FLAG_REF; - parsed->op_flags = branch->op_flags; /* for use by caller */ - branch->value.ui32 = atoi(parsed->value+1) - 1; - - if (branch->value.ui32 >= branches->number) { - /* out-of-range */ - return ptql_error(error, "Variable %s out of range (%d)", - parsed->value, branches->number); - } - else if (branch->value.ui32 == branches->number-1) { - /* self reference */ - return ptql_error(error, "Variable %s self reference", - parsed->value); - } - } - else { - if ((ptr = getenv(parsed->value+1))) { - branch->value.str = sigar_strdup(ptr); - } - else { - branch->value.str = NULL; - } - } - } - else if (branch->op_name == PTQL_OP_RE) { -#ifdef SIGAR_HAS_PCRE - const char *error; - int offset; - pcre *re = - pcre_compile(parsed->value, 0, - &error, &offset, NULL); - if (!re) { - /* XXX pcre_error ? */ - return ptql_error(error, "Invalid regex"); - } - is_set = 1; - branch->value.ptr = re; - branch->value_free = pcre_free; -#endif - } - - switch (lookup->type) { - case PTQL_VALUE_TYPE_UI64: - branch->match.ui64 = ptql_op_ui64[branch->op_name]; - if (!is_set) { - SIGAR_CLEAR_ERRNO(); - branch->value.ui64 = strtoull(parsed->value, &ptr, 10); - if (strtonum_failed(parsed->value, ptr)) { - return PTQL_ERRNAN; - } - } - break; - case PTQL_VALUE_TYPE_UI32: - branch->match.ui32 = ptql_op_ui32[branch->op_name]; - if (!is_set) { - SIGAR_CLEAR_ERRNO(); - branch->value.ui32 = strtoul(parsed->value, &ptr, 10); - if (strtonum_failed(parsed->value, ptr)) { - return PTQL_ERRNAN; - } - } - break; - case PTQL_VALUE_TYPE_DBL: - branch->match.dbl = ptql_op_dbl[branch->op_name]; - if (!is_set) { - SIGAR_CLEAR_ERRNO(); - branch->value.dbl = strtod(parsed->value, &ptr); - if (strtonum_failed(parsed->value, ptr)) { - return PTQL_ERRNAN; - } - } - break; - case PTQL_VALUE_TYPE_CHR: - branch->match.chr = ptql_op_chr[branch->op_name]; - if (!is_set) { - if (strlen(parsed->value) != 1) { - return ptql_error(error, "%s is not a char", parsed->value); - } - branch->value.chr[0] = parsed->value[0]; - } - break; - case PTQL_VALUE_TYPE_STR: - case PTQL_VALUE_TYPE_ANY: - branch->match.str = ptql_op_str[branch->op_name]; - if (!is_set) { - branch->value.str = sigar_strdup(parsed->value); - } - break; - } - - return SIGAR_OK; -} - -static int ptql_branch_compare(const void *b1, const void *b2) -{ - /* XXX can do better */ - ptql_branch_t *branch1 = (ptql_branch_t *)b1; - ptql_branch_t *branch2 = (ptql_branch_t *)b2; - return - branch1->lookup->type - - branch2->lookup->type; -} - -SIGAR_DECLARE(int) sigar_ptql_query_create(sigar_ptql_query_t **queryp, - char *ptql, - sigar_ptql_error_t *error) -{ - char *ptr, *ptql_copy = sigar_strdup(ptql); - int status = SIGAR_OK; - int has_ref = 0; - sigar_ptql_query_t *query = - *queryp = malloc(sizeof(*query)); - - (void)ptql_error(error, "Malformed query"); - -#ifdef PTQL_DEBUG - query->ptql = sigar_strdup(ptql); -#endif - - ptql = ptql_copy; - - ptql_branch_list_create(&query->branches); - - do { - ptql_parse_branch_t parsed; - - if ((ptr = strchr(ptql, ','))) { - *ptr = '\0'; - } - - status = ptql_branch_parse(ptql, &parsed, error); - if (status == SIGAR_OK) { - status = - ptql_branch_add(&parsed, &query->branches, error); - - if (status != SIGAR_OK) { - break; - } - if (parsed.op_flags & PTQL_OP_FLAG_REF) { - has_ref = 1; - } - } - else { - break; - } - - if (ptr) { - ptql = ++ptr; - } - else { - break; - } - } while (*ptql); - - free(ptql_copy); - - if (status != SIGAR_OK) { - sigar_ptql_query_destroy(query); - *queryp = NULL; - } - else if (!has_ref && (query->branches.number > 1)) { - qsort(query->branches.data, - query->branches.number, - sizeof(query->branches.data[0]), - ptql_branch_compare); - } - - if (status == SIGAR_OK) { - (void)ptql_error(error, "OK"); - } - return status; -} - -SIGAR_DECLARE(int) sigar_ptql_query_destroy(sigar_ptql_query_t *query) -{ -#ifdef PTQL_DEBUG - free(query->ptql); -#endif - ptql_branch_list_destroy(&query->branches); - free(query); - return SIGAR_OK; -} - -SIGAR_DECLARE(void) sigar_ptql_re_impl_set(sigar_t *sigar, void *data, - sigar_ptql_re_impl_t impl) -{ - sigar->ptql_re_data = data; - sigar->ptql_re_impl = impl; -} - -SIGAR_DECLARE(int) sigar_ptql_query_match(sigar_t *sigar, - sigar_ptql_query_t *query, - sigar_pid_t query_pid) -{ - int i; - - for (i=0; ibranches.number; i++) { - sigar_pid_t pid = query_pid; - int status, matched=0; - ptql_branch_t *branch = &query->branches.data[i]; - ptql_lookup_t *lookup = branch->lookup; - - if (branch->op_flags & PTQL_OP_FLAG_PARENT) { - sigar_proc_state_t state; - - status = sigar_proc_state_get(sigar, pid, &state); - if (status != SIGAR_OK) { - return status; - } - - pid = state.ppid; - } - - if (lookup->type == PTQL_VALUE_TYPE_ANY) { - /* Args, Env, etc. */ - status = lookup->get(sigar, pid, branch); - if (status == SIGAR_OK) { - matched = 1; - } - } - else { - /* standard sigar_proc_*_get / structptr + offset */ - if (!branch->data.ptr) { - branch->data_size = lookup->data_size; - branch->data.ptr = malloc(branch->data_size); - } - status = lookup->get(sigar, pid, branch->data.ptr); - if (status != SIGAR_OK) { - return status; - } - - if (branch->op_flags & PTQL_OP_FLAG_REF) { - ptql_branch_t *ref = - &query->branches.data[branch->value.ui32]; - - matched = ptql_branch_match_ref(branch, ref); - } -#ifndef SIGAR_HAS_PCRE - else if (branch->lookup->type == PTQL_VALUE_TYPE_STR) { - matched = ptql_str_match(sigar, branch, (char *)DATA_PTR(branch)); - } -#endif - else { - matched = ptql_branch_match(branch); - } - } - - if (!matched) { - return 1; - } - } - - return SIGAR_OK; -} - -static int ptql_proc_list_get(sigar_t *sigar, - sigar_ptql_query_t *query, - sigar_proc_list_t **proclist) -{ - int status; - int i; - - *proclist = NULL; - - for (i=0; ibranches.number; i++) { - ptql_branch_t *branch = &query->branches.data[i]; - - if (branch->op_flags & PTQL_OP_FLAG_PID) { - /* pre-filter pid list for Pid.* queries */ - /* XXX multiple Pid.* may result in dups */ - if (*proclist == NULL) { - *proclist = malloc(sizeof(**proclist)); - SIGAR_ZERO(*proclist); - sigar_proc_list_create(*proclist); - } - status = ptql_pid_list_get(sigar, branch, *proclist); - if (status != SIGAR_OK) { - sigar_proc_list_destroy(sigar, *proclist); - free(*proclist); - return status; - } - } - } - - if (*proclist) { - return SIGAR_OK; - } - - status = sigar_proc_list_get(sigar, NULL); - if (status != SIGAR_OK) { - return status; - } - *proclist = sigar->pids; - return SIGAR_OK; -} - -static int ptql_proc_list_destroy(sigar_t *sigar, - sigar_proc_list_t *proclist) -{ - if (proclist != sigar->pids) { - sigar_proc_list_destroy(sigar, proclist); - free(proclist); - } - - return SIGAR_OK; -} - -SIGAR_DECLARE(int) sigar_ptql_query_find_process(sigar_t *sigar, - sigar_ptql_query_t *query, - sigar_pid_t *pid) -{ - int status; - int i, matches=0; - sigar_proc_list_t *pids; - - status = ptql_proc_list_get(sigar, query, &pids); - if (status != SIGAR_OK) { - return status; - } - - for (i=0; inumber; i++) { - int query_status = - sigar_ptql_query_match(sigar, query, pids->data[i]); - - if (query_status == SIGAR_OK) { - *pid = pids->data[i]; - matches++; - } - else if (query_status == SIGAR_ENOTIMPL) { - /* let caller know query is invalid. */ - status = query_status; - break; - } /* else ok, e.g. permission denied */ - } - - ptql_proc_list_destroy(sigar, pids); - - if (status != SIGAR_OK) { - return status; - } - - if (matches == 1) { - return SIGAR_OK; - } - else if (matches == 0) { - sigar_strerror_set(sigar, - "Query did not match any processes"); - } - else { - sigar_strerror_printf(sigar, - "Query matched multiple processes (%d)", - matches); - } - - return -1; -} - -SIGAR_DECLARE(int) sigar_ptql_query_find(sigar_t *sigar, - sigar_ptql_query_t *query, - sigar_proc_list_t *proclist) -{ - int status; - int i; - sigar_proc_list_t *pids; - - status = ptql_proc_list_get(sigar, query, &pids); - if (status != SIGAR_OK) { - return status; - } - - sigar_proc_list_create(proclist); - - for (i=0; inumber; i++) { - int query_status = - sigar_ptql_query_match(sigar, query, pids->data[i]); - - if (query_status == SIGAR_OK) { - SIGAR_PROC_LIST_GROW(proclist); - proclist->data[proclist->number++] = pids->data[i]; - } - else if (query_status == SIGAR_ENOTIMPL) { - /* let caller know query is invalid. */ - status = query_status; - break; - } - } - - ptql_proc_list_destroy(sigar, pids); - - if (status != SIGAR_OK) { - sigar_proc_list_destroy(sigar, proclist); - return status; - } - - return SIGAR_OK; -} diff --git a/vendor/sigar/src/sigar_signal.c b/vendor/sigar/src/sigar_signal.c deleted file mode 100644 index e32d231..0000000 --- a/vendor/sigar/src/sigar_signal.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2007 Hyperic, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sigar.h" -#include "sigar_private.h" -#include "sigar_util.h" - -#ifdef WIN32 -#include -#endif - -#include -#include - -SIGAR_DECLARE(int) sigar_proc_kill(sigar_pid_t pid, int signum) -{ -#ifdef WIN32 - int status = -1; - HANDLE proc = - OpenProcess(PROCESS_ALL_ACCESS, - TRUE, (DWORD)pid); - - if (proc) { - switch (signum) { - case 0: - status = SIGAR_OK; - break; - default: - if (TerminateProcess(proc, signum)) { - status = SIGAR_OK; - } - break; - } - - CloseHandle(proc); - - if (status == SIGAR_OK) { - return SIGAR_OK; - } - } - return GetLastError(); -#else - if (kill(pid, signum) == -1) { - return errno; - } - return SIGAR_OK; -#endif -} - -SIGAR_DECLARE(int) sigar_signum_get(char *name) -{ - if (strnEQ(name, "SIG", 3)) { - name += 3; - } - - switch (*name) { - case 'A': -#ifdef SIGABRT - if (strEQ(name, "ABRT")) return SIGABRT; -#endif -#ifdef SIGALRM - if (strEQ(name, "ALRM")) return SIGALRM; -#endif - break; - case 'B': -#ifdef SIGBUS - if (strEQ(name, "BUS")) return SIGBUS; -#endif - break; - case 'C': -#ifdef SIGCONT - if (strEQ(name, "CONT")) return SIGCONT; -#endif -#ifdef SIGCHLD - if (strEQ(name, "CHLD")) return SIGCHLD; -#endif -#ifdef SIGCLD - if (strEQ(name, "CLD")) return SIGCLD; -#endif - break; - case 'E': -#ifdef SIGEMT - if (strEQ(name, "EMT")) return SIGEMT; -#endif - break; - case 'F': -#ifdef SIGFPE - if (strEQ(name, "FPE")) return SIGFPE; -#endif - break; - case 'H': -#ifdef SIGHUP - if (strEQ(name, "HUP")) return SIGHUP; -#endif - break; - case 'I': -#ifdef SIGINT - if (strEQ(name, "INT")) return SIGINT; -#endif -#ifdef SIGILL - if (strEQ(name, "ILL")) return SIGILL; -#endif -#ifdef SIGIOT - if (strEQ(name, "IOT")) return SIGIOT; -#endif -#ifdef SIGIO - if (strEQ(name, "IO")) return SIGIO; -#endif -#ifdef SIGINFO - if (strEQ(name, "INFO")) return SIGINFO; -#endif - break; - case 'K': -#ifdef SIGKILL - if (strEQ(name, "KILL")) return SIGKILL; -#endif - break; - case 'P': -#ifdef SIGPOLL - if (strEQ(name, "POLL")) return SIGPOLL; -#endif -#ifdef SIGPIPE - if (strEQ(name, "PIPE")) return SIGPIPE; -#endif -#ifdef SIGPROF - if (strEQ(name, "PROF")) return SIGPROF; -#endif -#ifdef SIGPWR - if (strEQ(name, "PWR")) return SIGPWR; -#endif - break; - case 'Q': -#ifdef SIGQUIT - if (strEQ(name, "QUIT")) return SIGQUIT; -#endif - break; - case 'S': -#ifdef SIGSEGV - if (strEQ(name, "SEGV")) return SIGSEGV; -#endif -#ifdef SIGSYS - if (strEQ(name, "SYS")) return SIGSYS; -#endif -#ifdef SIGSTOP - if (strEQ(name, "STOP")) return SIGSTOP; -#endif -#ifdef SIGSTKFLT - if (strEQ(name, "STKFLT")) return SIGSTKFLT; -#endif - break; - case 'T': -#ifdef SIGTRAP - if (strEQ(name, "TRAP")) return SIGTRAP; -#endif -#ifdef SIGTERM - if (strEQ(name, "TERM")) return SIGTERM; -#endif -#ifdef SIGTSTP - if (strEQ(name, "TSTP")) return SIGTSTP; -#endif -#ifdef SIGTTIN - if (strEQ(name, "TTIN")) return SIGTTIN; -#endif -#ifdef SIGTTOU - if (strEQ(name, "TTOU")) return SIGTTOU; -#endif - break; - case 'U': -#ifdef SIGURG - if (strEQ(name, "URG")) return SIGURG; -#endif -#ifdef SIGUSR1 - if (strEQ(name, "USR1")) return SIGUSR1; -#endif -#ifdef SIGUSR2 - if (strEQ(name, "USR2")) return SIGUSR2; -#endif - break; - case 'V': -#ifdef SIGVTALRM - if (strEQ(name, "VTALRM")) return SIGVTALRM; -#endif - break; - case 'W': -#ifdef SIGWINCH - if (strEQ(name, "WINCH")) return SIGWINCH; -#endif - break; - case 'X': -#ifdef SIGXCPU - if (strEQ(name, "XCPU")) return SIGXCPU; -#endif -#ifdef SIGXFSZ - if (strEQ(name, "XFSZ")) return SIGXFSZ; -#endif - break; - default: - break; - } - - return -1; -} - diff --git a/vendor/sigar/src/sigar_util.c b/vendor/sigar/src/sigar_util.c deleted file mode 100644 index 3c668fc..0000000 --- a/vendor/sigar/src/sigar_util.c +++ /dev/null @@ -1,1060 +0,0 @@ -/* - * Copyright (c) 2004-2009 Hyperic, Inc. - * Copyright (c) 2009 SpringSource, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include - -#include "sigar.h" -#include "sigar_private.h" -#include "sigar_util.h" -#include "sigar_os.h" - -#ifndef WIN32 - -#include -#include - -SIGAR_INLINE char *sigar_uitoa(char *buf, unsigned int n, int *len) -{ - char *start = buf + UITOA_BUFFER_SIZE - 1; - - *start = 0; - - do { - *--start = '0' + (n % 10); - ++*len; - n /= 10; - } while (n); - - return start; -} - -SIGAR_INLINE char *sigar_skip_line(char *buffer, int buflen) -{ - char *ptr = buflen ? - (char *)memchr(buffer, '\n', buflen) : /* bleh */ - strchr(buffer, '\n'); - return ++ptr; -} - -SIGAR_INLINE char *sigar_skip_token(char *p) -{ - while (sigar_isspace(*p)) p++; - while (*p && !sigar_isspace(*p)) p++; - return p; -} - -SIGAR_INLINE char *sigar_skip_multiple_token(char *p, int count) -{ - int i; - - for (i = 0; i < count; i++) { - p = sigar_skip_token(p); - } - - return p; -} - -char *sigar_getword(char **line, char stop) -{ - char *pos = *line; - int len; - char *res; - - while ((*pos != stop) && *pos) { - ++pos; - } - - len = pos - *line; - res = malloc(len + 1); - memcpy(res, *line, len); - res[len] = 0; - - if (stop) { - while (*pos == stop) { - ++pos; - } - } - - *line = pos; - - return res; -} - -/* avoiding sprintf */ - -char *sigar_proc_filename(char *buffer, int buflen, - sigar_pid_t bigpid, - const char *fname, int fname_len) -{ - int len = 0; - char *ptr = buffer; - unsigned int pid = (unsigned int)bigpid; /* XXX -- This isn't correct */ - char pid_buf[UITOA_BUFFER_SIZE]; - char *pid_str = sigar_uitoa(pid_buf, pid, &len); - - assert((unsigned int)buflen >= - (SSTRLEN(PROCP_FS_ROOT) + UITOA_BUFFER_SIZE + fname_len + 1)); - - memcpy(ptr, PROCP_FS_ROOT, SSTRLEN(PROCP_FS_ROOT)); - ptr += SSTRLEN(PROCP_FS_ROOT); - - memcpy(ptr, pid_str, len); - ptr += len; - - memcpy(ptr, fname, fname_len); - ptr += fname_len; - *ptr = '\0'; - - return buffer; -} - -int sigar_proc_file2str(char *buffer, int buflen, - sigar_pid_t pid, - const char *fname, - int fname_len) -{ - int retval; - - buffer = sigar_proc_filename(buffer, buflen, pid, - fname, fname_len); - - retval = sigar_file2str(buffer, buffer, buflen); - - if (retval != SIGAR_OK) { - switch (retval) { - case ENOENT: - retval = ESRCH; /* no such process */ - default: - break; - } - } - - return retval; -} - -int sigar_proc_list_procfs_get(sigar_t *sigar, - sigar_proc_list_t *proclist) -{ - DIR *dirp = opendir("/proc"); - struct dirent *ent; -#ifdef HAVE_READDIR_R - struct dirent dbuf; -#endif - - if (!dirp) { - return errno; - } - -#ifdef HAVE_READDIR_R - while (readdir_r(dirp, &dbuf, &ent) == 0) { - if (ent == NULL) { - break; - } -#else - while ((ent = readdir(dirp))) { -#endif - if (!sigar_isdigit(*ent->d_name)) { - continue; - } - - /* XXX: more sanity checking */ - - SIGAR_PROC_LIST_GROW(proclist); - - proclist->data[proclist->number++] = - strtoul(ent->d_name, NULL, 10); - } - - closedir(dirp); - - return SIGAR_OK; -} - -int sigar_proc_fd_count(sigar_t *sigar, sigar_pid_t pid, - sigar_uint64_t *total) -{ - DIR *dirp; - struct dirent *ent; -#ifdef HAVE_READDIR_R - struct dirent dbuf; -#endif - char name[BUFSIZ]; - - (void)SIGAR_PROC_FILENAME(name, pid, "/fd"); - - *total = 0; - - if (!(dirp = opendir(name))) { - return errno; - } - -#ifdef HAVE_READDIR_R - while (readdir_r(dirp, &dbuf, &ent) == 0) { - if (ent == NULL) { - break; - } -#else - while ((ent = readdir(dirp))) { -#endif - if (!sigar_isdigit(*ent->d_name)) { - continue; - } - - (*total)++; - } - - closedir(dirp); - - return SIGAR_OK; -} - -int sigar_procfs_args_get(sigar_t *sigar, sigar_pid_t pid, - sigar_proc_args_t *procargs) -{ - char buffer[9086], *buf=NULL, *ptr; - int fd, len, total=0; - - (void)SIGAR_PROC_FILENAME(buffer, pid, "/cmdline"); - - if ((fd = open(buffer, O_RDONLY)) < 0) { - if (errno == ENOENT) { - return ESRCH; - } - return errno; - } - - buffer[0] = '\0'; - - /* XXX: possible to get rid of some mallocs here. - * but, unlikely this will be called often so it - * might not even matter much. - */ - while ((len = read(fd, buffer, sizeof(buffer)-1)) > 0) { - if (len == 0) { - break; - } - buf = realloc(buf, total+len+1); - memcpy(buf+total, buffer, len); - total += len; - } - - close(fd); - - /* e.g. /proc/2/cmdline */ - if (total == 0) { - procargs->number = 0; - return SIGAR_OK; - } - - buf[total] = '\0'; - ptr = buf; - - while (total > 0) { - int alen = strlen(ptr)+1; - char *arg = malloc(alen); - - SIGAR_PROC_ARGS_GROW(procargs); - memcpy(arg, ptr, alen); - - procargs->data[procargs->number++] = arg; - - total -= alen; - if (total > 0) { - ptr += alen; - } - } - - free(buf); - - return SIGAR_OK; -} - -#endif /* WIN32 */ - -/* from httpd/server/util.c */ -char *sigar_strcasestr(const char *s1, const char *s2) -{ - char *p1, *p2; - if (*s2 == '\0') { - /* an empty s2 */ - return((char *)s1); - } - while(1) { - for ( ; (*s1 != '\0') && (sigar_tolower(*s1) != sigar_tolower(*s2)); s1++); - if (*s1 == '\0') { - return(NULL); - } - /* found first character of s2, see if the rest matches */ - p1 = (char *)s1; - p2 = (char *)s2; - for (++p1, ++p2; sigar_tolower(*p1) == sigar_tolower(*p2); ++p1, ++p2) { - if (*p1 == '\0') { - /* both strings ended together */ - return((char *)s1); - } - } - if (*p2 == '\0') { - /* second string ended, a match */ - break; - } - /* didn't find a match here, try starting at next character in s1 */ - s1++; - } - return((char *)s1); -} - -int sigar_mem_calc_ram(sigar_t *sigar, sigar_mem_t *mem) -{ - sigar_int64_t total = mem->total / 1024, diff; - sigar_uint64_t lram = (mem->total / (1024 * 1024)); - int ram = (int)lram; /* must cast after division */ - int remainder = ram % 8; - - if (remainder > 0) { - ram += (8 - remainder); - } - - mem->ram = ram; - - diff = total - (mem->actual_free / 1024); - mem->used_percent = - (double)(diff * 100) / total; - - diff = total - (mem->actual_used / 1024); - mem->free_percent = - (double)(diff * 100) / total; - - return ram; -} - -#ifndef WIN32 - -sigar_iodev_t *sigar_iodev_get(sigar_t *sigar, - const char *dirname) -{ - sigar_cache_entry_t *entry; - struct stat sb; - sigar_uint64_t id; - sigar_file_system_list_t fslist; - int i, status, is_dev=0; - int debug = SIGAR_LOG_IS_DEBUG(sigar); - char dev_name[SIGAR_FS_NAME_LEN]; - - if (!sigar->fsdev) { - sigar->fsdev = sigar_cache_new(15); - } - - if (*dirname != '/') { - snprintf(dev_name, sizeof(dev_name), - SIGAR_DEV_PREFIX "%s", dirname); - dirname = dev_name; - is_dev = 1; - } - else if (SIGAR_NAME_IS_DEV(dirname)) { - is_dev = 1; - } - - if (stat(dirname, &sb) < 0) { - if (debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[iodev] stat(%s) failed", - dirname); - } - return NULL; - } - - id = SIGAR_FSDEV_ID(sb); - - entry = sigar_cache_get(sigar->fsdev, id); - - if (entry->value != NULL) { - return (sigar_iodev_t *)entry->value; - } - - if (is_dev) { - sigar_iodev_t *iodev; - entry->value = iodev = malloc(sizeof(*iodev)); - SIGAR_ZERO(iodev); - SIGAR_SSTRCPY(iodev->name, dirname); - if (debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[iodev] %s is_dev=true", dirname); - } - return iodev; - } - - status = sigar_file_system_list_get(sigar, &fslist); - - if (status != SIGAR_OK) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[iodev] file_system_list failed: %s", - sigar_strerror(sigar, status)); - return NULL; - } - - for (i=0; itype == SIGAR_FSTYPE_LOCAL_DISK) { - int retval = stat(fsp->dir_name, &sb); - sigar_cache_entry_t *ent; - - if (retval < 0) { - if (debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[iodev] inode stat(%s) failed", - fsp->dir_name); - } - continue; /* cant cache w/o inode */ - } - - ent = sigar_cache_get(sigar->fsdev, SIGAR_FSDEV_ID(sb)); - if (ent->value) { - continue; /* already cached */ - } - - if (SIGAR_NAME_IS_DEV(fsp->dev_name)) { - sigar_iodev_t *iodev; - ent->value = iodev = malloc(sizeof(*iodev)); - SIGAR_ZERO(iodev); - iodev->is_partition = 1; - SIGAR_SSTRCPY(iodev->name, fsp->dev_name); - - if (debug) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[iodev] map %s -> %s", - fsp->dir_name, iodev->name); - } - } - } - } - - sigar_file_system_list_destroy(sigar, &fslist); - - if (entry->value && - (((sigar_iodev_t *)entry->value)->name[0] != '\0')) - { - return (sigar_iodev_t *)entry->value; - } - else { - return NULL; - } -} -#endif - -double sigar_file_system_usage_calc_used(sigar_t *sigar, - sigar_file_system_usage_t *fsusage) -{ - /* - * win32 will not convert __uint64 to double. - * convert to KB then do unsigned long -> double. - */ - sigar_uint64_t b_used = (fsusage->total - fsusage->free) / 1024; - sigar_uint64_t b_avail = fsusage->avail / 1024; - unsigned long utotal = b_used + b_avail; - unsigned long used = b_used; - - if (utotal != 0) { - unsigned long u100 = used * 100; - double pct = u100 / utotal + - ((u100 % utotal != 0) ? 1 : 0); - return pct / 100; - } - - return 0; -} - -typedef struct { - sigar_uint32_t eax; - sigar_uint32_t ebx; - sigar_uint32_t ecx; - sigar_uint32_t edx; -} sigar_cpuid_t; - -#if defined(__GNUC__) && !defined(__sun) - -# if defined(__i386__) -# define SIGAR_HAS_CPUID -static void sigar_cpuid(sigar_uint32_t request, sigar_cpuid_t *id) -{ - /* derived from: */ - /* http://svn.red-bean.com/repos/minor/trunk/gc/barriers-ia-32.c */ - asm volatile ("mov %%ebx, %%esi\n\t" - "cpuid\n\t" - "xchgl %%ebx, %%esi" - : "=a" (id->eax), - "=S" (id->ebx), - "=c" (id->ecx), - "=d" (id->edx) - : "0" (request) - : "memory"); -} -# elif defined(__amd64__) -# define SIGAR_HAS_CPUID -static void sigar_cpuid(sigar_uint32_t request, - sigar_cpuid_t *id) -{ - /* http://svn.red-bean.com/repos/minor/trunk/gc/barriers-amd64.c */ - asm volatile ("cpuid\n\t" - : "=a" (id->eax), - "=b" (id->ebx), - "=c" (id->ecx), - "=d" (id->edx) - : "0" (request) - : "memory"); -} -# endif -#elif defined(WIN32) -# ifdef _M_X64 -# include -# define SIGAR_HAS_CPUID -static void sigar_cpuid(sigar_uint32_t request, - sigar_cpuid_t *id) -{ - sigar_uint32_t info[4]; - __cpuid(info, request); /* as of MSVC 7 */ - memcpy(id, &info[0], sizeof(info)); -} -# else -# define SIGAR_HAS_CPUID -static void sigar_cpuid(sigar_uint32_t request, - sigar_cpuid_t *id) -{ - __asm { - mov edi, id - mov eax, [edi].eax - mov ecx, [edi].ecx - cpuid - mov [edi].eax, eax - mov [edi].ebx, ebx - mov [edi].ecx, ecx - mov [edi].edx, edx - } -} -# endif -#endif - -#define INTEL_ID 0x756e6547 -#define AMD_ID 0x68747541 - -int sigar_cpu_core_count(sigar_t *sigar) -{ -#if defined(SIGAR_HAS_CPUID) - sigar_cpuid_t id; - - if (sigar->lcpu == -1) { - sigar->lcpu = 1; - - sigar_cpuid(0, &id); - - if ((id.ebx == INTEL_ID) || (id.ebx == AMD_ID)) { - sigar_cpuid(1, &id); - - if (id.edx & (1<<28)) { - sigar->lcpu = (id.ebx & 0x00FF0000) >> 16; - } - } - - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[cpu] %d cores per socket", sigar->lcpu); - } - - return sigar->lcpu; -#elif defined(__sun) || defined(__hpux) || defined(_AIX) - return 1; -#else - sigar->lcpu = 1; - return sigar->lcpu; -#endif -} - -int sigar_cpu_core_rollup(sigar_t *sigar) -{ -#ifdef SIGAR_HAS_CPUID - int log_rollup = - SIGAR_LOG_IS_DEBUG(sigar) && - (sigar->lcpu == -1); - - (void)sigar_cpu_core_count(sigar); - - if (sigar->cpu_list_cores) { - if (log_rollup && (sigar->lcpu > 1)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[cpu] treating cores as-is"); - } - } - else { - if (log_rollup && (sigar->lcpu > 1)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "[cpu] rolling up cores to sockets"); - return 1; - } - } -#endif - return 0; -} - -#define IS_CPU_R(p) \ - ((*p == '(') && (*(p+1) == 'R') && (*(p+2) == ')')) - -typedef struct { - char *name; /* search */ - int len; - char *rname; /* replace */ - int rlen; -} cpu_model_str_t; - -/* to later replace 's' with 'r' */ -#define CPU_MODEL_ENT_R(s, r) \ - { s, sizeof(s)-1, r, sizeof(r) } - -#define CPU_MODEL_ENT(s) \ - CPU_MODEL_ENT_R(s, s) - -/* after the vendor part of the string is removed, - * looking for startsWith the entries below - * to remove the crap after the model name, see - * ../exp/intel_amd_cpu_models.txt - */ -static const cpu_model_str_t cpu_models[] = { - /* intel */ - CPU_MODEL_ENT("Xeon"), - CPU_MODEL_ENT_R("XEON", "Xeon"), - CPU_MODEL_ENT("Pentium III"), - CPU_MODEL_ENT("Pentium II"), - CPU_MODEL_ENT_R("Pentium(R) III", "Pentium III"), - CPU_MODEL_ENT_R("Pentium(R) 4", "Pentium 4"), - CPU_MODEL_ENT_R("Pentium(R) M", "Pentium M"), - CPU_MODEL_ENT("Pentium Pro"), - CPU_MODEL_ENT("Celeron"), - - /* amd */ - CPU_MODEL_ENT("Opteron"), - CPU_MODEL_ENT("Athlon"), - CPU_MODEL_ENT("Duron"), - CPU_MODEL_ENT_R("K6(tm)-III", "K6 III"), - CPU_MODEL_ENT_R("K6(tm) 3D+", "K6 3D+"), - { NULL } -}; - -/* common to win32 and linux */ -void sigar_cpu_model_adjust(sigar_t *sigar, sigar_cpu_info_t *info) -{ - int len, i; - char model[128], *ptr=model, *end; - - memcpy(model, info->model, sizeof(model)); - - /* trim leading and trailing spaces */ - len = strlen(model); - end = &model[len-1]; - while (*ptr == ' ') ++ptr; - while (*end == ' ') *end-- = '\0'; - - /* remove vendor from model name */ - len = strlen(info->vendor); - if (strnEQ(ptr, info->vendor, len)) { - ptr += len; - if (IS_CPU_R(ptr)) { - ptr += 3; /* remove (R) */ - } - while (*ptr == ' ') ++ptr; - } - - if (*ptr == '-') { - ++ptr; /* e.g. was AMD-K6... */ - } - - for (i=0; cpu_models[i].name; i++) { - const cpu_model_str_t *cpu_model = &cpu_models[i]; - - if (strnEQ(ptr, cpu_model->name, cpu_model->len)) { - memcpy(info->model, cpu_model->rname, cpu_model->rlen); - return; - } - } - - strcpy(info->model, ptr); -} - -/* attempt to derive MHz from model name - * currently works for certain intel strings - * see exp/intel_amd_cpu_models.txt - */ -int sigar_cpu_mhz_from_model(char *model) -{ - int mhz = SIGAR_FIELD_NOTIMPL; - char *ptr = model; - - while (*ptr && (ptr = strchr(ptr, ' '))) { - while(*ptr && !sigar_isdigit(*ptr)) { - ptr++; - } - mhz = sigar_strtoul(ptr); - - if (*ptr == '.') { - /* e.g. "2.40GHz" */ - ++ptr; - mhz *= 100; - mhz += sigar_strtoul(ptr); - break; - } - else if (strnEQ(ptr, "GHz", 3) || - strnEQ(ptr, "MHz", 3)) - { - /* e.g. "1500MHz" */ - break; - } - else { - mhz = SIGAR_FIELD_NOTIMPL; - } - } - - if (mhz != SIGAR_FIELD_NOTIMPL) { - if (strnEQ(ptr, "GHz", 3)) { - mhz *= 10; - } - } - - return mhz; -} - -#if !defined(WIN32) && !defined(NETWARE) -#include -#include -#include -#include -#ifdef SIGAR_HPUX -#include -#endif -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun) || defined(DARWIN) -#include -#endif -#if defined(__sun) || defined(SIGAR_HPUX) -#include -#endif -#if defined(_AIX) || defined(SIGAR_HPUX) || defined(__OpenBSD__) || defined(__NetBSD__) -#include -#endif - -static enum clnt_stat get_sockaddr(struct sockaddr_in *addr, char *host) -{ - register struct hostent *hp; - sigar_hostent_t data; - - memset(addr, 0, sizeof(struct sockaddr_in)); - addr->sin_family = AF_INET; - - if ((addr->sin_addr.s_addr = inet_addr(host)) == -1) { - if (!(hp = sigar_gethostbyname(host, &data))) { - return RPC_UNKNOWNHOST; - } - memcpy(&addr->sin_addr, hp->h_addr, hp->h_length); - } - - return RPC_SUCCESS; -} - -char *sigar_rpc_strerror(int err) -{ - return (char *)clnt_sperrno(err); -} - -SIGAR_DECLARE(int) sigar_rpc_ping(char *host, - int protocol, - unsigned long program, - unsigned long version) -{ - CLIENT *client; - struct sockaddr_in addr; - int sock; - struct timeval timeout; - unsigned short port = 0; - enum clnt_stat rpc_stat; - - rpc_stat = get_sockaddr(&addr, host); - if (rpc_stat != RPC_SUCCESS) { - return rpc_stat; - } - - timeout.tv_sec = 2; - timeout.tv_usec = 0; - addr.sin_port = htons(port); - sock = RPC_ANYSOCK; - - if (protocol == SIGAR_NETCONN_UDP) { - client = - clntudp_create(&addr, program, version, - timeout, &sock); - } - else if (protocol == SIGAR_NETCONN_TCP) { - client = - clnttcp_create(&addr, program, version, - &sock, 0, 0); - } - else { - return RPC_UNKNOWNPROTO; - } - - if (!client) { - return rpc_createerr.cf_stat; - } - - timeout.tv_sec = 10; - timeout.tv_usec = 0; - rpc_stat = clnt_call(client, NULLPROC, (xdrproc_t)xdr_void, NULL, - (xdrproc_t)xdr_void, NULL, timeout); - - clnt_destroy(client); - - return rpc_stat; -} -#endif - -int sigar_file2str(const char *fname, char *buffer, int buflen) -{ - int len, status; - int fd = open(fname, O_RDONLY); - - if (fd < 0) { - return ENOENT; - } - - if ((len = read(fd, buffer, buflen)) < 0) { - status = errno; - } - else { - status = SIGAR_OK; - buffer[len] = '\0'; - } - close(fd); - - return status; -} - -#ifdef WIN32 -#define vsnprintf _vsnprintf -#endif - -#ifdef WIN32 -# define rindex strrchr -#endif - -static int proc_module_get_self(void *data, char *name, int len) -{ - sigar_t *sigar = (sigar_t *)data; - char *ptr = rindex(name, '/'); - - if (!ptr) { - return SIGAR_OK; - } - - if (strnEQ(ptr+1, "libsigar-", 9)) { - int offset = ptr - name; - - sigar->self_path = sigar_strdup(name); - *(sigar->self_path + offset) = '\0'; /* chop libsigar-*.so */ - - if (SIGAR_LOG_IS_DEBUG(sigar)) { - sigar_log_printf(sigar, SIGAR_LOG_DEBUG, - "detected sigar-lib='%s'", - sigar->self_path); - } - - return !SIGAR_OK; /* break loop */ - } - - return SIGAR_OK; -} - -char *sigar_get_self_path(sigar_t *sigar) -{ - if (!sigar->self_path) { - sigar_proc_modules_t procmods; - char *self_path = getenv("SIGAR_PATH"); - - if (self_path) { - sigar->self_path = sigar_strdup(self_path); - return sigar->self_path; - } - - procmods.module_getter = proc_module_get_self; - procmods.data = sigar; - - sigar_proc_modules_get(sigar, - sigar_pid_get(sigar), - &procmods); - - if (!sigar->self_path) { - /* dont try again */ - sigar->self_path = sigar_strdup("."); - } - } - - return sigar->self_path; -} - -#ifdef SIGAR_HAS_DLINFO_MODULES - -static int sigar_dlinfo_get(sigar_t *sigar, const char *func, - void **handle, Link_map **map) -{ - Dl_info dli; - - if (!dladdr((void *)((uintptr_t)sigar_dlinfo_get), &dli)) { - sigar_log_printf(sigar, SIGAR_LOG_ERROR, - "[%s] dladdr(%s) = %s", - func, SIGAR_FUNC, dlerror()); - return ESRCH; - } - - if (!(*handle = dlopen(dli.dli_fname, RTLD_LAZY))) { - sigar_log_printf(sigar, SIGAR_LOG_ERROR, - "[%s] dlopen(%s) = %s", - func, dli.dli_fname, dlerror()); - return ESRCH; - } - - dlinfo(*handle, RTLD_DI_LINKMAP, map); - - if (!map) { - sigar_log_printf(sigar, SIGAR_LOG_ERROR, - "[%s] dlinfo = %s", - func, dlerror()); - return ESRCH; - } - - return SIGAR_OK; -} - -int sigar_dlinfo_modules(sigar_t *sigar, sigar_proc_modules_t *procmods) -{ - int status; - void *handle; - Link_map *map; - - status = sigar_dlinfo_get(sigar, SIGAR_FUNC, &handle, &map); - if (status != SIGAR_OK) { - return status; - } - - while (map->l_prev != NULL) { - map = map->l_prev; - } - - do { - int status = - procmods->module_getter(procmods->data, - (char *)map->l_name, - strlen(map->l_name)); - - if (status != SIGAR_OK) { - /* not an error; just stop iterating */ - break; - } - } while ((map = map->l_next)); - - dlclose(handle); - - return SIGAR_OK; -} -#endif - -SIGAR_DECLARE(void) sigar_log_printf(sigar_t *sigar, int level, - const char *format, ...) -{ - va_list args; - char buffer[8192]; - - if (level > sigar->log_level) { - return; - } - - if (!sigar->log_impl) { - return; - } - - va_start(args, format); - vsnprintf(buffer, sizeof(buffer), format, args); - va_end(args); - - sigar->log_impl(sigar, sigar->log_data, level, buffer); -} - -SIGAR_DECLARE(void) sigar_log(sigar_t *sigar, int level, char *message) -{ - if (level > sigar->log_level) { - return; - } - - if (!sigar->log_impl) { - return; - } - - sigar->log_impl(sigar, sigar->log_data, level, message); -} - -SIGAR_DECLARE(void) sigar_log_impl_set(sigar_t *sigar, void *data, - sigar_log_impl_t impl) -{ - sigar->log_data = data; - sigar->log_impl = impl; -} - -SIGAR_DECLARE(int) sigar_log_level_get(sigar_t *sigar) -{ - return sigar->log_level; -} - -static const char *log_levels[] = { - "FATAL", - "ERROR", - "WARN", - "INFO", - "DEBUG", - "TRACE" -}; - -SIGAR_DECLARE(const char *) sigar_log_level_string_get(sigar_t *sigar) -{ - return log_levels[sigar->log_level]; -} - -SIGAR_DECLARE(void) sigar_log_level_set(sigar_t *sigar, int level) -{ - sigar->log_level = level; -} - -SIGAR_DECLARE(void) sigar_log_impl_file(sigar_t *sigar, void *data, - int level, char *message) -{ - FILE *fp = (FILE*)data; - fprintf(fp, "[%s] %s\n", log_levels[level], message); -} - -#ifndef WIN32 -sigar_int64_t sigar_time_now_millis(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return ((tv.tv_sec * SIGAR_USEC) + tv.tv_usec) / SIGAR_MSEC; -} -#endif diff --git a/vendor/sigar/src/sigar_version_autoconf.c b/vendor/sigar/src/sigar_version_autoconf.c deleted file mode 100644 index 7b1f865..0000000 --- a/vendor/sigar/src/sigar_version_autoconf.c +++ /dev/null @@ -1,22 +0,0 @@ -#include "sigar.h" - -static sigar_version_t sigar_version = { - __DATE__, - "@SCM_REVISION@", - "libsigar 1.6.2", - "x86_64-apple-darwin11.4.0", - "darwin11.4.0", - "x86_64", - "SIGAR-1.6.2, " - "SCM revision @SCM_REVISION@, " - "built "__DATE__" as x86_64", - 1, - 6, - 2, - 0 -}; - -SIGAR_DECLARE(sigar_version_t *) sigar_version_get(void) -{ - return &sigar_version; -}