Core/Misc: ported cryptography updates and all that entrails from 335/master and killed bnetserver

This commit is contained in:
Ovahlord committed 2025-07-21 19:04:56 +02:00
1 parent a576c8328b
commit 64b77e359d
413 files changed
+8952 -56005

No files matched your search

+1 -2
View File
@@ -28,11 +28,10 @@ if(SERVERS)
add_subdirectory(mysql)
add_subdirectory(readline)
add_subdirectory(gsoap)
add_subdirectory(libzmq)
add_subdirectory(zmqpp)
add_subdirectory(rapidjson)
add_subdirectory(efsw)
add_subdirectory(short_alloc)
add_subdirectory(argon2)
endif()
if(TOOLS)
+4 -8
View File
@@ -40,10 +40,6 @@ libMPQ (a library for reading MPQ files)
https://github.com/mbroemme/libmpq/
Version: d59b4cf1d107b5f6a0f67d6bc545c6c6ebef3d74
libzmq (ZeroMQ core engine in C++, implements ZMTP/3.1)
https://github.com/zeromq/libzmq
Version: 4.2.3 stable
MariaDB:
https://mariadb.org/
Version: external
@@ -77,10 +73,10 @@ zlib (A Massively Spiffy Yet Delicately Unobtrusive Compression Library)
http://www.zlib.net/
Version: 1.2.12
zmqpp (C++ binding for 0mq/zmq is a 'high-level' library that hides most of the c-style interface core 0mq provides.)
https://github.com/zeromq/zmqpp
Version: 3.2.0 17e9f6afa98f56ecac1e3f3eecbfc112357a6732
MinHook (The Minimalistic x86/x64 API Hooking Library for Windows)
https://github.com/TsudaKageyu/minhook
Version: 0f25a2449b3cf878bcbdbf91b693c38149ecf029
argon2
https://github.com/P-H-C/phc-winner-argon2
Version: 62358ba
@@ -8,28 +8,34 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
file(GLOB_RECURSE sources_zmqpp zmqpp/*.cpp zmqpp/*.hpp zmqpp/*.h)
file(GLOB_RECURSE sources *.c)
add_library(zmqpp STATIC ${sources_zmqpp})
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
list(REMOVE_ITEM sources
${CMAKE_CURRENT_SOURCE_DIR}/argon2/opt.c)
else()
list(REMOVE_ITEM sources
${CMAKE_CURRENT_SOURCE_DIR}/argon2/ref.c)
endif()
target_include_directories(zmqpp
add_library(argon2 STATIC
${sources})
target_compile_definitions(argon2
PRIVATE
-DARGON2_NO_THREADS)
set_target_properties(argon2 PROPERTIES LINKER_LANGUAGE CXX)
target_include_directories(argon2
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(zmqpp
target_link_libraries(argon2
PRIVATE
trinity-dependency-interface
PUBLIC
libzmq)
trinity-dependency-interface)
set_target_properties(zmqpp
set_target_properties(argon2
PROPERTIES
FOLDER
"dep")
target_compile_definitions(zmqpp
PRIVATE
-DBUILD_VERSION_MAJOR=3
-DBUILD_VERSION_MINOR=2
-DBUILD_VERSION_REVISION=0
-DBUILD_VERSION="3.2.0")
+314
View File
@@ -0,0 +1,314 @@
Argon2 reference source code package - reference C implementations
Copyright 2015
Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
You may use this work under the terms of a Creative Commons CC0 1.0
License/Waiver or the Apache Public License 2.0, at your option. The terms of
these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
The terms of the licenses are reproduced below.
--------------------------------------------------------------------------------
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.
--------------------------------------------------------------------------------
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
+452
View File
@@ -0,0 +1,452 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "argon2.h"
#include "encoding.h"
#include "core.h"
const char *argon2_type2string(argon2_type type, int uppercase) {
switch (type) {
case Argon2_d:
return uppercase ? "Argon2d" : "argon2d";
case Argon2_i:
return uppercase ? "Argon2i" : "argon2i";
case Argon2_id:
return uppercase ? "Argon2id" : "argon2id";
}
return NULL;
}
int argon2_ctx(argon2_context *context, argon2_type type) {
/* 1. Validate all inputs */
int result = validate_inputs(context);
uint32_t memory_blocks, segment_length;
argon2_instance_t instance;
if (ARGON2_OK != result) {
return result;
}
if (Argon2_d != type && Argon2_i != type && Argon2_id != type) {
return ARGON2_INCORRECT_TYPE;
}
/* 2. Align memory size */
/* Minimum memory_blocks = 8L blocks, where L is the number of lanes */
memory_blocks = context->m_cost;
if (memory_blocks < 2 * ARGON2_SYNC_POINTS * context->lanes) {
memory_blocks = 2 * ARGON2_SYNC_POINTS * context->lanes;
}
segment_length = memory_blocks / (context->lanes * ARGON2_SYNC_POINTS);
/* Ensure that all segments have equal length */
memory_blocks = segment_length * (context->lanes * ARGON2_SYNC_POINTS);
instance.version = context->version;
instance.memory = NULL;
instance.passes = context->t_cost;
instance.memory_blocks = memory_blocks;
instance.segment_length = segment_length;
instance.lane_length = segment_length * ARGON2_SYNC_POINTS;
instance.lanes = context->lanes;
instance.threads = context->threads;
instance.type = type;
if (instance.threads > instance.lanes) {
instance.threads = instance.lanes;
}
/* 3. Initialization: Hashing inputs, allocating memory, filling first
* blocks
*/
result = initialize(&instance, context);
if (ARGON2_OK != result) {
return result;
}
/* 4. Filling memory */
result = fill_memory_blocks(&instance);
if (ARGON2_OK != result) {
return result;
}
/* 5. Finalization */
finalize(context, &instance);
return ARGON2_OK;
}
int argon2_hash(const uint32_t t_cost, const uint32_t m_cost,
const uint32_t parallelism, const void *pwd,
const size_t pwdlen, const void *salt, const size_t saltlen,
void *hash, const size_t hashlen, char *encoded,
const size_t encodedlen, argon2_type type,
const uint32_t version){
argon2_context context;
int result;
uint8_t *out;
if (pwdlen > ARGON2_MAX_PWD_LENGTH) {
return ARGON2_PWD_TOO_LONG;
}
if (saltlen > ARGON2_MAX_SALT_LENGTH) {
return ARGON2_SALT_TOO_LONG;
}
if (hashlen > ARGON2_MAX_OUTLEN) {
return ARGON2_OUTPUT_TOO_LONG;
}
if (hashlen < ARGON2_MIN_OUTLEN) {
return ARGON2_OUTPUT_TOO_SHORT;
}
out = malloc(hashlen);
if (!out) {
return ARGON2_MEMORY_ALLOCATION_ERROR;
}
context.out = (uint8_t *)out;
context.outlen = (uint32_t)hashlen;
context.pwd = CONST_CAST(uint8_t *)pwd;
context.pwdlen = (uint32_t)pwdlen;
context.salt = CONST_CAST(uint8_t *)salt;
context.saltlen = (uint32_t)saltlen;
context.secret = NULL;
context.secretlen = 0;
context.ad = NULL;
context.adlen = 0;
context.t_cost = t_cost;
context.m_cost = m_cost;
context.lanes = parallelism;
context.threads = parallelism;
context.allocate_cbk = NULL;
context.free_cbk = NULL;
context.flags = ARGON2_DEFAULT_FLAGS;
context.version = version;
result = argon2_ctx(&context, type);
if (result != ARGON2_OK) {
clear_internal_memory(out, hashlen);
free(out);
return result;
}
/* if raw hash requested, write it */
if (hash) {
memcpy(hash, out, hashlen);
}
/* if encoding requested, write it */
if (encoded && encodedlen) {
if (encode_string(encoded, encodedlen, &context, type) != ARGON2_OK) {
clear_internal_memory(out, hashlen); /* wipe buffers if error */
clear_internal_memory(encoded, encodedlen);
free(out);
return ARGON2_ENCODING_FAIL;
}
}
clear_internal_memory(out, hashlen);
free(out);
return ARGON2_OK;
}
int argon2i_hash_encoded(const uint32_t t_cost, const uint32_t m_cost,
const uint32_t parallelism, const void *pwd,
const size_t pwdlen, const void *salt,
const size_t saltlen, const size_t hashlen,
char *encoded, const size_t encodedlen) {
return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,
NULL, hashlen, encoded, encodedlen, Argon2_i,
ARGON2_VERSION_NUMBER);
}
int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
const uint32_t parallelism, const void *pwd,
const size_t pwdlen, const void *salt,
const size_t saltlen, void *hash, const size_t hashlen) {
return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,
hash, hashlen, NULL, 0, Argon2_i, ARGON2_VERSION_NUMBER);
}
int argon2d_hash_encoded(const uint32_t t_cost, const uint32_t m_cost,
const uint32_t parallelism, const void *pwd,
const size_t pwdlen, const void *salt,
const size_t saltlen, const size_t hashlen,
char *encoded, const size_t encodedlen) {
return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,
NULL, hashlen, encoded, encodedlen, Argon2_d,
ARGON2_VERSION_NUMBER);
}
int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
const uint32_t parallelism, const void *pwd,
const size_t pwdlen, const void *salt,
const size_t saltlen, void *hash, const size_t hashlen) {
return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,
hash, hashlen, NULL, 0, Argon2_d, ARGON2_VERSION_NUMBER);
}
int argon2id_hash_encoded(const uint32_t t_cost, const uint32_t m_cost,
const uint32_t parallelism, const void *pwd,
const size_t pwdlen, const void *salt,
const size_t saltlen, const size_t hashlen,
char *encoded, const size_t encodedlen) {
return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,
NULL, hashlen, encoded, encodedlen, Argon2_id,
ARGON2_VERSION_NUMBER);
}
int argon2id_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
const uint32_t parallelism, const void *pwd,
const size_t pwdlen, const void *salt,
const size_t saltlen, void *hash, const size_t hashlen) {
return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,
hash, hashlen, NULL, 0, Argon2_id,
ARGON2_VERSION_NUMBER);
}
static int argon2_compare(const uint8_t *b1, const uint8_t *b2, size_t len) {
size_t i;
uint8_t d = 0U;
for (i = 0U; i < len; i++) {
d |= b1[i] ^ b2[i];
}
return (int)((1 & ((d - 1) >> 8)) - 1);
}
int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen,
argon2_type type) {
argon2_context ctx;
uint8_t *desired_result = NULL;
int ret = ARGON2_OK;
size_t encoded_len;
uint32_t max_field_len;
if (pwdlen > ARGON2_MAX_PWD_LENGTH) {
return ARGON2_PWD_TOO_LONG;
}
if (encoded == NULL) {
return ARGON2_DECODING_FAIL;
}
encoded_len = strlen(encoded);
if (encoded_len > UINT32_MAX) {
return ARGON2_DECODING_FAIL;
}
/* No field can be longer than the encoded length */
max_field_len = (uint32_t)encoded_len;
ctx.saltlen = max_field_len;
ctx.outlen = max_field_len;
ctx.salt = malloc(ctx.saltlen);
ctx.out = malloc(ctx.outlen);
if (!ctx.salt || !ctx.out) {
ret = ARGON2_MEMORY_ALLOCATION_ERROR;
goto fail;
}
ctx.pwd = (uint8_t *)pwd;
ctx.pwdlen = (uint32_t)pwdlen;
ret = decode_string(&ctx, encoded, type);
if (ret != ARGON2_OK) {
goto fail;
}
/* Set aside the desired result, and get a new buffer. */
desired_result = ctx.out;
ctx.out = malloc(ctx.outlen);
if (!ctx.out) {
ret = ARGON2_MEMORY_ALLOCATION_ERROR;
goto fail;
}
ret = argon2_verify_ctx(&ctx, (char *)desired_result, type);
if (ret != ARGON2_OK) {
goto fail;
}
fail:
free(ctx.salt);
free(ctx.out);
free(desired_result);
return ret;
}
int argon2i_verify(const char *encoded, const void *pwd, const size_t pwdlen) {
return argon2_verify(encoded, pwd, pwdlen, Argon2_i);
}
int argon2d_verify(const char *encoded, const void *pwd, const size_t pwdlen) {
return argon2_verify(encoded, pwd, pwdlen, Argon2_d);
}
int argon2id_verify(const char *encoded, const void *pwd, const size_t pwdlen) {
return argon2_verify(encoded, pwd, pwdlen, Argon2_id);
}
int argon2d_ctx(argon2_context *context) {
return argon2_ctx(context, Argon2_d);
}
int argon2i_ctx(argon2_context *context) {
return argon2_ctx(context, Argon2_i);
}
int argon2id_ctx(argon2_context *context) {
return argon2_ctx(context, Argon2_id);
}
int argon2_verify_ctx(argon2_context *context, const char *hash,
argon2_type type) {
int ret = argon2_ctx(context, type);
if (ret != ARGON2_OK) {
return ret;
}
if (argon2_compare((uint8_t *)hash, context->out, context->outlen)) {
return ARGON2_VERIFY_MISMATCH;
}
return ARGON2_OK;
}
int argon2d_verify_ctx(argon2_context *context, const char *hash) {
return argon2_verify_ctx(context, hash, Argon2_d);
}
int argon2i_verify_ctx(argon2_context *context, const char *hash) {
return argon2_verify_ctx(context, hash, Argon2_i);
}
int argon2id_verify_ctx(argon2_context *context, const char *hash) {
return argon2_verify_ctx(context, hash, Argon2_id);
}
const char *argon2_error_message(int error_code) {
switch (error_code) {
case ARGON2_OK:
return "OK";
case ARGON2_OUTPUT_PTR_NULL:
return "Output pointer is NULL";
case ARGON2_OUTPUT_TOO_SHORT:
return "Output is too short";
case ARGON2_OUTPUT_TOO_LONG:
return "Output is too long";
case ARGON2_PWD_TOO_SHORT:
return "Password is too short";
case ARGON2_PWD_TOO_LONG:
return "Password is too long";
case ARGON2_SALT_TOO_SHORT:
return "Salt is too short";
case ARGON2_SALT_TOO_LONG:
return "Salt is too long";
case ARGON2_AD_TOO_SHORT:
return "Associated data is too short";
case ARGON2_AD_TOO_LONG:
return "Associated data is too long";
case ARGON2_SECRET_TOO_SHORT:
return "Secret is too short";
case ARGON2_SECRET_TOO_LONG:
return "Secret is too long";
case ARGON2_TIME_TOO_SMALL:
return "Time cost is too small";
case ARGON2_TIME_TOO_LARGE:
return "Time cost is too large";
case ARGON2_MEMORY_TOO_LITTLE:
return "Memory cost is too small";
case ARGON2_MEMORY_TOO_MUCH:
return "Memory cost is too large";
case ARGON2_LANES_TOO_FEW:
return "Too few lanes";
case ARGON2_LANES_TOO_MANY:
return "Too many lanes";
case ARGON2_PWD_PTR_MISMATCH:
return "Password pointer is NULL, but password length is not 0";
case ARGON2_SALT_PTR_MISMATCH:
return "Salt pointer is NULL, but salt length is not 0";
case ARGON2_SECRET_PTR_MISMATCH:
return "Secret pointer is NULL, but secret length is not 0";
case ARGON2_AD_PTR_MISMATCH:
return "Associated data pointer is NULL, but ad length is not 0";
case ARGON2_MEMORY_ALLOCATION_ERROR:
return "Memory allocation error";
case ARGON2_FREE_MEMORY_CBK_NULL:
return "The free memory callback is NULL";
case ARGON2_ALLOCATE_MEMORY_CBK_NULL:
return "The allocate memory callback is NULL";
case ARGON2_INCORRECT_PARAMETER:
return "Argon2_Context context is NULL";
case ARGON2_INCORRECT_TYPE:
return "There is no such version of Argon2";
case ARGON2_OUT_PTR_MISMATCH:
return "Output pointer mismatch";
case ARGON2_THREADS_TOO_FEW:
return "Not enough threads";
case ARGON2_THREADS_TOO_MANY:
return "Too many threads";
case ARGON2_MISSING_ARGS:
return "Missing arguments";
case ARGON2_ENCODING_FAIL:
return "Encoding failed";
case ARGON2_DECODING_FAIL:
return "Decoding failed";
case ARGON2_THREAD_FAIL:
return "Threading failure";
case ARGON2_DECODING_LENGTH_FAIL:
return "Some of encoded parameters are too long or too short";
case ARGON2_VERIFY_MISMATCH:
return "The password does not match the supplied hash";
default:
return "Unknown error code";
}
}
size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, uint32_t parallelism,
uint32_t saltlen, uint32_t hashlen, argon2_type type) {
return strlen("$$v=$m=,t=,p=$$") + strlen(argon2_type2string(type, 0)) +
numlen(t_cost) + numlen(m_cost) + numlen(parallelism) +
b64len(saltlen) + b64len(hashlen) + numlen(ARGON2_VERSION_NUMBER) + 1;
}
+437
View File
@@ -0,0 +1,437 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef ARGON2_H
#define ARGON2_H
#include <stdint.h>
#include <stddef.h>
#include <limits.h>
#if defined(__cplusplus)
extern "C" {
#endif
/* Symbols visibility control */
#ifdef A2_VISCTL
#define ARGON2_PUBLIC __attribute__((visibility("default")))
#define ARGON2_LOCAL __attribute__ ((visibility ("hidden")))
#elif _MSC_VER
#define ARGON2_PUBLIC __declspec(dllexport)
#define ARGON2_LOCAL
#else
#define ARGON2_PUBLIC
#define ARGON2_LOCAL
#endif
/*
* Argon2 input parameter restrictions
*/
/* Minimum and maximum number of lanes (degree of parallelism) */
#define ARGON2_MIN_LANES UINT32_C(1)
#define ARGON2_MAX_LANES UINT32_C(0xFFFFFF)
/* Minimum and maximum number of threads */
#define ARGON2_MIN_THREADS UINT32_C(1)
#define ARGON2_MAX_THREADS UINT32_C(0xFFFFFF)
/* Number of synchronization points between lanes per pass */
#define ARGON2_SYNC_POINTS UINT32_C(4)
/* Minimum and maximum digest size in bytes */
#define ARGON2_MIN_OUTLEN UINT32_C(4)
#define ARGON2_MAX_OUTLEN UINT32_C(0xFFFFFFFF)
/* Minimum and maximum number of memory blocks (each of BLOCK_SIZE bytes) */
#define ARGON2_MIN_MEMORY (2 * ARGON2_SYNC_POINTS) /* 2 blocks per slice */
#define ARGON2_MIN(a, b) ((a) < (b) ? (a) : (b))
/* Max memory size is addressing-space/2, topping at 2^32 blocks (4 TB) */
#define ARGON2_MAX_MEMORY_BITS \
ARGON2_MIN(UINT32_C(32), (sizeof(void *) * CHAR_BIT - 10 - 1))
#define ARGON2_MAX_MEMORY \
ARGON2_MIN(UINT32_C(0xFFFFFFFF), UINT64_C(1) << ARGON2_MAX_MEMORY_BITS)
/* Minimum and maximum number of passes */
#define ARGON2_MIN_TIME UINT32_C(1)
#define ARGON2_MAX_TIME UINT32_C(0xFFFFFFFF)
/* Minimum and maximum password length in bytes */
#define ARGON2_MIN_PWD_LENGTH UINT32_C(0)
#define ARGON2_MAX_PWD_LENGTH UINT32_C(0xFFFFFFFF)
/* Minimum and maximum associated data length in bytes */
#define ARGON2_MIN_AD_LENGTH UINT32_C(0)
#define ARGON2_MAX_AD_LENGTH UINT32_C(0xFFFFFFFF)
/* Minimum and maximum salt length in bytes */
#define ARGON2_MIN_SALT_LENGTH UINT32_C(8)
#define ARGON2_MAX_SALT_LENGTH UINT32_C(0xFFFFFFFF)
/* Minimum and maximum key length in bytes */
#define ARGON2_MIN_SECRET UINT32_C(0)
#define ARGON2_MAX_SECRET UINT32_C(0xFFFFFFFF)
/* Flags to determine which fields are securely wiped (default = no wipe). */
#define ARGON2_DEFAULT_FLAGS UINT32_C(0)
#define ARGON2_FLAG_CLEAR_PASSWORD (UINT32_C(1) << 0)
#define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1)
/* Global flag to determine if we are wiping internal memory buffers. This flag
* is defined in core.c and defaults to 1 (wipe internal memory). */
extern int FLAG_clear_internal_memory;
/* Error codes */
typedef enum Argon2_ErrorCodes {
ARGON2_OK = 0,
ARGON2_OUTPUT_PTR_NULL = -1,
ARGON2_OUTPUT_TOO_SHORT = -2,
ARGON2_OUTPUT_TOO_LONG = -3,
ARGON2_PWD_TOO_SHORT = -4,
ARGON2_PWD_TOO_LONG = -5,
ARGON2_SALT_TOO_SHORT = -6,
ARGON2_SALT_TOO_LONG = -7,
ARGON2_AD_TOO_SHORT = -8,
ARGON2_AD_TOO_LONG = -9,
ARGON2_SECRET_TOO_SHORT = -10,
ARGON2_SECRET_TOO_LONG = -11,
ARGON2_TIME_TOO_SMALL = -12,
ARGON2_TIME_TOO_LARGE = -13,
ARGON2_MEMORY_TOO_LITTLE = -14,
ARGON2_MEMORY_TOO_MUCH = -15,
ARGON2_LANES_TOO_FEW = -16,
ARGON2_LANES_TOO_MANY = -17,
ARGON2_PWD_PTR_MISMATCH = -18, /* NULL ptr with non-zero length */
ARGON2_SALT_PTR_MISMATCH = -19, /* NULL ptr with non-zero length */
ARGON2_SECRET_PTR_MISMATCH = -20, /* NULL ptr with non-zero length */
ARGON2_AD_PTR_MISMATCH = -21, /* NULL ptr with non-zero length */
ARGON2_MEMORY_ALLOCATION_ERROR = -22,
ARGON2_FREE_MEMORY_CBK_NULL = -23,
ARGON2_ALLOCATE_MEMORY_CBK_NULL = -24,
ARGON2_INCORRECT_PARAMETER = -25,
ARGON2_INCORRECT_TYPE = -26,
ARGON2_OUT_PTR_MISMATCH = -27,
ARGON2_THREADS_TOO_FEW = -28,
ARGON2_THREADS_TOO_MANY = -29,
ARGON2_MISSING_ARGS = -30,
ARGON2_ENCODING_FAIL = -31,
ARGON2_DECODING_FAIL = -32,
ARGON2_THREAD_FAIL = -33,
ARGON2_DECODING_LENGTH_FAIL = -34,
ARGON2_VERIFY_MISMATCH = -35
} argon2_error_codes;
/* Memory allocator types --- for external allocation */
typedef int (*allocate_fptr)(uint8_t **memory, size_t bytes_to_allocate);
typedef void (*deallocate_fptr)(uint8_t *memory, size_t bytes_to_allocate);
/* Argon2 external data structures */
/*
*****
* Context: structure to hold Argon2 inputs:
* output array and its length,
* password and its length,
* salt and its length,
* secret and its length,
* associated data and its length,
* number of passes, amount of used memory (in KBytes, can be rounded up a bit)
* number of parallel threads that will be run.
* All the parameters above affect the output hash value.
* Additionally, two function pointers can be provided to allocate and
* deallocate the memory (if NULL, memory will be allocated internally).
* Also, three flags indicate whether to erase password, secret as soon as they
* are pre-hashed (and thus not needed anymore), and the entire memory
*****
* Simplest situation: you have output array out[8], password is stored in
* pwd[32], salt is stored in salt[16], you do not have keys nor associated
* data. You need to spend 1 GB of RAM and you run 5 passes of Argon2d with
* 4 parallel lanes.
* You want to erase the password, but you're OK with last pass not being
* erased. You want to use the default memory allocator.
* Then you initialize:
Argon2_Context(out,8,pwd,32,salt,16,NULL,0,NULL,0,5,1<<20,4,4,NULL,NULL,true,false,false,false)
*/
typedef struct Argon2_Context {
uint8_t *out; /* output array */
uint32_t outlen; /* digest length */
uint8_t *pwd; /* password array */
uint32_t pwdlen; /* password length */
uint8_t *salt; /* salt array */
uint32_t saltlen; /* salt length */
uint8_t *secret; /* key array */
uint32_t secretlen; /* key length */
uint8_t *ad; /* associated data array */
uint32_t adlen; /* associated data length */
uint32_t t_cost; /* number of passes */
uint32_t m_cost; /* amount of memory requested (KB) */
uint32_t lanes; /* number of lanes */
uint32_t threads; /* maximum number of threads */
uint32_t version; /* version number */
allocate_fptr allocate_cbk; /* pointer to memory allocator */
deallocate_fptr free_cbk; /* pointer to memory deallocator */
uint32_t flags; /* array of bool options */
} argon2_context;
/* Argon2 primitive type */
typedef enum Argon2_type {
Argon2_d = 0,
Argon2_i = 1,
Argon2_id = 2
} argon2_type;
/* Version of the algorithm */
typedef enum Argon2_version {
ARGON2_VERSION_10 = 0x10,
ARGON2_VERSION_13 = 0x13,
ARGON2_VERSION_NUMBER = ARGON2_VERSION_13
} argon2_version;
/*
* Function that gives the string representation of an argon2_type.
* @param type The argon2_type that we want the string for
* @param uppercase Whether the string should have the first letter uppercase
* @return NULL if invalid type, otherwise the string representation.
*/
ARGON2_PUBLIC const char *argon2_type2string(argon2_type type, int uppercase);
/*
* Function that performs memory-hard hashing with certain degree of parallelism
* @param context Pointer to the Argon2 internal structure
* @return Error code if smth is wrong, ARGON2_OK otherwise
*/
ARGON2_PUBLIC int argon2_ctx(argon2_context *context, argon2_type type);
/**
* Hashes a password with Argon2i, producing an encoded hash
* @param t_cost Number of iterations
* @param m_cost Sets memory usage to m_cost kibibytes
* @param parallelism Number of threads and compute lanes
* @param pwd Pointer to password
* @param pwdlen Password size in bytes
* @param salt Pointer to salt
* @param saltlen Salt size in bytes
* @param hashlen Desired length of the hash in bytes
* @param encoded Buffer where to write the encoded hash
* @param encodedlen Size of the buffer (thus max size of the encoded hash)
* @pre Different parallelism levels will give different results
* @pre Returns ARGON2_OK if successful
*/
ARGON2_PUBLIC int argon2i_hash_encoded(const uint32_t t_cost,
const uint32_t m_cost,
const uint32_t parallelism,
const void *pwd, const size_t pwdlen,
const void *salt, const size_t saltlen,
const size_t hashlen, char *encoded,
const size_t encodedlen);
/**
* Hashes a password with Argon2i, producing a raw hash at @hash
* @param t_cost Number of iterations
* @param m_cost Sets memory usage to m_cost kibibytes
* @param parallelism Number of threads and compute lanes
* @param pwd Pointer to password
* @param pwdlen Password size in bytes
* @param salt Pointer to salt
* @param saltlen Salt size in bytes
* @param hash Buffer where to write the raw hash - updated by the function
* @param hashlen Desired length of the hash in bytes
* @pre Different parallelism levels will give different results
* @pre Returns ARGON2_OK if successful
*/
ARGON2_PUBLIC int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
const uint32_t parallelism, const void *pwd,
const size_t pwdlen, const void *salt,
const size_t saltlen, void *hash,
const size_t hashlen);
ARGON2_PUBLIC int argon2d_hash_encoded(const uint32_t t_cost,
const uint32_t m_cost,
const uint32_t parallelism,
const void *pwd, const size_t pwdlen,
const void *salt, const size_t saltlen,
const size_t hashlen, char *encoded,
const size_t encodedlen);
ARGON2_PUBLIC int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
const uint32_t parallelism, const void *pwd,
const size_t pwdlen, const void *salt,
const size_t saltlen, void *hash,
const size_t hashlen);
ARGON2_PUBLIC int argon2id_hash_encoded(const uint32_t t_cost,
const uint32_t m_cost,
const uint32_t parallelism,
const void *pwd, const size_t pwdlen,
const void *salt, const size_t saltlen,
const size_t hashlen, char *encoded,
const size_t encodedlen);
ARGON2_PUBLIC int argon2id_hash_raw(const uint32_t t_cost,
const uint32_t m_cost,
const uint32_t parallelism, const void *pwd,
const size_t pwdlen, const void *salt,
const size_t saltlen, void *hash,
const size_t hashlen);
/* generic function underlying the above ones */
ARGON2_PUBLIC int argon2_hash(const uint32_t t_cost, const uint32_t m_cost,
const uint32_t parallelism, const void *pwd,
const size_t pwdlen, const void *salt,
const size_t saltlen, void *hash,
const size_t hashlen, char *encoded,
const size_t encodedlen, argon2_type type,
const uint32_t version);
/**
* Verifies a password against an encoded string
* Encoded string is restricted as in validate_inputs()
* @param encoded String encoding parameters, salt, hash
* @param pwd Pointer to password
* @pre Returns ARGON2_OK if successful
*/
ARGON2_PUBLIC int argon2i_verify(const char *encoded, const void *pwd,
const size_t pwdlen);
ARGON2_PUBLIC int argon2d_verify(const char *encoded, const void *pwd,
const size_t pwdlen);
ARGON2_PUBLIC int argon2id_verify(const char *encoded, const void *pwd,
const size_t pwdlen);
/* generic function underlying the above ones */
ARGON2_PUBLIC int argon2_verify(const char *encoded, const void *pwd,
const size_t pwdlen, argon2_type type);
/**
* Argon2d: Version of Argon2 that picks memory blocks depending
* on the password and salt. Only for side-channel-free
* environment!!
*****
* @param context Pointer to current Argon2 context
* @return Zero if successful, a non zero error code otherwise
*/
ARGON2_PUBLIC int argon2d_ctx(argon2_context *context);
/**
* Argon2i: Version of Argon2 that picks memory blocks
* independent on the password and salt. Good for side-channels,
* but worse w.r.t. tradeoff attacks if only one pass is used.
*****
* @param context Pointer to current Argon2 context
* @return Zero if successful, a non zero error code otherwise
*/
ARGON2_PUBLIC int argon2i_ctx(argon2_context *context);
/**
* Argon2id: Version of Argon2 where the first half-pass over memory is
* password-independent, the rest are password-dependent (on the password and
* salt). OK against side channels (they reduce to 1/2-pass Argon2i), and
* better with w.r.t. tradeoff attacks (similar to Argon2d).
*****
* @param context Pointer to current Argon2 context
* @return Zero if successful, a non zero error code otherwise
*/
ARGON2_PUBLIC int argon2id_ctx(argon2_context *context);
/**
* Verify if a given password is correct for Argon2d hashing
* @param context Pointer to current Argon2 context
* @param hash The password hash to verify. The length of the hash is
* specified by the context outlen member
* @return Zero if successful, a non zero error code otherwise
*/
ARGON2_PUBLIC int argon2d_verify_ctx(argon2_context *context, const char *hash);
/**
* Verify if a given password is correct for Argon2i hashing
* @param context Pointer to current Argon2 context
* @param hash The password hash to verify. The length of the hash is
* specified by the context outlen member
* @return Zero if successful, a non zero error code otherwise
*/
ARGON2_PUBLIC int argon2i_verify_ctx(argon2_context *context, const char *hash);
/**
* Verify if a given password is correct for Argon2id hashing
* @param context Pointer to current Argon2 context
* @param hash The password hash to verify. The length of the hash is
* specified by the context outlen member
* @return Zero if successful, a non zero error code otherwise
*/
ARGON2_PUBLIC int argon2id_verify_ctx(argon2_context *context,
const char *hash);
/* generic function underlying the above ones */
ARGON2_PUBLIC int argon2_verify_ctx(argon2_context *context, const char *hash,
argon2_type type);
/**
* Get the associated error message for given error code
* @return The error message associated with the given error code
*/
ARGON2_PUBLIC const char *argon2_error_message(int error_code);
/**
* Returns the encoded hash length for the given input parameters
* @param t_cost Number of iterations
* @param m_cost Memory usage in kibibytes
* @param parallelism Number of threads; used to compute lanes
* @param saltlen Salt size in bytes
* @param hashlen Hash size in bytes
* @param type The argon2_type that we want the encoded length for
* @return The encoded hash length in bytes
*/
ARGON2_PUBLIC size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost,
uint32_t parallelism, uint32_t saltlen,
uint32_t hashlen, argon2_type type);
#if defined(__cplusplus)
}
#endif
#endif
+156
View File
@@ -0,0 +1,156 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef PORTABLE_BLAKE2_IMPL_H
#define PORTABLE_BLAKE2_IMPL_H
#include <stdint.h>
#include <string.h>
#if defined(_MSC_VER)
#define BLAKE2_INLINE __inline
#elif defined(__GNUC__) || defined(__clang__)
#define BLAKE2_INLINE __inline__
#else
#define BLAKE2_INLINE
#endif
/* Argon2 Team - Begin Code */
/*
Not an exhaustive list, but should cover the majority of modern platforms
Additionally, the code will always be correct---this is only a performance
tweak.
*/
#if (defined(__BYTE_ORDER__) && \
(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \
defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__MIPSEL__) || \
defined(__AARCH64EL__) || defined(__amd64__) || defined(__i386__) || \
defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || \
defined(_M_ARM)
#define NATIVE_LITTLE_ENDIAN
#endif
/* Argon2 Team - End Code */
static BLAKE2_INLINE uint32_t load32(const void *src) {
#if defined(NATIVE_LITTLE_ENDIAN)
uint32_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = (const uint8_t *)src;
uint32_t w = *p++;
w |= (uint32_t)(*p++) << 8;
w |= (uint32_t)(*p++) << 16;
w |= (uint32_t)(*p++) << 24;
return w;
#endif
}
static BLAKE2_INLINE uint64_t load64(const void *src) {
#if defined(NATIVE_LITTLE_ENDIAN)
uint64_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = (const uint8_t *)src;
uint64_t w = *p++;
w |= (uint64_t)(*p++) << 8;
w |= (uint64_t)(*p++) << 16;
w |= (uint64_t)(*p++) << 24;
w |= (uint64_t)(*p++) << 32;
w |= (uint64_t)(*p++) << 40;
w |= (uint64_t)(*p++) << 48;
w |= (uint64_t)(*p++) << 56;
return w;
#endif
}
static BLAKE2_INLINE void store32(void *dst, uint32_t w) {
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = (uint8_t *)dst;
*p++ = (uint8_t)w;
w >>= 8;
*p++ = (uint8_t)w;
w >>= 8;
*p++ = (uint8_t)w;
w >>= 8;
*p++ = (uint8_t)w;
#endif
}
static BLAKE2_INLINE void store64(void *dst, uint64_t w) {
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = (uint8_t *)dst;
*p++ = (uint8_t)w;
w >>= 8;
*p++ = (uint8_t)w;
w >>= 8;
*p++ = (uint8_t)w;
w >>= 8;
*p++ = (uint8_t)w;
w >>= 8;
*p++ = (uint8_t)w;
w >>= 8;
*p++ = (uint8_t)w;
w >>= 8;
*p++ = (uint8_t)w;
w >>= 8;
*p++ = (uint8_t)w;
#endif
}
static BLAKE2_INLINE uint64_t load48(const void *src) {
const uint8_t *p = (const uint8_t *)src;
uint64_t w = *p++;
w |= (uint64_t)(*p++) << 8;
w |= (uint64_t)(*p++) << 16;
w |= (uint64_t)(*p++) << 24;
w |= (uint64_t)(*p++) << 32;
w |= (uint64_t)(*p++) << 40;
return w;
}
static BLAKE2_INLINE void store48(void *dst, uint64_t w) {
uint8_t *p = (uint8_t *)dst;
*p++ = (uint8_t)w;
w >>= 8;
*p++ = (uint8_t)w;
w >>= 8;
*p++ = (uint8_t)w;
w >>= 8;
*p++ = (uint8_t)w;
w >>= 8;
*p++ = (uint8_t)w;
w >>= 8;
*p++ = (uint8_t)w;
}
static BLAKE2_INLINE uint32_t rotr32(const uint32_t w, const unsigned c) {
return (w >> c) | (w << (32 - c));
}
static BLAKE2_INLINE uint64_t rotr64(const uint64_t w, const unsigned c) {
return (w >> c) | (w << (64 - c));
}
void clear_internal_memory(void *v, size_t n);
#endif
+89
View File
@@ -0,0 +1,89 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef PORTABLE_BLAKE2_H
#define PORTABLE_BLAKE2_H
#include "../argon2.h"
#if defined(__cplusplus)
extern "C" {
#endif
enum blake2b_constant {
BLAKE2B_BLOCKBYTES = 128,
BLAKE2B_OUTBYTES = 64,
BLAKE2B_KEYBYTES = 64,
BLAKE2B_SALTBYTES = 16,
BLAKE2B_PERSONALBYTES = 16
};
#pragma pack(push, 1)
typedef struct __blake2b_param {
uint8_t digest_length; /* 1 */
uint8_t key_length; /* 2 */
uint8_t fanout; /* 3 */
uint8_t depth; /* 4 */
uint32_t leaf_length; /* 8 */
uint64_t node_offset; /* 16 */
uint8_t node_depth; /* 17 */
uint8_t inner_length; /* 18 */
uint8_t reserved[14]; /* 32 */
uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */
uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */
} blake2b_param;
#pragma pack(pop)
typedef struct __blake2b_state {
uint64_t h[8];
uint64_t t[2];
uint64_t f[2];
uint8_t buf[BLAKE2B_BLOCKBYTES];
unsigned buflen;
unsigned outlen;
uint8_t last_node;
} blake2b_state;
/* Ensure param structs have not been wrongly padded */
/* Poor man's static_assert */
enum {
blake2_size_check_0 = 1 / !!(CHAR_BIT == 8),
blake2_size_check_2 =
1 / !!(sizeof(blake2b_param) == sizeof(uint64_t) * CHAR_BIT)
};
/* Streaming API */
ARGON2_LOCAL int blake2b_init(blake2b_state *S, size_t outlen);
ARGON2_LOCAL int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key,
size_t keylen);
ARGON2_LOCAL int blake2b_init_param(blake2b_state *S, const blake2b_param *P);
ARGON2_LOCAL int blake2b_update(blake2b_state *S, const void *in, size_t inlen);
ARGON2_LOCAL int blake2b_final(blake2b_state *S, void *out, size_t outlen);
/* Simple API */
ARGON2_LOCAL int blake2b(void *out, size_t outlen, const void *in, size_t inlen,
const void *key, size_t keylen);
/* Argon2 Team - Begin Code */
ARGON2_LOCAL int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen);
/* Argon2 Team - End Code */
#if defined(__cplusplus)
}
#endif
#endif
+390
View File
@@ -0,0 +1,390 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
static const uint64_t blake2b_IV[8] = {
UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b),
UINT64_C(0x3c6ef372fe94f82b), UINT64_C(0xa54ff53a5f1d36f1),
UINT64_C(0x510e527fade682d1), UINT64_C(0x9b05688c2b3e6c1f),
UINT64_C(0x1f83d9abfb41bd6b), UINT64_C(0x5be0cd19137e2179)};
static const unsigned int blake2b_sigma[12][16] = {
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
{14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
{11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
{7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
{9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
{2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
{12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
{13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
{6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
{10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
{14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
};
static BLAKE2_INLINE void blake2b_set_lastnode(blake2b_state *S) {
S->f[1] = (uint64_t)-1;
}
static BLAKE2_INLINE void blake2b_set_lastblock(blake2b_state *S) {
if (S->last_node) {
blake2b_set_lastnode(S);
}
S->f[0] = (uint64_t)-1;
}
static BLAKE2_INLINE void blake2b_increment_counter(blake2b_state *S,
uint64_t inc) {
S->t[0] += inc;
S->t[1] += (S->t[0] < inc);
}
static BLAKE2_INLINE void blake2b_invalidate_state(blake2b_state *S) {
clear_internal_memory(S, sizeof(*S)); /* wipe */
blake2b_set_lastblock(S); /* invalidate for further use */
}
static BLAKE2_INLINE void blake2b_init0(blake2b_state *S) {
memset(S, 0, sizeof(*S));
memcpy(S->h, blake2b_IV, sizeof(S->h));
}
int blake2b_init_param(blake2b_state *S, const blake2b_param *P) {
const unsigned char *p = (const unsigned char *)P;
unsigned int i;
if (NULL == P || NULL == S) {
return -1;
}
blake2b_init0(S);
/* IV XOR Parameter Block */
for (i = 0; i < 8; ++i) {
S->h[i] ^= load64(&p[i * sizeof(S->h[i])]);
}
S->outlen = P->digest_length;
return 0;
}
/* Sequential blake2b initialization */
int blake2b_init(blake2b_state *S, size_t outlen) {
blake2b_param P;
if (S == NULL) {
return -1;
}
if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) {
blake2b_invalidate_state(S);
return -1;
}
/* Setup Parameter Block for unkeyed BLAKE2 */
P.digest_length = (uint8_t)outlen;
P.key_length = 0;
P.fanout = 1;
P.depth = 1;
P.leaf_length = 0;
P.node_offset = 0;
P.node_depth = 0;
P.inner_length = 0;
memset(P.reserved, 0, sizeof(P.reserved));
memset(P.salt, 0, sizeof(P.salt));
memset(P.personal, 0, sizeof(P.personal));
return blake2b_init_param(S, &P);
}
int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key,
size_t keylen) {
blake2b_param P;
if (S == NULL) {
return -1;
}
if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) {
blake2b_invalidate_state(S);
return -1;
}
if ((key == 0) || (keylen == 0) || (keylen > BLAKE2B_KEYBYTES)) {
blake2b_invalidate_state(S);
return -1;
}
/* Setup Parameter Block for keyed BLAKE2 */
P.digest_length = (uint8_t)outlen;
P.key_length = (uint8_t)keylen;
P.fanout = 1;
P.depth = 1;
P.leaf_length = 0;
P.node_offset = 0;
P.node_depth = 0;
P.inner_length = 0;
memset(P.reserved, 0, sizeof(P.reserved));
memset(P.salt, 0, sizeof(P.salt));
memset(P.personal, 0, sizeof(P.personal));
if (blake2b_init_param(S, &P) < 0) {
blake2b_invalidate_state(S);
return -1;
}
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset(block, 0, BLAKE2B_BLOCKBYTES);
memcpy(block, key, keylen);
blake2b_update(S, block, BLAKE2B_BLOCKBYTES);
/* Burn the key from stack */
clear_internal_memory(block, BLAKE2B_BLOCKBYTES);
}
return 0;
}
static void blake2b_compress(blake2b_state *S, const uint8_t *block) {
uint64_t m[16];
uint64_t v[16];
unsigned int i, r;
for (i = 0; i < 16; ++i) {
m[i] = load64(block + i * sizeof(m[i]));
}
for (i = 0; i < 8; ++i) {
v[i] = S->h[i];
}
v[8] = blake2b_IV[0];
v[9] = blake2b_IV[1];
v[10] = blake2b_IV[2];
v[11] = blake2b_IV[3];
v[12] = blake2b_IV[4] ^ S->t[0];
v[13] = blake2b_IV[5] ^ S->t[1];
v[14] = blake2b_IV[6] ^ S->f[0];
v[15] = blake2b_IV[7] ^ S->f[1];
#define G(r, i, a, b, c, d) \
do { \
a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \
d = rotr64(d ^ a, 32); \
c = c + d; \
b = rotr64(b ^ c, 24); \
a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \
d = rotr64(d ^ a, 16); \
c = c + d; \
b = rotr64(b ^ c, 63); \
} while ((void)0, 0)
#define ROUND(r) \
do { \
G(r, 0, v[0], v[4], v[8], v[12]); \
G(r, 1, v[1], v[5], v[9], v[13]); \
G(r, 2, v[2], v[6], v[10], v[14]); \
G(r, 3, v[3], v[7], v[11], v[15]); \
G(r, 4, v[0], v[5], v[10], v[15]); \
G(r, 5, v[1], v[6], v[11], v[12]); \
G(r, 6, v[2], v[7], v[8], v[13]); \
G(r, 7, v[3], v[4], v[9], v[14]); \
} while ((void)0, 0)
for (r = 0; r < 12; ++r) {
ROUND(r);
}
for (i = 0; i < 8; ++i) {
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
}
#undef G
#undef ROUND
}
int blake2b_update(blake2b_state *S, const void *in, size_t inlen) {
const uint8_t *pin = (const uint8_t *)in;
if (inlen == 0) {
return 0;
}
/* Sanity check */
if (S == NULL || in == NULL) {
return -1;
}
/* Is this a reused state? */
if (S->f[0] != 0) {
return -1;
}
if (S->buflen + inlen > BLAKE2B_BLOCKBYTES) {
/* Complete current block */
size_t left = S->buflen;
size_t fill = BLAKE2B_BLOCKBYTES - left;
memcpy(&S->buf[left], pin, fill);
blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
blake2b_compress(S, S->buf);
S->buflen = 0;
inlen -= fill;
pin += fill;
/* Avoid buffer copies when possible */
while (inlen > BLAKE2B_BLOCKBYTES) {
blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
blake2b_compress(S, pin);
inlen -= BLAKE2B_BLOCKBYTES;
pin += BLAKE2B_BLOCKBYTES;
}
}
memcpy(&S->buf[S->buflen], pin, inlen);
S->buflen += (unsigned int)inlen;
return 0;
}
int blake2b_final(blake2b_state *S, void *out, size_t outlen) {
uint8_t buffer[BLAKE2B_OUTBYTES] = {0};
unsigned int i;
/* Sanity checks */
if (S == NULL || out == NULL || outlen < S->outlen) {
return -1;
}
/* Is this a reused state? */
if (S->f[0] != 0) {
return -1;
}
blake2b_increment_counter(S, S->buflen);
blake2b_set_lastblock(S);
memset(&S->buf[S->buflen], 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */
blake2b_compress(S, S->buf);
for (i = 0; i < 8; ++i) { /* Output full hash to temp buffer */
store64(buffer + sizeof(S->h[i]) * i, S->h[i]);
}
memcpy(out, buffer, S->outlen);
clear_internal_memory(buffer, sizeof(buffer));
clear_internal_memory(S->buf, sizeof(S->buf));
clear_internal_memory(S->h, sizeof(S->h));
return 0;
}
int blake2b(void *out, size_t outlen, const void *in, size_t inlen,
const void *key, size_t keylen) {
blake2b_state S;
int ret = -1;
/* Verify parameters */
if (NULL == in && inlen > 0) {
goto fail;
}
if (NULL == out || outlen == 0 || outlen > BLAKE2B_OUTBYTES) {
goto fail;
}
if ((NULL == key && keylen > 0) || keylen > BLAKE2B_KEYBYTES) {
goto fail;
}
if (keylen > 0) {
if (blake2b_init_key(&S, outlen, key, keylen) < 0) {
goto fail;
}
} else {
if (blake2b_init(&S, outlen) < 0) {
goto fail;
}
}
if (blake2b_update(&S, in, inlen) < 0) {
goto fail;
}
ret = blake2b_final(&S, out, outlen);
fail:
clear_internal_memory(&S, sizeof(S));
return ret;
}
/* Argon2 Team - Begin Code */
int blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen) {
uint8_t *out = (uint8_t *)pout;
blake2b_state blake_state;
uint8_t outlen_bytes[sizeof(uint32_t)] = {0};
int ret = -1;
if (outlen > UINT32_MAX) {
goto fail;
}
/* Ensure little-endian byte order! */
store32(outlen_bytes, (uint32_t)outlen);
#define TRY(statement) \
do { \
ret = statement; \
if (ret < 0) { \
goto fail; \
} \
} while ((void)0, 0)
if (outlen <= BLAKE2B_OUTBYTES) {
TRY(blake2b_init(&blake_state, outlen));
TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)));
TRY(blake2b_update(&blake_state, in, inlen));
TRY(blake2b_final(&blake_state, out, outlen));
} else {
uint32_t toproduce;
uint8_t out_buffer[BLAKE2B_OUTBYTES];
uint8_t in_buffer[BLAKE2B_OUTBYTES];
TRY(blake2b_init(&blake_state, BLAKE2B_OUTBYTES));
TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)));
TRY(blake2b_update(&blake_state, in, inlen));
TRY(blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES));
memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);
out += BLAKE2B_OUTBYTES / 2;
toproduce = (uint32_t)outlen - BLAKE2B_OUTBYTES / 2;
while (toproduce > BLAKE2B_OUTBYTES) {
memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);
TRY(blake2b(out_buffer, BLAKE2B_OUTBYTES, in_buffer,
BLAKE2B_OUTBYTES, NULL, 0));
memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);
out += BLAKE2B_OUTBYTES / 2;
toproduce -= BLAKE2B_OUTBYTES / 2;
}
memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);
TRY(blake2b(out_buffer, toproduce, in_buffer, BLAKE2B_OUTBYTES, NULL,
0));
memcpy(out, out_buffer, toproduce);
}
fail:
clear_internal_memory(&blake_state, sizeof(blake_state));
return ret;
#undef TRY
}
/* Argon2 Team - End Code */
+471
View File
@@ -0,0 +1,471 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef BLAKE_ROUND_MKA_OPT_H
#define BLAKE_ROUND_MKA_OPT_H
#include "blake2-impl.h"
#include <emmintrin.h>
#if defined(__SSSE3__)
#include <tmmintrin.h> /* for _mm_shuffle_epi8 and _mm_alignr_epi8 */
#endif
#if defined(__XOP__) && (defined(__GNUC__) || defined(__clang__))
#include <x86intrin.h>
#endif
#if !defined(__AVX512F__)
#if !defined(__AVX2__)
#if !defined(__XOP__)
#if defined(__SSSE3__)
#define r16 \
(_mm_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9))
#define r24 \
(_mm_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10))
#define _mm_roti_epi64(x, c) \
(-(c) == 32) \
? _mm_shuffle_epi32((x), _MM_SHUFFLE(2, 3, 0, 1)) \
: (-(c) == 24) \
? _mm_shuffle_epi8((x), r24) \
: (-(c) == 16) \
? _mm_shuffle_epi8((x), r16) \
: (-(c) == 63) \
? _mm_xor_si128(_mm_srli_epi64((x), -(c)), \
_mm_add_epi64((x), (x))) \
: _mm_xor_si128(_mm_srli_epi64((x), -(c)), \
_mm_slli_epi64((x), 64 - (-(c))))
#else /* defined(__SSE2__) */
#define _mm_roti_epi64(r, c) \
_mm_xor_si128(_mm_srli_epi64((r), -(c)), _mm_slli_epi64((r), 64 - (-(c))))
#endif
#else
#endif
static BLAKE2_INLINE __m128i fBlaMka(__m128i x, __m128i y) {
const __m128i z = _mm_mul_epu32(x, y);
return _mm_add_epi64(_mm_add_epi64(x, y), _mm_add_epi64(z, z));
}
#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
A0 = fBlaMka(A0, B0); \
A1 = fBlaMka(A1, B1); \
\
D0 = _mm_xor_si128(D0, A0); \
D1 = _mm_xor_si128(D1, A1); \
\
D0 = _mm_roti_epi64(D0, -32); \
D1 = _mm_roti_epi64(D1, -32); \
\
C0 = fBlaMka(C0, D0); \
C1 = fBlaMka(C1, D1); \
\
B0 = _mm_xor_si128(B0, C0); \
B1 = _mm_xor_si128(B1, C1); \
\
B0 = _mm_roti_epi64(B0, -24); \
B1 = _mm_roti_epi64(B1, -24); \
} while ((void)0, 0)
#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
A0 = fBlaMka(A0, B0); \
A1 = fBlaMka(A1, B1); \
\
D0 = _mm_xor_si128(D0, A0); \
D1 = _mm_xor_si128(D1, A1); \
\
D0 = _mm_roti_epi64(D0, -16); \
D1 = _mm_roti_epi64(D1, -16); \
\
C0 = fBlaMka(C0, D0); \
C1 = fBlaMka(C1, D1); \
\
B0 = _mm_xor_si128(B0, C0); \
B1 = _mm_xor_si128(B1, C1); \
\
B0 = _mm_roti_epi64(B0, -63); \
B1 = _mm_roti_epi64(B1, -63); \
} while ((void)0, 0)
#if defined(__SSSE3__)
#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
__m128i t0 = _mm_alignr_epi8(B1, B0, 8); \
__m128i t1 = _mm_alignr_epi8(B0, B1, 8); \
B0 = t0; \
B1 = t1; \
\
t0 = C0; \
C0 = C1; \
C1 = t0; \
\
t0 = _mm_alignr_epi8(D1, D0, 8); \
t1 = _mm_alignr_epi8(D0, D1, 8); \
D0 = t1; \
D1 = t0; \
} while ((void)0, 0)
#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
__m128i t0 = _mm_alignr_epi8(B0, B1, 8); \
__m128i t1 = _mm_alignr_epi8(B1, B0, 8); \
B0 = t0; \
B1 = t1; \
\
t0 = C0; \
C0 = C1; \
C1 = t0; \
\
t0 = _mm_alignr_epi8(D0, D1, 8); \
t1 = _mm_alignr_epi8(D1, D0, 8); \
D0 = t1; \
D1 = t0; \
} while ((void)0, 0)
#else /* SSE2 */
#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
__m128i t0 = D0; \
__m128i t1 = B0; \
D0 = C0; \
C0 = C1; \
C1 = D0; \
D0 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t0, t0)); \
D1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(D1, D1)); \
B0 = _mm_unpackhi_epi64(B0, _mm_unpacklo_epi64(B1, B1)); \
B1 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(t1, t1)); \
} while ((void)0, 0)
#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
__m128i t0, t1; \
t0 = C0; \
C0 = C1; \
C1 = t0; \
t0 = B0; \
t1 = D0; \
B0 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(B0, B0)); \
B1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(B1, B1)); \
D0 = _mm_unpackhi_epi64(D0, _mm_unpacklo_epi64(D1, D1)); \
D1 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t1, t1)); \
} while ((void)0, 0)
#endif
#define BLAKE2_ROUND(A0, A1, B0, B1, C0, C1, D0, D1) \
do { \
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
\
DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
\
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
\
UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
} while ((void)0, 0)
#else /* __AVX2__ */
#include <immintrin.h>
#define rotr32(x) _mm256_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1))
#define rotr24(x) _mm256_shuffle_epi8(x, _mm256_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10, 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10))
#define rotr16(x) _mm256_shuffle_epi8(x, _mm256_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9, 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9))
#define rotr63(x) _mm256_xor_si256(_mm256_srli_epi64((x), 63), _mm256_add_epi64((x), (x)))
#define G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
do { \
__m256i ml = _mm256_mul_epu32(A0, B0); \
ml = _mm256_add_epi64(ml, ml); \
A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \
D0 = _mm256_xor_si256(D0, A0); \
D0 = rotr32(D0); \
\
ml = _mm256_mul_epu32(C0, D0); \
ml = _mm256_add_epi64(ml, ml); \
C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \
\
B0 = _mm256_xor_si256(B0, C0); \
B0 = rotr24(B0); \
\
ml = _mm256_mul_epu32(A1, B1); \
ml = _mm256_add_epi64(ml, ml); \
A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \
D1 = _mm256_xor_si256(D1, A1); \
D1 = rotr32(D1); \
\
ml = _mm256_mul_epu32(C1, D1); \
ml = _mm256_add_epi64(ml, ml); \
C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \
\
B1 = _mm256_xor_si256(B1, C1); \
B1 = rotr24(B1); \
} while((void)0, 0);
#define G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
do { \
__m256i ml = _mm256_mul_epu32(A0, B0); \
ml = _mm256_add_epi64(ml, ml); \
A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \
D0 = _mm256_xor_si256(D0, A0); \
D0 = rotr16(D0); \
\
ml = _mm256_mul_epu32(C0, D0); \
ml = _mm256_add_epi64(ml, ml); \
C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \
B0 = _mm256_xor_si256(B0, C0); \
B0 = rotr63(B0); \
\
ml = _mm256_mul_epu32(A1, B1); \
ml = _mm256_add_epi64(ml, ml); \
A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \
D1 = _mm256_xor_si256(D1, A1); \
D1 = rotr16(D1); \
\
ml = _mm256_mul_epu32(C1, D1); \
ml = _mm256_add_epi64(ml, ml); \
C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \
B1 = _mm256_xor_si256(B1, C1); \
B1 = rotr63(B1); \
} while((void)0, 0);
#define DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \
C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \
\
B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \
C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \
} while((void)0, 0);
#define DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
do { \
__m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \
__m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \
B1 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
B0 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
\
tmp1 = C0; \
C0 = C1; \
C1 = tmp1; \
\
tmp1 = _mm256_blend_epi32(D0, D1, 0xCC); \
tmp2 = _mm256_blend_epi32(D0, D1, 0x33); \
D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
} while(0);
#define UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \
C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \
\
B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \
C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \
} while((void)0, 0);
#define UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
do { \
__m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \
__m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \
B0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
B1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
\
tmp1 = C0; \
C0 = C1; \
C1 = tmp1; \
\
tmp1 = _mm256_blend_epi32(D0, D1, 0x33); \
tmp2 = _mm256_blend_epi32(D0, D1, 0xCC); \
D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
} while((void)0, 0);
#define BLAKE2_ROUND_1(A0, A1, B0, B1, C0, C1, D0, D1) \
do{ \
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
\
DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
\
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
\
UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
} while((void)0, 0);
#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \
do{ \
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
\
DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
\
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
\
UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
} while((void)0, 0);
#endif /* __AVX2__ */
#else /* __AVX512F__ */
#include <immintrin.h>
#define ror64(x, n) _mm512_ror_epi64((x), (n))
static __m512i muladd(__m512i x, __m512i y)
{
__m512i z = _mm512_mul_epu32(x, y);
return _mm512_add_epi64(_mm512_add_epi64(x, y), _mm512_add_epi64(z, z));
}
#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
A0 = muladd(A0, B0); \
A1 = muladd(A1, B1); \
\
D0 = _mm512_xor_si512(D0, A0); \
D1 = _mm512_xor_si512(D1, A1); \
\
D0 = ror64(D0, 32); \
D1 = ror64(D1, 32); \
\
C0 = muladd(C0, D0); \
C1 = muladd(C1, D1); \
\
B0 = _mm512_xor_si512(B0, C0); \
B1 = _mm512_xor_si512(B1, C1); \
\
B0 = ror64(B0, 24); \
B1 = ror64(B1, 24); \
} while ((void)0, 0)
#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
A0 = muladd(A0, B0); \
A1 = muladd(A1, B1); \
\
D0 = _mm512_xor_si512(D0, A0); \
D1 = _mm512_xor_si512(D1, A1); \
\
D0 = ror64(D0, 16); \
D1 = ror64(D1, 16); \
\
C0 = muladd(C0, D0); \
C1 = muladd(C1, D1); \
\
B0 = _mm512_xor_si512(B0, C0); \
B1 = _mm512_xor_si512(B1, C1); \
\
B0 = ror64(B0, 63); \
B1 = ror64(B1, 63); \
} while ((void)0, 0)
#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \
B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \
\
C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
\
D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \
D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \
} while ((void)0, 0)
#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \
B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \
\
C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
\
D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \
D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \
} while ((void)0, 0)
#define BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
\
DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
\
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
\
UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
} while ((void)0, 0)
#define SWAP_HALVES(A0, A1) \
do { \
__m512i t0, t1; \
t0 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(1, 0, 1, 0)); \
t1 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(3, 2, 3, 2)); \
A0 = t0; \
A1 = t1; \
} while((void)0, 0)
#define SWAP_QUARTERS(A0, A1) \
do { \
SWAP_HALVES(A0, A1); \
A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \
A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \
} while((void)0, 0)
#define UNSWAP_QUARTERS(A0, A1) \
do { \
A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \
A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \
SWAP_HALVES(A0, A1); \
} while((void)0, 0)
#define BLAKE2_ROUND_1(A0, C0, B0, D0, A1, C1, B1, D1) \
do { \
SWAP_HALVES(A0, B0); \
SWAP_HALVES(C0, D0); \
SWAP_HALVES(A1, B1); \
SWAP_HALVES(C1, D1); \
BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \
SWAP_HALVES(A0, B0); \
SWAP_HALVES(C0, D0); \
SWAP_HALVES(A1, B1); \
SWAP_HALVES(C1, D1); \
} while ((void)0, 0)
#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \
do { \
SWAP_QUARTERS(A0, A1); \
SWAP_QUARTERS(B0, B1); \
SWAP_QUARTERS(C0, C1); \
SWAP_QUARTERS(D0, D1); \
BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \
UNSWAP_QUARTERS(A0, A1); \
UNSWAP_QUARTERS(B0, B1); \
UNSWAP_QUARTERS(C0, C1); \
UNSWAP_QUARTERS(D0, D1); \
} while ((void)0, 0)
#endif /* __AVX512F__ */
#endif /* BLAKE_ROUND_MKA_OPT_H */
@@ -0,0 +1,56 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef BLAKE_ROUND_MKA_H
#define BLAKE_ROUND_MKA_H
#include "blake2.h"
#include "blake2-impl.h"
/* designed by the Lyra PHC team */
static BLAKE2_INLINE uint64_t fBlaMka(uint64_t x, uint64_t y) {
const uint64_t m = UINT64_C(0xFFFFFFFF);
const uint64_t xy = (x & m) * (y & m);
return x + y + 2 * xy;
}
#define G(a, b, c, d) \
do { \
a = fBlaMka(a, b); \
d = rotr64(d ^ a, 32); \
c = fBlaMka(c, d); \
b = rotr64(b ^ c, 24); \
a = fBlaMka(a, b); \
d = rotr64(d ^ a, 16); \
c = fBlaMka(c, d); \
b = rotr64(b ^ c, 63); \
} while ((void)0, 0)
#define BLAKE2_ROUND_NOMSG(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, \
v12, v13, v14, v15) \
do { \
G(v0, v4, v8, v12); \
G(v1, v5, v9, v13); \
G(v2, v6, v10, v14); \
G(v3, v7, v11, v15); \
G(v0, v5, v10, v15); \
G(v1, v6, v11, v12); \
G(v2, v7, v8, v13); \
G(v3, v4, v9, v14); \
} while ((void)0, 0)
#endif
+648
View File
@@ -0,0 +1,648 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
/*For memory wiping*/
#ifdef _MSC_VER
#include <windows.h>
#include <winbase.h> /* For SecureZeroMemory */
#endif
#if defined __STDC_LIB_EXT1__
#define __STDC_WANT_LIB_EXT1__ 1
#endif
#define VC_GE_2005(version) (version >= 1400)
/* for explicit_bzero() on glibc */
#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "core.h"
#include "thread.h"
#include "blake2/blake2.h"
#include "blake2/blake2-impl.h"
#ifdef GENKAT
#include "genkat.h"
#endif
#if defined(__clang__)
#if __has_attribute(optnone)
#define NOT_OPTIMIZED __attribute__((optnone))
#endif
#elif defined(__GNUC__)
#define GCC_VERSION \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#if GCC_VERSION >= 40400
#define NOT_OPTIMIZED __attribute__((optimize("O0")))
#endif
#endif
#ifndef NOT_OPTIMIZED
#define NOT_OPTIMIZED
#endif
/***************Instance and Position constructors**********/
void init_block_value(block *b, uint8_t in) { memset(b->v, in, sizeof(b->v)); }
void copy_block(block *dst, const block *src) {
memcpy(dst->v, src->v, sizeof(uint64_t) * ARGON2_QWORDS_IN_BLOCK);
}
void xor_block(block *dst, const block *src) {
int i;
for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
dst->v[i] ^= src->v[i];
}
}
static void load_block(block *dst, const void *input) {
unsigned i;
for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
dst->v[i] = load64((const uint8_t *)input + i * sizeof(dst->v[i]));
}
}
static void store_block(void *output, const block *src) {
unsigned i;
for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
store64((uint8_t *)output + i * sizeof(src->v[i]), src->v[i]);
}
}
/***************Memory functions*****************/
int allocate_memory(const argon2_context *context, uint8_t **memory,
size_t num, size_t size) {
size_t memory_size = num*size;
if (memory == NULL) {
return ARGON2_MEMORY_ALLOCATION_ERROR;
}
/* 1. Check for multiplication overflow */
if (size != 0 && memory_size / size != num) {
return ARGON2_MEMORY_ALLOCATION_ERROR;
}
/* 2. Try to allocate with appropriate allocator */
if (context->allocate_cbk) {
(context->allocate_cbk)(memory, memory_size);
} else {
*memory = malloc(memory_size);
}
if (*memory == NULL) {
return ARGON2_MEMORY_ALLOCATION_ERROR;
}
return ARGON2_OK;
}
void free_memory(const argon2_context *context, uint8_t *memory,
size_t num, size_t size) {
size_t memory_size = num*size;
clear_internal_memory(memory, memory_size);
if (context->free_cbk) {
(context->free_cbk)(memory, memory_size);
} else {
free(memory);
}
}
#if defined(__OpenBSD__)
#define HAVE_EXPLICIT_BZERO 1
#elif defined(__GLIBC__) && defined(__GLIBC_PREREQ)
#if __GLIBC_PREREQ(2,25)
#define HAVE_EXPLICIT_BZERO 1
#endif
#endif
void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) {
#if defined(_MSC_VER) && VC_GE_2005(_MSC_VER)
SecureZeroMemory(v, n);
#elif defined memset_s
memset_s(v, n, 0, n);
#elif defined(HAVE_EXPLICIT_BZERO)
explicit_bzero(v, n);
#else
static void *(*const volatile memset_sec)(void *, int, size_t) = &memset;
memset_sec(v, 0, n);
#endif
}
/* Memory clear flag defaults to true. */
int FLAG_clear_internal_memory = 1;
void clear_internal_memory(void *v, size_t n) {
if (FLAG_clear_internal_memory && v) {
secure_wipe_memory(v, n);
}
}
void finalize(const argon2_context *context, argon2_instance_t *instance) {
if (context != NULL && instance != NULL) {
block blockhash;
uint32_t l;
copy_block(&blockhash, instance->memory + instance->lane_length - 1);
/* XOR the last blocks */
for (l = 1; l < instance->lanes; ++l) {
uint32_t last_block_in_lane =
l * instance->lane_length + (instance->lane_length - 1);
xor_block(&blockhash, instance->memory + last_block_in_lane);
}
/* Hash the result */
{
uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];
store_block(blockhash_bytes, &blockhash);
blake2b_long(context->out, context->outlen, blockhash_bytes,
ARGON2_BLOCK_SIZE);
/* clear blockhash and blockhash_bytes */
clear_internal_memory(blockhash.v, ARGON2_BLOCK_SIZE);
clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE);
}
#ifdef GENKAT
print_tag(context->out, context->outlen);
#endif
free_memory(context, (uint8_t *)instance->memory,
instance->memory_blocks, sizeof(block));
}
}
uint32_t index_alpha(const argon2_instance_t *instance,
const argon2_position_t *position, uint32_t pseudo_rand,
int same_lane) {
/*
* Pass 0:
* This lane : all already finished segments plus already constructed
* blocks in this segment
* Other lanes : all already finished segments
* Pass 1+:
* This lane : (SYNC_POINTS - 1) last segments plus already constructed
* blocks in this segment
* Other lanes : (SYNC_POINTS - 1) last segments
*/
uint32_t reference_area_size;
uint64_t relative_position;
uint32_t start_position, absolute_position;
if (0 == position->pass) {
/* First pass */
if (0 == position->slice) {
/* First slice */
reference_area_size =
position->index - 1; /* all but the previous */
} else {
if (same_lane) {
/* The same lane => add current segment */
reference_area_size =
position->slice * instance->segment_length +
position->index - 1;
} else {
reference_area_size =
position->slice * instance->segment_length +
((position->index == 0) ? (-1) : 0);
}
}
} else {
/* Second pass */
if (same_lane) {
reference_area_size = instance->lane_length -
instance->segment_length + position->index -
1;
} else {
reference_area_size = instance->lane_length -
instance->segment_length +
((position->index == 0) ? (-1) : 0);
}
}
/* 1.2.4. Mapping pseudo_rand to 0..<reference_area_size-1> and produce
* relative position */
relative_position = pseudo_rand;
relative_position = relative_position * relative_position >> 32;
relative_position = reference_area_size - 1 -
(reference_area_size * relative_position >> 32);
/* 1.2.5 Computing starting position */
start_position = 0;
if (0 != position->pass) {
start_position = (position->slice == ARGON2_SYNC_POINTS - 1)
? 0
: (position->slice + 1) * instance->segment_length;
}
/* 1.2.6. Computing absolute position */
absolute_position = (start_position + relative_position) %
instance->lane_length; /* absolute position */
return absolute_position;
}
/* Single-threaded version for p=1 case */
static int fill_memory_blocks_st(argon2_instance_t *instance) {
uint32_t r, s, l;
for (r = 0; r < instance->passes; ++r) {
for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {
for (l = 0; l < instance->lanes; ++l) {
argon2_position_t position = {r, l, (uint8_t)s, 0};
fill_segment(instance, position);
}
}
#ifdef GENKAT
internal_kat(instance, r); /* Print all memory blocks */
#endif
}
return ARGON2_OK;
}
#if !defined(ARGON2_NO_THREADS)
#ifdef _WIN32
static unsigned __stdcall fill_segment_thr(void *thread_data)
#else
static void *fill_segment_thr(void *thread_data)
#endif
{
argon2_thread_data *my_data = thread_data;
fill_segment(my_data->instance_ptr, my_data->pos);
argon2_thread_exit();
return 0;
}
/* Multi-threaded version for p > 1 case */
static int fill_memory_blocks_mt(argon2_instance_t *instance) {
uint32_t r, s;
argon2_thread_handle_t *thread = NULL;
argon2_thread_data *thr_data = NULL;
int rc = ARGON2_OK;
/* 1. Allocating space for threads */
thread = calloc(instance->lanes, sizeof(argon2_thread_handle_t));
if (thread == NULL) {
rc = ARGON2_MEMORY_ALLOCATION_ERROR;
goto fail;
}
thr_data = calloc(instance->lanes, sizeof(argon2_thread_data));
if (thr_data == NULL) {
rc = ARGON2_MEMORY_ALLOCATION_ERROR;
goto fail;
}
for (r = 0; r < instance->passes; ++r) {
for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {
uint32_t l, ll;
/* 2. Calling threads */
for (l = 0; l < instance->lanes; ++l) {
argon2_position_t position;
/* 2.1 Join a thread if limit is exceeded */
if (l >= instance->threads) {
if (argon2_thread_join(thread[l - instance->threads])) {
rc = ARGON2_THREAD_FAIL;
goto fail;
}
}
/* 2.2 Create thread */
position.pass = r;
position.lane = l;
position.slice = (uint8_t)s;
position.index = 0;
thr_data[l].instance_ptr =
instance; /* preparing the thread input */
memcpy(&(thr_data[l].pos), &position,
sizeof(argon2_position_t));
if (argon2_thread_create(&thread[l], &fill_segment_thr,
(void *)&thr_data[l])) {
/* Wait for already running threads */
for (ll = 0; ll < l; ++ll)
argon2_thread_join(thread[ll]);
rc = ARGON2_THREAD_FAIL;
goto fail;
}
/* fill_segment(instance, position); */
/*Non-thread equivalent of the lines above */
}
/* 3. Joining remaining threads */
for (l = instance->lanes - instance->threads; l < instance->lanes;
++l) {
if (argon2_thread_join(thread[l])) {
rc = ARGON2_THREAD_FAIL;
goto fail;
}
}
}
#ifdef GENKAT
internal_kat(instance, r); /* Print all memory blocks */
#endif
}
fail:
if (thread != NULL) {
free(thread);
}
if (thr_data != NULL) {
free(thr_data);
}
return rc;
}
#endif /* ARGON2_NO_THREADS */
int fill_memory_blocks(argon2_instance_t *instance) {
if (instance == NULL || instance->lanes == 0) {
return ARGON2_INCORRECT_PARAMETER;
}
#if defined(ARGON2_NO_THREADS)
return fill_memory_blocks_st(instance);
#else
return instance->threads == 1 ?
fill_memory_blocks_st(instance) : fill_memory_blocks_mt(instance);
#endif
}
int validate_inputs(const argon2_context *context) {
if (NULL == context) {
return ARGON2_INCORRECT_PARAMETER;
}
if (NULL == context->out) {
return ARGON2_OUTPUT_PTR_NULL;
}
/* Validate output length */
if (ARGON2_MIN_OUTLEN > context->outlen) {
return ARGON2_OUTPUT_TOO_SHORT;
}
if (ARGON2_MAX_OUTLEN < context->outlen) {
return ARGON2_OUTPUT_TOO_LONG;
}
/* Validate password (required param) */
if (NULL == context->pwd) {
if (0 != context->pwdlen) {
return ARGON2_PWD_PTR_MISMATCH;
}
}
if (ARGON2_MIN_PWD_LENGTH > context->pwdlen) {
return ARGON2_PWD_TOO_SHORT;
}
if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) {
return ARGON2_PWD_TOO_LONG;
}
/* Validate salt (required param) */
if (NULL == context->salt) {
if (0 != context->saltlen) {
return ARGON2_SALT_PTR_MISMATCH;
}
}
if (ARGON2_MIN_SALT_LENGTH > context->saltlen) {
return ARGON2_SALT_TOO_SHORT;
}
if (ARGON2_MAX_SALT_LENGTH < context->saltlen) {
return ARGON2_SALT_TOO_LONG;
}
/* Validate secret (optional param) */
if (NULL == context->secret) {
if (0 != context->secretlen) {
return ARGON2_SECRET_PTR_MISMATCH;
}
} else {
if (ARGON2_MIN_SECRET > context->secretlen) {
return ARGON2_SECRET_TOO_SHORT;
}
if (ARGON2_MAX_SECRET < context->secretlen) {
return ARGON2_SECRET_TOO_LONG;
}
}
/* Validate associated data (optional param) */
if (NULL == context->ad) {
if (0 != context->adlen) {
return ARGON2_AD_PTR_MISMATCH;
}
} else {
if (ARGON2_MIN_AD_LENGTH > context->adlen) {
return ARGON2_AD_TOO_SHORT;
}
if (ARGON2_MAX_AD_LENGTH < context->adlen) {
return ARGON2_AD_TOO_LONG;
}
}
/* Validate memory cost */
if (ARGON2_MIN_MEMORY > context->m_cost) {
return ARGON2_MEMORY_TOO_LITTLE;
}
if (ARGON2_MAX_MEMORY < context->m_cost) {
return ARGON2_MEMORY_TOO_MUCH;
}
if (context->m_cost < 8 * context->lanes) {
return ARGON2_MEMORY_TOO_LITTLE;
}
/* Validate time cost */
if (ARGON2_MIN_TIME > context->t_cost) {
return ARGON2_TIME_TOO_SMALL;
}
if (ARGON2_MAX_TIME < context->t_cost) {
return ARGON2_TIME_TOO_LARGE;
}
/* Validate lanes */
if (ARGON2_MIN_LANES > context->lanes) {
return ARGON2_LANES_TOO_FEW;
}
if (ARGON2_MAX_LANES < context->lanes) {
return ARGON2_LANES_TOO_MANY;
}
/* Validate threads */
if (ARGON2_MIN_THREADS > context->threads) {
return ARGON2_THREADS_TOO_FEW;
}
if (ARGON2_MAX_THREADS < context->threads) {
return ARGON2_THREADS_TOO_MANY;
}
if (NULL != context->allocate_cbk && NULL == context->free_cbk) {
return ARGON2_FREE_MEMORY_CBK_NULL;
}
if (NULL == context->allocate_cbk && NULL != context->free_cbk) {
return ARGON2_ALLOCATE_MEMORY_CBK_NULL;
}
return ARGON2_OK;
}
void fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance) {
uint32_t l;
/* Make the first and second block in each lane as G(H0||0||i) or
G(H0||1||i) */
uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];
for (l = 0; l < instance->lanes; ++l) {
store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0);
store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l);
blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash,
ARGON2_PREHASH_SEED_LENGTH);
load_block(&instance->memory[l * instance->lane_length + 0],
blockhash_bytes);
store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1);
blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash,
ARGON2_PREHASH_SEED_LENGTH);
load_block(&instance->memory[l * instance->lane_length + 1],
blockhash_bytes);
}
clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE);
}
void initial_hash(uint8_t *blockhash, argon2_context *context,
argon2_type type) {
blake2b_state BlakeHash;
uint8_t value[sizeof(uint32_t)];
if (NULL == context || NULL == blockhash) {
return;
}
blake2b_init(&BlakeHash, ARGON2_PREHASH_DIGEST_LENGTH);
store32(&value, context->lanes);
blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));
store32(&value, context->outlen);
blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));
store32(&value, context->m_cost);
blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));
store32(&value, context->t_cost);
blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));
store32(&value, context->version);
blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));
store32(&value, (uint32_t)type);
blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));
store32(&value, context->pwdlen);
blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));
if (context->pwd != NULL) {
blake2b_update(&BlakeHash, (const uint8_t *)context->pwd,
context->pwdlen);
if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) {
secure_wipe_memory(context->pwd, context->pwdlen);
context->pwdlen = 0;
}
}
store32(&value, context->saltlen);
blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));
if (context->salt != NULL) {
blake2b_update(&BlakeHash, (const uint8_t *)context->salt,
context->saltlen);
}
store32(&value, context->secretlen);
blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));
if (context->secret != NULL) {
blake2b_update(&BlakeHash, (const uint8_t *)context->secret,
context->secretlen);
if (context->flags & ARGON2_FLAG_CLEAR_SECRET) {
secure_wipe_memory(context->secret, context->secretlen);
context->secretlen = 0;
}
}
store32(&value, context->adlen);
blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));
if (context->ad != NULL) {
blake2b_update(&BlakeHash, (const uint8_t *)context->ad,
context->adlen);
}
blake2b_final(&BlakeHash, blockhash, ARGON2_PREHASH_DIGEST_LENGTH);
}
int initialize(argon2_instance_t *instance, argon2_context *context) {
uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH];
int result = ARGON2_OK;
if (instance == NULL || context == NULL)
return ARGON2_INCORRECT_PARAMETER;
instance->context_ptr = context;
/* 1. Memory allocation */
result = allocate_memory(context, (uint8_t **)&(instance->memory),
instance->memory_blocks, sizeof(block));
if (result != ARGON2_OK) {
return result;
}
/* 2. Initial hashing */
/* H_0 + 8 extra bytes to produce the first blocks */
/* uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; */
/* Hashing all inputs */
initial_hash(blockhash, context, instance->type);
/* Zeroing 8 extra bytes */
clear_internal_memory(blockhash + ARGON2_PREHASH_DIGEST_LENGTH,
ARGON2_PREHASH_SEED_LENGTH -
ARGON2_PREHASH_DIGEST_LENGTH);
#ifdef GENKAT
initial_kat(blockhash, context, instance->type);
#endif
/* 3. Creating first blocks, we always have at least two blocks in a slice
*/
fill_first_blocks(blockhash, instance);
/* Clearing the hash */
clear_internal_memory(blockhash, ARGON2_PREHASH_SEED_LENGTH);
return ARGON2_OK;
}
+228
View File
@@ -0,0 +1,228 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef ARGON2_CORE_H
#define ARGON2_CORE_H
#include "argon2.h"
#define CONST_CAST(x) (x)(uintptr_t)
/**********************Argon2 internal constants*******************************/
enum argon2_core_constants {
/* Memory block size in bytes */
ARGON2_BLOCK_SIZE = 1024,
ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8,
ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16,
ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32,
ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64,
/* Number of pseudo-random values generated by one call to Blake in Argon2i
to
generate reference block positions */
ARGON2_ADDRESSES_IN_BLOCK = 128,
/* Pre-hashing digest length and its extension*/
ARGON2_PREHASH_DIGEST_LENGTH = 64,
ARGON2_PREHASH_SEED_LENGTH = 72
};
/*************************Argon2 internal data types***********************/
/*
* Structure for the (1KB) memory block implemented as 128 64-bit words.
* Memory blocks can be copied, XORed. Internal words can be accessed by [] (no
* bounds checking).
*/
typedef struct block_ { uint64_t v[ARGON2_QWORDS_IN_BLOCK]; } block;
/*****************Functions that work with the block******************/
/* Initialize each byte of the block with @in */
void init_block_value(block *b, uint8_t in);
/* Copy block @src to block @dst */
void copy_block(block *dst, const block *src);
/* XOR @src onto @dst bytewise */
void xor_block(block *dst, const block *src);
/*
* Argon2 instance: memory pointer, number of passes, amount of memory, type,
* and derived values.
* Used to evaluate the number and location of blocks to construct in each
* thread
*/
typedef struct Argon2_instance_t {
block *memory; /* Memory pointer */
uint32_t version;
uint32_t passes; /* Number of passes */
uint32_t memory_blocks; /* Number of blocks in memory */
uint32_t segment_length;
uint32_t lane_length;
uint32_t lanes;
uint32_t threads;
argon2_type type;
int print_internals; /* whether to print the memory blocks */
argon2_context *context_ptr; /* points back to original context */
} argon2_instance_t;
/*
* Argon2 position: where we construct the block right now. Used to distribute
* work between threads.
*/
typedef struct Argon2_position_t {
uint32_t pass;
uint32_t lane;
uint8_t slice;
uint32_t index;
} argon2_position_t;
/*Struct that holds the inputs for thread handling FillSegment*/
typedef struct Argon2_thread_data {
argon2_instance_t *instance_ptr;
argon2_position_t pos;
} argon2_thread_data;
/*************************Argon2 core functions********************************/
/* Allocates memory to the given pointer, uses the appropriate allocator as
* specified in the context. Total allocated memory is num*size.
* @param context argon2_context which specifies the allocator
* @param memory pointer to the pointer to the memory
* @param size the size in bytes for each element to be allocated
* @param num the number of elements to be allocated
* @return ARGON2_OK if @memory is a valid pointer and memory is allocated
*/
int allocate_memory(const argon2_context *context, uint8_t **memory,
size_t num, size_t size);
/*
* Frees memory at the given pointer, uses the appropriate deallocator as
* specified in the context. Also cleans the memory using clear_internal_memory.
* @param context argon2_context which specifies the deallocator
* @param memory pointer to buffer to be freed
* @param size the size in bytes for each element to be deallocated
* @param num the number of elements to be deallocated
*/
void free_memory(const argon2_context *context, uint8_t *memory,
size_t num, size_t size);
/* Function that securely cleans the memory. This ignores any flags set
* regarding clearing memory. Usually one just calls clear_internal_memory.
* @param mem Pointer to the memory
* @param s Memory size in bytes
*/
void secure_wipe_memory(void *v, size_t n);
/* Function that securely clears the memory if FLAG_clear_internal_memory is
* set. If the flag isn't set, this function does nothing.
* @param mem Pointer to the memory
* @param s Memory size in bytes
*/
void clear_internal_memory(void *v, size_t n);
/*
* Computes absolute position of reference block in the lane following a skewed
* distribution and using a pseudo-random value as input
* @param instance Pointer to the current instance
* @param position Pointer to the current position
* @param pseudo_rand 32-bit pseudo-random value used to determine the position
* @param same_lane Indicates if the block will be taken from the current lane.
* If so we can reference the current segment
* @pre All pointers must be valid
*/
uint32_t index_alpha(const argon2_instance_t *instance,
const argon2_position_t *position, uint32_t pseudo_rand,
int same_lane);
/*
* Function that validates all inputs against predefined restrictions and return
* an error code
* @param context Pointer to current Argon2 context
* @return ARGON2_OK if everything is all right, otherwise one of error codes
* (all defined in <argon2.h>
*/
int validate_inputs(const argon2_context *context);
/*
* Hashes all the inputs into @a blockhash[PREHASH_DIGEST_LENGTH], clears
* password and secret if needed
* @param context Pointer to the Argon2 internal structure containing memory
* pointer, and parameters for time and space requirements.
* @param blockhash Buffer for pre-hashing digest
* @param type Argon2 type
* @pre @a blockhash must have at least @a PREHASH_DIGEST_LENGTH bytes
* allocated
*/
void initial_hash(uint8_t *blockhash, argon2_context *context,
argon2_type type);
/*
* Function creates first 2 blocks per lane
* @param instance Pointer to the current instance
* @param blockhash Pointer to the pre-hashing digest
* @pre blockhash must point to @a PREHASH_SEED_LENGTH allocated values
*/
void fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance);
/*
* Function allocates memory, hashes the inputs with Blake, and creates first
* two blocks. Returns the pointer to the main memory with 2 blocks per lane
* initialized
* @param context Pointer to the Argon2 internal structure containing memory
* pointer, and parameters for time and space requirements.
* @param instance Current Argon2 instance
* @return Zero if successful, -1 if memory failed to allocate. @context->state
* will be modified if successful.
*/
int initialize(argon2_instance_t *instance, argon2_context *context);
/*
* XORing the last block of each lane, hashing it, making the tag. Deallocates
* the memory.
* @param context Pointer to current Argon2 context (use only the out parameters
* from it)
* @param instance Pointer to current instance of Argon2
* @pre instance->state must point to necessary amount of memory
* @pre context->out must point to outlen bytes of memory
* @pre if context->free_cbk is not NULL, it should point to a function that
* deallocates memory
*/
void finalize(const argon2_context *context, argon2_instance_t *instance);
/*
* Function that fills the segment using previous segments also from other
* threads
* @param context current context
* @param instance Pointer to the current instance
* @param position Current position
* @pre all block pointers must be valid
*/
void fill_segment(const argon2_instance_t *instance,
argon2_position_t position);
/*
* Function that fills the entire memory t_cost times based on the first two
* blocks in each lane
* @param instance Pointer to the current instance
* @return ARGON2_OK if successful, @context->state
*/
int fill_memory_blocks(argon2_instance_t *instance);
#endif
+463
View File
@@ -0,0 +1,463 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "encoding.h"
#include "core.h"
/*
* Example code for a decoder and encoder of "hash strings", with Argon2
* parameters.
*
* This code comprises three sections:
*
* -- The first section contains generic Base64 encoding and decoding
* functions. It is conceptually applicable to any hash function
* implementation that uses Base64 to encode and decode parameters,
* salts and outputs. It could be made into a library, provided that
* the relevant functions are made public (non-static) and be given
* reasonable names to avoid collisions with other functions.
*
* -- The second section is specific to Argon2. It encodes and decodes
* the parameters, salts and outputs. It does not compute the hash
* itself.
*
* The code was originally written by Thomas Pornin <pornin@bolet.org>,
* to whom comments and remarks may be sent. It is released under what
* should amount to Public Domain or its closest equivalent; the
* following mantra is supposed to incarnate that fact with all the
* proper legal rituals:
*
* ---------------------------------------------------------------------
* This file is provided under the terms of Creative Commons CC0 1.0
* Public Domain Dedication. To the extent possible under law, the
* author (Thomas Pornin) has waived all copyright and related or
* neighboring rights to this file. This work is published from: Canada.
* ---------------------------------------------------------------------
*
* Copyright (c) 2015 Thomas Pornin
*/
/* ==================================================================== */
/*
* Common code; could be shared between different hash functions.
*
* Note: the Base64 functions below assume that uppercase letters (resp.
* lowercase letters) have consecutive numerical codes, that fit on 8
* bits. All modern systems use ASCII-compatible charsets, where these
* properties are true. If you are stuck with a dinosaur of a system
* that still defaults to EBCDIC then you already have much bigger
* interoperability issues to deal with.
*/
/*
* Some macros for constant-time comparisons. These work over values in
* the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true".
*/
#define EQ(x, y) ((((0U - ((unsigned)(x) ^ (unsigned)(y))) >> 8) & 0xFF) ^ 0xFF)
#define GT(x, y) ((((unsigned)(y) - (unsigned)(x)) >> 8) & 0xFF)
#define GE(x, y) (GT(y, x) ^ 0xFF)
#define LT(x, y) GT(y, x)
#define LE(x, y) GE(y, x)
/*
* Convert value x (0..63) to corresponding Base64 character.
*/
static int b64_byte_to_char(unsigned x) {
return (LT(x, 26) & (x + 'A')) |
(GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) |
(GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '+') |
(EQ(x, 63) & '/');
}
/*
* Convert character c to the corresponding 6-bit value. If character c
* is not a Base64 character, then 0xFF (255) is returned.
*/
static unsigned b64_char_to_byte(int c) {
unsigned x;
x = (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) |
(GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) |
(GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '+') & 62) |
(EQ(c, '/') & 63);
return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF));
}
/*
* Convert some bytes to Base64. 'dst_len' is the length (in characters)
* of the output buffer 'dst'; if that buffer is not large enough to
* receive the result (including the terminating 0), then (size_t)-1
* is returned. Otherwise, the zero-terminated Base64 string is written
* in the buffer, and the output length (counted WITHOUT the terminating
* zero) is returned.
*/
static size_t to_base64(char *dst, size_t dst_len, const void *src,
size_t src_len) {
size_t olen;
const unsigned char *buf;
unsigned acc, acc_len;
olen = (src_len / 3) << 2;
switch (src_len % 3) {
case 2:
olen++;
/* fall through */
case 1:
olen += 2;
break;
}
if (dst_len <= olen) {
return (size_t)-1;
}
acc = 0;
acc_len = 0;
buf = (const unsigned char *)src;
while (src_len-- > 0) {
acc = (acc << 8) + (*buf++);
acc_len += 8;
while (acc_len >= 6) {
acc_len -= 6;
*dst++ = (char)b64_byte_to_char((acc >> acc_len) & 0x3F);
}
}
if (acc_len > 0) {
*dst++ = (char)b64_byte_to_char((acc << (6 - acc_len)) & 0x3F);
}
*dst++ = 0;
return olen;
}
/*
* Decode Base64 chars into bytes. The '*dst_len' value must initially
* contain the length of the output buffer '*dst'; when the decoding
* ends, the actual number of decoded bytes is written back in
* '*dst_len'.
*
* Decoding stops when a non-Base64 character is encountered, or when
* the output buffer capacity is exceeded. If an error occurred (output
* buffer is too small, invalid last characters leading to unprocessed
* buffered bits), then NULL is returned; otherwise, the returned value
* points to the first non-Base64 character in the source stream, which
* may be the terminating zero.
*/
static const char *from_base64(void *dst, size_t *dst_len, const char *src) {
size_t len;
unsigned char *buf;
unsigned acc, acc_len;
buf = (unsigned char *)dst;
len = 0;
acc = 0;
acc_len = 0;
for (;;) {
unsigned d;
d = b64_char_to_byte(*src);
if (d == 0xFF) {
break;
}
src++;
acc = (acc << 6) + d;
acc_len += 6;
if (acc_len >= 8) {
acc_len -= 8;
if ((len++) >= *dst_len) {
return NULL;
}
*buf++ = (acc >> acc_len) & 0xFF;
}
}
/*
* If the input length is equal to 1 modulo 4 (which is
* invalid), then there will remain 6 unprocessed bits;
* otherwise, only 0, 2 or 4 bits are buffered. The buffered
* bits must also all be zero.
*/
if (acc_len > 4 || (acc & (((unsigned)1 << acc_len) - 1)) != 0) {
return NULL;
}
*dst_len = len;
return src;
}
/*
* Decode decimal integer from 'str'; the value is written in '*v'.
* Returned value is a pointer to the next non-decimal character in the
* string. If there is no digit at all, or the value encoding is not
* minimal (extra leading zeros), or the value does not fit in an
* 'unsigned long', then NULL is returned.
*/
static const char *decode_decimal(const char *str, unsigned long *v) {
const char *orig;
unsigned long acc;
acc = 0;
for (orig = str;; str++) {
int c;
c = *str;
if (c < '0' || c > '9') {
break;
}
c -= '0';
if (acc > (ULONG_MAX / 10)) {
return NULL;
}
acc *= 10;
if ((unsigned long)c > (ULONG_MAX - acc)) {
return NULL;
}
acc += (unsigned long)c;
}
if (str == orig || (*orig == '0' && str != (orig + 1))) {
return NULL;
}
*v = acc;
return str;
}
/* ==================================================================== */
/*
* Code specific to Argon2.
*
* The code below applies the following format:
*
* $argon2<T>[$v=<num>]$m=<num>,t=<num>,p=<num>$<bin>$<bin>
*
* where <T> is either 'd', 'id', or 'i', <num> is a decimal integer (positive,
* fits in an 'unsigned long'), and <bin> is Base64-encoded data (no '=' padding
* characters, no newline or whitespace).
*
* The last two binary chunks (encoded in Base64) are, in that order,
* the salt and the output. Both are required. The binary salt length and the
* output length must be in the allowed ranges defined in argon2.h.
*
* The ctx struct must contain buffers large enough to hold the salt and pwd
* when it is fed into decode_string.
*/
int decode_string(argon2_context *ctx, const char *str, argon2_type type) {
/* check for prefix */
#define CC(prefix) \
do { \
size_t cc_len = strlen(prefix); \
if (strncmp(str, prefix, cc_len) != 0) { \
return ARGON2_DECODING_FAIL; \
} \
str += cc_len; \
} while ((void)0, 0)
/* optional prefix checking with supplied code */
#define CC_opt(prefix, code) \
do { \
size_t cc_len = strlen(prefix); \
if (strncmp(str, prefix, cc_len) == 0) { \
str += cc_len; \
{ code; } \
} \
} while ((void)0, 0)
/* Decoding prefix into decimal */
#define DECIMAL(x) \
do { \
unsigned long dec_x; \
str = decode_decimal(str, &dec_x); \
if (str == NULL) { \
return ARGON2_DECODING_FAIL; \
} \
(x) = dec_x; \
} while ((void)0, 0)
/* Decoding prefix into uint32_t decimal */
#define DECIMAL_U32(x) \
do { \
unsigned long dec_x; \
str = decode_decimal(str, &dec_x); \
if (str == NULL || dec_x > UINT32_MAX) { \
return ARGON2_DECODING_FAIL; \
} \
(x) = (uint32_t)dec_x; \
} while ((void)0, 0)
/* Decoding base64 into a binary buffer */
#define BIN(buf, max_len, len) \
do { \
size_t bin_len = (max_len); \
str = from_base64(buf, &bin_len, str); \
if (str == NULL || bin_len > UINT32_MAX) { \
return ARGON2_DECODING_FAIL; \
} \
(len) = (uint32_t)bin_len; \
} while ((void)0, 0)
size_t maxsaltlen = ctx->saltlen;
size_t maxoutlen = ctx->outlen;
int validation_result;
const char* type_string;
/* We should start with the argon2_type we are using */
type_string = argon2_type2string(type, 0);
if (!type_string) {
return ARGON2_INCORRECT_TYPE;
}
CC("$");
CC(type_string);
/* Reading the version number if the default is suppressed */
ctx->version = ARGON2_VERSION_10;
CC_opt("$v=", DECIMAL_U32(ctx->version));
CC("$m=");
DECIMAL_U32(ctx->m_cost);
CC(",t=");
DECIMAL_U32(ctx->t_cost);
CC(",p=");
DECIMAL_U32(ctx->lanes);
ctx->threads = ctx->lanes;
CC("$");
BIN(ctx->salt, maxsaltlen, ctx->saltlen);
CC("$");
BIN(ctx->out, maxoutlen, ctx->outlen);
/* The rest of the fields get the default values */
ctx->secret = NULL;
ctx->secretlen = 0;
ctx->ad = NULL;
ctx->adlen = 0;
ctx->allocate_cbk = NULL;
ctx->free_cbk = NULL;
ctx->flags = ARGON2_DEFAULT_FLAGS;
/* On return, must have valid context */
validation_result = validate_inputs(ctx);
if (validation_result != ARGON2_OK) {
return validation_result;
}
/* Can't have any additional characters */
if (*str == 0) {
return ARGON2_OK;
} else {
return ARGON2_DECODING_FAIL;
}
#undef CC
#undef CC_opt
#undef DECIMAL
#undef BIN
}
int encode_string(char *dst, size_t dst_len, argon2_context *ctx,
argon2_type type) {
#define SS(str) \
do { \
size_t pp_len = strlen(str); \
if (pp_len >= dst_len) { \
return ARGON2_ENCODING_FAIL; \
} \
memcpy(dst, str, pp_len + 1); \
dst += pp_len; \
dst_len -= pp_len; \
} while ((void)0, 0)
#define SX(x) \
do { \
char tmp[30]; \
sprintf(tmp, "%lu", (unsigned long)(x)); \
SS(tmp); \
} while ((void)0, 0)
#define SB(buf, len) \
do { \
size_t sb_len = to_base64(dst, dst_len, buf, len); \
if (sb_len == (size_t)-1) { \
return ARGON2_ENCODING_FAIL; \
} \
dst += sb_len; \
dst_len -= sb_len; \
} while ((void)0, 0)
const char* type_string = argon2_type2string(type, 0);
int validation_result = validate_inputs(ctx);
if (!type_string) {
return ARGON2_ENCODING_FAIL;
}
if (validation_result != ARGON2_OK) {
return validation_result;
}
SS("$");
SS(type_string);
SS("$v=");
SX(ctx->version);
SS("$m=");
SX(ctx->m_cost);
SS(",t=");
SX(ctx->t_cost);
SS(",p=");
SX(ctx->lanes);
SS("$");
SB(ctx->salt, ctx->saltlen);
SS("$");
SB(ctx->out, ctx->outlen);
return ARGON2_OK;
#undef SS
#undef SX
#undef SB
}
size_t b64len(uint32_t len) {
size_t olen = ((size_t)len / 3) << 2;
switch (len % 3) {
case 2:
olen++;
/* fall through */
case 1:
olen += 2;
break;
}
return olen;
}
size_t numlen(uint32_t num) {
size_t len = 1;
while (num >= 10) {
++len;
num = num / 10;
}
return len;
}
+57
View File
@@ -0,0 +1,57 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef ENCODING_H
#define ENCODING_H
#include "argon2.h"
#define ARGON2_MAX_DECODED_LANES UINT32_C(255)
#define ARGON2_MIN_DECODED_SALT_LEN UINT32_C(8)
#define ARGON2_MIN_DECODED_OUT_LEN UINT32_C(12)
/*
* encode an Argon2 hash string into the provided buffer. 'dst_len'
* contains the size, in characters, of the 'dst' buffer; if 'dst_len'
* is less than the number of required characters (including the
* terminating 0), then this function returns ARGON2_ENCODING_ERROR.
*
* on success, ARGON2_OK is returned.
*/
int encode_string(char *dst, size_t dst_len, argon2_context *ctx,
argon2_type type);
/*
* Decodes an Argon2 hash string into the provided structure 'ctx'.
* The only fields that must be set prior to this call are ctx.saltlen and
* ctx.outlen (which must be the maximal salt and out length values that are
* allowed), ctx.salt and ctx.out (which must be buffers of the specified
* length), and ctx.pwd and ctx.pwdlen which must hold a valid password.
*
* Invalid input string causes an error. On success, the ctx is valid and all
* fields have been initialized.
*
* Returned value is ARGON2_OK on success, other ARGON2_ codes on error.
*/
int decode_string(argon2_context *ctx, const char *str, argon2_type type);
/* Returns the length of the encoded byte stream with length len */
size_t b64len(uint32_t len);
/* Returns the length of the encoded number num */
size_t numlen(uint32_t num);
#endif
+283
View File
@@ -0,0 +1,283 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "argon2.h"
#include "core.h"
#include "blake2/blake2.h"
#include "blake2/blamka-round-opt.h"
/*
* Function fills a new memory block and optionally XORs the old block over the new one.
* Memory must be initialized.
* @param state Pointer to the just produced block. Content will be updated(!)
* @param ref_block Pointer to the reference block
* @param next_block Pointer to the block to be XORed over. May coincide with @ref_block
* @param with_xor Whether to XOR into the new block (1) or just overwrite (0)
* @pre all block pointers must be valid
*/
#if defined(__AVX512F__)
static void fill_block(__m512i *state, const block *ref_block,
block *next_block, int with_xor) {
__m512i block_XY[ARGON2_512BIT_WORDS_IN_BLOCK];
unsigned int i;
if (with_xor) {
for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
state[i] = _mm512_xor_si512(
state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));
block_XY[i] = _mm512_xor_si512(
state[i], _mm512_loadu_si512((const __m512i *)next_block->v + i));
}
} else {
for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
block_XY[i] = state[i] = _mm512_xor_si512(
state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));
}
}
for (i = 0; i < 2; ++i) {
BLAKE2_ROUND_1(
state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
}
for (i = 0; i < 2; ++i) {
BLAKE2_ROUND_2(
state[2 * 0 + i], state[2 * 1 + i], state[2 * 2 + i], state[2 * 3 + i],
state[2 * 4 + i], state[2 * 5 + i], state[2 * 6 + i], state[2 * 7 + i]);
}
for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
state[i] = _mm512_xor_si512(state[i], block_XY[i]);
_mm512_storeu_si512((__m512i *)next_block->v + i, state[i]);
}
}
#elif defined(__AVX2__)
static void fill_block(__m256i *state, const block *ref_block,
block *next_block, int with_xor) {
__m256i block_XY[ARGON2_HWORDS_IN_BLOCK];
unsigned int i;
if (with_xor) {
for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
state[i] = _mm256_xor_si256(
state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));
block_XY[i] = _mm256_xor_si256(
state[i], _mm256_loadu_si256((const __m256i *)next_block->v + i));
}
} else {
for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
block_XY[i] = state[i] = _mm256_xor_si256(
state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));
}
}
for (i = 0; i < 4; ++i) {
BLAKE2_ROUND_1(state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5],
state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]);
}
for (i = 0; i < 4; ++i) {
BLAKE2_ROUND_2(state[ 0 + i], state[ 4 + i], state[ 8 + i], state[12 + i],
state[16 + i], state[20 + i], state[24 + i], state[28 + i]);
}
for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
state[i] = _mm256_xor_si256(state[i], block_XY[i]);
_mm256_storeu_si256((__m256i *)next_block->v + i, state[i]);
}
}
#else
static void fill_block(__m128i *state, const block *ref_block,
block *next_block, int with_xor) {
__m128i block_XY[ARGON2_OWORDS_IN_BLOCK];
unsigned int i;
if (with_xor) {
for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {
state[i] = _mm_xor_si128(
state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));
block_XY[i] = _mm_xor_si128(
state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));
}
} else {
for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {
block_XY[i] = state[i] = _mm_xor_si128(
state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));
}
}
for (i = 0; i < 8; ++i) {
BLAKE2_ROUND(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2],
state[8 * i + 3], state[8 * i + 4], state[8 * i + 5],
state[8 * i + 6], state[8 * i + 7]);
}
for (i = 0; i < 8; ++i) {
BLAKE2_ROUND(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i],
state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i],
state[8 * 6 + i], state[8 * 7 + i]);
}
for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {
state[i] = _mm_xor_si128(state[i], block_XY[i]);
_mm_storeu_si128((__m128i *)next_block->v + i, state[i]);
}
}
#endif
static void next_addresses(block *address_block, block *input_block) {
/*Temporary zero-initialized blocks*/
#if defined(__AVX512F__)
__m512i zero_block[ARGON2_512BIT_WORDS_IN_BLOCK];
__m512i zero2_block[ARGON2_512BIT_WORDS_IN_BLOCK];
#elif defined(__AVX2__)
__m256i zero_block[ARGON2_HWORDS_IN_BLOCK];
__m256i zero2_block[ARGON2_HWORDS_IN_BLOCK];
#else
__m128i zero_block[ARGON2_OWORDS_IN_BLOCK];
__m128i zero2_block[ARGON2_OWORDS_IN_BLOCK];
#endif
memset(zero_block, 0, sizeof(zero_block));
memset(zero2_block, 0, sizeof(zero2_block));
/*Increasing index counter*/
input_block->v[6]++;
/*First iteration of G*/
fill_block(zero_block, input_block, address_block, 0);
/*Second iteration of G*/
fill_block(zero2_block, address_block, address_block, 0);
}
void fill_segment(const argon2_instance_t *instance,
argon2_position_t position) {
block *ref_block = NULL, *curr_block = NULL;
block address_block, input_block;
uint64_t pseudo_rand, ref_index, ref_lane;
uint32_t prev_offset, curr_offset;
uint32_t starting_index, i;
#if defined(__AVX512F__)
__m512i state[ARGON2_512BIT_WORDS_IN_BLOCK];
#elif defined(__AVX2__)
__m256i state[ARGON2_HWORDS_IN_BLOCK];
#else
__m128i state[ARGON2_OWORDS_IN_BLOCK];
#endif
int data_independent_addressing;
if (instance == NULL) {
return;
}
data_independent_addressing =
(instance->type == Argon2_i) ||
(instance->type == Argon2_id && (position.pass == 0) &&
(position.slice < ARGON2_SYNC_POINTS / 2));
if (data_independent_addressing) {
init_block_value(&input_block, 0);
input_block.v[0] = position.pass;
input_block.v[1] = position.lane;
input_block.v[2] = position.slice;
input_block.v[3] = instance->memory_blocks;
input_block.v[4] = instance->passes;
input_block.v[5] = instance->type;
}
starting_index = 0;
if ((0 == position.pass) && (0 == position.slice)) {
starting_index = 2; /* we have already generated the first two blocks */
/* Don't forget to generate the first block of addresses: */
if (data_independent_addressing) {
next_addresses(&address_block, &input_block);
}
}
/* Offset of the current block */
curr_offset = position.lane * instance->lane_length +
position.slice * instance->segment_length + starting_index;
if (0 == curr_offset % instance->lane_length) {
/* Last block in this lane */
prev_offset = curr_offset + instance->lane_length - 1;
} else {
/* Previous block */
prev_offset = curr_offset - 1;
}
memcpy(state, ((instance->memory + prev_offset)->v), ARGON2_BLOCK_SIZE);
for (i = starting_index; i < instance->segment_length;
++i, ++curr_offset, ++prev_offset) {
/*1.1 Rotating prev_offset if needed */
if (curr_offset % instance->lane_length == 1) {
prev_offset = curr_offset - 1;
}
/* 1.2 Computing the index of the reference block */
/* 1.2.1 Taking pseudo-random value from the previous block */
if (data_independent_addressing) {
if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {
next_addresses(&address_block, &input_block);
}
pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];
} else {
pseudo_rand = instance->memory[prev_offset].v[0];
}
/* 1.2.2 Computing the lane of the reference block */
ref_lane = ((pseudo_rand >> 32)) % instance->lanes;
if ((position.pass == 0) && (position.slice == 0)) {
/* Can not reference other lanes yet */
ref_lane = position.lane;
}
/* 1.2.3 Computing the number of possible reference block within the
* lane.
*/
position.index = i;
ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF,
ref_lane == position.lane);
/* 2 Creating a new block */
ref_block =
instance->memory + instance->lane_length * ref_lane + ref_index;
curr_block = instance->memory + curr_offset;
if (ARGON2_VERSION_10 == instance->version) {
/* version 1.2.1 and earlier: overwrite, not XOR */
fill_block(state, ref_block, curr_block, 0);
} else {
if(0 == position.pass) {
fill_block(state, ref_block, curr_block, 0);
} else {
fill_block(state, ref_block, curr_block, 1);
}
}
}
}
+194
View File
@@ -0,0 +1,194 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "argon2.h"
#include "core.h"
#include "blake2/blamka-round-ref.h"
#include "blake2/blake2-impl.h"
#include "blake2/blake2.h"
/*
* Function fills a new memory block and optionally XORs the old block over the new one.
* @next_block must be initialized.
* @param prev_block Pointer to the previous block
* @param ref_block Pointer to the reference block
* @param next_block Pointer to the block to be constructed
* @param with_xor Whether to XOR into the new block (1) or just overwrite (0)
* @pre all block pointers must be valid
*/
static void fill_block(const block *prev_block, const block *ref_block,
block *next_block, int with_xor) {
block blockR, block_tmp;
unsigned i;
copy_block(&blockR, ref_block);
xor_block(&blockR, prev_block);
copy_block(&block_tmp, &blockR);
/* Now blockR = ref_block + prev_block and block_tmp = ref_block + prev_block */
if (with_xor) {
/* Saving the next block contents for XOR over: */
xor_block(&block_tmp, next_block);
/* Now blockR = ref_block + prev_block and
block_tmp = ref_block + prev_block + next_block */
}
/* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then
(16,17,..31)... finally (112,113,...127) */
for (i = 0; i < 8; ++i) {
BLAKE2_ROUND_NOMSG(
blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2],
blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5],
blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8],
blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11],
blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14],
blockR.v[16 * i + 15]);
}
/* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then
(2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */
for (i = 0; i < 8; i++) {
BLAKE2_ROUND_NOMSG(
blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16],
blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33],
blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64],
blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81],
blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112],
blockR.v[2 * i + 113]);
}
copy_block(next_block, &block_tmp);
xor_block(next_block, &blockR);
}
static void next_addresses(block *address_block, block *input_block,
const block *zero_block) {
input_block->v[6]++;
fill_block(zero_block, input_block, address_block, 0);
fill_block(zero_block, address_block, address_block, 0);
}
void fill_segment(const argon2_instance_t *instance,
argon2_position_t position) {
block *ref_block = NULL, *curr_block = NULL;
block address_block, input_block, zero_block;
uint64_t pseudo_rand, ref_index, ref_lane;
uint32_t prev_offset, curr_offset;
uint32_t starting_index;
uint32_t i;
int data_independent_addressing;
if (instance == NULL) {
return;
}
data_independent_addressing =
(instance->type == Argon2_i) ||
(instance->type == Argon2_id && (position.pass == 0) &&
(position.slice < ARGON2_SYNC_POINTS / 2));
if (data_independent_addressing) {
init_block_value(&zero_block, 0);
init_block_value(&input_block, 0);
input_block.v[0] = position.pass;
input_block.v[1] = position.lane;
input_block.v[2] = position.slice;
input_block.v[3] = instance->memory_blocks;
input_block.v[4] = instance->passes;
input_block.v[5] = instance->type;
}
starting_index = 0;
if ((0 == position.pass) && (0 == position.slice)) {
starting_index = 2; /* we have already generated the first two blocks */
/* Don't forget to generate the first block of addresses: */
if (data_independent_addressing) {
next_addresses(&address_block, &input_block, &zero_block);
}
}
/* Offset of the current block */
curr_offset = position.lane * instance->lane_length +
position.slice * instance->segment_length + starting_index;
if (0 == curr_offset % instance->lane_length) {
/* Last block in this lane */
prev_offset = curr_offset + instance->lane_length - 1;
} else {
/* Previous block */
prev_offset = curr_offset - 1;
}
for (i = starting_index; i < instance->segment_length;
++i, ++curr_offset, ++prev_offset) {
/*1.1 Rotating prev_offset if needed */
if (curr_offset % instance->lane_length == 1) {
prev_offset = curr_offset - 1;
}
/* 1.2 Computing the index of the reference block */
/* 1.2.1 Taking pseudo-random value from the previous block */
if (data_independent_addressing) {
if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {
next_addresses(&address_block, &input_block, &zero_block);
}
pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];
} else {
pseudo_rand = instance->memory[prev_offset].v[0];
}
/* 1.2.2 Computing the lane of the reference block */
ref_lane = ((pseudo_rand >> 32)) % instance->lanes;
if ((position.pass == 0) && (position.slice == 0)) {
/* Can not reference other lanes yet */
ref_lane = position.lane;
}
/* 1.2.3 Computing the number of possible reference block within the
* lane.
*/
position.index = i;
ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF,
ref_lane == position.lane);
/* 2 Creating a new block */
ref_block =
instance->memory + instance->lane_length * ref_lane + ref_index;
curr_block = instance->memory + curr_offset;
if (ARGON2_VERSION_10 == instance->version) {
/* version 1.2.1 and earlier: overwrite, not XOR */
fill_block(instance->memory + prev_offset, ref_block, curr_block, 0);
} else {
if(0 == position.pass) {
fill_block(instance->memory + prev_offset, ref_block,
curr_block, 0);
} else {
fill_block(instance->memory + prev_offset, ref_block,
curr_block, 1);
}
}
}
}
+57
View File
@@ -0,0 +1,57 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#if !defined(ARGON2_NO_THREADS)
#include "thread.h"
#if defined(_WIN32)
#include <windows.h>
#endif
int argon2_thread_create(argon2_thread_handle_t *handle,
argon2_thread_func_t func, void *args) {
if (NULL == handle || func == NULL) {
return -1;
}
#if defined(_WIN32)
*handle = _beginthreadex(NULL, 0, func, args, 0, NULL);
return *handle != 0 ? 0 : -1;
#else
return pthread_create(handle, NULL, func, args);
#endif
}
int argon2_thread_join(argon2_thread_handle_t handle) {
#if defined(_WIN32)
if (WaitForSingleObject((HANDLE)handle, INFINITE) == WAIT_OBJECT_0) {
return CloseHandle((HANDLE)handle) != 0 ? 0 : -1;
}
return -1;
#else
return pthread_join(handle, NULL);
#endif
}
void argon2_thread_exit(void) {
#if defined(_WIN32)
_endthreadex(0);
#else
pthread_exit(NULL);
#endif
}
#endif /* ARGON2_NO_THREADS */
+67
View File
@@ -0,0 +1,67 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef ARGON2_THREAD_H
#define ARGON2_THREAD_H
#if !defined(ARGON2_NO_THREADS)
/*
Here we implement an abstraction layer for the simpĺe requirements
of the Argon2 code. We only require 3 primitives---thread creation,
joining, and termination---so full emulation of the pthreads API
is unwarranted. Currently we wrap pthreads and Win32 threads.
The API defines 2 types: the function pointer type,
argon2_thread_func_t,
and the type of the thread handle---argon2_thread_handle_t.
*/
#if defined(_WIN32)
#include <process.h>
typedef unsigned(__stdcall *argon2_thread_func_t)(void *);
typedef uintptr_t argon2_thread_handle_t;
#else
#include <pthread.h>
typedef void *(*argon2_thread_func_t)(void *);
typedef pthread_t argon2_thread_handle_t;
#endif
/* Creates a thread
* @param handle pointer to a thread handle, which is the output of this
* function. Must not be NULL.
* @param func A function pointer for the thread's entry point. Must not be
* NULL.
* @param args Pointer that is passed as an argument to @func. May be NULL.
* @return 0 if @handle and @func are valid pointers and a thread is successfully
* created.
*/
int argon2_thread_create(argon2_thread_handle_t *handle,
argon2_thread_func_t func, void *args);
/* Waits for a thread to terminate
* @param handle Handle to a thread created with argon2_thread_create.
* @return 0 if @handle is a valid handle, and joining completed successfully.
*/
int argon2_thread_join(argon2_thread_handle_t handle);
/* Terminate the current thread. Must be run inside a thread created by
* argon2_thread_create.
*/
void argon2_thread_exit(void);
#endif /* ARGON2_NO_THREADS */
#endif
-219
View File
@@ -1,219 +0,0 @@
# Use the bundled source on windows
set (libzmq_STAT_SRCS
src/address.cpp
src/client.cpp
src/clock.cpp
src/ctx.cpp
src/dealer.cpp
src/devpoll.cpp
src/dgram.cpp
src/dist.cpp
src/epoll.cpp
src/err.cpp
src/fq.cpp
src/io_object.cpp
src/io_thread.cpp
src/ip.cpp
src/ipc_address.cpp
src/ipc_connecter.cpp
src/ipc_listener.cpp
src/lb.cpp
src/kqueue.cpp
src/mailbox.cpp
src/mailbox_safe.cpp
src/mechanism.cpp
src/mechanism_base.cpp
src/metadata.cpp
src/msg.cpp
src/mtrie.cpp
src/object.cpp
src/options.cpp
src/own.cpp
src/null_mechanism.cpp
src/pair.cpp
src/pipe.cpp
src/plain_client.cpp
src/plain_server.cpp
src/poll.cpp
src/poller_base.cpp
src/pollset.cpp
src/proxy.cpp
src/pub.cpp
src/pull.cpp
src/push.cpp
src/random.cpp
src/raw_encoder.cpp
src/raw_decoder.cpp
src/reaper.cpp
src/rep.cpp
src/req.cpp
src/router.cpp
src/select.cpp
src/server.cpp
src/session_base.cpp
src/signaler.cpp
src/socket_base.cpp
src/socks.cpp
src/socks_connecter.cpp
src/stream.cpp
src/stream_engine.cpp
src/sub.cpp
src/tcp.cpp
src/tcp_address.cpp
src/tcp_connecter.cpp
src/tcp_listener.cpp
src/thread.cpp
src/trie.cpp
src/v1_decoder.cpp
src/v1_encoder.cpp
src/v2_decoder.cpp
src/v2_encoder.cpp
src/xpub.cpp
src/xsub.cpp
src/zmq.cpp
src/zmq_utils.cpp
src/decoder_allocators.cpp
src/socket_poller.cpp
src/timers.cpp
src/config.hpp
src/radio.cpp
src/dish.cpp
src/udp_engine.cpp
src/udp_address.cpp
src/scatter.cpp
src/gather.cpp
src/zap_client.cpp
)
if (WIN32)
set(ZMQ_PLATFORM -DZMQ_HAVE_WINDOWS)
elseif (APPLE)
set(ZMQ_PLATFORM -DZMQ_HAVE_OSX)
elseif (UNIX)
set(ZMQ_PLATFORM -DZMQ_HAVE_LINUX)
endif()
set (POLLER "")
include (CheckFunctionExists)
include (CheckTypeSize)
if (POLLER STREQUAL "")
set (CMAKE_REQUIRED_INCLUDES sys/event.h)
check_function_exists (kqueue HAVE_KQUEUE)
set (CMAKE_REQUIRED_INCLUDES)
if (HAVE_KQUEUE)
set (POLLER "kqueue")
endif()
endif ()
if (POLLER STREQUAL "")
set (CMAKE_REQUIRED_INCLUDES sys/epoll.h)
check_function_exists (epoll_create HAVE_EPOLL)
set (CMAKE_REQUIRED_INCLUDES)
if (HAVE_EPOLL)
set (POLLER "epoll")
endif ()
endif ()
if (POLLER STREQUAL "")
set (CMAKE_REQUIRED_INCLUDES sys/devpoll.h)
check_type_size ("struct pollfd" DEVPOLL)
set (CMAKE_REQUIRED_INCLUDES)
if (HAVE_DEVPOLL)
set (POLLER "devpoll")
endif ()
endif ()
if (POLLER STREQUAL "")
set (CMAKE_REQUIRED_INCLUDES sys/pollset.h)
check_function_exists (pollset_create HAVE_POLLSET)
set (CMAKE_REQUIRED_INCLUDES)
if (HAVE_POLLSET)
set (POLLER "pollset")
endif()
endif ()
if (POLLER STREQUAL "")
set (CMAKE_REQUIRED_INCLUDES poll.h)
check_function_exists (poll HAVE_POLL)
set (CMAKE_REQUIRED_INCLUDES)
if (HAVE_POLL)
set (POLLER "poll")
endif ()
endif ()
if (POLLER STREQUAL "")
if (WIN32)
set (CMAKE_REQUIRED_INCLUDES winsock2.h)
set (HAVE_SELECT 1)
else ()
set (CMAKE_REQUIRED_INCLUDES sys/select.h)
check_function_exists (select HAVE_SELECT)
set (CMAKE_REQUIRED_INCLUDES)
endif ()
if (HAVE_SELECT)
set (POLLER "select")
else ()
message (FATAL_ERROR
"Could not autodetect polling method")
endif ()
endif ()
if (POLLER STREQUAL "kqueue"
OR POLLER STREQUAL "epoll"
OR POLLER STREQUAL "devpoll"
OR POLLER STREQUAL "pollset"
OR POLLER STREQUAL "poll"
OR POLLER STREQUAL "select")
message (STATUS "Detected ${POLLER} polling method")
string (TOUPPER ${POLLER} UPPER_POLLER)
else ()
message (FATAL_ERROR "Invalid polling method")
endif ()
include (CheckIncludeFiles)
set(ADDITIONAL_DEFINES "")
check_include_files (ifaddrs.h HAVE_IFADDRS)
if (HAVE_IFADDRS)
list(APPEND ADDITIONAL_DEFINES -DZMQ_HAVE_IFADDRS)
endif()
check_include_files (sys/uio.h HAVE_UIO)
if (HAVE_UIO)
list(APPEND ADDITIONAL_DEFINES -DZMQ_HAVE_UIO)
endif()
check_include_files (sys/eventfd.h HAVE_EVENTFD)
if (HAVE_EVENTFD)
list(APPEND ADDITIONAL_DEFINES -DZMQ_HAVE_EVENTFD)
endif()
add_library(libzmq STATIC ${libzmq_STAT_SRCS})
target_include_directories(libzmq
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src)
target_link_libraries(libzmq
PRIVATE
trinity-dependency-interface
PUBLIC
bzip2
zlib)
set_target_properties(libzmq
PROPERTIES
FOLDER
"dep")
target_compile_definitions(libzmq
PUBLIC
-DZMQ_USE_${UPPER_POLLER}
-DZMQ_STATIC
${ZMQ_PLATFORM}
${ADDITIONAL_DEFINES})
-708
View File
@@ -1,708 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*************************************************************************
NOTE to contributors. This file comprises the principal public contract
for ZeroMQ API users. Any change to this file supplied in a stable
release SHOULD not break existing applications.
In practice this means that the value of constants must not change, and
that old values may not be reused for new constants.
*************************************************************************
*/
#ifndef __ZMQ_H_INCLUDED__
#define __ZMQ_H_INCLUDED__
/* Version macros for compile-time API version detection */
#define ZMQ_VERSION_MAJOR 4
#define ZMQ_VERSION_MINOR 2
#define ZMQ_VERSION_PATCH 3
#define ZMQ_MAKE_VERSION(major, minor, patch) \
((major) * 10000 + (minor) * 100 + (patch))
#define ZMQ_VERSION \
ZMQ_MAKE_VERSION(ZMQ_VERSION_MAJOR, ZMQ_VERSION_MINOR, ZMQ_VERSION_PATCH)
#ifdef __cplusplus
extern "C" {
#endif
#if !defined _WIN32_WCE
#include <errno.h>
#endif
#include <stddef.h>
#include <stdio.h>
#if defined _WIN32
// Set target version to Windows Server 2008, Windows Vista or higher.
// Windows XP (0x0501) is supported but without client & server socket types.
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif
#ifdef __MINGW32__
// Require Windows XP or higher with MinGW for getaddrinfo().
#if(_WIN32_WINNT >= 0x0501)
#else
#error You need at least Windows XP target
#endif
#endif
#include <winsock2.h>
#endif
/* Handle DSO symbol visibility */
#if defined _WIN32
# if defined ZMQ_STATIC
# define ZMQ_EXPORT
# elif defined DLL_EXPORT
# define ZMQ_EXPORT __declspec(dllexport)
# else
# define ZMQ_EXPORT __declspec(dllimport)
# endif
#else
# if defined __SUNPRO_C || defined __SUNPRO_CC
# define ZMQ_EXPORT __global
# elif (defined __GNUC__ && __GNUC__ >= 4) || defined __INTEL_COMPILER
# define ZMQ_EXPORT __attribute__ ((visibility("default")))
# else
# define ZMQ_EXPORT
# endif
#endif
/* Define integer types needed for event interface */
#define ZMQ_DEFINED_STDINT 1
#if defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_OPENVMS
# include <inttypes.h>
#elif defined _MSC_VER && _MSC_VER < 1600
# ifndef int32_t
typedef __int32 int32_t;
# endif
# ifndef uint32_t
typedef unsigned __int32 uint32_t;
# endif
# ifndef uint16_t
typedef unsigned __int16 uint16_t;
# endif
# ifndef uint8_t
typedef unsigned __int8 uint8_t;
# endif
#else
# include <stdint.h>
#endif
// 32-bit AIX's pollfd struct members are called reqevents and rtnevents so it
// defines compatibility macros for them. Need to include that header first to
// stop build failures since zmq_pollset_t defines them as events and revents.
#ifdef ZMQ_HAVE_AIX
#include <poll.h>
#endif
/******************************************************************************/
/* 0MQ errors. */
/******************************************************************************/
/* A number random enough not to collide with different errno ranges on */
/* different OSes. The assumption is that error_t is at least 32-bit type. */
#define ZMQ_HAUSNUMERO 156384712
/* On Windows platform some of the standard POSIX errnos are not defined. */
#ifndef ENOTSUP
#define ENOTSUP (ZMQ_HAUSNUMERO + 1)
#endif
#ifndef EPROTONOSUPPORT
#define EPROTONOSUPPORT (ZMQ_HAUSNUMERO + 2)
#endif
#ifndef ENOBUFS
#define ENOBUFS (ZMQ_HAUSNUMERO + 3)
#endif
#ifndef ENETDOWN
#define ENETDOWN (ZMQ_HAUSNUMERO + 4)
#endif
#ifndef EADDRINUSE
#define EADDRINUSE (ZMQ_HAUSNUMERO + 5)
#endif
#ifndef EADDRNOTAVAIL
#define EADDRNOTAVAIL (ZMQ_HAUSNUMERO + 6)
#endif
#ifndef ECONNREFUSED
#define ECONNREFUSED (ZMQ_HAUSNUMERO + 7)
#endif
#ifndef EINPROGRESS
#define EINPROGRESS (ZMQ_HAUSNUMERO + 8)
#endif
#ifndef ENOTSOCK
#define ENOTSOCK (ZMQ_HAUSNUMERO + 9)
#endif
#ifndef EMSGSIZE
#define EMSGSIZE (ZMQ_HAUSNUMERO + 10)
#endif
#ifndef EAFNOSUPPORT
#define EAFNOSUPPORT (ZMQ_HAUSNUMERO + 11)
#endif
#ifndef ENETUNREACH
#define ENETUNREACH (ZMQ_HAUSNUMERO + 12)
#endif
#ifndef ECONNABORTED
#define ECONNABORTED (ZMQ_HAUSNUMERO + 13)
#endif
#ifndef ECONNRESET
#define ECONNRESET (ZMQ_HAUSNUMERO + 14)
#endif
#ifndef ENOTCONN
#define ENOTCONN (ZMQ_HAUSNUMERO + 15)
#endif
#ifndef ETIMEDOUT
#define ETIMEDOUT (ZMQ_HAUSNUMERO + 16)
#endif
#ifndef EHOSTUNREACH
#define EHOSTUNREACH (ZMQ_HAUSNUMERO + 17)
#endif
#ifndef ENETRESET
#define ENETRESET (ZMQ_HAUSNUMERO + 18)
#endif
/* Native 0MQ error codes. */
#define EFSM (ZMQ_HAUSNUMERO + 51)
#define ENOCOMPATPROTO (ZMQ_HAUSNUMERO + 52)
#define ETERM (ZMQ_HAUSNUMERO + 53)
#define EMTHREAD (ZMQ_HAUSNUMERO + 54)
/* This function retrieves the errno as it is known to 0MQ library. The goal */
/* of this function is to make the code 100% portable, including where 0MQ */
/* compiled with certain CRT library (on Windows) is linked to an */
/* application that uses different CRT library. */
ZMQ_EXPORT int zmq_errno (void);
/* Resolves system errors and 0MQ errors to human-readable string. */
ZMQ_EXPORT const char *zmq_strerror (int errnum);
/* Run-time API version detection */
ZMQ_EXPORT void zmq_version (int *major, int *minor, int *patch);
/******************************************************************************/
/* 0MQ infrastructure (a.k.a. context) initialisation & termination. */
/******************************************************************************/
/* Context options */
#define ZMQ_IO_THREADS 1
#define ZMQ_MAX_SOCKETS 2
#define ZMQ_SOCKET_LIMIT 3
#define ZMQ_THREAD_PRIORITY 3
#define ZMQ_THREAD_SCHED_POLICY 4
#define ZMQ_MAX_MSGSZ 5
/* Default for new contexts */
#define ZMQ_IO_THREADS_DFLT 1
#define ZMQ_MAX_SOCKETS_DFLT 1023
#define ZMQ_THREAD_PRIORITY_DFLT -1
#define ZMQ_THREAD_SCHED_POLICY_DFLT -1
ZMQ_EXPORT void *zmq_ctx_new (void);
ZMQ_EXPORT int zmq_ctx_term (void *context);
ZMQ_EXPORT int zmq_ctx_shutdown (void *context);
ZMQ_EXPORT int zmq_ctx_set (void *context, int option, int optval);
ZMQ_EXPORT int zmq_ctx_get (void *context, int option);
/* Old (legacy) API */
ZMQ_EXPORT void *zmq_init (int io_threads);
ZMQ_EXPORT int zmq_term (void *context);
ZMQ_EXPORT int zmq_ctx_destroy (void *context);
/******************************************************************************/
/* 0MQ message definition. */
/******************************************************************************/
/* Some architectures, like sparc64 and some variants of aarch64, enforce pointer
* alignment and raise sigbus on violations. Make sure applications allocate
* zmq_msg_t on addresses aligned on a pointer-size boundary to avoid this issue.
*/
typedef struct zmq_msg_t {
#if defined (__GNUC__) || defined ( __INTEL_COMPILER) || \
(defined (__SUNPRO_C) && __SUNPRO_C >= 0x590) || \
(defined (__SUNPRO_CC) && __SUNPRO_CC >= 0x590)
unsigned char _ [64] __attribute__ ((aligned (sizeof (void *))));
#elif defined (_MSC_VER) && (defined (_M_X64) || defined (_M_ARM64))
__declspec (align (8)) unsigned char _ [64];
#elif defined (_MSC_VER) && (defined (_M_IX86) || defined (_M_ARM_ARMV7VE))
__declspec (align (4)) unsigned char _ [64];
#else
unsigned char _ [64];
#endif
} zmq_msg_t;
typedef void (zmq_free_fn) (void *data, void *hint);
ZMQ_EXPORT int zmq_msg_init (zmq_msg_t *msg);
ZMQ_EXPORT int zmq_msg_init_size (zmq_msg_t *msg, size_t size);
ZMQ_EXPORT int zmq_msg_init_data (zmq_msg_t *msg, void *data,
size_t size, zmq_free_fn *ffn, void *hint);
ZMQ_EXPORT int zmq_msg_send (zmq_msg_t *msg, void *s, int flags);
ZMQ_EXPORT int zmq_msg_recv (zmq_msg_t *msg, void *s, int flags);
ZMQ_EXPORT int zmq_msg_close (zmq_msg_t *msg);
ZMQ_EXPORT int zmq_msg_move (zmq_msg_t *dest, zmq_msg_t *src);
ZMQ_EXPORT int zmq_msg_copy (zmq_msg_t *dest, zmq_msg_t *src);
ZMQ_EXPORT void *zmq_msg_data (zmq_msg_t *msg);
ZMQ_EXPORT size_t zmq_msg_size (const zmq_msg_t *msg);
ZMQ_EXPORT int zmq_msg_more (const zmq_msg_t *msg);
ZMQ_EXPORT int zmq_msg_get (const zmq_msg_t *msg, int property);
ZMQ_EXPORT int zmq_msg_set (zmq_msg_t *msg, int property, int optval);
ZMQ_EXPORT const char *zmq_msg_gets (const zmq_msg_t *msg, const char *property);
/******************************************************************************/
/* 0MQ socket definition. */
/******************************************************************************/
/* Socket types. */
#define ZMQ_PAIR 0
#define ZMQ_PUB 1
#define ZMQ_SUB 2
#define ZMQ_REQ 3
#define ZMQ_REP 4
#define ZMQ_DEALER 5
#define ZMQ_ROUTER 6
#define ZMQ_PULL 7
#define ZMQ_PUSH 8
#define ZMQ_XPUB 9
#define ZMQ_XSUB 10
#define ZMQ_STREAM 11
/* Deprecated aliases */
#define ZMQ_XREQ ZMQ_DEALER
#define ZMQ_XREP ZMQ_ROUTER
/* Socket options. */
#define ZMQ_AFFINITY 4
#define ZMQ_ROUTING_ID 5
#define ZMQ_SUBSCRIBE 6
#define ZMQ_UNSUBSCRIBE 7
#define ZMQ_RATE 8
#define ZMQ_RECOVERY_IVL 9
#define ZMQ_SNDBUF 11
#define ZMQ_RCVBUF 12
#define ZMQ_RCVMORE 13
#define ZMQ_FD 14
#define ZMQ_EVENTS 15
#define ZMQ_TYPE 16
#define ZMQ_LINGER 17
#define ZMQ_RECONNECT_IVL 18
#define ZMQ_BACKLOG 19
#define ZMQ_RECONNECT_IVL_MAX 21
#define ZMQ_MAXMSGSIZE 22
#define ZMQ_SNDHWM 23
#define ZMQ_RCVHWM 24
#define ZMQ_MULTICAST_HOPS 25
#define ZMQ_RCVTIMEO 27
#define ZMQ_SNDTIMEO 28
#define ZMQ_LAST_ENDPOINT 32
#define ZMQ_ROUTER_MANDATORY 33
#define ZMQ_TCP_KEEPALIVE 34
#define ZMQ_TCP_KEEPALIVE_CNT 35
#define ZMQ_TCP_KEEPALIVE_IDLE 36
#define ZMQ_TCP_KEEPALIVE_INTVL 37
#define ZMQ_IMMEDIATE 39
#define ZMQ_XPUB_VERBOSE 40
#define ZMQ_ROUTER_RAW 41
#define ZMQ_IPV6 42
#define ZMQ_MECHANISM 43
#define ZMQ_PLAIN_SERVER 44
#define ZMQ_PLAIN_USERNAME 45
#define ZMQ_PLAIN_PASSWORD 46
#define ZMQ_CURVE_SERVER 47
#define ZMQ_CURVE_PUBLICKEY 48
#define ZMQ_CURVE_SECRETKEY 49
#define ZMQ_CURVE_SERVERKEY 50
#define ZMQ_PROBE_ROUTER 51
#define ZMQ_REQ_CORRELATE 52
#define ZMQ_REQ_RELAXED 53
#define ZMQ_CONFLATE 54
#define ZMQ_ZAP_DOMAIN 55
#define ZMQ_ROUTER_HANDOVER 56
#define ZMQ_TOS 57
#define ZMQ_CONNECT_ROUTING_ID 61
#define ZMQ_GSSAPI_SERVER 62
#define ZMQ_GSSAPI_PRINCIPAL 63
#define ZMQ_GSSAPI_SERVICE_PRINCIPAL 64
#define ZMQ_GSSAPI_PLAINTEXT 65
#define ZMQ_HANDSHAKE_IVL 66
#define ZMQ_SOCKS_PROXY 68
#define ZMQ_XPUB_NODROP 69
#define ZMQ_BLOCKY 70
#define ZMQ_XPUB_MANUAL 71
#define ZMQ_XPUB_WELCOME_MSG 72
#define ZMQ_STREAM_NOTIFY 73
#define ZMQ_INVERT_MATCHING 74
#define ZMQ_HEARTBEAT_IVL 75
#define ZMQ_HEARTBEAT_TTL 76
#define ZMQ_HEARTBEAT_TIMEOUT 77
#define ZMQ_XPUB_VERBOSER 78
#define ZMQ_CONNECT_TIMEOUT 79
#define ZMQ_TCP_MAXRT 80
#define ZMQ_THREAD_SAFE 81
#define ZMQ_MULTICAST_MAXTPDU 84
#define ZMQ_VMCI_BUFFER_SIZE 85
#define ZMQ_VMCI_BUFFER_MIN_SIZE 86
#define ZMQ_VMCI_BUFFER_MAX_SIZE 87
#define ZMQ_VMCI_CONNECT_TIMEOUT 88
#define ZMQ_USE_FD 89
/* Message options */
#define ZMQ_MORE 1
#define ZMQ_SHARED 3
/* Send/recv options. */
#define ZMQ_DONTWAIT 1
#define ZMQ_SNDMORE 2
/* Security mechanisms */
#define ZMQ_NULL 0
#define ZMQ_PLAIN 1
#define ZMQ_CURVE 2
#define ZMQ_GSSAPI 3
/* RADIO-DISH protocol */
#define ZMQ_GROUP_MAX_LENGTH 15
/* Deprecated options and aliases */
#define ZMQ_IDENTITY ZMQ_ROUTING_ID
#define ZMQ_CONNECT_RID ZMQ_CONNECT_ROUTING_ID
#define ZMQ_TCP_ACCEPT_FILTER 38
#define ZMQ_IPC_FILTER_PID 58
#define ZMQ_IPC_FILTER_UID 59
#define ZMQ_IPC_FILTER_GID 60
#define ZMQ_IPV4ONLY 31
#define ZMQ_DELAY_ATTACH_ON_CONNECT ZMQ_IMMEDIATE
#define ZMQ_NOBLOCK ZMQ_DONTWAIT
#define ZMQ_FAIL_UNROUTABLE ZMQ_ROUTER_MANDATORY
#define ZMQ_ROUTER_BEHAVIOR ZMQ_ROUTER_MANDATORY
/* Deprecated Message options */
#define ZMQ_SRCFD 2
/******************************************************************************/
/* 0MQ socket events and monitoring */
/******************************************************************************/
/* Socket transport events (TCP, IPC and TIPC only) */
#define ZMQ_EVENT_CONNECTED 0x0001
#define ZMQ_EVENT_CONNECT_DELAYED 0x0002
#define ZMQ_EVENT_CONNECT_RETRIED 0x0004
#define ZMQ_EVENT_LISTENING 0x0008
#define ZMQ_EVENT_BIND_FAILED 0x0010
#define ZMQ_EVENT_ACCEPTED 0x0020
#define ZMQ_EVENT_ACCEPT_FAILED 0x0040
#define ZMQ_EVENT_CLOSED 0x0080
#define ZMQ_EVENT_CLOSE_FAILED 0x0100
#define ZMQ_EVENT_DISCONNECTED 0x0200
#define ZMQ_EVENT_MONITOR_STOPPED 0x0400
#define ZMQ_EVENT_ALL 0xFFFF
ZMQ_EXPORT void *zmq_socket (void *, int type);
ZMQ_EXPORT int zmq_close (void *s);
ZMQ_EXPORT int zmq_setsockopt (void *s, int option, const void *optval,
size_t optvallen);
ZMQ_EXPORT int zmq_getsockopt (void *s, int option, void *optval,
size_t *optvallen);
ZMQ_EXPORT int zmq_bind (void *s, const char *addr);
ZMQ_EXPORT int zmq_connect (void *s, const char *addr);
ZMQ_EXPORT int zmq_unbind (void *s, const char *addr);
ZMQ_EXPORT int zmq_disconnect (void *s, const char *addr);
ZMQ_EXPORT int zmq_send (void *s, const void *buf, size_t len, int flags);
ZMQ_EXPORT int zmq_send_const (void *s, const void *buf, size_t len, int flags);
ZMQ_EXPORT int zmq_recv (void *s, void *buf, size_t len, int flags);
ZMQ_EXPORT int zmq_socket_monitor (void *s, const char *addr, int events);
/******************************************************************************/
/* Deprecated I/O multiplexing. Prefer using zmq_poller API */
/******************************************************************************/
#define ZMQ_POLLIN 1
#define ZMQ_POLLOUT 2
#define ZMQ_POLLERR 4
#define ZMQ_POLLPRI 8
typedef struct zmq_pollitem_t
{
void *socket;
#if defined _WIN32
SOCKET fd;
#else
int fd;
#endif
short events;
short revents;
} zmq_pollitem_t;
#define ZMQ_POLLITEMS_DFLT 16
ZMQ_EXPORT int zmq_poll (zmq_pollitem_t *items, int nitems, long timeout);
/******************************************************************************/
/* Message proxying */
/******************************************************************************/
ZMQ_EXPORT int zmq_proxy (void *frontend, void *backend, void *capture);
ZMQ_EXPORT int zmq_proxy_steerable (void *frontend, void *backend, void *capture, void *control);
/******************************************************************************/
/* Probe library capabilities */
/******************************************************************************/
#define ZMQ_HAS_CAPABILITIES 1
ZMQ_EXPORT int zmq_has (const char *capability);
/* Deprecated aliases */
#define ZMQ_STREAMER 1
#define ZMQ_FORWARDER 2
#define ZMQ_QUEUE 3
/* Deprecated methods */
ZMQ_EXPORT int zmq_device (int type, void *frontend, void *backend);
ZMQ_EXPORT int zmq_sendmsg (void *s, zmq_msg_t *msg, int flags);
ZMQ_EXPORT int zmq_recvmsg (void *s, zmq_msg_t *msg, int flags);
struct iovec;
ZMQ_EXPORT int zmq_sendiov (void *s, struct iovec *iov, size_t count, int flags);
ZMQ_EXPORT int zmq_recviov (void *s, struct iovec *iov, size_t *count, int flags);
/******************************************************************************/
/* Encryption functions */
/******************************************************************************/
/* Encode data with Z85 encoding. Returns encoded data */
ZMQ_EXPORT char *zmq_z85_encode (char *dest, const uint8_t *data, size_t size);
/* Decode data with Z85 encoding. Returns decoded data */
ZMQ_EXPORT uint8_t *zmq_z85_decode (uint8_t *dest, const char *string);
/* Generate z85-encoded public and private keypair with tweetnacl/libsodium. */
/* Returns 0 on success. */
ZMQ_EXPORT int zmq_curve_keypair (char *z85_public_key, char *z85_secret_key);
/* Derive the z85-encoded public key from the z85-encoded secret key. */
/* Returns 0 on success. */
ZMQ_EXPORT int zmq_curve_public (char *z85_public_key, const char *z85_secret_key);
/******************************************************************************/
/* Atomic utility methods */
/******************************************************************************/
ZMQ_EXPORT void *zmq_atomic_counter_new (void);
ZMQ_EXPORT void zmq_atomic_counter_set (void *counter, int value);
ZMQ_EXPORT int zmq_atomic_counter_inc (void *counter);
ZMQ_EXPORT int zmq_atomic_counter_dec (void *counter);
ZMQ_EXPORT int zmq_atomic_counter_value (void *counter);
ZMQ_EXPORT void zmq_atomic_counter_destroy (void **counter_p);
/******************************************************************************/
/* These functions are not documented by man pages -- use at your own risk. */
/* If you need these to be part of the formal ZMQ API, then (a) write a man */
/* page, and (b) write a test case in tests. */
/******************************************************************************/
/* Helper functions are used by perf tests so that they don't have to care */
/* about minutiae of time-related functions on different OS platforms. */
/* Starts the stopwatch. Returns the handle to the watch. */
ZMQ_EXPORT void *zmq_stopwatch_start (void);
/* Stops the stopwatch. Returns the number of microseconds elapsed since */
/* the stopwatch was started. */
ZMQ_EXPORT unsigned long zmq_stopwatch_stop (void *watch_);
/* Sleeps for specified number of seconds. */
ZMQ_EXPORT void zmq_sleep (int seconds_);
typedef void (zmq_thread_fn) (void*);
/* Start a thread. Returns a handle to the thread. */
ZMQ_EXPORT void *zmq_threadstart (zmq_thread_fn* func, void* arg);
/* Wait for thread to complete then free up resources. */
ZMQ_EXPORT void zmq_threadclose (void* thread);
/******************************************************************************/
/* These functions are DRAFT and disabled in stable releases, and subject to */
/* change at ANY time until declared stable. */
/******************************************************************************/
#ifdef ZMQ_BUILD_DRAFT_API
/* DRAFT Socket types. */
#define ZMQ_SERVER 12
#define ZMQ_CLIENT 13
#define ZMQ_RADIO 14
#define ZMQ_DISH 15
#define ZMQ_GATHER 16
#define ZMQ_SCATTER 17
#define ZMQ_DGRAM 18
/* DRAFT Socket options. */
#define ZMQ_GSSAPI_PRINCIPAL_NAMETYPE 90
#define ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE 91
#define ZMQ_BINDTODEVICE 92
#define ZMQ_ZAP_ENFORCE_DOMAIN 93
/* DRAFT 0MQ socket events and monitoring */
/* Unspecified system errors during handshake. Event value is an errno. */
#define ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL 0x0800
/* Handshake complete successfully with successful authentication (if *
* enabled). Event value is unused. */
#define ZMQ_EVENT_HANDSHAKE_SUCCEEDED 0x1000
/* Protocol errors between ZMTP peers or between server and ZAP handler. *
* Event value is one of ZMQ_PROTOCOL_ERROR_* */
#define ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL 0x2000
/* Failed authentication requests. Event value is the numeric ZAP status *
* code, i.e. 300, 400 or 500. */
#define ZMQ_EVENT_HANDSHAKE_FAILED_AUTH 0x4000
#define ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED 0x10000000
#define ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND 0x10000001
#define ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE 0x10000002
#define ZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE 0x10000003
#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED 0x10000011
#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE 0x10000012
#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO 0x10000013
#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE 0x10000014
#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR 0x10000015
#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY 0x10000016
#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME 0x10000017
#define ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA 0x10000018
// the following two may be due to erroneous configuration of a peer
#define ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC 0x11000001
#define ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH 0x11000002
#define ZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED 0x20000000
#define ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY 0x20000001
#define ZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID 0x20000002
#define ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION 0x20000003
#define ZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE 0x20000004
#define ZMQ_PROTOCOL_ERROR_ZAP_INVALID_METADATA 0x20000005
/* DRAFT Context options */
#define ZMQ_MSG_T_SIZE 6
#define ZMQ_THREAD_AFFINITY_CPU_ADD 7
#define ZMQ_THREAD_AFFINITY_CPU_REMOVE 8
#define ZMQ_THREAD_NAME_PREFIX 9
/* DRAFT Socket methods. */
ZMQ_EXPORT int zmq_join (void *s, const char *group);
ZMQ_EXPORT int zmq_leave (void *s, const char *group);
/* DRAFT Msg methods. */
ZMQ_EXPORT int zmq_msg_set_routing_id(zmq_msg_t *msg, uint32_t routing_id);
ZMQ_EXPORT uint32_t zmq_msg_routing_id(zmq_msg_t *msg);
ZMQ_EXPORT int zmq_msg_set_group(zmq_msg_t *msg, const char *group);
ZMQ_EXPORT const char *zmq_msg_group(zmq_msg_t *msg);
/* DRAFT Msg property names. */
#define ZMQ_MSG_PROPERTY_ROUTING_ID "Routing-Id"
#define ZMQ_MSG_PROPERTY_SOCKET_TYPE "Socket-Type"
#define ZMQ_MSG_PROPERTY_USER_ID "User-Id"
#define ZMQ_MSG_PROPERTY_PEER_ADDRESS "Peer-Address"
/******************************************************************************/
/* Poller polling on sockets,fd and thread-safe sockets */
/******************************************************************************/
#define ZMQ_HAVE_POLLER
typedef struct zmq_poller_event_t
{
void *socket;
#if defined _WIN32
SOCKET fd;
#else
int fd;
#endif
void *user_data;
short events;
} zmq_poller_event_t;
ZMQ_EXPORT void *zmq_poller_new (void);
ZMQ_EXPORT int zmq_poller_destroy (void **poller_p);
ZMQ_EXPORT int zmq_poller_add (void *poller, void *socket, void *user_data, short events);
ZMQ_EXPORT int zmq_poller_modify (void *poller, void *socket, short events);
ZMQ_EXPORT int zmq_poller_remove (void *poller, void *socket);
ZMQ_EXPORT int zmq_poller_wait (void *poller, zmq_poller_event_t *event, long timeout);
ZMQ_EXPORT int zmq_poller_wait_all (void *poller, zmq_poller_event_t *events, int n_events, long timeout);
#if defined _WIN32
ZMQ_EXPORT int zmq_poller_add_fd (void *poller, SOCKET fd, void *user_data, short events);
ZMQ_EXPORT int zmq_poller_modify_fd (void *poller, SOCKET fd, short events);
ZMQ_EXPORT int zmq_poller_remove_fd (void *poller, SOCKET fd);
#else
ZMQ_EXPORT int zmq_poller_add_fd (void *poller, int fd, void *user_data, short events);
ZMQ_EXPORT int zmq_poller_modify_fd (void *poller, int fd, short events);
ZMQ_EXPORT int zmq_poller_remove_fd (void *poller, int fd);
#endif
ZMQ_EXPORT int zmq_socket_get_peer_state (void *socket,
const void *routing_id,
size_t routing_id_size);
/******************************************************************************/
/* Scheduling timers */
/******************************************************************************/
#define ZMQ_HAVE_TIMERS
typedef void (zmq_timer_fn)(int timer_id, void *arg);
ZMQ_EXPORT void *zmq_timers_new (void);
ZMQ_EXPORT int zmq_timers_destroy (void **timers_p);
ZMQ_EXPORT int zmq_timers_add (void *timers, size_t interval, zmq_timer_fn handler, void *arg);
ZMQ_EXPORT int zmq_timers_cancel (void *timers, int timer_id);
ZMQ_EXPORT int zmq_timers_set_interval (void *timers, int timer_id, size_t interval);
ZMQ_EXPORT int zmq_timers_reset (void *timers, int timer_id);
ZMQ_EXPORT long zmq_timers_timeout (void *timers);
ZMQ_EXPORT int zmq_timers_execute (void *timers);
/******************************************************************************/
/* GSSAPI definitions */
/******************************************************************************/
/* GSSAPI principal name types */
#define ZMQ_GSSAPI_NT_HOSTBASED 0
#define ZMQ_GSSAPI_NT_USER_NAME 1
#define ZMQ_GSSAPI_NT_KRB5_PRINCIPAL 2
#endif // ZMQ_BUILD_DRAFT_API
#undef ZMQ_EXPORT
#ifdef __cplusplus
}
#endif
#endif
-48
View File
@@ -1,48 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* This file is deprecated, and all its functionality provided by zmq.h */
/* Note that -Wpedantic compilation requires GCC to avoid using its custom
extensions such as #warning, hence the trick below. Also, pragmas for
warnings or other messages are not standard, not portable, and not all
compilers even have an equivalent concept.
So in the worst case, this include file is treated as silently empty. */
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) || defined(_MSC_VER)
#if defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic push
#pragma GCC diagnostic warning "-Wcpp"
#pragma GCC diagnostic ignored "-Werror"
#pragma GCC diagnostic ignored "-Wall"
#endif
#pragma message("Warning: zmq_utils.h is deprecated. All its functionality is provided by zmq.h.")
#if defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic pop
#endif
#endif
-134
View File
@@ -1,134 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#include "address.hpp"
#include "ctx.hpp"
#include "err.hpp"
#include "tcp_address.hpp"
#include "udp_address.hpp"
#include "ipc_address.hpp"
#include "tipc_address.hpp"
#if defined ZMQ_HAVE_VMCI
#include "vmci_address.hpp"
#endif
#include <string>
#include <sstream>
zmq::address_t::address_t (
const std::string &protocol_, const std::string &address_, ctx_t *parent_)
: protocol (protocol_),
address (address_),
parent (parent_)
{
memset (&resolved, 0, sizeof resolved);
}
zmq::address_t::~address_t ()
{
if (protocol == "tcp") {
if (resolved.tcp_addr) {
LIBZMQ_DELETE(resolved.tcp_addr);
}
}
if (protocol == "udp") {
if (resolved.udp_addr) {
LIBZMQ_DELETE(resolved.udp_addr);
}
}
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
else
if (protocol == "ipc") {
if (resolved.ipc_addr) {
LIBZMQ_DELETE(resolved.ipc_addr);
}
}
#endif
#if defined ZMQ_HAVE_TIPC
else
if (protocol == "tipc") {
if (resolved.tipc_addr) {
LIBZMQ_DELETE(resolved.tipc_addr);
}
}
#endif
#if defined ZMQ_HAVE_VMCI
else
if (protocol == "vmci") {
if (resolved.vmci_addr) {
LIBZMQ_DELETE(resolved.vmci_addr);
}
}
#endif
}
int zmq::address_t::to_string (std::string &addr_) const
{
if (protocol == "tcp") {
if (resolved.tcp_addr)
return resolved.tcp_addr->to_string (addr_);
}
if (protocol == "udp") {
if (resolved.udp_addr)
return resolved.udp_addr->to_string (addr_);
}
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
else
if (protocol == "ipc") {
if (resolved.ipc_addr)
return resolved.ipc_addr->to_string (addr_);
}
#endif
#if defined ZMQ_HAVE_TIPC
else
if (protocol == "tipc") {
if (resolved.tipc_addr)
return resolved.tipc_addr->to_string (addr_);
}
#endif
#if defined ZMQ_HAVE_VMCI
else
if (protocol == "vmci") {
if (resolved.vmci_addr)
return resolved.vmci_addr->to_string (addr_);
}
#endif
if (!protocol.empty () && !address.empty ()) {
std::stringstream s;
s << protocol << "://" << address;
addr_ = s.str ();
return 0;
}
addr_.clear ();
return -1;
}
-77
View File
@@ -1,77 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_ADDRESS_HPP_INCLUDED__
#define __ZMQ_ADDRESS_HPP_INCLUDED__
#include <string>
namespace zmq
{
class ctx_t;
class tcp_address_t;
class udp_address_t;
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
class ipc_address_t;
#endif
#if defined ZMQ_HAVE_LINUX
class tipc_address_t;
#endif
#if defined ZMQ_HAVE_VMCI
class vmci_address_t;
#endif
struct address_t {
address_t (const std::string &protocol_, const std::string &address_, ctx_t *parent_);
~address_t ();
const std::string protocol;
const std::string address;
ctx_t *parent;
// Protocol specific resolved address
union {
tcp_address_t *tcp_addr;
udp_address_t *udp_addr;
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
ipc_address_t *ipc_addr;
#endif
#if defined ZMQ_HAVE_LINUX
tipc_address_t *tipc_addr;
#endif
#if defined ZMQ_HAVE_VMCI
vmci_address_t *vmci_addr;
#endif
} resolved;
int to_string (std::string &addr_) const;
};
}
#endif
-167
View File
@@ -1,167 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_ARRAY_INCLUDED__
#define __ZMQ_ARRAY_INCLUDED__
#include <vector>
#include <algorithm>
namespace zmq
{
// Implementation of fast arrays with O(1) access, insertion and
// removal. The array stores pointers rather than objects.
// O(1) is achieved by making items inheriting from
// array_item_t<ID> class which internally stores the position
// in the array.
// The ID template argument is used to differentiate among arrays
// and thus let an object be stored in different arrays.
// Base class for objects stored in the array. If you want to store
// same object in multiple arrays, each of those arrays has to have
// different ID. The item itself has to be derived from instantiations of
// array_item_t template for all relevant IDs.
template <int ID = 0> class array_item_t
{
public:
inline array_item_t () :
array_index (-1)
{
}
// The destructor doesn't have to be virtual. It is made virtual
// just to keep ICC and code checking tools from complaining.
inline virtual ~array_item_t ()
{
}
inline void set_array_index (int index_)
{
array_index = index_;
}
inline int get_array_index ()
{
return array_index;
}
private:
int array_index;
array_item_t (const array_item_t&);
const array_item_t &operator = (const array_item_t&);
};
template <typename T, int ID = 0> class array_t
{
private:
typedef array_item_t <ID> item_t;
public:
typedef typename std::vector <T*>::size_type size_type;
inline array_t ()
{
}
inline ~array_t ()
{
}
inline size_type size ()
{
return items.size ();
}
inline bool empty ()
{
return items.empty ();
}
inline T *&operator [] (size_type index_)
{
return items [index_];
}
inline void push_back (T *item_)
{
if (item_)
((item_t*) item_)->set_array_index ((int) items.size ());
items.push_back (item_);
}
inline void erase (T *item_) {
erase (((item_t*) item_)->get_array_index ());
}
inline void erase (size_type index_) {
if (items.back ())
((item_t*) items.back ())->set_array_index ((int) index_);
items [index_] = items.back ();
items.pop_back ();
}
inline void swap (size_type index1_, size_type index2_)
{
if (items [index1_])
((item_t*) items [index1_])->set_array_index ((int) index2_);
if (items [index2_])
((item_t*) items [index2_])->set_array_index ((int) index1_);
std::swap (items [index1_], items [index2_]);
}
inline void clear ()
{
items.clear ();
}
inline size_type index (T *item_)
{
return (size_type) ((item_t*) item_)->get_array_index ();
}
private:
typedef std::vector <T*> items_t;
items_t items;
array_t (const array_t&);
const array_t &operator = (const array_t&);
};
}
#endif
-249
View File
@@ -1,249 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_ATOMIC_COUNTER_HPP_INCLUDED__
#define __ZMQ_ATOMIC_COUNTER_HPP_INCLUDED__
#include "stdint.hpp"
#if defined ZMQ_FORCE_MUTEXES
#define ZMQ_ATOMIC_COUNTER_MUTEX
#elif defined ZMQ_HAVE_ATOMIC_INTRINSICS
#define ZMQ_ATOMIC_COUNTER_INTRINSIC
#elif (defined __cplusplus && __cplusplus >= 201103L)
#define ZMQ_ATOMIC_COUNTER_CXX11
#elif (defined __i386__ || defined __x86_64__) && defined __GNUC__
#define ZMQ_ATOMIC_COUNTER_X86
#elif defined __ARM_ARCH_7A__ && defined __GNUC__
#define ZMQ_ATOMIC_COUNTER_ARM
#elif defined ZMQ_HAVE_WINDOWS
#define ZMQ_ATOMIC_COUNTER_WINDOWS
#elif (defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_NETBSD || defined ZMQ_HAVE_GNU)
#define ZMQ_ATOMIC_COUNTER_ATOMIC_H
#elif defined __tile__
#define ZMQ_ATOMIC_COUNTER_TILE
#else
#define ZMQ_ATOMIC_COUNTER_MUTEX
#endif
#if defined ZMQ_ATOMIC_COUNTER_MUTEX
#include "mutex.hpp"
#elif defined ZMQ_ATOMIC_COUNTER_CXX11
#include <atomic>
#elif defined ZMQ_ATOMIC_COUNTER_WINDOWS
#include "windows.hpp"
#elif defined ZMQ_ATOMIC_COUNTER_ATOMIC_H
#include <atomic.h>
#elif defined ZMQ_ATOMIC_COUNTER_TILE
#include <arch/atomic.h>
#endif
namespace zmq
{
// This class represents an integer that can be incremented/decremented
// in atomic fashion.
//
// In zmq::shared_message_memory_allocator a buffer with an atomic_counter_t
// at the start is allocated. If the class does not align to pointer size,
// access to pointers in structures in the buffer will cause SIGBUS on
// architectures that do not allow mis-aligned pointers (eg: SPARC).
// Force the compiler to align to pointer size, which will cause the object
// to grow from 4 bytes to 8 bytes on 64 bit architectures (when not using
// mutexes).
#if defined (_MSC_VER) && (defined (_M_X64) || defined (_M_ARM64))
class __declspec (align (8)) atomic_counter_t
#elif defined (_MSC_VER) && (defined (_M_IX86) || defined (_M_ARM_ARMV7VE))
class __declspec (align (4)) atomic_counter_t
#else
class atomic_counter_t
#endif
{
public:
typedef uint32_t integer_t;
inline atomic_counter_t (integer_t value_ = 0) :
value (value_)
{
}
inline ~atomic_counter_t ()
{
}
// Set counter value (not thread-safe).
inline void set (integer_t value_)
{
value = value_;
}
// Atomic addition. Returns the old value.
inline integer_t add (integer_t increment_)
{
integer_t old_value;
#if defined ZMQ_ATOMIC_COUNTER_WINDOWS
old_value = InterlockedExchangeAdd ((LONG*) &value, increment_);
#elif defined ZMQ_ATOMIC_COUNTER_INTRINSIC
old_value = __atomic_fetch_add(&value, increment_, __ATOMIC_ACQ_REL);
#elif defined ZMQ_ATOMIC_COUNTER_CXX11
old_value = value.fetch_add(increment_, std::memory_order_acq_rel);
#elif defined ZMQ_ATOMIC_COUNTER_ATOMIC_H
integer_t new_value = atomic_add_32_nv (&value, increment_);
old_value = new_value - increment_;
#elif defined ZMQ_ATOMIC_COUNTER_TILE
old_value = arch_atomic_add (&value, increment_);
#elif defined ZMQ_ATOMIC_COUNTER_X86
__asm__ volatile (
"lock; xadd %0, %1 \n\t"
: "=r" (old_value), "=m" (value)
: "0" (increment_), "m" (value)
: "cc", "memory");
#elif defined ZMQ_ATOMIC_COUNTER_ARM
integer_t flag, tmp;
__asm__ volatile (
" dmb sy\n\t"
"1: ldrex %0, [%5]\n\t"
" add %2, %0, %4\n\t"
" strex %1, %2, [%5]\n\t"
" teq %1, #0\n\t"
" bne 1b\n\t"
" dmb sy\n\t"
: "=&r"(old_value), "=&r"(flag), "=&r"(tmp), "+Qo"(value)
: "Ir"(increment_), "r"(&value)
: "cc");
#elif defined ZMQ_ATOMIC_COUNTER_MUTEX
sync.lock ();
old_value = value;
value += increment_;
sync.unlock ();
#else
#error atomic_counter is not implemented for this platform
#endif
return old_value;
}
// Atomic subtraction. Returns false if the counter drops to zero.
inline bool sub (integer_t decrement)
{
#if defined ZMQ_ATOMIC_COUNTER_WINDOWS
LONG delta = - ((LONG) decrement);
integer_t old = InterlockedExchangeAdd ((LONG*) &value, delta);
return old - decrement != 0;
#elif defined ZMQ_ATOMIC_COUNTER_INTRINSIC
integer_t nv = __atomic_sub_fetch(&value, decrement, __ATOMIC_ACQ_REL);
return nv != 0;
#elif defined ZMQ_ATOMIC_COUNTER_CXX11
integer_t old = value.fetch_sub(decrement, std::memory_order_acq_rel);
return old - decrement != 0;
#elif defined ZMQ_ATOMIC_COUNTER_ATOMIC_H
int32_t delta = - ((int32_t) decrement);
integer_t nv = atomic_add_32_nv (&value, delta);
return nv != 0;
#elif defined ZMQ_ATOMIC_COUNTER_TILE
int32_t delta = - ((int32_t) decrement);
integer_t nv = arch_atomic_add (&value, delta);
return nv != 0;
#elif defined ZMQ_ATOMIC_COUNTER_X86
integer_t oldval = -decrement;
volatile integer_t *val = &value;
__asm__ volatile ("lock; xaddl %0,%1"
: "=r" (oldval), "=m" (*val)
: "0" (oldval), "m" (*val)
: "cc", "memory");
return oldval != decrement;
#elif defined ZMQ_ATOMIC_COUNTER_ARM
integer_t old_value, flag, tmp;
__asm__ volatile (
" dmb sy\n\t"
"1: ldrex %0, [%5]\n\t"
" sub %2, %0, %4\n\t"
" strex %1, %2, [%5]\n\t"
" teq %1, #0\n\t"
" bne 1b\n\t"
" dmb sy\n\t"
: "=&r"(old_value), "=&r"(flag), "=&r"(tmp), "+Qo"(value)
: "Ir"(decrement), "r"(&value)
: "cc");
return old_value - decrement != 0;
#elif defined ZMQ_ATOMIC_COUNTER_MUTEX
sync.lock ();
value -= decrement;
bool result = value ? true : false;
sync.unlock ();
return result;
#else
#error atomic_counter is not implemented for this platform
#endif
}
inline integer_t get () const
{
return value;
}
private:
#if defined ZMQ_ATOMIC_COUNTER_CXX11
std::atomic<integer_t> value;
#else
volatile integer_t value;
#endif
#if defined ZMQ_ATOMIC_COUNTER_MUTEX
mutex_t sync;
#endif
#if ! defined ZMQ_ATOMIC_COUNTER_CXX11
atomic_counter_t (const atomic_counter_t&);
const atomic_counter_t& operator = (const atomic_counter_t&);
#endif
#if defined (__GNUC__) || defined ( __INTEL_COMPILER) || \
(defined (__SUNPRO_C) && __SUNPRO_C >= 0x590) || \
(defined (__SUNPRO_CC) && __SUNPRO_CC >= 0x590)
} __attribute__ ((aligned (sizeof (void *))));
#else
};
#endif
}
// Remove macros local to this file.
#undef ZMQ_ATOMIC_COUNTER_MUTEX
#undef ZMQ_ATOMIC_COUNTER_INTRINSIC
#undef ZMQ_ATOMIC_COUNTER_CXX11
#undef ZMQ_ATOMIC_COUNTER_X86
#undef ZMQ_ATOMIC_COUNTER_ARM
#undef ZMQ_ATOMIC_COUNTER_WINDOWS
#undef ZMQ_ATOMIC_COUNTER_ATOMIC_H
#undef ZMQ_ATOMIC_COUNTER_TILE
#endif
-227
View File
@@ -1,227 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_ATOMIC_PTR_HPP_INCLUDED__
#define __ZMQ_ATOMIC_PTR_HPP_INCLUDED__
#if defined ZMQ_FORCE_MUTEXES
#define ZMQ_ATOMIC_PTR_MUTEX
#elif defined ZMQ_HAVE_ATOMIC_INTRINSICS
#define ZMQ_ATOMIC_PTR_INTRINSIC
#elif (defined __cplusplus && __cplusplus >= 201103L)
#define ZMQ_ATOMIC_PTR_CXX11
#elif (defined __i386__ || defined __x86_64__) && defined __GNUC__
#define ZMQ_ATOMIC_PTR_X86
#elif defined __ARM_ARCH_7A__ && defined __GNUC__
#define ZMQ_ATOMIC_PTR_ARM
#elif defined __tile__
#define ZMQ_ATOMIC_PTR_TILE
#elif defined ZMQ_HAVE_WINDOWS
#define ZMQ_ATOMIC_PTR_WINDOWS
#elif (defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_NETBSD || defined ZMQ_HAVE_GNU)
#define ZMQ_ATOMIC_PTR_ATOMIC_H
#else
#define ZMQ_ATOMIC_PTR_MUTEX
#endif
#if defined ZMQ_ATOMIC_PTR_MUTEX
#include "mutex.hpp"
#elif defined ZMQ_ATOMIC_PTR_CXX11
#include <atomic>
#elif defined ZMQ_ATOMIC_PTR_WINDOWS
#include "windows.hpp"
#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
#include <atomic.h>
#elif defined ZMQ_ATOMIC_PTR_TILE
#include <arch/atomic.h>
#endif
namespace zmq
{
// This class encapsulates several atomic operations on pointers.
template <typename T> class atomic_ptr_t
{
public:
// Initialise atomic pointer
inline atomic_ptr_t ()
{
ptr = NULL;
}
// Destroy atomic pointer
inline ~atomic_ptr_t ()
{
}
// Set value of atomic pointer in a non-threadsafe way
// Use this function only when you are sure that at most one
// thread is accessing the pointer at the moment.
inline void set (T *ptr_)
{
this->ptr = ptr_;
}
// Perform atomic 'exchange pointers' operation. Pointer is set
// to the 'val' value. Old value is returned.
inline T *xchg (T *val_)
{
#if defined ZMQ_ATOMIC_PTR_WINDOWS
return (T*) InterlockedExchangePointer ((PVOID*) &ptr, val_);
#elif defined ZMQ_ATOMIC_PTR_INTRINSIC
return (T*) __atomic_exchange_n (&ptr, val_, __ATOMIC_ACQ_REL);
#elif defined ZMQ_ATOMIC_PTR_CXX11
return ptr.exchange(val_, std::memory_order_acq_rel);
#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
return (T*) atomic_swap_ptr (&ptr, val_);
#elif defined ZMQ_ATOMIC_PTR_TILE
return (T*) arch_atomic_exchange (&ptr, val_);
#elif defined ZMQ_ATOMIC_PTR_X86
T *old;
__asm__ volatile (
"lock; xchg %0, %2"
: "=r" (old), "=m" (ptr)
: "m" (ptr), "0" (val_));
return old;
#elif defined ZMQ_ATOMIC_PTR_ARM
T* old;
unsigned int flag;
__asm__ volatile (
" dmb sy\n\t"
"1: ldrex %1, [%3]\n\t"
" strex %0, %4, [%3]\n\t"
" teq %0, #0\n\t"
" bne 1b\n\t"
" dmb sy\n\t"
: "=&r"(flag), "=&r"(old), "+Qo"(ptr)
: "r"(&ptr), "r"(val_)
: "cc");
return old;
#elif defined ZMQ_ATOMIC_PTR_MUTEX
sync.lock ();
T *old = (T*) ptr;
ptr = val_;
sync.unlock ();
return old;
#else
#error atomic_ptr is not implemented for this platform
#endif
}
// Perform atomic 'compare and swap' operation on the pointer.
// The pointer is compared to 'cmp' argument and if they are
// equal, its value is set to 'val'. Old value of the pointer
// is returned.
inline T *cas (T *cmp_, T *val_)
{
#if defined ZMQ_ATOMIC_PTR_WINDOWS
return (T*) InterlockedCompareExchangePointer (
(volatile PVOID*) &ptr, val_, cmp_);
#elif defined ZMQ_ATOMIC_PTR_INTRINSIC
T *old = cmp_;
__atomic_compare_exchange_n (&ptr, (volatile T**) &old, val_, false,
__ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
return old;
#elif defined ZMQ_ATOMIC_PTR_CXX11
ptr.compare_exchange_strong(cmp_, val_, std::memory_order_acq_rel);
return cmp_;
#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
return (T*) atomic_cas_ptr (&ptr, cmp_, val_);
#elif defined ZMQ_ATOMIC_PTR_TILE
return (T*) arch_atomic_val_compare_and_exchange (&ptr, cmp_, val_);
#elif defined ZMQ_ATOMIC_PTR_X86
T *old;
__asm__ volatile (
"lock; cmpxchg %2, %3"
: "=a" (old), "=m" (ptr)
: "r" (val_), "m" (ptr), "0" (cmp_)
: "cc");
return old;
#elif defined ZMQ_ATOMIC_PTR_ARM
T *old;
unsigned int flag;
__asm__ volatile (
" dmb sy\n\t"
"1: ldrex %1, [%3]\n\t"
" mov %0, #0\n\t"
" teq %1, %4\n\t"
" it eq\n\t"
" strexeq %0, %5, [%3]\n\t"
" teq %0, #0\n\t"
" bne 1b\n\t"
" dmb sy\n\t"
: "=&r"(flag), "=&r"(old), "+Qo"(ptr)
: "r"(&ptr), "r"(cmp_), "r"(val_)
: "cc");
return old;
#elif defined ZMQ_ATOMIC_PTR_MUTEX
sync.lock ();
T *old = (T*) ptr;
if (ptr == cmp_)
ptr = val_;
sync.unlock ();
return old;
#else
#error atomic_ptr is not implemented for this platform
#endif
}
private:
#if defined ZMQ_ATOMIC_PTR_CXX11
std::atomic<T*> ptr;
#else
volatile T *ptr;
#endif
#if defined ZMQ_ATOMIC_PTR_MUTEX
mutex_t sync;
#endif
#if ! defined ZMQ_ATOMIC_PTR_CXX11
atomic_ptr_t (const atomic_ptr_t&);
const atomic_ptr_t &operator = (const atomic_ptr_t&);
#endif
};
}
// Remove macros local to this file.
#undef ZMQ_ATOMIC_PTR_MUTEX
#undef ZMQ_ATOMIC_PTR_INTRINSIC
#undef ZMQ_ATOMIC_PTR_CXX11
#undef ZMQ_ATOMIC_PTR_X86
#undef ZMQ_ATOMIC_PTR_ARM
#undef ZMQ_ATOMIC_PTR_TILE
#undef ZMQ_ATOMIC_PTR_WINDOWS
#undef ZMQ_ATOMIC_PTR_ATOMIC_H
#endif
-186
View File
@@ -1,186 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_BLOB_HPP_INCLUDED__
#define __ZMQ_BLOB_HPP_INCLUDED__
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#if __cplusplus >= 201103L || defined(_MSC_VER) && _MSC_VER >= 1700
#define ZMQ_HAS_MOVE_SEMANTICS
#define ZMQ_MAP_INSERT_OR_EMPLACE(k, v) emplace (k,v)
#define ZMQ_PUSH_OR_EMPLACE_BACK emplace_back
#define ZMQ_MOVE(x) std::move (x)
#else
#define ZMQ_MAP_INSERT_OR_EMPLACE(k, v) insert (std::make_pair (k, v))
#define ZMQ_PUSH_OR_EMPLACE_BACK push_back
#define ZMQ_MOVE(x) (x)
#endif
namespace zmq
{
struct reference_tag_t {};
// Object to hold dynamically allocated opaque binary data.
// On modern compilers, it will be movable but not copyable. Copies
// must be explicitly created by set_deep_copy.
// On older compilers, it is copyable for syntactical reasons.
struct blob_t
{
// Creates an empty blob_t.
blob_t () : data_ (0), size_ (0), owned_ (true) {}
// Creates a blob_t of a given size, with uninitialized content.
blob_t (const size_t size)
: data_ ((unsigned char*)malloc (size))
, size_ (size)
, owned_ (true)
{
}
// Creates a blob_t of a given size, an initializes content by copying
// from another buffer.
blob_t(const unsigned char * const data, const size_t size)
: data_ ((unsigned char*)malloc (size))
, size_ (size)
, owned_ (true)
{
memcpy(data_, data, size_);
}
// Creates a blob_t for temporary use that only references a
// pre-allocated block of data.
// Use with caution and ensure that the blob_t will not outlive
// the referenced data.
blob_t (unsigned char * const data, const size_t size, reference_tag_t)
: data_ (data)
, size_ (size)
, owned_ (false)
{
}
// Returns the size of the blob_t.
size_t size () const { return size_; }
// Returns a pointer to the data of the blob_t.
const unsigned char *data() const {
return data_;
}
// Returns a pointer to the data of the blob_t.
unsigned char *data() {
return data_;
}
// Defines an order relationship on blob_t.
bool operator< (blob_t const &other) const {
int cmpres = memcmp (data_, other.data_, std::min (size_, other.size_));
return cmpres < 0 || (cmpres == 0 && size_ < other.size_);
}
// Sets a blob_t to a deep copy of another blob_t.
void set_deep_copy (blob_t const &other)
{
clear ();
data_ = (unsigned char*)malloc (other.size_);
size_ = other.size_;
owned_ = true;
memcpy (data_, other.data_, size_);
}
// Sets a blob_t to a copy of a given buffer.
void set (const unsigned char * const data, const size_t size)
{
clear ();
data_ = (unsigned char*)malloc (size);
size_ = size;
owned_ = true;
memcpy (data_, data, size_);
}
// Empties a blob_t.
void clear () {
if (owned_) { free (data_); }
data_ = 0; size_ = 0;
}
~blob_t () {
if (owned_) { free (data_); }
}
#ifdef ZMQ_HAS_MOVE_SEMANTICS
blob_t (const blob_t &) = delete;
blob_t &operator= (const blob_t &) = delete;
blob_t (blob_t&& other)
: data_ (other.data_)
, size_ (other.size_)
, owned_ (other.owned_)
{
other.owned_ = false;
}
blob_t &operator= (blob_t&& other) {
if (this != &other)
{
clear ();
data_ = other.data_;
size_ = other.size_;
owned_ = other.owned_;
other.owned_ = false;
}
return *this;
}
#else
blob_t (const blob_t &other)
: owned_(false)
{
set_deep_copy (other);
}
blob_t &operator= (const blob_t &other) {
if (this != &other)
{
clear ();
set_deep_copy (other);
}
return *this;
}
#endif
private:
unsigned char *data_;
size_t size_;
bool owned_;
};
}
#endif
-116
View File
@@ -1,116 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#include "client.hpp"
#include "err.hpp"
#include "msg.hpp"
zmq::client_t::client_t (class ctx_t *parent_, uint32_t tid_, int sid_) :
socket_base_t (parent_, tid_, sid_, true)
{
options.type = ZMQ_CLIENT;
}
zmq::client_t::~client_t ()
{
}
void zmq::client_t::xattach_pipe (pipe_t *pipe_, bool subscribe_to_all_)
{
LIBZMQ_UNUSED (subscribe_to_all_);
zmq_assert (pipe_);
fq.attach (pipe_);
lb.attach (pipe_);
}
int zmq::client_t::xsend (msg_t *msg_)
{
// CLIENT sockets do not allow multipart data (ZMQ_SNDMORE)
if (msg_->flags () & msg_t::more) {
errno = EINVAL;
return -1;
}
return lb.sendpipe (msg_, NULL);
}
int zmq::client_t::xrecv (msg_t *msg_)
{
int rc = fq.recvpipe (msg_, NULL);
// Drop any messages with more flag
while (rc == 0 && msg_->flags () & msg_t::more) {
// drop all frames of the current multi-frame message
rc = fq.recvpipe (msg_, NULL);
while (rc == 0 && msg_->flags () & msg_t::more)
rc = fq.recvpipe (msg_, NULL);
// get the new message
if (rc == 0)
rc = fq.recvpipe (msg_, NULL);
}
return rc;
}
bool zmq::client_t::xhas_in ()
{
return fq.has_in ();
}
bool zmq::client_t::xhas_out ()
{
return lb.has_out ();
}
const zmq::blob_t &zmq::client_t::get_credential () const
{
return fq.get_credential ();
}
void zmq::client_t::xread_activated (pipe_t *pipe_)
{
fq.activated (pipe_);
}
void zmq::client_t::xwrite_activated (pipe_t *pipe_)
{
lb.activated (pipe_);
}
void zmq::client_t::xpipe_terminated (pipe_t *pipe_)
{
fq.pipe_terminated (pipe_);
lb.pipe_terminated (pipe_);
}
-81
View File
@@ -1,81 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_CLIENT_HPP_INCLUDED__
#define __ZMQ_CLIENT_HPP_INCLUDED__
#include "socket_base.hpp"
#include "session_base.hpp"
#include "fq.hpp"
#include "lb.hpp"
namespace zmq
{
class ctx_t;
class msg_t;
class pipe_t;
class io_thread_t;
class socket_base_t;
class client_t :
public socket_base_t
{
public:
client_t (zmq::ctx_t *parent_, uint32_t tid_, int sid);
~client_t ();
protected:
// Overrides of functions from socket_base_t.
void xattach_pipe (zmq::pipe_t *pipe_, bool subscribe_to_all_);
int xsend (zmq::msg_t *msg_);
int xrecv (zmq::msg_t *msg_);
bool xhas_in ();
bool xhas_out ();
const blob_t &get_credential () const;
void xread_activated (zmq::pipe_t *pipe_);
void xwrite_activated (zmq::pipe_t *pipe_);
void xpipe_terminated (zmq::pipe_t *pipe_);
private:
// Messages are fair-queued from inbound pipes. And load-balanced to
// the outbound pipes.
fq_t fq;
lb_t lb;
client_t (const client_t &);
const client_t &operator = (const client_t&);
};
}
#endif
-253
View File
@@ -1,253 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "clock.hpp"
#include "likely.hpp"
#include "config.hpp"
#include "err.hpp"
#include "mutex.hpp"
#include <stddef.h>
#if defined _MSC_VER
#if defined _WIN32_WCE
#include <cmnintrin.h>
#else
#include <intrin.h>
#endif
#endif
#if !defined ZMQ_HAVE_WINDOWS
#include <sys/time.h>
#endif
#if defined HAVE_CLOCK_GETTIME || defined HAVE_GETHRTIME
#include <time.h>
#endif
#if defined ZMQ_HAVE_OSX
#include <mach/clock.h>
#include <mach/mach.h>
#include <time.h>
#include <sys/time.h>
int alt_clock_gettime (int clock_id, timespec *ts)
{
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service (mach_host_self (), clock_id, &cclock);
clock_get_time (cclock, &mts);
mach_port_deallocate (mach_task_self (), cclock);
ts->tv_sec = mts.tv_sec;
ts->tv_nsec = mts.tv_nsec;
return 0;
}
#endif
#ifdef ZMQ_HAVE_WINDOWS
typedef ULONGLONG (*f_compatible_get_tick_count64)();
static zmq::mutex_t compatible_get_tick_count64_mutex;
ULONGLONG compatible_get_tick_count64()
{
#ifdef ZMQ_HAVE_WINDOWS_UWP
const ULONGLONG result = ::GetTickCount64();
return result;
#else
zmq::scoped_lock_t locker(compatible_get_tick_count64_mutex);
static DWORD s_wrap = 0;
static DWORD s_last_tick = 0;
const DWORD current_tick = ::GetTickCount();
if (current_tick < s_last_tick)
++s_wrap;
s_last_tick = current_tick;
const ULONGLONG result = (static_cast<ULONGLONG>(s_wrap) << 32) + static_cast<ULONGLONG>(current_tick);
return result;
#endif
}
f_compatible_get_tick_count64 init_compatible_get_tick_count64()
{
f_compatible_get_tick_count64 func = NULL;
#if !defined ZMQ_HAVE_WINDOWS_UWP
HMODULE module = ::LoadLibraryA("Kernel32.dll");
if (module != NULL)
func = reinterpret_cast<f_compatible_get_tick_count64>(::GetProcAddress(module, "GetTickCount64"));
#endif
if (func == NULL)
func = compatible_get_tick_count64;
#if !defined ZMQ_HAVE_WINDOWS_UWP
::FreeLibrary(module);
#endif
return func;
}
static f_compatible_get_tick_count64 my_get_tick_count64 = init_compatible_get_tick_count64();
#endif
zmq::clock_t::clock_t () :
last_tsc (rdtsc ()),
#ifdef ZMQ_HAVE_WINDOWS
last_time (static_cast<uint64_t>((*my_get_tick_count64)()))
#else
last_time (now_us () / 1000)
#endif
{
}
zmq::clock_t::~clock_t ()
{
}
uint64_t zmq::clock_t::now_us ()
{
#if defined ZMQ_HAVE_WINDOWS
// Get the high resolution counter's accuracy.
LARGE_INTEGER ticksPerSecond;
QueryPerformanceFrequency (&ticksPerSecond);
// What time is it?
LARGE_INTEGER tick;
QueryPerformanceCounter (&tick);
// Convert the tick number into the number of seconds
// since the system was started.
double ticks_div = ticksPerSecond.QuadPart / 1000000.0;
return (uint64_t) (tick.QuadPart / ticks_div);
#elif defined HAVE_CLOCK_GETTIME && defined CLOCK_MONOTONIC
// Use POSIX clock_gettime function to get precise monotonic time.
struct timespec tv;
#if defined ZMQ_HAVE_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 // less than macOS 10.12
int rc = alt_clock_gettime (SYSTEM_CLOCK, &tv);
#else
int rc = clock_gettime (CLOCK_MONOTONIC, &tv);
#endif
// Fix case where system has clock_gettime but CLOCK_MONOTONIC is not supported.
// This should be a configuration check, but I looked into it and writing an
// AC_FUNC_CLOCK_MONOTONIC seems beyond my powers.
if( rc != 0) {
// Use POSIX gettimeofday function to get precise time.
struct timeval tv;
int rc = gettimeofday (&tv, NULL);
errno_assert (rc == 0);
return (tv.tv_sec * (uint64_t) 1000000 + tv.tv_usec);
}
return (tv.tv_sec * (uint64_t) 1000000 + tv.tv_nsec / 1000);
#elif defined HAVE_GETHRTIME
return (gethrtime () / 1000);
#else
// Use POSIX gettimeofday function to get precise time.
struct timeval tv;
int rc = gettimeofday (&tv, NULL);
errno_assert (rc == 0);
return (tv.tv_sec * (uint64_t) 1000000 + tv.tv_usec);
#endif
}
uint64_t zmq::clock_t::now_ms ()
{
uint64_t tsc = rdtsc ();
// If TSC is not supported, get precise time and chop off the microseconds.
if (!tsc)
{
#ifdef ZMQ_HAVE_WINDOWS
// Under Windows, now_us is not so reliable since QueryPerformanceCounter
// does not guarantee that it will use a hardware that offers a monotonic timer.
// So, lets use GetTickCount when GetTickCount64 is not available with an workaround
// to its 32 bit limitation.
return static_cast<uint64_t>((*my_get_tick_count64)());
#else
return now_us () / 1000;
#endif
}
// If TSC haven't jumped back (in case of migration to a different
// CPU core) and if not too much time elapsed since last measurement,
// we can return cached time value.
if (likely (tsc - last_tsc <= (clock_precision / 2) && tsc >= last_tsc))
return last_time;
last_tsc = tsc;
#ifdef ZMQ_HAVE_WINDOWS
last_time = static_cast<uint64_t>((*my_get_tick_count64)());
#else
last_time = now_us () / 1000;
#endif
return last_time;
}
uint64_t zmq::clock_t::rdtsc ()
{
#if (defined _MSC_VER && (defined _M_IX86 || defined _M_X64))
return __rdtsc ();
#elif (defined __GNUC__ && (defined __i386__ || defined __x86_64__))
uint32_t low, high;
__asm__ volatile ("rdtsc" : "=a" (low), "=d" (high));
return (uint64_t) high << 32 | low;
#elif (defined __SUNPRO_CC && (__SUNPRO_CC >= 0x5100) && (defined __i386 || \
defined __amd64 || defined __x86_64))
union {
uint64_t u64val;
uint32_t u32val [2];
} tsc;
asm("rdtsc" : "=a" (tsc.u32val [0]), "=d" (tsc.u32val [1]));
return tsc.u64val;
#elif defined(__s390__)
uint64_t tsc;
asm("\tstck\t%0\n" : "=Q" (tsc) : : "cc");
return(tsc);
#else
struct timespec ts;
#if defined ZMQ_HAVE_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 // less than macOS 10.12
alt_clock_gettime (SYSTEM_CLOCK, &ts);
#else
clock_gettime (CLOCK_MONOTONIC, &ts);
#endif
return (uint64_t)(ts.tv_sec) * 1000000000 + ts.tv_nsec;
#endif
}
-83
View File
@@ -1,83 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_CLOCK_HPP_INCLUDED__
#define __ZMQ_CLOCK_HPP_INCLUDED__
#include "stdint.hpp"
#if defined ZMQ_HAVE_OSX
#include <mach/clock.h>
#include <mach/mach.h>
#include <time.h>
#include <sys/time.h>
int alt_clock_gettime (int clock_id, timespec *ts);
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif
#ifndef HAVE_CLOCK_GETTIME
#define HAVE_CLOCK_GETTIME
#endif
#endif
namespace zmq
{
class clock_t
{
public:
clock_t ();
~clock_t ();
// CPU's timestamp counter. Returns 0 if it's not available.
static uint64_t rdtsc ();
// High precision timestamp.
static uint64_t now_us ();
// Low precision timestamp. In tight loops generating it can be
// 10 to 100 times faster than the high precision timestamp.
uint64_t now_ms ();
private:
// TSC timestamp of when last time measurement was made.
uint64_t last_tsc;
// Physical time corresponding to the TSC above (in milliseconds).
uint64_t last_time;
clock_t (const clock_t&);
const clock_t &operator = (const clock_t&);
};
}
#endif
-188
View File
@@ -1,188 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_COMMAND_HPP_INCLUDED__
#define __ZMQ_COMMAND_HPP_INCLUDED__
#include <string>
#include "stdint.hpp"
namespace zmq
{
class object_t;
class own_t;
struct i_engine;
class pipe_t;
class socket_base_t;
// This structure defines the commands that can be sent between threads.
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4324) // C4324: alignment padding warnings
__declspec(align(64))
#endif
struct command_t
{
// Object to process the command.
zmq::object_t *destination;
enum type_t
{
stop,
plug,
own,
attach,
bind,
activate_read,
activate_write,
hiccup,
pipe_term,
pipe_term_ack,
pipe_hwm,
term_req,
term,
term_ack,
term_endpoint,
reap,
reaped,
inproc_connected,
done
} type;
union args_t
{
// Sent to I/O thread to let it know that it should
// terminate itself.
struct {
} stop;
// Sent to I/O object to make it register with its I/O thread.
struct {
} plug;
// Sent to socket to let it know about the newly created object.
struct {
zmq::own_t *object;
} own;
// Attach the engine to the session. If engine is NULL, it informs
// session that the connection have failed.
struct {
struct i_engine *engine;
} attach;
// Sent from session to socket to establish pipe(s) between them.
// Caller have used inc_seqnum beforehand sending the command.
struct {
zmq::pipe_t *pipe;
} bind;
// Sent by pipe writer to inform dormant pipe reader that there
// are messages in the pipe.
struct {
} activate_read;
// Sent by pipe reader to inform pipe writer about how many
// messages it has read so far.
struct {
uint64_t msgs_read;
} activate_write;
// Sent by pipe reader to writer after creating a new inpipe.
// The parameter is actually of type pipe_t::upipe_t, however,
// its definition is private so we'll have to do with void*.
struct {
void *pipe;
} hiccup;
// Sent by pipe reader to pipe writer to ask it to terminate
// its end of the pipe.
struct {
} pipe_term;
// Pipe writer acknowledges pipe_term command.
struct {
} pipe_term_ack;
// Sent by one of pipe to another part for modify hwm
struct {
int inhwm;
int outhwm;
} pipe_hwm;
// Sent by I/O object ot the socket to request the shutdown of
// the I/O object.
struct {
zmq::own_t *object;
} term_req;
// Sent by socket to I/O object to start its shutdown.
struct {
int linger;
} term;
// Sent by I/O object to the socket to acknowledge it has
// shut down.
struct {
} term_ack;
// Sent by session_base (I/O thread) to socket (application thread)
// to ask to disconnect the endpoint.
struct {
std::string *endpoint;
} term_endpoint;
// Transfers the ownership of the closed socket
// to the reaper thread.
struct {
zmq::socket_base_t *socket;
} reap;
// Closed socket notifies the reaper that it's already deallocated.
struct {
} reaped;
// Sent by reaper thread to the term thread when all the sockets
// are successfully deallocated.
struct {
} done;
} args;
#ifdef _MSC_VER
};
#pragma warning(pop)
#else
} __attribute__((aligned(64)));
#endif
}
#endif
-279
View File
@@ -1,279 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_CONDITON_VARIABLE_HPP_INCLUDED__
#define __ZMQ_CONDITON_VARIABLE_HPP_INCLUDED__
#include "clock.hpp"
#include "err.hpp"
#include "mutex.hpp"
// Condition variable class encapsulates OS mutex in a platform-independent way.
#ifdef ZMQ_HAVE_WINDOWS
#include "windows.hpp"
#if defined(_MSC_VER)
#if _MSC_VER >= 1800
#define _SUPPORT_CONDITION_VARIABLE 1
#else
#define _SUPPORT_CONDITION_VARIABLE 0
#endif
#else
#if _cplusplus >= 201103L
#define _SUPPORT_CONDITION_VARIABLE 1
#else
#define _SUPPORT_CONDITION_VARIABLE 0
#endif
#endif
// Condition variable is supported from Windows Vista only, to use condition variable define _WIN32_WINNT to 0x0600
#if _WIN32_WINNT < 0x0600 && !_SUPPORT_CONDITION_VARIABLE
namespace zmq
{
class condition_variable_t
{
public:
inline condition_variable_t ()
{
zmq_assert(false);
}
inline ~condition_variable_t ()
{
}
inline int wait (mutex_t* mutex_, int timeout_ )
{
zmq_assert(false);
return -1;
}
inline void broadcast ()
{
zmq_assert(false);
}
private:
// Disable copy construction and assignment.
condition_variable_t (const condition_variable_t&);
void operator = (const condition_variable_t&);
};
}
#else
#if _SUPPORT_CONDITION_VARIABLE || defined(ZMQ_HAVE_WINDOWS_TARGET_XP)
#include <condition_variable>
#include <mutex>
#endif
namespace zmq
{
#if !defined(ZMQ_HAVE_WINDOWS_TARGET_XP) && _WIN32_WINNT >= 0x0600
class condition_variable_t
{
public:
inline condition_variable_t ()
{
InitializeConditionVariable (&cv);
}
inline ~condition_variable_t ()
{
}
inline int wait (mutex_t* mutex_, int timeout_ )
{
int rc = SleepConditionVariableCS(&cv, mutex_->get_cs (), timeout_);
if (rc != 0)
return 0;
rc = GetLastError();
if (rc != ERROR_TIMEOUT)
win_assert(rc);
errno = EAGAIN;
return -1;
}
inline void broadcast ()
{
WakeAllConditionVariable(&cv);
}
private:
CONDITION_VARIABLE cv;
// Disable copy construction and assignment.
condition_variable_t (const condition_variable_t&);
void operator = (const condition_variable_t&);
};
#else
class condition_variable_t
{
public:
inline condition_variable_t()
{
}
inline ~condition_variable_t()
{
}
inline int wait(mutex_t* mutex_, int timeout_)
{
std::unique_lock<std::mutex> lck(mtx); // lock mtx
mutex_->unlock(); // unlock mutex_
int res = 0;
if(timeout_ == -1) {
cv.wait(lck); // unlock mtx and wait cv.notify_all(), lock mtx after cv.notify_all()
} else if (cv.wait_for(lck, std::chrono::milliseconds(timeout_)) == std::cv_status::timeout) {
// time expired
errno = EAGAIN;
res = -1;
}
lck.unlock(); // unlock mtx
mutex_->lock(); // lock mutex_
return res;
}
inline void broadcast()
{
std::unique_lock<std::mutex> lck(mtx); // lock mtx
cv.notify_all();
}
private:
std::condition_variable cv;
std::mutex mtx;
// Disable copy construction and assignment.
condition_variable_t(const condition_variable_t&);
void operator = (const condition_variable_t&);
};
#endif
}
#endif
#else
#include <pthread.h>
namespace zmq
{
class condition_variable_t
{
public:
inline condition_variable_t ()
{
int rc = pthread_cond_init (&cond, NULL);
posix_assert (rc);
}
inline ~condition_variable_t ()
{
int rc = pthread_cond_destroy (&cond);
posix_assert (rc);
}
inline int wait (mutex_t* mutex_, int timeout_)
{
int rc;
if (timeout_ != -1) {
struct timespec timeout;
#if defined ZMQ_HAVE_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 // less than macOS 10.12
alt_clock_gettime(SYSTEM_CLOCK, &timeout);
#else
clock_gettime(CLOCK_MONOTONIC, &timeout);
#endif
timeout.tv_sec += timeout_ / 1000;
timeout.tv_nsec += (timeout_ % 1000) * 1000000;
if (timeout.tv_nsec > 1000000000) {
timeout.tv_sec++;
timeout.tv_nsec -= 1000000000;
}
rc = pthread_cond_timedwait (&cond, mutex_->get_mutex (), &timeout);
}
else
rc = pthread_cond_wait(&cond, mutex_->get_mutex());
if (rc == 0)
return 0;
if (rc == ETIMEDOUT){
errno= EAGAIN;
return -1;
}
posix_assert (rc);
return -1;
}
inline void broadcast ()
{
int rc = pthread_cond_broadcast (&cond);
posix_assert (rc);
}
private:
pthread_cond_t cond;
// Disable copy construction and assignment.
condition_variable_t (const condition_variable_t&);
const condition_variable_t &operator = (const condition_variable_t&);
};
}
#endif
#endif
-98
View File
@@ -1,98 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_CONFIG_HPP_INCLUDED__
#define __ZMQ_CONFIG_HPP_INCLUDED__
namespace zmq
{
// Compile-time settings.
enum
{
// Number of new messages in message pipe needed to trigger new memory
// allocation. Setting this parameter to 256 decreases the impact of
// memory allocation by approximately 99.6%
message_pipe_granularity = 256,
// Commands in pipe per allocation event.
command_pipe_granularity = 16,
// Determines how often does socket poll for new commands when it
// still has unprocessed messages to handle. Thus, if it is set to 100,
// socket will process 100 inbound messages before doing the poll.
// If there are no unprocessed messages available, poll is done
// immediately. Decreasing the value trades overall latency for more
// real-time behaviour (less latency peaks).
inbound_poll_rate = 100,
// Maximal batching size for engines with receiving functionality.
// So, if there are 10 messages that fit into the batch size, all of
// them may be read by a single 'recv' system call, thus avoiding
// unnecessary network stack traversals.
in_batch_size = 8192,
// Maximal batching size for engines with sending functionality.
// So, if there are 10 messages that fit into the batch size, all of
// them may be written by a single 'send' system call, thus avoiding
// unnecessary network stack traversals.
out_batch_size = 8192,
// Maximal delta between high and low watermark.
max_wm_delta = 1024,
// Maximum number of events the I/O thread can process in one go.
max_io_events = 256,
// Maximal delay to process command in API thread (in CPU ticks).
// 3,000,000 ticks equals to 1 - 2 milliseconds on current CPUs.
// Note that delay is only applied when there is continuous stream of
// messages to process. If not so, commands are processed immediately.
max_command_delay = 3000000,
// Low-precision clock precision in CPU ticks. 1ms. Value of 1000000
// should be OK for CPU frequencies above 1GHz. If should work
// reasonably well for CPU frequencies above 500MHz. For lower CPU
// frequencies you may consider lowering this value to get best
// possible latencies.
clock_precision = 1000000,
// On some OSes the signaler has to be emulated using a TCP
// connection. In such cases following port is used.
// If 0, it lets the OS choose a free port without requiring use of a
// global mutex. The original implementation of a Windows signaler
// socket used port 5905 instead of letting the OS choose a free port.
// https://github.com/zeromq/libzmq/issues/1542
signaler_port = 0
};
}
#endif
-644
View File
@@ -1,644 +0,0 @@
/*
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#ifndef ZMQ_HAVE_WINDOWS
#include <unistd.h>
#endif
#include <limits>
#include <climits>
#include <new>
#include <sstream>
#include <string.h>
#include "ctx.hpp"
#include "socket_base.hpp"
#include "io_thread.hpp"
#include "reaper.hpp"
#include "pipe.hpp"
#include "err.hpp"
#include "msg.hpp"
#include "random.hpp"
#ifdef ZMQ_HAVE_VMCI
#include <vmci_sockets.h>
#endif
#define ZMQ_CTX_TAG_VALUE_GOOD 0xabadcafe
#define ZMQ_CTX_TAG_VALUE_BAD 0xdeadbeef
int clipped_maxsocket (int max_requested)
{
if (max_requested >= zmq::poller_t::max_fds () && zmq::poller_t::max_fds () != -1)
// -1 because we need room for the reaper mailbox.
max_requested = zmq::poller_t::max_fds () - 1;
return max_requested;
}
zmq::ctx_t::ctx_t () :
tag (ZMQ_CTX_TAG_VALUE_GOOD),
starting (true),
terminating (false),
reaper (NULL),
slot_count (0),
slots (NULL),
max_sockets (clipped_maxsocket (ZMQ_MAX_SOCKETS_DFLT)),
max_msgsz (INT_MAX),
io_thread_count (ZMQ_IO_THREADS_DFLT),
blocky (true),
ipv6 (false),
thread_priority (ZMQ_THREAD_PRIORITY_DFLT),
thread_sched_policy (ZMQ_THREAD_SCHED_POLICY_DFLT)
{
#ifdef HAVE_FORK
pid = getpid();
#endif
#ifdef ZMQ_HAVE_VMCI
vmci_fd = -1;
vmci_family = -1;
#endif
// Initialise crypto library, if needed.
zmq::random_open ();
}
bool zmq::ctx_t::check_tag ()
{
return tag == ZMQ_CTX_TAG_VALUE_GOOD;
}
zmq::ctx_t::~ctx_t ()
{
// Check that there are no remaining sockets.
zmq_assert (sockets.empty ());
// Ask I/O threads to terminate. If stop signal wasn't sent to I/O
// thread subsequent invocation of destructor would hang-up.
for (io_threads_t::size_type i = 0; i != io_threads.size (); i++) {
io_threads [i]->stop ();
}
// Wait till I/O threads actually terminate.
for (io_threads_t::size_type i = 0; i != io_threads.size (); i++) {
LIBZMQ_DELETE(io_threads [i]);
}
// Deallocate the reaper thread object.
LIBZMQ_DELETE(reaper);
// Deallocate the array of mailboxes. No special work is
// needed as mailboxes themselves were deallocated with their
// corresponding io_thread/socket objects.
free (slots);
// De-initialise crypto library, if needed.
zmq::random_close ();
// Remove the tag, so that the object is considered dead.
tag = ZMQ_CTX_TAG_VALUE_BAD;
}
int zmq::ctx_t::terminate ()
{
slot_sync.lock();
bool saveTerminating = terminating;
terminating = false;
// Connect up any pending inproc connections, otherwise we will hang
pending_connections_t copy = pending_connections;
for (pending_connections_t::iterator p = copy.begin (); p != copy.end (); ++p) {
zmq::socket_base_t *s = create_socket (ZMQ_PAIR);
// create_socket might fail eg: out of memory/sockets limit reached
zmq_assert (s);
s->bind (p->first.c_str ());
s->close ();
}
terminating = saveTerminating;
if (!starting) {
#ifdef HAVE_FORK
if (pid != getpid ()) {
// we are a forked child process. Close all file descriptors
// inherited from the parent.
for (sockets_t::size_type i = 0; i != sockets.size (); i++)
sockets [i]->get_mailbox ()->forked ();
term_mailbox.forked ();
}
#endif
// Check whether termination was already underway, but interrupted and now
// restarted.
bool restarted = terminating;
terminating = true;
// First attempt to terminate the context.
if (!restarted) {
// First send stop command to sockets so that any blocking calls
// can be interrupted. If there are no sockets we can ask reaper
// thread to stop.
for (sockets_t::size_type i = 0; i != sockets.size (); i++)
sockets [i]->stop ();
if (sockets.empty ())
reaper->stop ();
}
slot_sync.unlock();
// Wait till reaper thread closes all the sockets.
command_t cmd;
int rc = term_mailbox.recv (&cmd, -1);
if (rc == -1 && errno == EINTR)
return -1;
errno_assert (rc == 0);
zmq_assert (cmd.type == command_t::done);
slot_sync.lock ();
zmq_assert (sockets.empty ());
}
slot_sync.unlock ();
#ifdef ZMQ_HAVE_VMCI
vmci_sync.lock ();
VMCISock_ReleaseAFValueFd (vmci_fd);
vmci_family = -1;
vmci_fd = -1;
vmci_sync.unlock ();
#endif
// Deallocate the resources.
delete this;
return 0;
}
int zmq::ctx_t::shutdown ()
{
scoped_lock_t locker(slot_sync);
if (!starting && !terminating) {
terminating = true;
// Send stop command to sockets so that any blocking calls
// can be interrupted. If there are no sockets we can ask reaper
// thread to stop.
for (sockets_t::size_type i = 0; i != sockets.size (); i++)
sockets [i]->stop ();
if (sockets.empty ())
reaper->stop ();
}
return 0;
}
int zmq::ctx_t::set (int option_, int optval_)
{
int rc = 0;
if (option_ == ZMQ_MAX_SOCKETS
&& optval_ >= 1 && optval_ == clipped_maxsocket (optval_)) {
scoped_lock_t locker(opt_sync);
max_sockets = optval_;
}
else
if (option_ == ZMQ_IO_THREADS && optval_ >= 0) {
scoped_lock_t locker(opt_sync);
io_thread_count = optval_;
}
else
if (option_ == ZMQ_IPV6 && optval_ >= 0) {
scoped_lock_t locker(opt_sync);
ipv6 = (optval_ != 0);
}
else
if (option_ == ZMQ_THREAD_PRIORITY && optval_ >= 0) {
scoped_lock_t locker(opt_sync);
thread_priority = optval_;
}
else
if (option_ == ZMQ_THREAD_SCHED_POLICY && optval_ >= 0) {
scoped_lock_t locker(opt_sync);
thread_sched_policy = optval_;
}
else
if (option_ == ZMQ_THREAD_AFFINITY_CPU_ADD && optval_ >= 0) {
scoped_lock_t locker(opt_sync);
thread_affinity_cpus.insert( optval_ );
}
else
if (option_ == ZMQ_THREAD_AFFINITY_CPU_REMOVE && optval_ >= 0) {
scoped_lock_t locker(opt_sync);
std::set<int>::iterator it = thread_affinity_cpus.find( optval_ );
if (it != thread_affinity_cpus.end()) {
thread_affinity_cpus.erase( it );
} else {
errno = EINVAL;
rc = -1;
}
}
else
if (option_ == ZMQ_THREAD_NAME_PREFIX && optval_ >= 0) {
std::ostringstream s;
s << optval_;
scoped_lock_t locker(opt_sync);
thread_name_prefix = s.str();
}
else
if (option_ == ZMQ_BLOCKY && optval_ >= 0) {
scoped_lock_t locker(opt_sync);
blocky = (optval_ != 0);
}
else
if (option_ == ZMQ_MAX_MSGSZ && optval_ >= 0) {
scoped_lock_t locker(opt_sync);
max_msgsz = optval_ < INT_MAX? optval_: INT_MAX;
}
else {
errno = EINVAL;
rc = -1;
}
return rc;
}
int zmq::ctx_t::get (int option_)
{
int rc = 0;
if (option_ == ZMQ_MAX_SOCKETS)
rc = max_sockets;
else
if (option_ == ZMQ_SOCKET_LIMIT)
rc = clipped_maxsocket (65535);
else
if (option_ == ZMQ_IO_THREADS)
rc = io_thread_count;
else
if (option_ == ZMQ_IPV6)
rc = ipv6;
else
if (option_ == ZMQ_BLOCKY)
rc = blocky;
else
if (option_ == ZMQ_MAX_MSGSZ)
rc = max_msgsz;
else
if (option_ == ZMQ_MSG_T_SIZE)
rc = sizeof (zmq_msg_t);
else {
errno = EINVAL;
rc = -1;
}
return rc;
}
zmq::socket_base_t *zmq::ctx_t::create_socket (int type_)
{
scoped_lock_t locker(slot_sync);
if (unlikely (starting)) {
starting = false;
// Initialise the array of mailboxes. Additional three slots are for
// zmq_ctx_term thread and reaper thread.
opt_sync.lock ();
int mazmq = max_sockets;
int ios = io_thread_count;
opt_sync.unlock ();
slot_count = mazmq + ios + 2;
slots = (i_mailbox **) malloc (sizeof (i_mailbox*) * slot_count);
alloc_assert (slots);
// Initialise the infrastructure for zmq_ctx_term thread.
slots [term_tid] = &term_mailbox;
// Create the reaper thread.
reaper = new (std::nothrow) reaper_t (this, reaper_tid);
alloc_assert (reaper);
slots [reaper_tid] = reaper->get_mailbox ();
reaper->start ();
// Create I/O thread objects and launch them.
for (int i = 2; i != ios + 2; i++) {
io_thread_t *io_thread = new (std::nothrow) io_thread_t (this, i);
alloc_assert (io_thread);
io_threads.push_back (io_thread);
slots [i] = io_thread->get_mailbox ();
io_thread->start ();
}
// In the unused part of the slot array, create a list of empty slots.
for (int32_t i = (int32_t) slot_count - 1;
i >= (int32_t) ios + 2; i--) {
empty_slots.push_back (i);
slots [i] = NULL;
}
}
// Once zmq_ctx_term() was called, we can't create new sockets.
if (terminating) {
errno = ETERM;
return NULL;
}
// If max_sockets limit was reached, return error.
if (empty_slots.empty ()) {
errno = EMFILE;
return NULL;
}
// Choose a slot for the socket.
uint32_t slot = empty_slots.back ();
empty_slots.pop_back ();
// Generate new unique socket ID.
int sid = ((int) max_socket_id.add (1)) + 1;
// Create the socket and register its mailbox.
socket_base_t *s = socket_base_t::create (type_, this, slot, sid);
if (!s) {
empty_slots.push_back (slot);
return NULL;
}
sockets.push_back (s);
slots [slot] = s->get_mailbox ();
return s;
}
void zmq::ctx_t::destroy_socket (class socket_base_t *socket_)
{
scoped_lock_t locker(slot_sync);
// Free the associated thread slot.
uint32_t tid = socket_->get_tid ();
empty_slots.push_back (tid);
slots [tid] = NULL;
// Remove the socket from the list of sockets.
sockets.erase (socket_);
// If zmq_ctx_term() was already called and there are no more socket
// we can ask reaper thread to terminate.
if (terminating && sockets.empty ())
reaper->stop ();
}
zmq::object_t *zmq::ctx_t::get_reaper ()
{
return reaper;
}
void zmq::ctx_t::start_thread (thread_t &thread_, thread_fn *tfn_, void *arg_) const
{
static unsigned int nthreads_started = 0;
thread_.setSchedulingParameters(thread_priority, thread_sched_policy, thread_affinity_cpus);
thread_.start(tfn_, arg_);
#ifndef ZMQ_HAVE_ANDROID
std::ostringstream s;
if (!thread_name_prefix.empty())
s << thread_name_prefix << "/";
s << "ZMQbg/" << nthreads_started;
thread_.setThreadName (s.str().c_str());
#endif
nthreads_started++;
}
void zmq::ctx_t::send_command (uint32_t tid_, const command_t &command_)
{
slots [tid_]->send (command_);
}
zmq::io_thread_t *zmq::ctx_t::choose_io_thread (uint64_t affinity_)
{
if (io_threads.empty ())
return NULL;
// Find the I/O thread with minimum load.
int min_load = -1;
io_thread_t *selected_io_thread = NULL;
for (io_threads_t::size_type i = 0; i != io_threads.size (); i++) {
if (!affinity_ || (affinity_ & (uint64_t (1) << i))) {
int load = io_threads [i]->get_load ();
if (selected_io_thread == NULL || load < min_load) {
min_load = load;
selected_io_thread = io_threads [i];
}
}
}
return selected_io_thread;
}
int zmq::ctx_t::register_endpoint (const char *addr_,
const endpoint_t &endpoint_)
{
scoped_lock_t locker(endpoints_sync);
const bool inserted = endpoints.ZMQ_MAP_INSERT_OR_EMPLACE (addr_,
endpoint_).second;
if (!inserted) {
errno = EADDRINUSE;
return -1;
}
return 0;
}
int zmq::ctx_t::unregister_endpoint (
const std::string &addr_, socket_base_t *socket_)
{
scoped_lock_t locker(endpoints_sync);
const endpoints_t::iterator it = endpoints.find (addr_);
if (it == endpoints.end () || it->second.socket != socket_) {
errno = ENOENT;
return -1;
}
// Remove endpoint.
endpoints.erase (it);
return 0;
}
void zmq::ctx_t::unregister_endpoints (socket_base_t *socket_)
{
scoped_lock_t locker(endpoints_sync);
endpoints_t::iterator it = endpoints.begin ();
while (it != endpoints.end ()) {
if (it->second.socket == socket_) {
endpoints_t::iterator to_erase = it;
++it;
endpoints.erase (to_erase);
continue;
}
++it;
}
}
zmq::endpoint_t zmq::ctx_t::find_endpoint (const char *addr_)
{
scoped_lock_t locker(endpoints_sync);
endpoints_t::iterator it = endpoints.find (addr_);
if (it == endpoints.end ()) {
errno = ECONNREFUSED;
endpoint_t empty = {NULL, options_t()};
return empty;
}
endpoint_t endpoint = it->second;
// Increment the command sequence number of the peer so that it won't
// get deallocated until "bind" command is issued by the caller.
// The subsequent 'bind' has to be called with inc_seqnum parameter
// set to false, so that the seqnum isn't incremented twice.
endpoint.socket->inc_seqnum ();
return endpoint;
}
void zmq::ctx_t::pend_connection (const std::string &addr_,
const endpoint_t &endpoint_, pipe_t **pipes_)
{
scoped_lock_t locker(endpoints_sync);
const pending_connection_t pending_connection = {endpoint_, pipes_ [0], pipes_ [1]};
endpoints_t::iterator it = endpoints.find (addr_);
if (it == endpoints.end ()) {
// Still no bind.
endpoint_.socket->inc_seqnum ();
pending_connections.ZMQ_MAP_INSERT_OR_EMPLACE (addr_, pending_connection);
} else {
// Bind has happened in the mean time, connect directly
connect_inproc_sockets(it->second.socket, it->second.options, pending_connection, connect_side);
}
}
void zmq::ctx_t::connect_pending (const char *addr_, zmq::socket_base_t *bind_socket_)
{
scoped_lock_t locker(endpoints_sync);
std::pair<pending_connections_t::iterator, pending_connections_t::iterator> pending = pending_connections.equal_range(addr_);
for (pending_connections_t::iterator p = pending.first; p != pending.second; ++p)
connect_inproc_sockets(bind_socket_, endpoints[addr_].options, p->second, bind_side);
pending_connections.erase(pending.first, pending.second);
}
void zmq::ctx_t::connect_inproc_sockets (zmq::socket_base_t *bind_socket_,
options_t& bind_options, const pending_connection_t &pending_connection_, side side_)
{
bind_socket_->inc_seqnum();
pending_connection_.bind_pipe->set_tid (bind_socket_->get_tid ());
if (!bind_options.recv_routing_id) {
msg_t msg;
const bool ok = pending_connection_.bind_pipe->read (&msg);
zmq_assert (ok);
const int rc = msg.close ();
errno_assert (rc == 0);
}
bool conflate = pending_connection_.endpoint.options.conflate &&
(pending_connection_.endpoint.options.type == ZMQ_DEALER ||
pending_connection_.endpoint.options.type == ZMQ_PULL ||
pending_connection_.endpoint.options.type == ZMQ_PUSH ||
pending_connection_.endpoint.options.type == ZMQ_PUB ||
pending_connection_.endpoint.options.type == ZMQ_SUB);
if (!conflate) {
pending_connection_.connect_pipe->set_hwms_boost(bind_options.sndhwm, bind_options.rcvhwm);
pending_connection_.bind_pipe->set_hwms_boost(pending_connection_.endpoint.options.sndhwm, pending_connection_.endpoint.options.rcvhwm);
pending_connection_.connect_pipe->set_hwms(pending_connection_.endpoint.options.rcvhwm, pending_connection_.endpoint.options.sndhwm);
pending_connection_.bind_pipe->set_hwms(bind_options.rcvhwm, bind_options.sndhwm);
}
else {
pending_connection_.connect_pipe->set_hwms(-1, -1);
pending_connection_.bind_pipe->set_hwms(-1, -1);
}
if (side_ == bind_side) {
command_t cmd;
cmd.type = command_t::bind;
cmd.args.bind.pipe = pending_connection_.bind_pipe;
bind_socket_->process_command (cmd);
bind_socket_->send_inproc_connected (pending_connection_.endpoint.socket);
}
else
pending_connection_.connect_pipe->send_bind (bind_socket_, pending_connection_.bind_pipe, false);
// When a ctx is terminated all pending inproc connection will be
// connected, but the socket will already be closed and the pipe will be
// in waiting_for_delimiter state, which means no more writes can be done
// and the routing id write fails and causes an assert. Check if the socket
// is open before sending.
if (pending_connection_.endpoint.options.recv_routing_id &&
pending_connection_.endpoint.socket->check_tag ()) {
msg_t routing_id;
const int rc = routing_id.init_size (bind_options.routing_id_size);
errno_assert (rc == 0);
memcpy (routing_id.data (), bind_options.routing_id, bind_options.routing_id_size);
routing_id.set_flags (msg_t::routing_id);
const bool written = pending_connection_.bind_pipe->write (&routing_id);
zmq_assert (written);
pending_connection_.bind_pipe->flush ();
}
}
#ifdef ZMQ_HAVE_VMCI
int zmq::ctx_t::get_vmci_socket_family ()
{
zmq::scoped_lock_t locker(vmci_sync);
if (vmci_fd == -1) {
vmci_family = VMCISock_GetAFValueFd (&vmci_fd);
if (vmci_fd != -1) {
#ifdef FD_CLOEXEC
int rc = fcntl (vmci_fd, F_SETFD, FD_CLOEXEC);
errno_assert (rc != -1);
#endif
}
}
return vmci_family;
}
#endif
// The last used socket ID, or 0 if no socket was used so far. Note that this
// is a global variable. Thus, even sockets created in different contexts have
// unique IDs.
zmq::atomic_counter_t zmq::ctx_t::max_socket_id;
-242
View File
@@ -1,242 +0,0 @@
/*
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_CTX_HPP_INCLUDED__
#define __ZMQ_CTX_HPP_INCLUDED__
#include <map>
#include <vector>
#include <string>
#include <stdarg.h>
#include "mailbox.hpp"
#include "array.hpp"
#include "config.hpp"
#include "mutex.hpp"
#include "stdint.hpp"
#include "options.hpp"
#include "atomic_counter.hpp"
#include "thread.hpp"
namespace zmq
{
class object_t;
class io_thread_t;
class socket_base_t;
class reaper_t;
class pipe_t;
// Information associated with inproc endpoint. Note that endpoint options
// are registered as well so that the peer can access them without a need
// for synchronisation, handshaking or similar.
struct endpoint_t
{
socket_base_t *socket;
options_t options;
};
// Context object encapsulates all the global state associated with
// the library.
class ctx_t
{
public:
// Create the context object.
ctx_t ();
// Returns false if object is not a context.
bool check_tag ();
// This function is called when user invokes zmq_ctx_term. If there are
// no more sockets open it'll cause all the infrastructure to be shut
// down. If there are open sockets still, the deallocation happens
// after the last one is closed.
int terminate ();
// This function starts the terminate process by unblocking any blocking
// operations currently in progress and stopping any more socket activity
// (except zmq_close).
// This function is non-blocking.
// terminate must still be called afterwards.
// This function is optional, terminate will unblock any current
// operations as well.
int shutdown();
// Set and get context properties.
int set (int option_, int optval_);
int get (int option_);
// Create and destroy a socket.
zmq::socket_base_t *create_socket (int type_);
void destroy_socket (zmq::socket_base_t *socket_);
// Start a new thread with proper scheduling parameters.
void start_thread (thread_t &thread_, thread_fn *tfn_, void *arg_) const;
// Send command to the destination thread.
void send_command (uint32_t tid_, const command_t &command_);
// Returns the I/O thread that is the least busy at the moment.
// Affinity specifies which I/O threads are eligible (0 = all).
// Returns NULL if no I/O thread is available.
zmq::io_thread_t *choose_io_thread (uint64_t affinity_);
// Returns reaper thread object.
zmq::object_t *get_reaper ();
// Management of inproc endpoints.
int register_endpoint (const char *addr_, const endpoint_t &endpoint_);
int unregister_endpoint (const std::string &addr_, socket_base_t *socket_);
void unregister_endpoints (zmq::socket_base_t *socket_);
endpoint_t find_endpoint (const char *addr_);
void pend_connection (const std::string &addr_,
const endpoint_t &endpoint_, pipe_t **pipes_);
void connect_pending (const char *addr_, zmq::socket_base_t *bind_socket_);
#ifdef ZMQ_HAVE_VMCI
// Return family for the VMCI socket or -1 if it's not available.
int get_vmci_socket_family ();
#endif
enum {
term_tid = 0,
reaper_tid = 1
};
~ctx_t ();
private:
struct pending_connection_t
{
endpoint_t endpoint;
pipe_t* connect_pipe;
pipe_t* bind_pipe;
};
// Used to check whether the object is a context.
uint32_t tag;
// Sockets belonging to this context. We need the list so that
// we can notify the sockets when zmq_ctx_term() is called.
// The sockets will return ETERM then.
typedef array_t <socket_base_t> sockets_t;
sockets_t sockets;
// List of unused thread slots.
typedef std::vector <uint32_t> empty_slots_t;
empty_slots_t empty_slots;
// If true, zmq_init has been called but no socket has been created
// yet. Launching of I/O threads is delayed.
bool starting;
// If true, zmq_ctx_term was already called.
bool terminating;
// Synchronisation of accesses to global slot-related data:
// sockets, empty_slots, terminating. It also synchronises
// access to zombie sockets as such (as opposed to slots) and provides
// a memory barrier to ensure that all CPU cores see the same data.
mutex_t slot_sync;
// The reaper thread.
zmq::reaper_t *reaper;
// I/O threads.
typedef std::vector <zmq::io_thread_t*> io_threads_t;
io_threads_t io_threads;
// Array of pointers to mailboxes for both application and I/O threads.
uint32_t slot_count;
i_mailbox **slots;
// Mailbox for zmq_ctx_term thread.
mailbox_t term_mailbox;
// List of inproc endpoints within this context.
typedef std::map <std::string, endpoint_t> endpoints_t;
endpoints_t endpoints;
// List of inproc connection endpoints pending a bind
typedef std::multimap <std::string, pending_connection_t> pending_connections_t;
pending_connections_t pending_connections;
// Synchronisation of access to the list of inproc endpoints.
mutex_t endpoints_sync;
// Maximum socket ID.
static atomic_counter_t max_socket_id;
// Maximum number of sockets that can be opened at the same time.
int max_sockets;
// Maximum allowed message size
int max_msgsz;
// Number of I/O threads to launch.
int io_thread_count;
// Does context wait (possibly forever) on termination?
bool blocky;
// Is IPv6 enabled on this context?
bool ipv6;
// Thread parameters.
int thread_priority;
int thread_sched_policy;
std::set<int> thread_affinity_cpus;
std::string thread_name_prefix;
// Synchronisation of access to context options.
mutex_t opt_sync;
ctx_t (const ctx_t&);
const ctx_t &operator = (const ctx_t&);
#ifdef HAVE_FORK
// the process that created this context. Used to detect forking.
pid_t pid;
#endif
enum side { connect_side, bind_side };
void connect_inproc_sockets(zmq::socket_base_t *bind_socket_, options_t& bind_options, const pending_connection_t &pending_connection_, side side_);
#ifdef ZMQ_HAVE_VMCI
int vmci_fd;
int vmci_family;
mutex_t vmci_sync;
#endif
};
}
#endif
-87
View File
@@ -1,87 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_CURVE_CLIENT_HPP_INCLUDED__
#define __ZMQ_CURVE_CLIENT_HPP_INCLUDED__
#ifdef ZMQ_HAVE_CURVE
#include "curve_mechanism_base.hpp"
#include "options.hpp"
#include "curve_client_tools.hpp"
namespace zmq
{
class msg_t;
class session_base_t;
class curve_client_t : public curve_mechanism_base_t
{
public:
curve_client_t (session_base_t *session_, const options_t &options_);
virtual ~curve_client_t ();
// mechanism implementation
virtual int next_handshake_command (msg_t *msg_);
virtual int process_handshake_command (msg_t *msg_);
virtual int encode (msg_t *msg_);
virtual int decode (msg_t *msg_);
virtual status_t status () const;
private:
enum state_t {
send_hello,
expect_welcome,
send_initiate,
expect_ready,
error_received,
connected
};
// Current FSM state
state_t state;
// CURVE protocol tools
curve_client_tools_t tools;
int produce_hello (msg_t *msg_);
int process_welcome (const uint8_t *cmd_data, size_t data_size);
int produce_initiate (msg_t *msg_);
int process_ready (const uint8_t *cmd_data, size_t data_size);
int process_error (const uint8_t *cmd_data, size_t data_size);
};
}
#endif
#endif
-94
View File
@@ -1,94 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_CURVE_SERVER_HPP_INCLUDED__
#define __ZMQ_CURVE_SERVER_HPP_INCLUDED__
#ifdef ZMQ_HAVE_CURVE
#include "curve_mechanism_base.hpp"
#include "options.hpp"
#include "zap_client.hpp"
namespace zmq
{
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4250)
#endif
class curve_server_t : public zap_client_common_handshake_t,
public curve_mechanism_base_t
{
public:
curve_server_t (session_base_t *session_,
const std::string &peer_address_,
const options_t &options_);
virtual ~curve_server_t ();
// mechanism implementation
virtual int next_handshake_command (msg_t *msg_);
virtual int process_handshake_command (msg_t *msg_);
virtual int encode (msg_t *msg_);
virtual int decode (msg_t *msg_);
private:
// Our secret key (s)
uint8_t secret_key [crypto_box_SECRETKEYBYTES];
// Our short-term public key (S')
uint8_t cn_public [crypto_box_PUBLICKEYBYTES];
// Our short-term secret key (s')
uint8_t cn_secret [crypto_box_SECRETKEYBYTES];
// Client's short-term public key (C')
uint8_t cn_client [crypto_box_PUBLICKEYBYTES];
// Key used to produce cookie
uint8_t cookie_key [crypto_secretbox_KEYBYTES];
int process_hello (msg_t *msg_);
int produce_welcome (msg_t *msg_);
int process_initiate (msg_t *msg_);
int produce_ready (msg_t *msg_);
int produce_error (msg_t *msg_) const;
void send_zap_request (const uint8_t *key);
};
#ifdef _MSC_VER
#pragma warning (pop)
#endif
}
#endif
#endif
-144
View File
@@ -1,144 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_DBUFFER_HPP_INCLUDED__
#define __ZMQ_DBUFFER_HPP_INCLUDED__
#include <stdlib.h>
#include <stddef.h>
#include <algorithm>
#include "mutex.hpp"
#include "msg.hpp"
namespace zmq
{
// dbuffer is a single-producer single-consumer double-buffer
// implementation.
//
// The producer writes to a back buffer and then tries to swap
// pointers between the back and front buffers. If it fails,
// due to the consumer reading from the front buffer, it just
// gives up, which is ok since writes are many and redundant.
//
// The reader simply reads from the front buffer.
//
// has_msg keeps track of whether there has been a not yet read
// value written, it is used by ypipe_conflate to mimic ypipe
// functionality regarding a reader being asleep
template <typename T> class dbuffer_t;
template <> class dbuffer_t<msg_t>
{
public:
inline dbuffer_t ()
: back (&storage[0])
, front (&storage[1])
, has_msg (false)
{
back->init ();
front->init ();
}
inline ~dbuffer_t()
{
back->close ();
front->close ();
}
inline void write (const msg_t &value_)
{
msg_t& xvalue = const_cast<msg_t&>(value_);
zmq_assert (xvalue.check ());
back->move (xvalue); // cannot just overwrite, might leak
zmq_assert (back->check ());
if (sync.try_lock ())
{
std::swap (back, front);
has_msg = true;
sync.unlock ();
}
}
inline bool read (msg_t *value_)
{
if (!value_)
return false;
{
scoped_lock_t lock (sync);
if (!has_msg)
return false;
zmq_assert (front->check ());
*value_ = *front;
front->init (); // avoid double free
has_msg = false;
return true;
}
}
inline bool check_read ()
{
scoped_lock_t lock (sync);
return has_msg;
}
inline bool probe (bool (*fn)(const msg_t &))
{
scoped_lock_t lock (sync);
return (*fn) (*front);
}
private:
msg_t storage[2];
msg_t *back, *front;
mutex_t sync;
bool has_msg;
// Disable copying of dbuffer.
dbuffer_t (const dbuffer_t&);
const dbuffer_t &operator = (const dbuffer_t&);
};
}
#endif
-143
View File
@@ -1,143 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#include "dealer.hpp"
#include "err.hpp"
#include "msg.hpp"
zmq::dealer_t::dealer_t (class ctx_t *parent_, uint32_t tid_, int sid_) :
socket_base_t (parent_, tid_, sid_),
probe_router (false)
{
options.type = ZMQ_DEALER;
}
zmq::dealer_t::~dealer_t ()
{
}
void zmq::dealer_t::xattach_pipe (pipe_t *pipe_, bool subscribe_to_all_)
{
LIBZMQ_UNUSED (subscribe_to_all_);
zmq_assert (pipe_);
if (probe_router) {
msg_t probe_msg_;
int rc = probe_msg_.init ();
errno_assert (rc == 0);
rc = pipe_->write (&probe_msg_);
// zmq_assert (rc) is not applicable here, since it is not a bug.
pipe_->flush ();
rc = probe_msg_.close ();
errno_assert (rc == 0);
}
fq.attach (pipe_);
lb.attach (pipe_);
}
int zmq::dealer_t::xsetsockopt (int option_, const void *optval_,
size_t optvallen_)
{
bool is_int = (optvallen_ == sizeof (int));
int value = 0;
if (is_int) memcpy(&value, optval_, sizeof (int));
switch (option_) {
case ZMQ_PROBE_ROUTER:
if (is_int && value >= 0) {
probe_router = (value != 0);
return 0;
}
break;
default:
break;
}
errno = EINVAL;
return -1;
}
int zmq::dealer_t::xsend (msg_t *msg_)
{
return sendpipe (msg_, NULL);
}
int zmq::dealer_t::xrecv (msg_t *msg_)
{
return recvpipe (msg_, NULL);
}
bool zmq::dealer_t::xhas_in ()
{
return fq.has_in ();
}
bool zmq::dealer_t::xhas_out ()
{
return lb.has_out ();
}
const zmq::blob_t &zmq::dealer_t::get_credential () const
{
return fq.get_credential ();
}
void zmq::dealer_t::xread_activated (pipe_t *pipe_)
{
fq.activated (pipe_);
}
void zmq::dealer_t::xwrite_activated (pipe_t *pipe_)
{
lb.activated (pipe_);
}
void zmq::dealer_t::xpipe_terminated (pipe_t *pipe_)
{
fq.pipe_terminated (pipe_);
lb.pipe_terminated (pipe_);
}
int zmq::dealer_t::sendpipe (msg_t *msg_, pipe_t **pipe_)
{
return lb.sendpipe (msg_, pipe_);
}
int zmq::dealer_t::recvpipe (msg_t *msg_, pipe_t **pipe_)
{
return fq.recvpipe (msg_, pipe_);
}
-89
View File
@@ -1,89 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_DEALER_HPP_INCLUDED__
#define __ZMQ_DEALER_HPP_INCLUDED__
#include "socket_base.hpp"
#include "session_base.hpp"
#include "fq.hpp"
#include "lb.hpp"
namespace zmq
{
class ctx_t;
class msg_t;
class pipe_t;
class io_thread_t;
class socket_base_t;
class dealer_t :
public socket_base_t
{
public:
dealer_t (zmq::ctx_t *parent_, uint32_t tid_, int sid);
~dealer_t ();
protected:
// Overrides of functions from socket_base_t.
void xattach_pipe (zmq::pipe_t *pipe_, bool subscribe_to_all_);
int xsetsockopt (int option_, const void *optval_, size_t optvallen_);
int xsend (zmq::msg_t *msg_);
int xrecv (zmq::msg_t *msg_);
bool xhas_in ();
bool xhas_out ();
const blob_t &get_credential () const;
void xread_activated (zmq::pipe_t *pipe_);
void xwrite_activated (zmq::pipe_t *pipe_);
void xpipe_terminated (zmq::pipe_t *pipe_);
// Send and recv - knowing which pipe was used.
int sendpipe (zmq::msg_t *msg_, zmq::pipe_t **pipe_);
int recvpipe (zmq::msg_t *msg_, zmq::pipe_t **pipe_);
private:
// Messages are fair-queued from inbound pipes. And load-balanced to
// the outbound pipes.
fq_t fq;
lb_t lb;
// if true, send an empty message to every connected router peer
bool probe_router;
dealer_t (const dealer_t&);
const dealer_t &operator = (const dealer_t&);
};
}
#endif
-198
View File
@@ -1,198 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_DECODER_HPP_INCLUDED__
#define __ZMQ_DECODER_HPP_INCLUDED__
#include <algorithm>
#include <cstddef>
#include <cstring>
#include "decoder_allocators.hpp"
#include "err.hpp"
#include "i_decoder.hpp"
#include "msg.hpp"
#include "stdint.hpp"
namespace zmq
{
// Helper base class for decoders that know the amount of data to read
// in advance at any moment. Knowing the amount in advance is a property
// of the protocol used. 0MQ framing protocol is based size-prefixed
// paradigm, which qualifies it to be parsed by this class.
// On the other hand, XML-based transports (like XMPP or SOAP) don't allow
// for knowing the size of data to read in advance and should use different
// decoding algorithms.
//
// This class implements the state machine that parses the incoming buffer.
// Derived class should implement individual state machine actions.
//
// Buffer management is done by an allocator policy.
template <typename T, typename A = c_single_allocator>
class decoder_base_t : public i_decoder
{
public:
explicit decoder_base_t (A *allocator_) :
next (NULL),
read_pos (NULL),
to_read (0),
allocator(allocator_)
{
buf = allocator->allocate ();
}
// The destructor doesn't have to be virtual. It is made virtual
// just to keep ICC and code checking tools from complaining.
virtual ~decoder_base_t ()
{
allocator->deallocate ();
}
// Returns a buffer to be filled with binary data.
void get_buffer (unsigned char **data_, std::size_t *size_)
{
buf = allocator->allocate ();
// If we are expected to read large message, we'll opt for zero-
// copy, i.e. we'll ask caller to fill the data directly to the
// message. Note that subsequent read(s) are non-blocking, thus
// each single read reads at most SO_RCVBUF bytes at once not
// depending on how large is the chunk returned from here.
// As a consequence, large messages being received won't block
// other engines running in the same I/O thread for excessive
// amounts of time.
if (to_read >= allocator->size ()) {
*data_ = read_pos;
*size_ = to_read;
return;
}
*data_ = buf;
*size_ = allocator->size ();
}
// Processes the data in the buffer previously allocated using
// get_buffer function. size_ argument specifies number of bytes
// actually filled into the buffer. Function returns 1 when the
// whole message was decoded or 0 when more data is required.
// On error, -1 is returned and errno set accordingly.
// Number of bytes processed is returned in bytes_used_.
int decode (const unsigned char *data_, std::size_t size_,
std::size_t &bytes_used_)
{
bytes_used_ = 0;
// In case of zero-copy simply adjust the pointers, no copying
// is required. Also, run the state machine in case all the data
// were processed.
if (data_ == read_pos) {
zmq_assert (size_ <= to_read);
read_pos += size_;
to_read -= size_;
bytes_used_ = size_;
while (!to_read) {
const int rc =
(static_cast <T *> (this)->*next) (data_ + bytes_used_);
if (rc != 0)
return rc;
}
return 0;
}
while (bytes_used_ < size_) {
// Copy the data from buffer to the message.
const size_t to_copy = std::min (to_read, size_ - bytes_used_);
// Only copy when destination address is different from the
// current address in the buffer.
if (read_pos != data_ + bytes_used_) {
memcpy (read_pos, data_ + bytes_used_, to_copy);
}
read_pos += to_copy;
to_read -= to_copy;
bytes_used_ += to_copy;
// Try to get more space in the message to fill in.
// If none is available, return.
while (to_read == 0) {
// pass current address in the buffer
const int rc =
(static_cast <T *> (this)->*next) (data_ + bytes_used_);
if (rc != 0)
return rc;
}
}
return 0;
}
virtual void resize_buffer (std::size_t new_size)
{
allocator->resize (new_size);
}
protected:
// Prototype of state machine action. Action should return false if
// it is unable to push the data to the system.
typedef int (T:: *step_t) (unsigned char const *);
// This function should be called from derived class to read data
// from the buffer and schedule next state machine action.
void next_step (void *read_pos_, std::size_t to_read_, step_t next_)
{
read_pos = static_cast <unsigned char*> (read_pos_);
to_read = to_read_;
next = next_;
}
private:
// Next step. If set to NULL, it means that associated data stream
// is dead. Note that there can be still data in the process in such
// case.
step_t next;
// Where to store the read data.
unsigned char *read_pos;
// How much data to read before taking next step.
std::size_t to_read;
// The duffer for data to decode.
A *allocator;
unsigned char *buf;
decoder_base_t (const decoder_base_t &);
const decoder_base_t &operator = (const decoder_base_t &);
};
}
#endif
-144
View File
@@ -1,144 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "decoder_allocators.hpp"
#include <cmath>
#include "msg.hpp"
zmq::shared_message_memory_allocator::shared_message_memory_allocator (std::size_t bufsize_) :
buf(NULL),
bufsize(0),
max_size(bufsize_),
msg_content(NULL),
maxCounters (static_cast <size_t> (std::ceil (static_cast <double> (max_size) / static_cast <double> (msg_t::max_vsm_size))))
{
}
zmq::shared_message_memory_allocator::shared_message_memory_allocator (std::size_t bufsize_, std::size_t maxMessages) :
buf(NULL),
bufsize(0),
max_size(bufsize_),
msg_content(NULL),
maxCounters(maxMessages)
{
}
zmq::shared_message_memory_allocator::~shared_message_memory_allocator ()
{
deallocate();
}
unsigned char* zmq::shared_message_memory_allocator::allocate ()
{
if (buf) {
// release reference count to couple lifetime to messages
zmq::atomic_counter_t* c = reinterpret_cast<zmq::atomic_counter_t* >(buf);
// if refcnt drops to 0, there are no message using the buffer
// because either all messages have been closed or only vsm-messages
// were created
if (c->sub (1)) {
// buffer is still in use as message data. "Release" it and create a new one
// release pointer because we are going to create a new buffer
release ();
}
}
// if buf != NULL it is not used by any message so we can re-use it for the next run
if (!buf) {
// allocate memory for reference counters together with reception buffer
std::size_t const allocationsize =
max_size + sizeof (zmq::atomic_counter_t) +
maxCounters * sizeof (zmq::msg_t::content_t);
buf = static_cast <unsigned char *> (std::malloc (allocationsize));
alloc_assert (buf);
new (buf) atomic_counter_t (1);
} else {
// release reference count to couple lifetime to messages
zmq::atomic_counter_t *c = reinterpret_cast <zmq::atomic_counter_t *> (buf);
c->set (1);
}
bufsize = max_size;
msg_content = reinterpret_cast <zmq::msg_t::content_t*> (buf + sizeof (atomic_counter_t) + max_size);
return buf + sizeof (zmq::atomic_counter_t);
}
void zmq::shared_message_memory_allocator::deallocate ()
{
zmq::atomic_counter_t* c = reinterpret_cast<zmq::atomic_counter_t* >(buf);
if (buf && !c->sub(1)) {
std::free(buf);
}
release();
}
unsigned char* zmq::shared_message_memory_allocator::release ()
{
unsigned char* b = buf;
buf = NULL;
bufsize = 0;
msg_content = NULL;
return b;
}
void zmq::shared_message_memory_allocator::inc_ref ()
{
(reinterpret_cast <zmq::atomic_counter_t*> (buf))->add (1);
}
void zmq::shared_message_memory_allocator::call_dec_ref(void*, void* hint)
{
zmq_assert (hint);
unsigned char* buf = static_cast <unsigned char*> (hint);
zmq::atomic_counter_t* c = reinterpret_cast <zmq::atomic_counter_t*> (buf);
if (!c->sub (1)) {
c->~atomic_counter_t ();
std::free (buf);
buf = NULL;
}
}
std::size_t zmq::shared_message_memory_allocator::size () const
{
return bufsize;
}
unsigned char* zmq::shared_message_memory_allocator::data ()
{
return buf + sizeof (zmq::atomic_counter_t);
}
-155
View File
@@ -1,155 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_DECODER_ALLOCATORS_HPP_INCLUDED__
#define __ZMQ_DECODER_ALLOCATORS_HPP_INCLUDED__
#include <cstddef>
#include <cstdlib>
#include "atomic_counter.hpp"
#include "msg.hpp"
#include "err.hpp"
namespace zmq
{
// Static buffer policy.
class c_single_allocator
{
public:
explicit c_single_allocator (std::size_t bufsize_) :
bufsize(bufsize_),
buf(static_cast <unsigned char*> (std::malloc (bufsize)))
{
alloc_assert (buf);
}
~c_single_allocator ()
{
std::free (buf);
}
unsigned char* allocate ()
{
return buf;
}
void deallocate ()
{
}
std::size_t size () const
{
return bufsize;
}
void resize (std::size_t new_size)
{
bufsize = new_size;
}
private:
std::size_t bufsize;
unsigned char* buf;
c_single_allocator (c_single_allocator const&);
c_single_allocator& operator = (c_single_allocator const&);
};
// This allocator allocates a reference counted buffer which is used by v2_decoder_t
// to use zero-copy msg::init_data to create messages with memory from this buffer as
// data storage.
//
// The buffer is allocated with a reference count of 1 to make sure that is is alive while
// decoding messages. Otherwise, it is possible that e.g. the first message increases the count
// from zero to one, gets passed to the user application, processed in the user thread and deleted
// which would then deallocate the buffer. The drawback is that the buffer may be allocated longer
// than necessary because it is only deleted when allocate is called the next time.
class shared_message_memory_allocator
{
public:
explicit shared_message_memory_allocator (std::size_t bufsize_);
// Create an allocator for a maximum number of messages
shared_message_memory_allocator (std::size_t bufsize_, std::size_t maxMessages);
~shared_message_memory_allocator ();
// Allocate a new buffer
//
// This releases the current buffer to be bound to the lifetime of the messages
// created on this buffer.
unsigned char* allocate ();
// force deallocation of buffer.
void deallocate ();
// Give up ownership of the buffer. The buffer's lifetime is now coupled to
// the messages constructed on top of it.
unsigned char* release ();
void inc_ref ();
static void call_dec_ref (void*, void* buffer);
std::size_t size () const;
// Return pointer to the first message data byte.
unsigned char* data ();
// Return pointer to the first byte of the buffer.
unsigned char* buffer ()
{
return buf;
}
void resize (std::size_t new_size)
{
bufsize = new_size;
}
zmq::msg_t::content_t* provide_content ()
{
return msg_content;
}
void advance_content ()
{
msg_content++;
}
private:
unsigned char* buf;
std::size_t bufsize;
std::size_t max_size;
zmq::msg_t::content_t* msg_content;
std::size_t maxCounters;
};
}
#endif
-205
View File
@@ -1,205 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "devpoll.hpp"
#if defined ZMQ_USE_DEVPOLL
#include <sys/devpoll.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <algorithm>
#include "devpoll.hpp"
#include "err.hpp"
#include "config.hpp"
#include "i_poll_events.hpp"
zmq::devpoll_t::devpoll_t (const zmq::ctx_t &ctx_) :
ctx(ctx_),
stopping (false)
{
devpoll_fd = open ("/dev/poll", O_RDWR);
errno_assert (devpoll_fd != -1);
}
zmq::devpoll_t::~devpoll_t ()
{
worker.stop ();
close (devpoll_fd);
}
void zmq::devpoll_t::devpoll_ctl (fd_t fd_, short events_)
{
struct pollfd pfd = {fd_, events_, 0};
ssize_t rc = write (devpoll_fd, &pfd, sizeof pfd);
zmq_assert (rc == sizeof pfd);
}
zmq::devpoll_t::handle_t zmq::devpoll_t::add_fd (fd_t fd_,
i_poll_events *reactor_)
{
// If the file descriptor table is too small expand it.
fd_table_t::size_type sz = fd_table.size ();
if (sz <= (fd_table_t::size_type) fd_) {
fd_table.resize (fd_ + 1);
while (sz != (fd_table_t::size_type) (fd_ + 1)) {
fd_table [sz].valid = false;
++sz;
}
}
zmq_assert (!fd_table [fd_].valid);
fd_table [fd_].events = 0;
fd_table [fd_].reactor = reactor_;
fd_table [fd_].valid = true;
fd_table [fd_].accepted = false;
devpoll_ctl (fd_, 0);
pending_list.push_back (fd_);
// Increase the load metric of the thread.
adjust_load (1);
return fd_;
}
void zmq::devpoll_t::rm_fd (handle_t handle_)
{
zmq_assert (fd_table [handle_].valid);
devpoll_ctl (handle_, POLLREMOVE);
fd_table [handle_].valid = false;
// Decrease the load metric of the thread.
adjust_load (-1);
}
void zmq::devpoll_t::set_pollin (handle_t handle_)
{
devpoll_ctl (handle_, POLLREMOVE);
fd_table [handle_].events |= POLLIN;
devpoll_ctl (handle_, fd_table [handle_].events);
}
void zmq::devpoll_t::reset_pollin (handle_t handle_)
{
devpoll_ctl (handle_, POLLREMOVE);
fd_table [handle_].events &= ~((short) POLLIN);
devpoll_ctl (handle_, fd_table [handle_].events);
}
void zmq::devpoll_t::set_pollout (handle_t handle_)
{
devpoll_ctl (handle_, POLLREMOVE);
fd_table [handle_].events |= POLLOUT;
devpoll_ctl (handle_, fd_table [handle_].events);
}
void zmq::devpoll_t::reset_pollout (handle_t handle_)
{
devpoll_ctl (handle_, POLLREMOVE);
fd_table [handle_].events &= ~((short) POLLOUT);
devpoll_ctl (handle_, fd_table [handle_].events);
}
void zmq::devpoll_t::start ()
{
ctx.start_thread (worker, worker_routine, this);
}
void zmq::devpoll_t::stop ()
{
stopping = true;
}
int zmq::devpoll_t::max_fds ()
{
return -1;
}
void zmq::devpoll_t::loop ()
{
while (!stopping) {
struct pollfd ev_buf [max_io_events];
struct dvpoll poll_req;
for (pending_list_t::size_type i = 0; i < pending_list.size (); i ++)
fd_table [pending_list [i]].accepted = true;
pending_list.clear ();
// Execute any due timers.
int timeout = (int) execute_timers ();
// Wait for events.
// On Solaris, we can retrieve no more then (OPEN_MAX - 1) events.
poll_req.dp_fds = &ev_buf [0];
#if defined ZMQ_HAVE_SOLARIS
poll_req.dp_nfds = std::min ((int) max_io_events, OPEN_MAX - 1);
#else
poll_req.dp_nfds = max_io_events;
#endif
poll_req.dp_timeout = timeout ? timeout : -1;
int n = ioctl (devpoll_fd, DP_POLL, &poll_req);
if (n == -1 && errno == EINTR)
continue;
errno_assert (n != -1);
for (int i = 0; i < n; i ++) {
fd_entry_t *fd_ptr = &fd_table [ev_buf [i].fd];
if (!fd_ptr->valid || !fd_ptr->accepted)
continue;
if (ev_buf [i].revents & (POLLERR | POLLHUP))
fd_ptr->reactor->in_event ();
if (!fd_ptr->valid || !fd_ptr->accepted)
continue;
if (ev_buf [i].revents & POLLOUT)
fd_ptr->reactor->out_event ();
if (!fd_ptr->valid || !fd_ptr->accepted)
continue;
if (ev_buf [i].revents & POLLIN)
fd_ptr->reactor->in_event ();
}
}
}
void zmq::devpoll_t::worker_routine (void *arg_)
{
((devpoll_t*) arg_)->loop ();
}
#endif
-119
View File
@@ -1,119 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_DEVPOLL_HPP_INCLUDED__
#define __ZMQ_DEVPOLL_HPP_INCLUDED__
// poller.hpp decides which polling mechanism to use.
#include "poller.hpp"
#if defined ZMQ_USE_DEVPOLL
#include <vector>
#include "ctx.hpp"
#include "fd.hpp"
#include "thread.hpp"
#include "poller_base.hpp"
namespace zmq
{
struct i_poll_events;
// Implements socket polling mechanism using the "/dev/poll" interface.
class devpoll_t : public poller_base_t
{
public:
typedef fd_t handle_t;
devpoll_t (const ctx_t &ctx_);
~devpoll_t ();
// "poller" concept.
handle_t add_fd (fd_t fd_, zmq::i_poll_events *events_);
void rm_fd (handle_t handle_);
void set_pollin (handle_t handle_);
void reset_pollin (handle_t handle_);
void set_pollout (handle_t handle_);
void reset_pollout (handle_t handle_);
void start ();
void stop ();
static int max_fds ();
private:
// Main worker thread routine.
static void worker_routine (void *arg_);
// Main event loop.
void loop ();
// Reference to ZMQ context.
const ctx_t &ctx;
// File descriptor referring to "/dev/poll" pseudo-device.
fd_t devpoll_fd;
struct fd_entry_t
{
short events;
zmq::i_poll_events *reactor;
bool valid;
bool accepted;
};
typedef std::vector <fd_entry_t> fd_table_t;
fd_table_t fd_table;
typedef std::vector <fd_t> pending_list_t;
pending_list_t pending_list;
// Pollset manipulation function.
void devpoll_ctl (fd_t fd_, short events_);
// If true, thread is in the process of shutting down.
bool stopping;
// Handle of the physical thread doing the I/O work.
thread_t worker;
devpoll_t (const devpoll_t&);
const devpoll_t &operator = (const devpoll_t&);
};
typedef devpoll_t poller_t;
}
#endif
#endif
-177
View File
@@ -1,177 +0,0 @@
/*
Copyright (c) 2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#include "dgram.hpp"
#include "pipe.hpp"
#include "wire.hpp"
#include "random.hpp"
#include "likely.hpp"
#include "err.hpp"
zmq::dgram_t::dgram_t (class ctx_t *parent_, uint32_t tid_, int sid_) :
socket_base_t (parent_, tid_, sid_),
pipe (NULL),
last_in (NULL),
more_out (false)
{
options.type = ZMQ_DGRAM;
options.raw_socket = true;
}
zmq::dgram_t::~dgram_t ()
{
zmq_assert (!pipe);
}
void zmq::dgram_t::xattach_pipe (pipe_t *pipe_, bool subscribe_to_all_)
{
LIBZMQ_UNUSED(subscribe_to_all_);
zmq_assert (pipe_);
// ZMQ_DGRAM socket can only be connected to a single peer.
// The socket rejects any further connection requests.
if (pipe == NULL)
pipe = pipe_;
else
pipe_->terminate (false);
}
void zmq::dgram_t::xpipe_terminated (pipe_t *pipe_)
{
if (pipe_ == pipe) {
if (last_in == pipe) {
saved_credential.set_deep_copy (last_in->get_credential ());
last_in = NULL;
}
pipe = NULL;
}
}
void zmq::dgram_t::xread_activated (pipe_t *)
{
// There's just one pipe. No lists of active and inactive pipes.
// There's nothing to do here.
}
void zmq::dgram_t::xwrite_activated (pipe_t *)
{
// There's just one pipe. No lists of active and inactive pipes.
// There's nothing to do here.
}
int zmq::dgram_t::xsend (msg_t *msg_)
{
// If there's no out pipe, just drop it.
if (!pipe) {
int rc = msg_->close ();
errno_assert (rc == 0);
return -1;
}
// If this is the first part of the message it's the ID of the
// peer to send the message to.
if (!more_out) {
if (!(msg_->flags () & msg_t::more)) {
errno = EINVAL;
return -1;
}
// Expect one more message frame.
more_out = true;
}
else {
// dgram messages are two part only, reject part if more is set
if (msg_->flags () & msg_t::more) {
errno = EINVAL;
return -1;
}
// This is the last part of the message.
more_out = false;
}
// Push the message into the pipe.
if (!pipe->write (msg_)) {
errno = EAGAIN;
return -1;
}
if (!(msg_->flags () & msg_t::more))
pipe->flush ();
// Detach the message from the data buffer.
int rc = msg_->init ();
errno_assert (rc == 0);
return 0;
}
int zmq::dgram_t::xrecv (msg_t *msg_)
{
// Deallocate old content of the message.
int rc = msg_->close ();
errno_assert (rc == 0);
if (!pipe || !pipe->read (msg_)) {
// Initialise the output parameter to be a 0-byte message.
rc = msg_->init ();
errno_assert (rc == 0);
errno = EAGAIN;
return -1;
}
last_in = pipe;
return 0;
}
bool zmq::dgram_t::xhas_in ()
{
if (!pipe)
return false;
return pipe->check_read ();
}
bool zmq::dgram_t::xhas_out ()
{
if (!pipe)
return false;
return pipe->check_write ();
}
const zmq::blob_t &zmq::dgram_t::get_credential () const
{
return last_in? last_in->get_credential (): saved_credential;
}
-81
View File
@@ -1,81 +0,0 @@
/*
Copyright (c) 2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_DGRAM_HPP_INCLUDED__
#define __ZMQ_DGRAM_HPP_INCLUDED__
#include "blob.hpp"
#include "socket_base.hpp"
#include "session_base.hpp"
namespace zmq
{
class ctx_t;
class msg_t;
class pipe_t;
class io_thread_t;
class dgram_t :
public socket_base_t
{
public:
dgram_t (zmq::ctx_t *parent_, uint32_t tid_, int sid);
~dgram_t ();
// Overrides of functions from socket_base_t.
void xattach_pipe (zmq::pipe_t *pipe_, bool subscribe_to_all_);
int xsend (zmq::msg_t *msg_);
int xrecv (zmq::msg_t *msg_);
bool xhas_in ();
bool xhas_out ();
const blob_t &get_credential () const;
void xread_activated (zmq::pipe_t *pipe_);
void xwrite_activated (zmq::pipe_t *pipe_);
void xpipe_terminated (zmq::pipe_t *pipe_);
private:
zmq::pipe_t *pipe;
zmq::pipe_t *last_in;
blob_t saved_credential;
// If true, more outgoing message parts are expected.
bool more_out;
dgram_t (const dgram_t&);
const dgram_t &operator = (const dgram_t&);
};
}
#endif
-360
View File
@@ -1,360 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include <string.h>
#include "macros.hpp"
#include "dish.hpp"
#include "err.hpp"
zmq::dish_t::dish_t (class ctx_t *parent_, uint32_t tid_, int sid_) :
socket_base_t (parent_, tid_, sid_, true),
has_message (false)
{
options.type = ZMQ_DISH;
// When socket is being closed down we don't want to wait till pending
// subscription commands are sent to the wire.
options.linger = 0;
int rc = message.init ();
errno_assert (rc == 0);
}
zmq::dish_t::~dish_t ()
{
int rc = message.close ();
errno_assert (rc == 0);
}
void zmq::dish_t::xattach_pipe (pipe_t *pipe_, bool subscribe_to_all_)
{
LIBZMQ_UNUSED (subscribe_to_all_);
zmq_assert (pipe_);
fq.attach (pipe_);
dist.attach (pipe_);
// Send all the cached subscriptions to the new upstream peer.
send_subscriptions (pipe_);
}
void zmq::dish_t::xread_activated (pipe_t *pipe_)
{
fq.activated (pipe_);
}
void zmq::dish_t::xwrite_activated (pipe_t *pipe_)
{
dist.activated (pipe_);
}
void zmq::dish_t::xpipe_terminated (pipe_t *pipe_)
{
fq.pipe_terminated (pipe_);
dist.pipe_terminated (pipe_);
}
void zmq::dish_t::xhiccuped (pipe_t *pipe_)
{
// Send all the cached subscriptions to the hiccuped pipe.
send_subscriptions (pipe_);
}
int zmq::dish_t::xjoin (const char* group_)
{
std::string group = std::string (group_);
if (group.length () > ZMQ_GROUP_MAX_LENGTH) {
errno = EINVAL;
return -1;
}
subscriptions_t::iterator it = subscriptions.find (group);
// User cannot join same group twice
if (it != subscriptions.end ()) {
errno = EINVAL;
return -1;
}
subscriptions.insert (group);
msg_t msg;
int rc = msg.init_join ();
errno_assert (rc == 0);
rc = msg.set_group (group_);
errno_assert (rc == 0);
int err = 0;
rc = dist.send_to_all (&msg);
if (rc != 0)
err = errno;
int rc2 = msg.close ();
errno_assert (rc2 == 0);
if (rc != 0)
errno = err;
return rc;
}
int zmq::dish_t::xleave (const char* group_)
{
std::string group = std::string (group_);
if (group.length () > ZMQ_GROUP_MAX_LENGTH) {
errno = EINVAL;
return -1;
}
subscriptions_t::iterator it = std::find (subscriptions.begin (), subscriptions.end (), group);
if (it == subscriptions.end ()) {
errno = EINVAL;
return -1;
}
subscriptions.erase (it);
msg_t msg;
int rc = msg.init_leave ();
errno_assert (rc == 0);
rc = msg.set_group (group_);
errno_assert (rc == 0);
int err = 0;
rc = dist.send_to_all (&msg);
if (rc != 0)
err = errno;
int rc2 = msg.close ();
errno_assert (rc2 == 0);
if (rc != 0)
errno = err;
return rc;
}
int zmq::dish_t::xsend (msg_t *msg_)
{
LIBZMQ_UNUSED (msg_);
errno = ENOTSUP;
return -1;
}
bool zmq::dish_t::xhas_out ()
{
// Subscription can be added/removed anytime.
return true;
}
int zmq::dish_t::xrecv (msg_t *msg_)
{
// If there's already a message prepared by a previous call to zmq_poll,
// return it straight ahead.
if (has_message) {
int rc = msg_->move (message);
errno_assert (rc == 0);
has_message = false;
return 0;
}
while (true) {
// Get a message using fair queueing algorithm.
int rc = fq.recv (msg_);
// If there's no message available, return immediately.
// The same when error occurs.
if (rc != 0)
return -1;
// Filtering non matching messages
subscriptions_t::iterator it = subscriptions.find (std::string(msg_->group ()));
if (it != subscriptions.end ())
return 0;
}
}
bool zmq::dish_t::xhas_in ()
{
// If there's already a message prepared by a previous call to zmq_poll,
// return straight ahead.
if (has_message)
return true;
while (true) {
// Get a message using fair queueing algorithm.
int rc = fq.recv (&message);
// If there's no message available, return immediately.
// The same when error occurs.
if (rc != 0) {
errno_assert (errno == EAGAIN);
return false;
}
// Filtering non matching messages
subscriptions_t::iterator it = subscriptions.find (std::string(message.group ()));
if (it != subscriptions.end ()) {
has_message = true;
return true;
}
}
}
const zmq::blob_t &zmq::dish_t::get_credential () const
{
return fq.get_credential ();
}
void zmq::dish_t::send_subscriptions (pipe_t *pipe_)
{
for (subscriptions_t::iterator it = subscriptions.begin (); it != subscriptions.end (); ++it) {
msg_t msg;
int rc = msg.init_join ();
errno_assert (rc == 0);
rc = msg.set_group (it->c_str());
errno_assert (rc == 0);
// Send it to the pipe.
pipe_->write (&msg);
msg.close ();
}
pipe_->flush ();
}
zmq::dish_session_t::dish_session_t (io_thread_t *io_thread_, bool connect_,
socket_base_t *socket_, const options_t &options_,
address_t *addr_) :
session_base_t (io_thread_, connect_, socket_, options_, addr_),
state (group)
{
}
zmq::dish_session_t::~dish_session_t ()
{
}
int zmq::dish_session_t::push_msg (msg_t *msg_)
{
if (state == group) {
if ((msg_->flags() & msg_t::more) != msg_t::more) {
errno = EFAULT;
return -1;
}
if (msg_->size() > ZMQ_GROUP_MAX_LENGTH) {
errno = EFAULT;
return -1;
}
group_msg = *msg_;
state = body;
int rc = msg_->init ();
errno_assert (rc == 0);
return 0;
}
else {
// Set the message group
int rc = msg_->set_group ((char*)group_msg.data (), group_msg. size());
errno_assert (rc == 0);
// We set the group, so we don't need the group_msg anymore
rc = group_msg.close ();
errno_assert (rc == 0);
// Thread safe socket doesn't support multipart messages
if ((msg_->flags() & msg_t::more) == msg_t::more) {
errno = EFAULT;
return -1;
}
// Push message to dish socket
rc = session_base_t::push_msg (msg_);
if (rc == 0)
state = group;
return rc;
}
}
int zmq::dish_session_t::pull_msg (msg_t *msg_)
{
int rc = session_base_t::pull_msg (msg_);
if (rc != 0)
return rc;
if (!msg_->is_join () && !msg_->is_leave ())
return rc;
else {
int group_length = (int) strlen (msg_->group ());
msg_t command;
int offset;
if (msg_->is_join ()) {
rc = command.init_size (group_length + 5);
errno_assert(rc == 0);
offset = 5;
memcpy (command.data (), "\4JOIN", 5);
}
else {
rc = command.init_size (group_length + 6);
errno_assert(rc == 0);
offset = 6;
memcpy (command.data (), "\5LEAVE", 6);
}
command.set_flags (msg_t::command);
char* command_data = (char*)command.data ();
// Copy the group
memcpy (command_data + offset, msg_->group (), group_length);
// Close the join message
rc = msg_->close ();
errno_assert (rc == 0);
*msg_ = command;
return 0;
}
}
void zmq::dish_session_t::reset ()
{
session_base_t::reset ();
state = group;
}
-125
View File
@@ -1,125 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_DISH_HPP_INCLUDED__
#define __ZMQ_DISH_HPP_INCLUDED__
#include <string>
#include <vector>
#include "socket_base.hpp"
#include "session_base.hpp"
#include "dist.hpp"
#include "fq.hpp"
#include "trie.hpp"
namespace zmq
{
class ctx_t;
class pipe_t;
class io_thread_t;
class dish_t :
public socket_base_t
{
public:
dish_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);
~dish_t ();
protected:
// Overrides of functions from socket_base_t.
void xattach_pipe (zmq::pipe_t *pipe_, bool subscribe_to_all_);
int xsend (zmq::msg_t *msg_);
bool xhas_out ();
int xrecv (zmq::msg_t *msg_);
bool xhas_in ();
const blob_t &get_credential () const;
void xread_activated (zmq::pipe_t *pipe_);
void xwrite_activated (zmq::pipe_t *pipe_);
void xhiccuped (pipe_t *pipe_);
void xpipe_terminated (zmq::pipe_t *pipe_);
int xjoin (const char *group_);
int xleave (const char *group_);
private:
// Send subscriptions to a pipe
void send_subscriptions (pipe_t *pipe_);
// Fair queueing object for inbound pipes.
fq_t fq;
// Object for distributing the subscriptions upstream.
dist_t dist;
// The repository of subscriptions.
typedef std::set<std::string> subscriptions_t;
subscriptions_t subscriptions;
// If true, 'message' contains a matching message to return on the
// next recv call.
bool has_message;
msg_t message;
dish_t (const dish_t&);
const dish_t &operator = (const dish_t&);
};
class dish_session_t : public session_base_t
{
public:
dish_session_t (zmq::io_thread_t *io_thread_, bool connect_,
zmq::socket_base_t *socket_, const options_t &options_,
address_t *addr_);
~dish_session_t ();
// Overrides of the functions from session_base_t.
int push_msg (msg_t *msg_);
int pull_msg (msg_t *msg_);
void reset ();
private:
enum {
group,
body
} state;
msg_t group_msg;
dish_session_t (const dish_session_t&);
const dish_session_t &operator = (const dish_session_t&);
};
}
#endif
-235
View File
@@ -1,235 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "dist.hpp"
#include "pipe.hpp"
#include "err.hpp"
#include "msg.hpp"
#include "likely.hpp"
zmq::dist_t::dist_t () :
matching (0),
active (0),
eligible (0),
more (false)
{
}
zmq::dist_t::~dist_t ()
{
zmq_assert (pipes.empty ());
}
void zmq::dist_t::attach (pipe_t *pipe_)
{
// If we are in the middle of sending a message, we'll add new pipe
// into the list of eligible pipes. Otherwise we add it to the list
// of active pipes.
if (more) {
pipes.push_back (pipe_);
pipes.swap (eligible, pipes.size () - 1);
eligible++;
}
else {
pipes.push_back (pipe_);
pipes.swap (active, pipes.size () - 1);
active++;
eligible++;
}
}
void zmq::dist_t::match (pipe_t *pipe_)
{
// If pipe is already matching do nothing.
if (pipes.index (pipe_) < matching)
return;
// If the pipe isn't eligible, ignore it.
if (pipes.index (pipe_) >= eligible)
return;
// Mark the pipe as matching.
pipes.swap (pipes.index (pipe_), matching);
matching++;
}
void zmq::dist_t::reverse_match ()
{
pipes_t::size_type prev_matching = matching;
// Reset matching to 0
unmatch();
// Mark all matching pipes as not matching and vice-versa.
// To do this, push all pipes that are eligible but not
// matched - i.e. between "matching" and "eligible" -
// to the beginning of the queue.
for (pipes_t::size_type i = prev_matching; i < eligible; ++i) {
pipes.swap(i, matching++);
}
}
void zmq::dist_t::unmatch ()
{
matching = 0;
}
void zmq::dist_t::pipe_terminated (pipe_t *pipe_)
{
// Remove the pipe from the list; adjust number of matching, active and/or
// eligible pipes accordingly.
if (pipes.index (pipe_) < matching) {
pipes.swap (pipes.index (pipe_), matching - 1);
matching--;
}
if (pipes.index (pipe_) < active) {
pipes.swap (pipes.index (pipe_), active - 1);
active--;
}
if (pipes.index (pipe_) < eligible) {
pipes.swap (pipes.index (pipe_), eligible - 1);
eligible--;
}
pipes.erase (pipe_);
}
void zmq::dist_t::activated (pipe_t *pipe_)
{
// Move the pipe from passive to eligible state.
if (eligible < pipes.size ()) {
pipes.swap (pipes.index (pipe_), eligible);
eligible++;
}
// If there's no message being sent at the moment, move it to
// the active state.
if (!more && active < pipes.size ()) {
pipes.swap (eligible - 1, active);
active++;
}
}
int zmq::dist_t::send_to_all (msg_t *msg_)
{
matching = active;
return send_to_matching (msg_);
}
int zmq::dist_t::send_to_matching (msg_t *msg_)
{
// Is this end of a multipart message?
bool msg_more = msg_->flags () & msg_t::more ? true : false;
// Push the message to matching pipes.
distribute (msg_);
// If multipart message is fully sent, activate all the eligible pipes.
if (!msg_more)
active = eligible;
more = msg_more;
return 0;
}
void zmq::dist_t::distribute (msg_t *msg_)
{
// If there are no matching pipes available, simply drop the message.
if (matching == 0) {
int rc = msg_->close ();
errno_assert (rc == 0);
rc = msg_->init ();
errno_assert (rc == 0);
return;
}
if (msg_->is_vsm ()) {
for (pipes_t::size_type i = 0; i < matching; ++i)
if(!write (pipes [i], msg_))
--i; // Retry last write because index will have been swapped
int rc = msg_->close();
errno_assert (rc == 0);
rc = msg_->init ();
errno_assert (rc == 0);
return;
}
// Add matching-1 references to the message. We already hold one reference,
// that's why -1.
msg_->add_refs ((int) matching - 1);
// Push copy of the message to each matching pipe.
int failed = 0;
for (pipes_t::size_type i = 0; i < matching; ++i)
if (!write (pipes [i], msg_)) {
++failed;
--i; // Retry last write because index will have been swapped
}
if (unlikely (failed))
msg_->rm_refs (failed);
// Detach the original message from the data buffer. Note that we don't
// close the message. That's because we've already used all the references.
int rc = msg_->init ();
errno_assert (rc == 0);
}
bool zmq::dist_t::has_out ()
{
return true;
}
bool zmq::dist_t::write (pipe_t *pipe_, msg_t *msg_)
{
if (!pipe_->write (msg_)) {
pipes.swap (pipes.index (pipe_), matching - 1);
matching--;
pipes.swap (pipes.index (pipe_), active - 1);
active--;
pipes.swap (active, eligible - 1);
eligible--;
return false;
}
if (!(msg_->flags () & msg_t::more))
pipe_->flush ();
return true;
}
bool zmq::dist_t::check_hwm ()
{
for (pipes_t::size_type i = 0; i < matching; ++i)
if (!pipes [i]->check_hwm ())
return false;
return true;
}
-120
View File
@@ -1,120 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_DIST_HPP_INCLUDED__
#define __ZMQ_DIST_HPP_INCLUDED__
#include <vector>
#include "array.hpp"
#include "pipe.hpp"
namespace zmq
{
class pipe_t;
class msg_t;
// Class manages a set of outbound pipes. It sends each messages to
// each of them.
class dist_t
{
public:
dist_t ();
~dist_t ();
// Adds the pipe to the distributor object.
void attach (zmq::pipe_t *pipe_);
// Activates pipe that have previously reached high watermark.
void activated (zmq::pipe_t *pipe_);
// Mark the pipe as matching. Subsequent call to send_to_matching
// will send message also to this pipe.
void match (zmq::pipe_t *pipe_);
// Marks all pipes that are not matched as matched and vice-versa.
void reverse_match();
// Mark all pipes as non-matching.
void unmatch ();
// Removes the pipe from the distributor object.
void pipe_terminated (zmq::pipe_t *pipe_);
// Send the message to the matching outbound pipes.
int send_to_matching (zmq::msg_t *msg_);
// Send the message to all the outbound pipes.
int send_to_all (zmq::msg_t *msg_);
bool has_out ();
// check HWM of all pipes matching
bool check_hwm ();
private:
// Write the message to the pipe. Make the pipe inactive if writing
// fails. In such a case false is returned.
bool write (zmq::pipe_t *pipe_, zmq::msg_t *msg_);
// Put the message to all active pipes.
void distribute (zmq::msg_t *msg_);
// List of outbound pipes.
typedef array_t <zmq::pipe_t, 2> pipes_t;
pipes_t pipes;
// Number of all the pipes to send the next message to.
pipes_t::size_type matching;
// Number of active pipes. All the active pipes are located at the
// beginning of the pipes array. These are the pipes the messages
// can be sent to at the moment.
pipes_t::size_type active;
// Number of pipes eligible for sending messages to. This includes all
// the active pipes plus all the pipes that we can in theory send
// messages to (the HWM is not yet reached), but sending a message
// to them would result in partial message being delivered, ie. message
// with initial parts missing.
pipes_t::size_type eligible;
// True if last we are in the middle of a multipart message.
bool more;
dist_t (const dist_t&);
const dist_t &operator = (const dist_t&);
};
}
#endif
-189
View File
@@ -1,189 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_ENCODER_HPP_INCLUDED__
#define __ZMQ_ENCODER_HPP_INCLUDED__
#if defined(_MSC_VER)
#ifndef NOMINMAX
#define NOMINMAX
#endif
#endif
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include "err.hpp"
#include "msg.hpp"
#include "i_encoder.hpp"
namespace zmq
{
// Helper base class for encoders. It implements the state machine that
// fills the outgoing buffer. Derived classes should implement individual
// state machine actions.
template <typename T> class encoder_base_t : public i_encoder
{
public:
inline encoder_base_t (size_t bufsize_) :
write_pos(0),
to_write(0),
next(NULL),
new_msg_flag(false),
bufsize (bufsize_),
in_progress (NULL)
{
buf = (unsigned char*) malloc (bufsize_);
alloc_assert (buf);
}
// The destructor doesn't have to be virtual. It is made virtual
// just to keep ICC and code checking tools from complaining.
inline virtual ~encoder_base_t ()
{
free (buf);
}
// The function returns a batch of binary data. The data
// are filled to a supplied buffer. If no buffer is supplied (data_
// points to NULL) decoder object will provide buffer of its own.
inline size_t encode (unsigned char **data_, size_t size_)
{
unsigned char *buffer = !*data_ ? buf : *data_;
size_t buffersize = !*data_ ? bufsize : size_;
if (in_progress == NULL)
return 0;
size_t pos = 0;
while (pos < buffersize) {
// If there are no more data to return, run the state machine.
// If there are still no data, return what we already have
// in the buffer.
if (!to_write) {
if (new_msg_flag) {
int rc = in_progress->close ();
errno_assert (rc == 0);
rc = in_progress->init ();
errno_assert (rc == 0);
in_progress = NULL;
break;
}
(static_cast <T*> (this)->*next) ();
}
// If there are no data in the buffer yet and we are able to
// fill whole buffer in a single go, let's use zero-copy.
// There's no disadvantage to it as we cannot stuck multiple
// messages into the buffer anyway. Note that subsequent
// write(s) are non-blocking, thus each single write writes
// at most SO_SNDBUF bytes at once not depending on how large
// is the chunk returned from here.
// As a consequence, large messages being sent won't block
// other engines running in the same I/O thread for excessive
// amounts of time.
if (!pos && !*data_ && to_write >= buffersize) {
*data_ = write_pos;
pos = to_write;
write_pos = NULL;
to_write = 0;
return pos;
}
// Copy data to the buffer. If the buffer is full, return.
size_t to_copy = std::min (to_write, buffersize - pos);
memcpy (buffer + pos, write_pos, to_copy);
pos += to_copy;
write_pos += to_copy;
to_write -= to_copy;
}
*data_ = buffer;
return pos;
}
void load_msg (msg_t *msg_)
{
zmq_assert (in_progress == NULL);
in_progress = msg_;
(static_cast <T*> (this)->*next) ();
}
protected:
// Prototype of state machine action.
typedef void (T::*step_t) ();
// This function should be called from derived class to write the data
// to the buffer and schedule next state machine action.
inline void next_step (void *write_pos_, size_t to_write_,
step_t next_, bool new_msg_flag_)
{
write_pos = (unsigned char*) write_pos_;
to_write = to_write_;
next = next_;
new_msg_flag = new_msg_flag_;
}
private:
// Where to get the data to write from.
unsigned char *write_pos;
// How much data to write before next step should be executed.
size_t to_write;
// Next step. If set to NULL, it means that associated data stream
// is dead.
step_t next;
bool new_msg_flag;
// The buffer for encoded data.
size_t bufsize;
unsigned char *buf;
encoder_base_t (const encoder_base_t&);
void operator = (const encoder_base_t&);
protected:
msg_t *in_progress;
};
}
#endif
-206
View File
@@ -1,206 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "epoll.hpp"
#if defined ZMQ_USE_EPOLL
#include <sys/epoll.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <algorithm>
#include <new>
#include "macros.hpp"
#include "epoll.hpp"
#include "err.hpp"
#include "config.hpp"
#include "i_poll_events.hpp"
zmq::epoll_t::epoll_t (const zmq::ctx_t &ctx_) :
ctx(ctx_),
stopping (false)
{
#ifdef ZMQ_USE_EPOLL_CLOEXEC
// Setting this option result in sane behaviour when exec() functions
// are used. Old sockets are closed and don't block TCP ports, avoid
// leaks, etc.
epoll_fd = epoll_create1 (EPOLL_CLOEXEC);
#else
epoll_fd = epoll_create (1);
#endif
errno_assert (epoll_fd != -1);
}
zmq::epoll_t::~epoll_t ()
{
// Wait till the worker thread exits.
worker.stop ();
close (epoll_fd);
for (retired_t::iterator it = retired.begin (); it != retired.end (); ++it) {
LIBZMQ_DELETE(*it);
}
}
zmq::epoll_t::handle_t zmq::epoll_t::add_fd (fd_t fd_, i_poll_events *events_)
{
poll_entry_t *pe = new (std::nothrow) poll_entry_t;
alloc_assert (pe);
// The memset is not actually needed. It's here to prevent debugging
// tools to complain about using uninitialised memory.
memset (pe, 0, sizeof (poll_entry_t));
pe->fd = fd_;
pe->ev.events = 0;
pe->ev.data.ptr = pe;
pe->events = events_;
int rc = epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd_, &pe->ev);
errno_assert (rc != -1);
// Increase the load metric of the thread.
adjust_load (1);
return pe;
}
void zmq::epoll_t::rm_fd (handle_t handle_)
{
poll_entry_t *pe = (poll_entry_t*) handle_;
int rc = epoll_ctl (epoll_fd, EPOLL_CTL_DEL, pe->fd, &pe->ev);
errno_assert (rc != -1);
pe->fd = retired_fd;
retired_sync.lock ();
retired.push_back (pe);
retired_sync.unlock ();
// Decrease the load metric of the thread.
adjust_load (-1);
}
void zmq::epoll_t::set_pollin (handle_t handle_)
{
poll_entry_t *pe = (poll_entry_t*) handle_;
pe->ev.events |= EPOLLIN;
int rc = epoll_ctl (epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
errno_assert (rc != -1);
}
void zmq::epoll_t::reset_pollin (handle_t handle_)
{
poll_entry_t *pe = (poll_entry_t*) handle_;
pe->ev.events &= ~((short) EPOLLIN);
int rc = epoll_ctl (epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
errno_assert (rc != -1);
}
void zmq::epoll_t::set_pollout (handle_t handle_)
{
poll_entry_t *pe = (poll_entry_t*) handle_;
pe->ev.events |= EPOLLOUT;
int rc = epoll_ctl (epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
errno_assert (rc != -1);
}
void zmq::epoll_t::reset_pollout (handle_t handle_)
{
poll_entry_t *pe = (poll_entry_t*) handle_;
pe->ev.events &= ~((short) EPOLLOUT);
int rc = epoll_ctl (epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
errno_assert (rc != -1);
}
void zmq::epoll_t::start ()
{
ctx.start_thread (worker, worker_routine, this);
}
void zmq::epoll_t::stop ()
{
stopping = true;
}
int zmq::epoll_t::max_fds ()
{
return -1;
}
void zmq::epoll_t::loop ()
{
epoll_event ev_buf [max_io_events];
while (!stopping) {
// Execute any due timers.
int timeout = (int) execute_timers ();
// Wait for events.
int n = epoll_wait (epoll_fd, &ev_buf [0], max_io_events,
timeout ? timeout : -1);
if (n == -1) {
errno_assert (errno == EINTR);
continue;
}
for (int i = 0; i < n; i ++) {
poll_entry_t *pe = ((poll_entry_t*) ev_buf [i].data.ptr);
if (pe->fd == retired_fd)
continue;
if (ev_buf [i].events & (EPOLLERR | EPOLLHUP))
pe->events->in_event ();
if (pe->fd == retired_fd)
continue;
if (ev_buf [i].events & EPOLLOUT)
pe->events->out_event ();
if (pe->fd == retired_fd)
continue;
if (ev_buf [i].events & EPOLLIN)
pe->events->in_event ();
}
// Destroy retired event sources.
retired_sync.lock ();
for (retired_t::iterator it = retired.begin (); it != retired.end (); ++it) {
LIBZMQ_DELETE(*it);
}
retired.clear ();
retired_sync.unlock ();
}
}
void zmq::epoll_t::worker_routine (void *arg_)
{
((epoll_t*) arg_)->loop ();
}
#endif
-119
View File
@@ -1,119 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_EPOLL_HPP_INCLUDED__
#define __ZMQ_EPOLL_HPP_INCLUDED__
// poller.hpp decides which polling mechanism to use.
#include "poller.hpp"
#if defined ZMQ_USE_EPOLL
#include <vector>
#include <sys/epoll.h>
#include "ctx.hpp"
#include "fd.hpp"
#include "thread.hpp"
#include "poller_base.hpp"
#include "mutex.hpp"
namespace zmq
{
struct i_poll_events;
// This class implements socket polling mechanism using the Linux-specific
// epoll mechanism.
class epoll_t : public poller_base_t
{
public:
typedef void* handle_t;
epoll_t (const ctx_t &ctx_);
~epoll_t ();
// "poller" concept.
handle_t add_fd (fd_t fd_, zmq::i_poll_events *events_);
void rm_fd (handle_t handle_);
void set_pollin (handle_t handle_);
void reset_pollin (handle_t handle_);
void set_pollout (handle_t handle_);
void reset_pollout (handle_t handle_);
void start ();
void stop ();
static int max_fds ();
private:
// Main worker thread routine.
static void worker_routine (void *arg_);
// Main event loop.
void loop ();
// Reference to ZMQ context.
const ctx_t &ctx;
// Main epoll file descriptor
fd_t epoll_fd;
struct poll_entry_t
{
fd_t fd;
epoll_event ev;
zmq::i_poll_events *events;
};
// List of retired event sources.
typedef std::vector <poll_entry_t*> retired_t;
retired_t retired;
// If true, thread is in the process of shutting down.
bool stopping;
// Handle of the physical thread doing the I/O work.
thread_t worker;
// Synchronisation of retired event sources
mutex_t retired_sync;
epoll_t (const epoll_t&);
const epoll_t &operator = (const epoll_t&);
};
typedef epoll_t poller_t;
}
#endif
#endif
-447
View File
@@ -1,447 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "err.hpp"
const char *zmq::errno_to_string (int errno_)
{
switch (errno_) {
#if defined ZMQ_HAVE_WINDOWS
case ENOTSUP:
return "Not supported";
case EPROTONOSUPPORT:
return "Protocol not supported";
case ENOBUFS:
return "No buffer space available";
case ENETDOWN:
return "Network is down";
case EADDRINUSE:
return "Address in use";
case EADDRNOTAVAIL:
return "Address not available";
case ECONNREFUSED:
return "Connection refused";
case EINPROGRESS:
return "Operation in progress";
#endif
case EFSM:
return "Operation cannot be accomplished in current state";
case ENOCOMPATPROTO:
return "The protocol is not compatible with the socket type";
case ETERM:
return "Context was terminated";
case EMTHREAD:
return "No thread available";
case EHOSTUNREACH:
return "Host unreachable";
default:
#if defined _MSC_VER
#pragma warning (push)
#pragma warning (disable:4996)
#endif
return strerror (errno_);
#if defined _MSC_VER
#pragma warning (pop)
#endif
}
}
void zmq::zmq_abort(const char *errmsg_)
{
#if defined ZMQ_HAVE_WINDOWS
// Raise STATUS_FATAL_APP_EXIT.
ULONG_PTR extra_info [1];
extra_info [0] = (ULONG_PTR) errmsg_;
RaiseException (0x40000015, EXCEPTION_NONCONTINUABLE, 1, extra_info);
#else
(void)errmsg_;
print_backtrace();
abort ();
#endif
}
#ifdef ZMQ_HAVE_WINDOWS
const char *zmq::wsa_error()
{
return wsa_error_no (WSAGetLastError(), NULL);
}
const char *zmq::wsa_error_no (int no_, const char * wsae_wouldblock_string)
{
// TODO: It seems that list of Windows socket errors is longer than this.
// Investigate whether there's a way to convert it into the string
// automatically (wsaError->HRESULT->string?).
return
(no_ == WSABASEERR) ?
"No Error" :
(no_ == WSAEINTR) ?
"Interrupted system call" :
(no_ == WSAEBADF) ?
"Bad file number" :
(no_ == WSAEACCES) ?
"Permission denied" :
(no_ == WSAEFAULT) ?
"Bad address" :
(no_ == WSAEINVAL) ?
"Invalid argument" :
(no_ == WSAEMFILE) ?
"Too many open files" :
(no_ == WSAEWOULDBLOCK) ?
wsae_wouldblock_string :
(no_ == WSAEINPROGRESS) ?
"Operation now in progress" :
(no_ == WSAEALREADY) ?
"Operation already in progress" :
(no_ == WSAENOTSOCK) ?
"Socket operation on non-socket" :
(no_ == WSAEDESTADDRREQ) ?
"Destination address required" :
(no_ == WSAEMSGSIZE) ?
"Message too long" :
(no_ == WSAEPROTOTYPE) ?
"Protocol wrong type for socket" :
(no_ == WSAENOPROTOOPT) ?
"Bad protocol option" :
(no_ == WSAEPROTONOSUPPORT) ?
"Protocol not supported" :
(no_ == WSAESOCKTNOSUPPORT) ?
"Socket type not supported" :
(no_ == WSAEOPNOTSUPP) ?
"Operation not supported on socket" :
(no_ == WSAEPFNOSUPPORT) ?
"Protocol family not supported" :
(no_ == WSAEAFNOSUPPORT) ?
"Address family not supported by protocol family" :
(no_ == WSAEADDRINUSE) ?
"Address already in use" :
(no_ == WSAEADDRNOTAVAIL) ?
"Can't assign requested address" :
(no_ == WSAENETDOWN) ?
"Network is down" :
(no_ == WSAENETUNREACH) ?
"Network is unreachable" :
(no_ == WSAENETRESET) ?
"Net dropped connection or reset" :
(no_ == WSAECONNABORTED) ?
"Software caused connection abort" :
(no_ == WSAECONNRESET) ?
"Connection reset by peer" :
(no_ == WSAENOBUFS) ?
"No buffer space available" :
(no_ == WSAEISCONN) ?
"Socket is already connected" :
(no_ == WSAENOTCONN) ?
"Socket is not connected" :
(no_ == WSAESHUTDOWN) ?
"Can't send after socket shutdown" :
(no_ == WSAETOOMANYREFS) ?
"Too many references can't splice" :
(no_ == WSAETIMEDOUT) ?
"Connection timed out" :
(no_ == WSAECONNREFUSED) ?
"Connection refused" :
(no_ == WSAELOOP) ?
"Too many levels of symbolic links" :
(no_ == WSAENAMETOOLONG) ?
"File name too long" :
(no_ == WSAEHOSTDOWN) ?
"Host is down" :
(no_ == WSAEHOSTUNREACH) ?
"No Route to Host" :
(no_ == WSAENOTEMPTY) ?
"Directory not empty" :
(no_ == WSAEPROCLIM) ?
"Too many processes" :
(no_ == WSAEUSERS) ?
"Too many users" :
(no_ == WSAEDQUOT) ?
"Disc Quota Exceeded" :
(no_ == WSAESTALE) ?
"Stale NFS file handle" :
(no_ == WSAEREMOTE) ?
"Too many levels of remote in path" :
(no_ == WSASYSNOTREADY) ?
"Network SubSystem is unavailable" :
(no_ == WSAVERNOTSUPPORTED) ?
"WINSOCK DLL Version out of range" :
(no_ == WSANOTINITIALISED) ?
"Successful WSASTARTUP not yet performed" :
(no_ == WSAHOST_NOT_FOUND) ?
"Host not found" :
(no_ == WSATRY_AGAIN) ?
"Non-Authoritative Host not found" :
(no_ == WSANO_RECOVERY) ?
"Non-Recoverable errors: FORMERR REFUSED NOTIMP" :
(no_ == WSANO_DATA) ?
"Valid name no data record of requested" :
"error not defined";
}
void zmq::win_error (char *buffer_, size_t buffer_size_)
{
DWORD errcode = GetLastError ();
#if defined _WIN32_WCE
DWORD rc = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errcode, MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT), (LPWSTR)buffer_, buffer_size_ / sizeof(wchar_t), NULL);
#else
DWORD rc = FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errcode, MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT), buffer_, (DWORD) buffer_size_, NULL);
#endif
zmq_assert (rc);
}
int zmq::wsa_error_to_errno (int errcode)
{
switch (errcode) {
// 10004 - Interrupted system call.
case WSAEINTR:
return EINTR;
// 10009 - File handle is not valid.
case WSAEBADF:
return EBADF;
// 10013 - Permission denied.
case WSAEACCES:
return EACCES;
// 10014 - Bad address.
case WSAEFAULT:
return EFAULT;
// 10022 - Invalid argument.
case WSAEINVAL:
return EINVAL;
// 10024 - Too many open files.
case WSAEMFILE:
return EMFILE;
// 10035 - Operation would block.
case WSAEWOULDBLOCK:
return EBUSY;
// 10036 - Operation now in progress.
case WSAEINPROGRESS:
return EAGAIN;
// 10037 - Operation already in progress.
case WSAEALREADY:
return EAGAIN;
// 10038 - Socket operation on non-socket.
case WSAENOTSOCK:
return ENOTSOCK;
// 10039 - Destination address required.
case WSAEDESTADDRREQ:
return EFAULT;
// 10040 - Message too long.
case WSAEMSGSIZE:
return EMSGSIZE;
// 10041 - Protocol wrong type for socket.
case WSAEPROTOTYPE:
return EFAULT;
// 10042 - Bad protocol option.
case WSAENOPROTOOPT:
return EINVAL;
// 10043 - Protocol not supported.
case WSAEPROTONOSUPPORT:
return EPROTONOSUPPORT;
// 10044 - Socket type not supported.
case WSAESOCKTNOSUPPORT:
return EFAULT;
// 10045 - Operation not supported on socket.
case WSAEOPNOTSUPP:
return EFAULT;
// 10046 - Protocol family not supported.
case WSAEPFNOSUPPORT:
return EPROTONOSUPPORT;
// 10047 - Address family not supported by protocol family.
case WSAEAFNOSUPPORT:
return EAFNOSUPPORT;
// 10048 - Address already in use.
case WSAEADDRINUSE:
return EADDRINUSE;
// 10049 - Cannot assign requested address.
case WSAEADDRNOTAVAIL:
return EADDRNOTAVAIL;
// 10050 - Network is down.
case WSAENETDOWN:
return ENETDOWN;
// 10051 - Network is unreachable.
case WSAENETUNREACH:
return ENETUNREACH;
// 10052 - Network dropped connection on reset.
case WSAENETRESET:
return ENETRESET;
// 10053 - Software caused connection abort.
case WSAECONNABORTED:
return ECONNABORTED;
// 10054 - Connection reset by peer.
case WSAECONNRESET:
return ECONNRESET;
// 10055 - No buffer space available.
case WSAENOBUFS:
return ENOBUFS;
// 10056 - Socket is already connected.
case WSAEISCONN:
return EFAULT;
// 10057 - Socket is not connected.
case WSAENOTCONN:
return ENOTCONN;
// 10058 - Can't send after socket shutdown.
case WSAESHUTDOWN:
return EFAULT;
// 10059 - Too many references can't splice.
case WSAETOOMANYREFS:
return EFAULT;
// 10060 - Connection timed out.
case WSAETIMEDOUT:
return ETIMEDOUT;
// 10061 - Connection refused.
case WSAECONNREFUSED:
return ECONNREFUSED;
// 10062 - Too many levels of symbolic links.
case WSAELOOP:
return EFAULT;
// 10063 - File name too long.
case WSAENAMETOOLONG:
return EFAULT;
// 10064 - Host is down.
case WSAEHOSTDOWN:
return EAGAIN;
// 10065 - No route to host.
case WSAEHOSTUNREACH:
return EHOSTUNREACH;
// 10066 - Directory not empty.
case WSAENOTEMPTY:
return EFAULT;
// 10067 - Too many processes.
case WSAEPROCLIM:
return EFAULT;
// 10068 - Too many users.
case WSAEUSERS:
return EFAULT;
// 10069 - Disc Quota Exceeded.
case WSAEDQUOT:
return EFAULT;
// 10070 - Stale NFS file handle.
case WSAESTALE:
return EFAULT;
// 10071 - Too many levels of remote in path.
case WSAEREMOTE:
return EFAULT;
// 10091 - Network SubSystem is unavailable.
case WSASYSNOTREADY:
return EFAULT;
// 10092 - WINSOCK DLL Version out of range.
case WSAVERNOTSUPPORTED:
return EFAULT;
// 10093 - Successful WSASTARTUP not yet performed.
case WSANOTINITIALISED:
return EFAULT;
// 11001 - Host not found.
case WSAHOST_NOT_FOUND:
return EFAULT;
// 11002 - Non-Authoritative Host not found.
case WSATRY_AGAIN:
return EFAULT;
// 11003 - Non-Recoverable errors: FORMERR REFUSED NOTIMP.
case WSANO_RECOVERY:
return EFAULT;
// 11004 - Valid name no data record of requested.
case WSANO_DATA:
return EFAULT;
default:
wsa_assert (false);
}
// Not reachable
return 0;
}
#endif
#ifdef HAVE_LIBUNWIND
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <dlfcn.h>
#include <cxxabi.h>
#include "mutex.hpp"
void zmq::print_backtrace (void)
{
static zmq::mutex_t mtx;
mtx.lock ();
Dl_info dl_info;
unw_cursor_t cursor;
unw_context_t ctx;
unsigned frame_n = 0;
unw_getcontext (&ctx);
unw_init_local (&cursor, &ctx);
while (unw_step (&cursor) > 0) {
unw_word_t offset;
unw_proc_info_t p_info;
const char *file_name;
char *demangled_name;
char func_name[256] = "";
void *addr;
int rc;
if (unw_get_proc_info (&cursor, &p_info))
break;
rc = unw_get_proc_name (&cursor, func_name, 256, &offset);
if (rc == -UNW_ENOINFO)
strcpy(func_name, "?");
addr = (void *)(p_info.start_ip + offset);
if (dladdr (addr, &dl_info) && dl_info.dli_fname)
file_name = dl_info.dli_fname;
else
file_name = "?";
demangled_name = abi::__cxa_demangle (func_name, NULL, NULL, &rc);
printf ("#%u %p in %s (%s+0x%lx)\n", frame_n++, addr, file_name,
rc ? func_name : demangled_name, (unsigned long) offset);
free (demangled_name);
}
puts ("");
fflush (stdout);
mtx.unlock ();
}
#else
void zmq::print_backtrace (void)
{
}
#endif
-173
View File
@@ -1,173 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_ERR_HPP_INCLUDED__
#define __ZMQ_ERR_HPP_INCLUDED__
#include <assert.h>
#if defined _WIN32_WCE
#include "..\builds\msvc\errno.hpp"
#else
#include <errno.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#ifndef ZMQ_HAVE_WINDOWS
#include <netdb.h>
#endif
#include "likely.hpp"
// 0MQ-specific error codes are defined in zmq.h
// EPROTO is not used by OpenBSD and maybe other platforms.
#ifndef EPROTO
#define EPROTO 0
#endif
namespace zmq
{
const char *errno_to_string (int errno_);
void zmq_abort (const char *errmsg_);
void print_backtrace (void);
}
#ifdef ZMQ_HAVE_WINDOWS
namespace zmq
{
const char *wsa_error ();
const char *wsa_error_no (int no_, const char * wsae_wouldblock_string = "Operation would block");
void win_error (char *buffer_, size_t buffer_size_);
int wsa_error_to_errno (int errcode);
}
// Provides convenient way to check WSA-style errors on Windows.
#define wsa_assert(x) \
do {\
if (unlikely (!(x))) {\
const char *errstr = zmq::wsa_error ();\
if (errstr != NULL) {\
fprintf (stderr, "Assertion failed: %s (%s:%d)\n", errstr, \
__FILE__, __LINE__);\
fflush (stderr);\
zmq::zmq_abort (errstr);\
}\
}\
} while (false)
// Provides convenient way to assert on WSA-style errors on Windows.
#define wsa_assert_no(no) \
do {\
const char *errstr = zmq::wsa_error_no (no);\
if (errstr != NULL) {\
fprintf (stderr, "Assertion failed: %s (%s:%d)\n", errstr, \
__FILE__, __LINE__);\
fflush (stderr);\
zmq::zmq_abort (errstr);\
}\
} while (false)
// Provides convenient way to check GetLastError-style errors on Windows.
#define win_assert(x) \
do {\
if (unlikely (!(x))) {\
char errstr [256];\
zmq::win_error (errstr, 256);\
fprintf (stderr, "Assertion failed: %s (%s:%d)\n", errstr, \
__FILE__, __LINE__);\
fflush (stderr);\
zmq::zmq_abort (errstr);\
}\
} while (false)
#endif
// This macro works in exactly the same way as the normal assert. It is used
// in its stead because standard assert on Win32 in broken - it prints nothing
// when used within the scope of JNI library.
#define zmq_assert(x) \
do {\
if (unlikely (!(x))) {\
fprintf (stderr, "Assertion failed: %s (%s:%d)\n", #x, \
__FILE__, __LINE__);\
fflush (stderr);\
zmq::zmq_abort (#x);\
}\
} while (false)
// Provides convenient way to check for errno-style errors.
#define errno_assert(x) \
do {\
if (unlikely (!(x))) {\
const char *errstr = strerror (errno);\
fprintf (stderr, "%s (%s:%d)\n", errstr, __FILE__, __LINE__);\
fflush (stderr);\
zmq::zmq_abort (errstr);\
}\
} while (false)
// Provides convenient way to check for POSIX errors.
#define posix_assert(x) \
do {\
if (unlikely (x)) {\
const char *errstr = strerror (x);\
fprintf (stderr, "%s (%s:%d)\n", errstr, __FILE__, __LINE__);\
fflush (stderr);\
zmq::zmq_abort (errstr);\
}\
} while (false)
// Provides convenient way to check for errors from getaddrinfo.
#define gai_assert(x) \
do {\
if (unlikely (x)) {\
const char *errstr = gai_strerror (x);\
fprintf (stderr, "%s (%s:%d)\n", errstr, __FILE__, __LINE__);\
fflush (stderr);\
zmq::zmq_abort (errstr);\
}\
} while (false)
// Provides convenient way to check whether memory allocation have succeeded.
#define alloc_assert(x) \
do {\
if (unlikely (!x)) {\
fprintf (stderr, "FATAL ERROR: OUT OF MEMORY (%s:%d)\n",\
__FILE__, __LINE__);\
fflush (stderr);\
zmq::zmq_abort ("FATAL ERROR: OUT OF MEMORY");\
}\
} while (false)
#endif
-52
View File
@@ -1,52 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_FD_HPP_INCLUDED__
#define __ZMQ_FD_HPP_INCLUDED__
#if defined _WIN32
#include "windows.hpp"
#endif
namespace zmq
{
#ifdef ZMQ_HAVE_WINDOWS
#if defined _MSC_VER &&_MSC_VER <= 1400
typedef UINT_PTR fd_t;
enum {retired_fd = (fd_t)(~0)};
#else
typedef SOCKET fd_t;
enum {retired_fd = (fd_t)INVALID_SOCKET};
#endif
#else
typedef int fd_t;
enum {retired_fd = -1};
#endif
}
#endif
-163
View File
@@ -1,163 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "fq.hpp"
#include "pipe.hpp"
#include "err.hpp"
#include "msg.hpp"
zmq::fq_t::fq_t () :
active (0),
last_in (NULL),
current (0),
more (false)
{
}
zmq::fq_t::~fq_t ()
{
zmq_assert (pipes.empty ());
}
void zmq::fq_t::attach (pipe_t *pipe_)
{
pipes.push_back (pipe_);
pipes.swap (active, pipes.size () - 1);
active++;
}
void zmq::fq_t::pipe_terminated (pipe_t *pipe_)
{
const pipes_t::size_type index = pipes.index (pipe_);
// Remove the pipe from the list; adjust number of active pipes
// accordingly.
if (index < active) {
active--;
pipes.swap (index, active);
if (current == active)
current = 0;
}
pipes.erase (pipe_);
if (last_in == pipe_) {
saved_credential.set_deep_copy (last_in->get_credential ());
last_in = NULL;
}
}
void zmq::fq_t::activated (pipe_t *pipe_)
{
// Move the pipe to the list of active pipes.
pipes.swap (pipes.index (pipe_), active);
active++;
}
int zmq::fq_t::recv (msg_t *msg_)
{
return recvpipe (msg_, NULL);
}
int zmq::fq_t::recvpipe (msg_t *msg_, pipe_t **pipe_)
{
// Deallocate old content of the message.
int rc = msg_->close ();
errno_assert (rc == 0);
// Round-robin over the pipes to get the next message.
while (active > 0) {
// Try to fetch new message. If we've already read part of the message
// subsequent part should be immediately available.
bool fetched = pipes [current]->read (msg_);
// Note that when message is not fetched, current pipe is deactivated
// and replaced by another active pipe. Thus we don't have to increase
// the 'current' pointer.
if (fetched) {
if (pipe_)
*pipe_ = pipes [current];
more = msg_->flags () & msg_t::more? true: false;
if (!more) {
last_in = pipes [current];
current = (current + 1) % active;
}
return 0;
}
// Check the atomicity of the message.
// If we've already received the first part of the message
// we should get the remaining parts without blocking.
zmq_assert (!more);
active--;
pipes.swap (current, active);
if (current == active)
current = 0;
}
// No message is available. Initialise the output parameter
// to be a 0-byte message.
rc = msg_->init ();
errno_assert (rc == 0);
errno = EAGAIN;
return -1;
}
bool zmq::fq_t::has_in ()
{
// There are subsequent parts of the partly-read message available.
if (more)
return true;
// Note that messing with current doesn't break the fairness of fair
// queueing algorithm. If there are no messages available current will
// get back to its original value. Otherwise it'll point to the first
// pipe holding messages, skipping only pipes with no messages available.
while (active > 0) {
if (pipes [current]->check_read ())
return true;
// Deactivate the pipe.
active--;
pipes.swap (current, active);
if (current == active)
current = 0;
}
return false;
}
const zmq::blob_t &zmq::fq_t::get_credential () const
{
return last_in?
last_in->get_credential (): saved_credential;
}
-92
View File
@@ -1,92 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_FQ_HPP_INCLUDED__
#define __ZMQ_FQ_HPP_INCLUDED__
#include "array.hpp"
#include "blob.hpp"
#include "pipe.hpp"
#include "msg.hpp"
namespace zmq
{
// Class manages a set of inbound pipes. On receive it performs fair
// queueing so that senders gone berserk won't cause denial of
// service for decent senders.
class fq_t
{
public:
fq_t ();
~fq_t ();
void attach (pipe_t *pipe_);
void activated (pipe_t *pipe_);
void pipe_terminated (pipe_t *pipe_);
int recv (msg_t *msg_);
int recvpipe (msg_t *msg_, pipe_t **pipe_);
bool has_in ();
const blob_t &get_credential () const;
private:
// Inbound pipes.
typedef array_t <pipe_t, 1> pipes_t;
pipes_t pipes;
// Number of active pipes. All the active pipes are located at the
// beginning of the pipes array.
pipes_t::size_type active;
// Pointer to the last pipe we received message from.
// NULL when no message has been received or the pipe
// has terminated.
pipe_t *last_in;
// Index of the next bound pipe to read a message from.
pipes_t::size_type current;
// If true, part of a multipart message was already received, but
// there are following parts still waiting in the current pipe.
bool more;
// Holds credential after the last_active_pipe has terminated.
blob_t saved_credential;
fq_t (const fq_t&);
const fq_t &operator = (const fq_t&);
};
}
#endif
-94
View File
@@ -1,94 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#include "gather.hpp"
#include "err.hpp"
#include "msg.hpp"
#include "pipe.hpp"
zmq::gather_t::gather_t (class ctx_t *parent_, uint32_t tid_, int sid_) :
socket_base_t (parent_, tid_, sid_, true)
{
options.type = ZMQ_GATHER;
}
zmq::gather_t::~gather_t ()
{
}
void zmq::gather_t::xattach_pipe (pipe_t *pipe_, bool subscribe_to_all_)
{
LIBZMQ_UNUSED (subscribe_to_all_);
zmq_assert (pipe_);
fq.attach (pipe_);
}
void zmq::gather_t::xread_activated (pipe_t *pipe_)
{
fq.activated (pipe_);
}
void zmq::gather_t::xpipe_terminated (pipe_t *pipe_)
{
fq.pipe_terminated (pipe_);
}
int zmq::gather_t::xrecv (msg_t *msg_)
{
int rc = fq.recvpipe (msg_, NULL);
// Drop any messages with more flag
while (rc == 0 && msg_->flags () & msg_t::more) {
// drop all frames of the current multi-frame message
rc = fq.recvpipe (msg_, NULL);
while (rc == 0 && msg_->flags () & msg_t::more)
rc = fq.recvpipe (msg_, NULL);
// get the new message
if (rc == 0)
rc = fq.recvpipe (msg_, NULL);
}
return rc;
}
bool zmq::gather_t::xhas_in ()
{
return fq.has_in ();
}
const zmq::blob_t &zmq::gather_t::get_credential () const
{
return fq.get_credential ();
}
-75
View File
@@ -1,75 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_GATHER_HPP_INCLUDED__
#define __ZMQ_GATHER_HPP_INCLUDED__
#include "socket_base.hpp"
#include "session_base.hpp"
#include "fq.hpp"
namespace zmq
{
class ctx_t;
class pipe_t;
class msg_t;
class io_thread_t;
class gather_t :
public socket_base_t
{
public:
gather_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);
~gather_t ();
protected:
// Overrides of functions from socket_base_t.
void xattach_pipe (zmq::pipe_t *pipe_, bool subscribe_to_all_);
int xrecv (zmq::msg_t *msg_);
bool xhas_in ();
const blob_t &get_credential () const;
void xread_activated (zmq::pipe_t *pipe_);
void xpipe_terminated (zmq::pipe_t *pipe_);
private:
// Fair queueing object for inbound pipes.
fq_t fq;
gather_t (const gather_t&);
const gather_t &operator = (const gather_t&);
};
}
#endif
-94
View File
@@ -1,94 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_GSSAPI_CLIENT_HPP_INCLUDED__
#define __ZMQ_GSSAPI_CLIENT_HPP_INCLUDED__
#ifdef HAVE_LIBGSSAPI_KRB5
#include "gssapi_mechanism_base.hpp"
namespace zmq
{
class msg_t;
class session_base_t;
class gssapi_client_t : public gssapi_mechanism_base_t
{
public:
gssapi_client_t (session_base_t *session_, const options_t &options_);
virtual ~gssapi_client_t ();
// mechanism implementation
virtual int next_handshake_command (msg_t *msg_);
virtual int process_handshake_command (msg_t *msg_);
virtual int encode (msg_t *msg_);
virtual int decode (msg_t *msg_);
virtual status_t status () const;
private:
enum state_t {
call_next_init,
send_next_token,
recv_next_token,
send_ready,
recv_ready,
connected
};
// Human-readable principal name of the service we are connecting to
char * service_name;
gss_OID service_name_type;
// Current FSM state
state_t state;
// Points to either send_tok or recv_tok
// during context initialization
gss_buffer_desc *token_ptr;
// The desired underlying mechanism
gss_OID_set_desc mechs;
// True iff client considers the server authenticated
bool security_context_established;
int initialize_context ();
int produce_next_token (msg_t *msg_);
int process_next_token (msg_t *msg_);
};
}
#endif
#endif
-95
View File
@@ -1,95 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_GSSAPI_SERVER_HPP_INCLUDED__
#define __ZMQ_GSSAPI_SERVER_HPP_INCLUDED__
#ifdef HAVE_LIBGSSAPI_KRB5
#include "gssapi_mechanism_base.hpp"
#include "zap_client.hpp"
namespace zmq
{
class msg_t;
class session_base_t;
class gssapi_server_t
: public gssapi_mechanism_base_t, public zap_client_t
{
public:
gssapi_server_t (session_base_t *session_,
const std::string &peer_address,
const options_t &options_);
virtual ~gssapi_server_t ();
// mechanism implementation
virtual int next_handshake_command (msg_t *msg_);
virtual int process_handshake_command (msg_t *msg_);
virtual int encode (msg_t *msg_);
virtual int decode (msg_t *msg_);
virtual int zap_msg_available ();
virtual status_t status () const;
private:
enum state_t {
send_next_token,
recv_next_token,
expect_zap_reply,
send_ready,
recv_ready,
connected
};
session_base_t * const session;
const std::string peer_address;
// Current FSM state
state_t state;
// True iff server considers the client authenticated
bool security_context_established;
// The underlying mechanism type (ignored)
gss_OID doid;
void accept_context ();
int produce_next_token (msg_t *msg_);
int process_next_token (msg_t *msg_);
void send_zap_request ();
};
}
#endif
#endif
-64
View File
@@ -1,64 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_I_DECODER_HPP_INCLUDED__
#define __ZMQ_I_DECODER_HPP_INCLUDED__
#include "stdint.hpp"
namespace zmq
{
class msg_t;
// Interface to be implemented by message decoder.
class i_decoder
{
public:
virtual ~i_decoder () {}
virtual void get_buffer (unsigned char **data_, size_t *size_) = 0;
virtual void resize_buffer(size_t) = 0;
// Decodes data pointed to by data_.
// When a message is decoded, 1 is returned.
// When the decoder needs more data, 0 is returned.
// On error, -1 is returned and errno is set accordingly.
virtual int decode (const unsigned char *data_, size_t size_,
size_t &processed) = 0;
virtual msg_t *msg () = 0;
};
}
#endif
-60
View File
@@ -1,60 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_I_ENCODER_HPP_INCLUDED__
#define __ZMQ_I_ENCODER_HPP_INCLUDED__
#include "stdint.hpp"
namespace zmq
{
// Forward declaration
class msg_t;
// Interface to be implemented by message encoder.
struct i_encoder
{
virtual ~i_encoder () {}
// The function returns a batch of binary data. The data
// are filled to a supplied buffer. If no buffer is supplied (data_
// is NULL) encoder will provide buffer of its own.
// Function returns 0 when a new message is required.
virtual size_t encode (unsigned char **data_, size_t size) = 0;
// Load a new message into encoder.
virtual void load_msg (msg_t *msg_) = 0;
};
}
#endif
-68
View File
@@ -1,68 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_I_ENGINE_HPP_INCLUDED__
#define __ZMQ_I_ENGINE_HPP_INCLUDED__
namespace zmq
{
class io_thread_t;
// Abstract interface to be implemented by various engines.
struct i_engine
{
virtual ~i_engine () {}
// Plug the engine to the session.
virtual void plug (zmq::io_thread_t *io_thread_,
class session_base_t *session_) = 0;
// Terminate and deallocate the engine. Note that 'detached'
// events are not fired on termination.
virtual void terminate () = 0;
// This method is called by the session to signalise that more
// messages can be written to the pipe.
virtual void restart_input () = 0;
// This method is called by the session to signalise that there
// are messages to send available.
virtual void restart_output () = 0;
virtual void zap_msg_available () = 0;
virtual const char * get_endpoint() const = 0;
};
}
#endif
-60
View File
@@ -1,60 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_I_MAILBOX_HPP_INCLUDED__
#define __ZMQ_I_MAILBOX_HPP_INCLUDED__
#include "stdint.hpp"
namespace zmq
{
// Interface to be implemented by mailbox.
class i_mailbox
{
public:
virtual ~i_mailbox () {}
virtual void send (const command_t &cmd_) = 0;
virtual int recv (command_t *cmd_, int timeout_) = 0;
#ifdef HAVE_FORK
// close the file descriptors in the signaller. This is used in a forked
// child process to close the file descriptors so that they do not interfere
// with the context in the parent process.
virtual void forked () = 0;
#endif
};
}
#endif
-55
View File
@@ -1,55 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_I_POLL_EVENTS_HPP_INCLUDED__
#define __ZMQ_I_POLL_EVENTS_HPP_INCLUDED__
namespace zmq
{
// Virtual interface to be exposed by object that want to be notified
// about events on file descriptors.
struct i_poll_events
{
virtual ~i_poll_events () {}
// Called by I/O thread when file descriptor is ready for reading.
virtual void in_event () = 0;
// Called by I/O thread when file descriptor is ready for writing.
virtual void out_event () = 0;
// Called when timer expires.
virtual void timer_event (int id_) = 0;
};
}
#endif
-117
View File
@@ -1,117 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "io_object.hpp"
#include "io_thread.hpp"
#include "err.hpp"
zmq::io_object_t::io_object_t (io_thread_t *io_thread_) :
poller (NULL)
{
if (io_thread_)
plug (io_thread_);
}
zmq::io_object_t::~io_object_t ()
{
}
void zmq::io_object_t::plug (io_thread_t *io_thread_)
{
zmq_assert (io_thread_);
zmq_assert (!poller);
// Retrieve the poller from the thread we are running in.
poller = io_thread_->get_poller ();
}
void zmq::io_object_t::unplug ()
{
zmq_assert (poller);
// Forget about old poller in preparation to be migrated
// to a different I/O thread.
poller = NULL;
}
zmq::io_object_t::handle_t zmq::io_object_t::add_fd (fd_t fd_)
{
return poller->add_fd (fd_, this);
}
void zmq::io_object_t::rm_fd (handle_t handle_)
{
poller->rm_fd (handle_);
}
void zmq::io_object_t::set_pollin (handle_t handle_)
{
poller->set_pollin (handle_);
}
void zmq::io_object_t::reset_pollin (handle_t handle_)
{
poller->reset_pollin (handle_);
}
void zmq::io_object_t::set_pollout (handle_t handle_)
{
poller->set_pollout (handle_);
}
void zmq::io_object_t::reset_pollout (handle_t handle_)
{
poller->reset_pollout (handle_);
}
void zmq::io_object_t::add_timer (int timeout_, int id_)
{
poller->add_timer (timeout_, this, id_);
}
void zmq::io_object_t::cancel_timer (int id_)
{
poller->cancel_timer (this, id_);
}
void zmq::io_object_t::in_event ()
{
zmq_assert (false);
}
void zmq::io_object_t::out_event ()
{
zmq_assert (false);
}
void zmq::io_object_t::timer_event (int)
{
zmq_assert (false);
}
-89
View File
@@ -1,89 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_IO_OBJECT_HPP_INCLUDED__
#define __ZMQ_IO_OBJECT_HPP_INCLUDED__
#include <stddef.h>
#include "stdint.hpp"
#include "poller.hpp"
#include "i_poll_events.hpp"
namespace zmq
{
class io_thread_t;
// Simple base class for objects that live in I/O threads.
// It makes communication with the poller object easier and
// makes defining unneeded event handlers unnecessary.
class io_object_t : public i_poll_events
{
public:
io_object_t (zmq::io_thread_t *io_thread_ = NULL);
~io_object_t ();
// When migrating an object from one I/O thread to another, first
// unplug it, then migrate it, then plug it to the new thread.
void plug (zmq::io_thread_t *io_thread_);
void unplug ();
protected:
typedef poller_t::handle_t handle_t;
// Methods to access underlying poller object.
handle_t add_fd (fd_t fd_);
void rm_fd (handle_t handle_);
void set_pollin (handle_t handle_);
void reset_pollin (handle_t handle_);
void set_pollout (handle_t handle_);
void reset_pollout (handle_t handle_);
void add_timer (int timout_, int id_);
void cancel_timer (int id_);
// i_poll_events interface implementation.
void in_event ();
void out_event ();
void timer_event (int id_);
private:
poller_t *poller;
io_object_t (const io_object_t&);
const io_object_t &operator = (const io_object_t&);
};
}
#endif
-114
View File
@@ -1,114 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include <new>
#include "macros.hpp"
#include "io_thread.hpp"
#include "err.hpp"
#include "ctx.hpp"
zmq::io_thread_t::io_thread_t (ctx_t *ctx_, uint32_t tid_) :
object_t (ctx_, tid_)
{
poller = new (std::nothrow) poller_t (*ctx_);
alloc_assert (poller);
mailbox_handle = poller->add_fd (mailbox.get_fd (), this);
poller->set_pollin (mailbox_handle);
}
zmq::io_thread_t::~io_thread_t ()
{
LIBZMQ_DELETE(poller);
}
void zmq::io_thread_t::start ()
{
// Start the underlying I/O thread.
poller->start ();
}
void zmq::io_thread_t::stop ()
{
send_stop ();
}
zmq::mailbox_t *zmq::io_thread_t::get_mailbox ()
{
return &mailbox;
}
int zmq::io_thread_t::get_load ()
{
return poller->get_load ();
}
void zmq::io_thread_t::in_event ()
{
// TODO: Do we want to limit number of commands I/O thread can
// process in a single go?
command_t cmd;
int rc = mailbox.recv (&cmd, 0);
while (rc == 0 || errno == EINTR) {
if (rc == 0)
cmd.destination->process_command (cmd);
rc = mailbox.recv (&cmd, 0);
}
errno_assert (rc != 0 && errno == EAGAIN);
}
void zmq::io_thread_t::out_event ()
{
// We are never polling for POLLOUT here. This function is never called.
zmq_assert (false);
}
void zmq::io_thread_t::timer_event (int)
{
// No timers here. This function is never called.
zmq_assert (false);
}
zmq::poller_t *zmq::io_thread_t::get_poller ()
{
zmq_assert (poller);
return poller;
}
void zmq::io_thread_t::process_stop ()
{
poller->rm_fd (mailbox_handle);
poller->stop ();
}
-99
View File
@@ -1,99 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_IO_THREAD_HPP_INCLUDED__
#define __ZMQ_IO_THREAD_HPP_INCLUDED__
#include <vector>
#include "stdint.hpp"
#include "object.hpp"
#include "poller.hpp"
#include "i_poll_events.hpp"
#include "mailbox.hpp"
namespace zmq
{
class ctx_t;
// Generic part of the I/O thread. Polling-mechanism-specific features
// are implemented in separate "polling objects".
class io_thread_t : public object_t, public i_poll_events
{
public:
io_thread_t (zmq::ctx_t *ctx_, uint32_t tid_);
// Clean-up. If the thread was started, it's necessary to call 'stop'
// before invoking destructor. Otherwise the destructor would hang up.
~io_thread_t ();
// Launch the physical thread.
void start ();
// Ask underlying thread to stop.
void stop ();
// Returns mailbox associated with this I/O thread.
mailbox_t *get_mailbox ();
// i_poll_events implementation.
void in_event ();
void out_event ();
void timer_event (int id_);
// Used by io_objects to retrieve the associated poller object.
poller_t *get_poller ();
// Command handlers.
void process_stop ();
// Returns load experienced by the I/O thread.
int get_load ();
private:
// I/O thread accesses incoming commands via this mailbox.
mailbox_t mailbox;
// Handle associated with mailbox' file descriptor.
poller_t::handle_t mailbox_handle;
// I/O multiplexing is performed using a poller object.
poller_t *poller;
io_thread_t (const io_thread_t&);
const io_thread_t &operator = (const io_thread_t&);
};
}
#endif
-235
View File
@@ -1,235 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "ip.hpp"
#include "err.hpp"
#include "macros.hpp"
#if !defined ZMQ_HAVE_WINDOWS
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#endif
#if defined ZMQ_HAVE_OPENVMS
#include <ioctl.h>
#endif
zmq::fd_t zmq::open_socket (int domain_, int type_, int protocol_)
{
int rc;
// Setting this option result in sane behaviour when exec() functions
// are used. Old sockets are closed and don't block TCP ports etc.
#if defined ZMQ_HAVE_SOCK_CLOEXEC
type_ |= SOCK_CLOEXEC;
#endif
fd_t s = socket (domain_, type_, protocol_);
#ifdef ZMQ_HAVE_WINDOWS
if (s == INVALID_SOCKET)
return INVALID_SOCKET;
#else
if (s == -1)
return -1;
#endif
// If there's no SOCK_CLOEXEC, let's try the second best option. Note that
// race condition can cause socket not to be closed (if fork happens
// between socket creation and this point).
#if !defined ZMQ_HAVE_SOCK_CLOEXEC && defined FD_CLOEXEC
rc = fcntl (s, F_SETFD, FD_CLOEXEC);
errno_assert (rc != -1);
#endif
// On Windows, preventing sockets to be inherited by child processes.
#if defined ZMQ_HAVE_WINDOWS && defined HANDLE_FLAG_INHERIT
BOOL brc = SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
win_assert (brc);
#endif
// Socket is not yet connected so EINVAL is not a valid networking error
rc = zmq::set_nosigpipe (s);
errno_assert (rc == 0);
return s;
}
void zmq::unblock_socket (fd_t s_)
{
#if defined ZMQ_HAVE_WINDOWS
u_long nonblock = 1;
int rc = ioctlsocket (s_, FIONBIO, &nonblock);
wsa_assert (rc != SOCKET_ERROR);
#elif defined ZMQ_HAVE_OPENVMS
int nonblock = 1;
int rc = ioctl (s_, FIONBIO, &nonblock);
errno_assert (rc != -1);
#else
int flags = fcntl (s_, F_GETFL, 0);
if (flags == -1)
flags = 0;
int rc = fcntl (s_, F_SETFL, flags | O_NONBLOCK);
errno_assert (rc != -1);
#endif
}
void zmq::enable_ipv4_mapping (fd_t s_)
{
(void) s_;
#if defined IPV6_V6ONLY && !defined ZMQ_HAVE_OPENBSD
#ifdef ZMQ_HAVE_WINDOWS
DWORD flag = 0;
#else
int flag = 0;
#endif
int rc = setsockopt (s_, IPPROTO_IPV6, IPV6_V6ONLY, (const char*) &flag,
sizeof (flag));
#ifdef ZMQ_HAVE_WINDOWS
wsa_assert (rc != SOCKET_ERROR);
#else
errno_assert (rc == 0);
#endif
#endif
}
int zmq::get_peer_ip_address (fd_t sockfd_, std::string &ip_addr_)
{
int rc;
struct sockaddr_storage ss;
#if defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_WINDOWS
int addrlen = static_cast <int> (sizeof ss);
#else
socklen_t addrlen = sizeof ss;
#endif
rc = getpeername (sockfd_, (struct sockaddr*) &ss, &addrlen);
#ifdef ZMQ_HAVE_WINDOWS
if (rc == SOCKET_ERROR) {
const int last_error = WSAGetLastError();
wsa_assert (last_error != WSANOTINITIALISED &&
last_error != WSAEFAULT &&
last_error != WSAEINPROGRESS &&
last_error != WSAENOTSOCK);
return 0;
}
#else
if (rc == -1) {
errno_assert (errno != EBADF &&
errno != EFAULT &&
errno != ENOTSOCK);
return 0;
}
#endif
char host [NI_MAXHOST];
rc = getnameinfo ((struct sockaddr*) &ss, addrlen, host, sizeof host,
NULL, 0, NI_NUMERICHOST);
if (rc != 0)
return 0;
ip_addr_ = host;
union {
struct sockaddr sa;
struct sockaddr_storage sa_stor;
} u;
u.sa_stor = ss;
return (int) u.sa.sa_family;
}
void zmq::set_ip_type_of_service (fd_t s_, int iptos)
{
int rc = setsockopt(s_, IPPROTO_IP, IP_TOS, reinterpret_cast<const char*>(&iptos), sizeof(iptos));
#ifdef ZMQ_HAVE_WINDOWS
wsa_assert (rc != SOCKET_ERROR);
#else
errno_assert (rc == 0);
#endif
// Windows and Hurd do not support IPV6_TCLASS
#if !defined (ZMQ_HAVE_WINDOWS) && defined (IPV6_TCLASS)
rc = setsockopt(
s_,
IPPROTO_IPV6,
IPV6_TCLASS,
reinterpret_cast<const char*>(&iptos),
sizeof(iptos));
// If IPv6 is not enabled ENOPROTOOPT will be returned on Linux and
// EINVAL on OSX
if (rc == -1) {
errno_assert (errno == ENOPROTOOPT ||
errno == EINVAL);
}
#endif
}
int zmq::set_nosigpipe (fd_t s_)
{
#ifdef SO_NOSIGPIPE
// Make sure that SIGPIPE signal is not generated when writing to a
// connection that was already closed by the peer.
// As per POSIX spec, EINVAL will be returned if the socket was valid but
// the connection has been reset by the peer. Return an error so that the
// socket can be closed and the connection retried if necessary.
int set = 1;
int rc = setsockopt (s_, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof (int));
if (rc != 0 && errno == EINVAL)
return -1;
errno_assert (rc == 0);
#else
LIBZMQ_UNUSED (s_);
#endif
return 0;
}
void zmq::bind_to_device (fd_t s_, std::string &bound_device_)
{
#ifdef ZMQ_HAVE_SO_BINDTODEVICE
int rc = setsockopt(s_, SOL_SOCKET, SO_BINDTODEVICE, bound_device_.c_str (), bound_device_.length ());
#ifdef ZMQ_HAVE_WINDOWS
wsa_assert (rc != SOCKET_ERROR);
#else
errno_assert (rc == 0);
#endif
#else
LIBZMQ_UNUSED (s_);
LIBZMQ_UNUSED (bound_device_);
#endif
}
-64
View File
@@ -1,64 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_IP_HPP_INCLUDED__
#define __ZMQ_IP_HPP_INCLUDED__
#include <string>
#include "fd.hpp"
namespace zmq
{
// Same as socket(2), but allows for transparent tweaking the options.
fd_t open_socket (int domain_, int type_, int protocol_);
// Sets the socket into non-blocking mode.
void unblock_socket (fd_t s_);
// Enable IPv4-mapping of addresses in case it is disabled by default.
void enable_ipv4_mapping (fd_t s_);
// Returns string representation of peer's address.
// Socket sockfd_ must be connected. Returns true iff successful.
int get_peer_ip_address (fd_t sockfd_, std::string &ip_addr_);
// Sets the IP Type-Of-Service for the underlying socket
void set_ip_type_of_service (fd_t s_, int iptos);
// Sets the SO_NOSIGPIPE option for the underlying socket.
// Return 0 on success, -1 if the connection has been closed by the peer
int set_nosigpipe (fd_t s_);
// Binds the underlying socket to the given device, eg. VRF or interface
void bind_to_device (fd_t s_, std::string &bound_device_);
}
#endif
-106
View File
@@ -1,106 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "ipc_address.hpp"
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
#include "err.hpp"
#include <string>
#include <sstream>
zmq::ipc_address_t::ipc_address_t ()
{
memset (&address, 0, sizeof address);
}
zmq::ipc_address_t::ipc_address_t (const sockaddr *sa, socklen_t sa_len)
{
zmq_assert (sa && sa_len > 0);
memset (&address, 0, sizeof address);
if (sa->sa_family == AF_UNIX)
memcpy(&address, sa, sa_len);
}
zmq::ipc_address_t::~ipc_address_t ()
{
}
int zmq::ipc_address_t::resolve (const char *path_)
{
if (strlen (path_) >= sizeof address.sun_path) {
errno = ENAMETOOLONG;
return -1;
}
if (path_ [0] == '@' && !path_ [1]) {
errno = EINVAL;
return -1;
}
address.sun_family = AF_UNIX;
strcpy (address.sun_path, path_);
/* Abstract sockets start with '\0' */
if (path_ [0] == '@')
*address.sun_path = '\0';
return 0;
}
int zmq::ipc_address_t::to_string (std::string &addr_)
{
if (address.sun_family != AF_UNIX) {
addr_.clear ();
return -1;
}
std::stringstream s;
s << "ipc://";
if (!address.sun_path [0] && address.sun_path [1])
s << "@" << address.sun_path + 1;
else
s << address.sun_path;
addr_ = s.str ();
return 0;
}
const sockaddr *zmq::ipc_address_t::addr () const
{
return (sockaddr*) &address;
}
socklen_t zmq::ipc_address_t::addrlen () const
{
if (!address.sun_path [0] && address.sun_path [1])
return (socklen_t) strlen (address.sun_path + 1) + sizeof (sa_family_t) + 1;
return (socklen_t) sizeof address;
}
#endif
-74
View File
@@ -1,74 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_IPC_ADDRESS_HPP_INCLUDED__
#define __ZMQ_IPC_ADDRESS_HPP_INCLUDED__
#include <string>
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
#include <sys/socket.h>
#include <sys/un.h>
namespace zmq
{
class ipc_address_t
{
public:
ipc_address_t ();
ipc_address_t (const sockaddr *sa, socklen_t sa_len);
~ipc_address_t ();
// This function sets up the address for UNIX domain transport.
int resolve (const char *path_);
// The opposite to resolve()
int to_string (std::string &addr_);
const sockaddr *addr () const;
socklen_t addrlen () const;
private:
struct sockaddr_un address;
ipc_address_t (const ipc_address_t&);
const ipc_address_t &operator = (const ipc_address_t&);
};
}
#endif
#endif
-278
View File
@@ -1,278 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "ipc_connecter.hpp"
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
#include <new>
#include <string>
#include "stream_engine.hpp"
#include "io_thread.hpp"
#include "random.hpp"
#include "err.hpp"
#include "ip.hpp"
#include "address.hpp"
#include "ipc_address.hpp"
#include "session_base.hpp"
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
zmq::ipc_connecter_t::ipc_connecter_t (class io_thread_t *io_thread_,
class session_base_t *session_, const options_t &options_,
const address_t *addr_, bool delayed_start_) :
own_t (io_thread_, options_),
io_object_t (io_thread_),
addr (addr_),
s (retired_fd),
handle_valid (false),
delayed_start (delayed_start_),
timer_started (false),
session (session_),
current_reconnect_ivl(options.reconnect_ivl)
{
zmq_assert (addr);
zmq_assert (addr->protocol == "ipc");
addr->to_string (endpoint);
socket = session-> get_socket();
}
zmq::ipc_connecter_t::~ipc_connecter_t ()
{
zmq_assert (!timer_started);
zmq_assert (!handle_valid);
zmq_assert (s == retired_fd);
}
void zmq::ipc_connecter_t::process_plug ()
{
if (delayed_start)
add_reconnect_timer ();
else
start_connecting ();
}
void zmq::ipc_connecter_t::process_term (int linger_)
{
if (timer_started) {
cancel_timer (reconnect_timer_id);
timer_started = false;
}
if (handle_valid) {
rm_fd (handle);
handle_valid = false;
}
if (s != retired_fd)
close ();
own_t::process_term (linger_);
}
void zmq::ipc_connecter_t::in_event ()
{
// We are not polling for incoming data, so we are actually called
// because of error here. However, we can get error on out event as well
// on some platforms, so we'll simply handle both events in the same way.
out_event ();
}
void zmq::ipc_connecter_t::out_event ()
{
fd_t fd = connect ();
rm_fd (handle);
handle_valid = false;
// Handle the error condition by attempt to reconnect.
if (fd == retired_fd) {
close ();
add_reconnect_timer();
return;
}
// Create the engine object for this connection.
stream_engine_t *engine = new (std::nothrow)
stream_engine_t (fd, options, endpoint);
alloc_assert (engine);
// Attach the engine to the corresponding session object.
send_attach (session, engine);
// Shut the connecter down.
terminate ();
socket->event_connected (endpoint, fd);
}
void zmq::ipc_connecter_t::timer_event (int id_)
{
zmq_assert (id_ == reconnect_timer_id);
timer_started = false;
start_connecting ();
}
void zmq::ipc_connecter_t::start_connecting ()
{
// Open the connecting socket.
int rc = open ();
// Connect may succeed in synchronous manner.
if (rc == 0) {
handle = add_fd (s);
handle_valid = true;
out_event ();
}
// Connection establishment may be delayed. Poll for its completion.
else
if (rc == -1 && errno == EINPROGRESS) {
handle = add_fd (s);
handle_valid = true;
set_pollout (handle);
socket->event_connect_delayed (endpoint, zmq_errno());
}
// Handle any other error condition by eventual reconnect.
else {
if (s != retired_fd)
close ();
add_reconnect_timer ();
}
}
void zmq::ipc_connecter_t::add_reconnect_timer()
{
int rc_ivl = get_new_reconnect_ivl();
add_timer (rc_ivl, reconnect_timer_id);
socket->event_connect_retried (endpoint, rc_ivl);
timer_started = true;
}
int zmq::ipc_connecter_t::get_new_reconnect_ivl ()
{
// The new interval is the current interval + random value.
int this_interval = current_reconnect_ivl +
(generate_random () % options.reconnect_ivl);
// Only change the current reconnect interval if the maximum reconnect
// interval was set and if it's larger than the reconnect interval.
if (options.reconnect_ivl_max > 0 &&
options.reconnect_ivl_max > options.reconnect_ivl) {
// Calculate the next interval
current_reconnect_ivl = current_reconnect_ivl * 2;
if(current_reconnect_ivl >= options.reconnect_ivl_max) {
current_reconnect_ivl = options.reconnect_ivl_max;
}
}
return this_interval;
}
int zmq::ipc_connecter_t::open ()
{
zmq_assert (s == retired_fd);
// Create the socket.
s = open_socket (AF_UNIX, SOCK_STREAM, 0);
if (s == -1)
return -1;
// Set the non-blocking flag.
unblock_socket (s);
// Connect to the remote peer.
int rc = ::connect (
s, addr->resolved.ipc_addr->addr (),
addr->resolved.ipc_addr->addrlen ());
// Connect was successful immediately.
if (rc == 0)
return 0;
// Translate other error codes indicating asynchronous connect has been
// launched to a uniform EINPROGRESS.
if (rc == -1 && errno == EINTR) {
errno = EINPROGRESS;
return -1;
}
// Forward the error.
return -1;
}
int zmq::ipc_connecter_t::close ()
{
zmq_assert (s != retired_fd);
int rc = ::close (s);
errno_assert (rc == 0);
socket->event_closed (endpoint, s);
s = retired_fd;
return 0;
}
zmq::fd_t zmq::ipc_connecter_t::connect ()
{
// Following code should handle both Berkeley-derived socket
// implementations and Solaris.
int err = 0;
#if defined ZMQ_HAVE_HPUX
int len = sizeof (err);
#else
socklen_t len = sizeof (err);
#endif
int rc = getsockopt (s, SOL_SOCKET, SO_ERROR, (char*) &err, &len);
if (rc == -1) {
if (errno == ENOPROTOOPT)
errno = 0;
err = errno;
}
if (err != 0) {
// Assert if the error was caused by 0MQ bug.
// Networking problems are OK. No need to assert.
errno = err;
errno_assert (errno == ECONNREFUSED || errno == ECONNRESET ||
errno == ETIMEDOUT || errno == EHOSTUNREACH ||
errno == ENETUNREACH || errno == ENETDOWN);
return retired_fd;
}
fd_t result = s;
s = retired_fd;
return result;
}
#endif
-135
View File
@@ -1,135 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __IPC_CONNECTER_HPP_INCLUDED__
#define __IPC_CONNECTER_HPP_INCLUDED__
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
#include "fd.hpp"
#include "own.hpp"
#include "stdint.hpp"
#include "io_object.hpp"
namespace zmq
{
class io_thread_t;
class session_base_t;
struct address_t;
class ipc_connecter_t : public own_t, public io_object_t
{
public:
// If 'delayed_start' is true connecter first waits for a while,
// then starts connection process.
ipc_connecter_t (zmq::io_thread_t *io_thread_,
zmq::session_base_t *session_, const options_t &options_,
const address_t *addr_, bool delayed_start_);
~ipc_connecter_t ();
private:
// ID of the timer used to delay the reconnection.
enum {reconnect_timer_id = 1};
// Handlers for incoming commands.
void process_plug ();
void process_term (int linger_);
// Handlers for I/O events.
void in_event ();
void out_event ();
void timer_event (int id_);
// Internal function to start the actual connection establishment.
void start_connecting ();
// Internal function to add a reconnect timer
void add_reconnect_timer();
// Internal function to return a reconnect backoff delay.
// Will modify the current_reconnect_ivl used for next call
// Returns the currently used interval
int get_new_reconnect_ivl ();
// Open IPC connecting socket. Returns -1 in case of error,
// 0 if connect was successful immediately. Returns -1 with
// EAGAIN errno if async connect was launched.
int open ();
// Close the connecting socket.
int close ();
// Get the file descriptor of newly created connection. Returns
// retired_fd if the connection was unsuccessful.
fd_t connect ();
// Address to connect to. Owned by session_base_t.
const address_t *addr;
// Underlying socket.
fd_t s;
// Handle corresponding to the listening socket.
handle_t handle;
// If true file descriptor is registered with the poller and 'handle'
// contains valid value.
bool handle_valid;
// If true, connecter is waiting a while before trying to connect.
const bool delayed_start;
// True iff a timer has been started.
bool timer_started;
// Reference to the session we belong to.
zmq::session_base_t *session;
// Current reconnect ivl, updated for backoff strategy
int current_reconnect_ivl;
// String representation of endpoint to connect to
std::string endpoint;
// Socket
zmq::socket_base_t *socket;
ipc_connecter_t (const ipc_connecter_t&);
const ipc_connecter_t &operator = (const ipc_connecter_t&);
};
}
#endif
#endif
-427
View File
@@ -1,427 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "ipc_listener.hpp"
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
#include <new>
#include <string.h>
#include "stream_engine.hpp"
#include "ipc_address.hpp"
#include "io_thread.hpp"
#include "session_base.hpp"
#include "config.hpp"
#include "err.hpp"
#include "ip.hpp"
#include "socket_base.hpp"
#include <unistd.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <sys/un.h>
#include <sys/stat.h>
#ifdef ZMQ_HAVE_LOCAL_PEERCRED
# include <sys/types.h>
# include <sys/ucred.h>
#endif
#ifdef ZMQ_HAVE_SO_PEERCRED
# include <sys/types.h>
# include <pwd.h>
# include <grp.h>
# if defined ZMQ_HAVE_OPENBSD
# define ucred sockpeercred
# endif
#endif
const char *zmq::ipc_listener_t::tmp_env_vars[] = {
"TMPDIR",
"TEMPDIR",
"TMP",
0 // Sentinel
};
int zmq::ipc_listener_t::create_wildcard_address(std::string& path_,
std::string& file_)
{
std::string tmp_path;
// If TMPDIR, TEMPDIR, or TMP are available and are directories, create
// the socket directory there.
const char **tmp_env = tmp_env_vars;
while ( tmp_path.empty() && *tmp_env != 0 ) {
char *tmpdir = getenv(*tmp_env);
struct stat statbuf;
// Confirm it is actually a directory before trying to use
if ( tmpdir != 0 && ::stat(tmpdir, &statbuf) == 0 && S_ISDIR(statbuf.st_mode) ) {
tmp_path.assign(tmpdir);
if ( *(tmp_path.rbegin()) != '/' ) {
tmp_path.push_back('/');
}
}
// Try the next environment variable
++tmp_env;
}
// Append a directory name
tmp_path.append("tmpXXXXXX");
// We need room for tmp_path + trailing NUL
std::vector<char> buffer(tmp_path.length()+1);
strcpy (&buffer[0], tmp_path.c_str ());
#ifdef HAVE_MKDTEMP
// Create the directory. POSIX requires that mkdtemp() creates the
// directory with 0700 permissions, meaning the only possible race
// with socket creation could be the same user. However, since
// each socket is created in a directory created by mkdtemp(), and
// mkdtemp() guarantees a unique directory name, there will be no
// collision.
if (mkdtemp (&buffer[0]) == 0) {
return -1;
}
path_.assign (&buffer[0]);
file_.assign (path_ + "/socket");
#else
// Silence -Wunused-parameter. #pragma and __attribute__((unused)) are not
// very portable unfortunately...
(void) path_;
int fd = mkstemp (&buffer[0]);
if (fd == -1)
return -1;
::close (fd);
file_.assign (&buffer[0]);
#endif
return 0;
}
zmq::ipc_listener_t::ipc_listener_t (io_thread_t *io_thread_,
socket_base_t *socket_, const options_t &options_) :
own_t (io_thread_, options_),
io_object_t (io_thread_),
has_file (false),
s (retired_fd),
socket (socket_)
{
}
zmq::ipc_listener_t::~ipc_listener_t ()
{
zmq_assert (s == retired_fd);
}
void zmq::ipc_listener_t::process_plug ()
{
// Start polling for incoming connections.
handle = add_fd (s);
set_pollin (handle);
}
void zmq::ipc_listener_t::process_term (int linger_)
{
rm_fd (handle);
close ();
own_t::process_term (linger_);
}
void zmq::ipc_listener_t::in_event ()
{
fd_t fd = accept ();
// If connection was reset by the peer in the meantime, just ignore it.
// TODO: Handle specific errors like ENFILE/EMFILE etc.
if (fd == retired_fd) {
socket->event_accept_failed (endpoint, zmq_errno());
return;
}
// Create the engine object for this connection.
stream_engine_t *engine = new (std::nothrow)
stream_engine_t (fd, options, endpoint);
alloc_assert (engine);
// Choose I/O thread to run connecter in. Given that we are already
// running in an I/O thread, there must be at least one available.
io_thread_t *io_thread = choose_io_thread (options.affinity);
zmq_assert (io_thread);
// Create and launch a session object.
session_base_t *session = session_base_t::create (io_thread, false, socket,
options, NULL);
errno_assert (session);
session->inc_seqnum ();
launch_child (session);
send_attach (session, engine, false);
socket->event_accepted (endpoint, fd);
}
int zmq::ipc_listener_t::get_address (std::string &addr_)
{
struct sockaddr_storage ss;
#ifdef ZMQ_HAVE_HPUX
int sl = sizeof (ss);
#else
socklen_t sl = sizeof (ss);
#endif
int rc = getsockname (s, (sockaddr *) &ss, &sl);
if (rc != 0) {
addr_.clear ();
return rc;
}
ipc_address_t addr ((struct sockaddr *) &ss, sl);
return addr.to_string (addr_);
}
int zmq::ipc_listener_t::set_address (const char *addr_)
{
// Create addr on stack for auto-cleanup
std::string addr (addr_);
// Allow wildcard file
if (options.use_fd == -1 && addr [0] == '*') {
if ( create_wildcard_address(tmp_socket_dirname, addr) < 0 ) {
return -1;
}
}
// Get rid of the file associated with the UNIX domain socket that
// may have been left behind by the previous run of the application.
// MUST NOT unlink if the FD is managed by the user, or it will stop
// working after the first client connects. The user will take care of
// cleaning up the file after the service is stopped.
if (options.use_fd == -1) {
::unlink (addr.c_str());
}
filename.clear ();
// Initialise the address structure.
ipc_address_t address;
int rc = address.resolve (addr.c_str());
if (rc != 0) {
if ( !tmp_socket_dirname.empty() ) {
// We need to preserve errno to return to the user
int errno_ = errno;
::rmdir(tmp_socket_dirname.c_str ());
tmp_socket_dirname.clear();
errno = errno_;
}
return -1;
}
address.to_string (endpoint);
if (options.use_fd != -1) {
s = options.use_fd;
} else {
// Create a listening socket.
s = open_socket (AF_UNIX, SOCK_STREAM, 0);
if (s == -1) {
if ( !tmp_socket_dirname.empty() ) {
// We need to preserve errno to return to the user
int errno_ = errno;
::rmdir(tmp_socket_dirname.c_str ());
tmp_socket_dirname.clear();
errno = errno_;
}
return -1;
}
// Bind the socket to the file path.
rc = bind (s, address.addr (), address.addrlen ());
if (rc != 0)
goto error;
// Listen for incoming connections.
rc = listen (s, options.backlog);
if (rc != 0)
goto error;
}
filename.assign (addr.c_str());
has_file = true;
socket->event_listening (endpoint, s);
return 0;
error:
int err = errno;
close ();
errno = err;
return -1;
}
int zmq::ipc_listener_t::close ()
{
zmq_assert (s != retired_fd);
int fd_for_event = s;
int rc = ::close (s);
errno_assert (rc == 0);
s = retired_fd;
if (has_file && options.use_fd == -1) {
rc = 0;
if ( rc == 0 && !tmp_socket_dirname.empty() ) {
rc = ::rmdir(tmp_socket_dirname.c_str ());
tmp_socket_dirname.clear();
}
if (rc != 0) {
socket->event_close_failed (endpoint, zmq_errno());
return -1;
}
}
socket->event_closed (endpoint, fd_for_event);
return 0;
}
#if defined ZMQ_HAVE_SO_PEERCRED
bool zmq::ipc_listener_t::filter (fd_t sock)
{
if (options.ipc_uid_accept_filters.empty () &&
options.ipc_pid_accept_filters.empty () &&
options.ipc_gid_accept_filters.empty ())
return true;
struct ucred cred;
socklen_t size = sizeof (cred);
if (getsockopt (sock, SOL_SOCKET, SO_PEERCRED, &cred, &size))
return false;
if (options.ipc_uid_accept_filters.find (cred.uid) != options.ipc_uid_accept_filters.end () ||
options.ipc_gid_accept_filters.find (cred.gid) != options.ipc_gid_accept_filters.end () ||
options.ipc_pid_accept_filters.find (cred.pid) != options.ipc_pid_accept_filters.end ())
return true;
struct passwd *pw;
struct group *gr;
if (!(pw = getpwuid (cred.uid)))
return false;
for (options_t::ipc_gid_accept_filters_t::const_iterator it = options.ipc_gid_accept_filters.begin ();
it != options.ipc_gid_accept_filters.end (); it++) {
if (!(gr = getgrgid (*it)))
continue;
for (char **mem = gr->gr_mem; *mem; mem++) {
if (!strcmp (*mem, pw->pw_name))
return true;
}
}
return false;
}
#elif defined ZMQ_HAVE_LOCAL_PEERCRED
bool zmq::ipc_listener_t::filter (fd_t sock)
{
if (options.ipc_uid_accept_filters.empty () &&
options.ipc_gid_accept_filters.empty ())
return true;
struct xucred cred;
socklen_t size = sizeof (cred);
if (getsockopt (sock, 0, LOCAL_PEERCRED, &cred, &size))
return false;
if (cred.cr_version != XUCRED_VERSION)
return false;
if (options.ipc_uid_accept_filters.find (cred.cr_uid) != options.ipc_uid_accept_filters.end ())
return true;
for (int i = 0; i < cred.cr_ngroups; i++) {
if (options.ipc_gid_accept_filters.find (cred.cr_groups[i]) != options.ipc_gid_accept_filters.end ())
return true;
}
return false;
}
#endif
zmq::fd_t zmq::ipc_listener_t::accept ()
{
// Accept one connection and deal with different failure modes.
// The situation where connection cannot be accepted due to insufficient
// resources is considered valid and treated by ignoring the connection.
zmq_assert (s != retired_fd);
#if defined ZMQ_HAVE_SOCK_CLOEXEC && defined HAVE_ACCEPT4
fd_t sock = ::accept4 (s, NULL, NULL, SOCK_CLOEXEC);
#else
fd_t sock = ::accept (s, NULL, NULL);
#endif
if (sock == -1) {
errno_assert (errno == EAGAIN || errno == EWOULDBLOCK ||
errno == EINTR || errno == ECONNABORTED || errno == EPROTO ||
errno == ENFILE);
return retired_fd;
}
#if (!defined ZMQ_HAVE_SOCK_CLOEXEC || !defined HAVE_ACCEPT4) && defined FD_CLOEXEC
// Race condition can cause socket not to be closed (if fork happens
// between accept and this point).
int rc = fcntl (sock, F_SETFD, FD_CLOEXEC);
errno_assert (rc != -1);
#endif
// IPC accept() filters
#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
if (!filter (sock)) {
int rc = ::close (sock);
errno_assert (rc == 0);
return retired_fd;
}
#endif
if (zmq::set_nosigpipe (sock)) {
#ifdef ZMQ_HAVE_WINDOWS
int rc = closesocket (sock);
wsa_assert (rc != SOCKET_ERROR);
#else
int rc = ::close (sock);
errno_assert (rc == 0);
#endif
return retired_fd;
}
return sock;
}
#endif
-123
View File
@@ -1,123 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_IPC_LISTENER_HPP_INCLUDED__
#define __ZMQ_IPC_LISTENER_HPP_INCLUDED__
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
#include <string>
#include "fd.hpp"
#include "own.hpp"
#include "stdint.hpp"
#include "io_object.hpp"
namespace zmq
{
class io_thread_t;
class socket_base_t;
class ipc_listener_t : public own_t, public io_object_t
{
public:
ipc_listener_t (zmq::io_thread_t *io_thread_,
zmq::socket_base_t *socket_, const options_t &options_);
~ipc_listener_t ();
// Set address to listen on.
int set_address (const char *addr_);
// Get the bound address for use with wildcards
int get_address (std::string &addr_);
private:
// Handlers for incoming commands.
void process_plug ();
void process_term (int linger_);
// Handlers for I/O events.
void in_event ();
// Close the listening socket.
int close ();
// Create wildcard path address
static int create_wildcard_address(std::string& path_,
std::string& file_);
// Filter new connections if the OS provides a mechanism to get
// the credentials of the peer process. Called from accept().
# if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
bool filter (fd_t sock);
# endif
// Accept the new connection. Returns the file descriptor of the
// newly created connection. The function may return retired_fd
// if the connection was dropped while waiting in the listen backlog.
fd_t accept ();
// True, if the underlying file for UNIX domain socket exists.
bool has_file;
// Name of the temporary directory (if any) that has the
// the UNIX domain socket
std::string tmp_socket_dirname;
// Name of the file associated with the UNIX domain address.
std::string filename;
// Underlying socket.
fd_t s;
// Handle corresponding to the listening socket.
handle_t handle;
// Socket the listener belongs to.
zmq::socket_base_t *socket;
// String representation of endpoint to bind to
std::string endpoint;
// Acceptable temporary directory environment variables
static const char *tmp_env_vars[];
ipc_listener_t (const ipc_listener_t&);
const ipc_listener_t &operator = (const ipc_listener_t&);
};
}
#endif
#endif
-227
View File
@@ -1,227 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "kqueue.hpp"
#if defined ZMQ_USE_KQUEUE
#include <sys/time.h>
#include <sys/types.h>
#include <sys/event.h>
#include <stdlib.h>
#include <unistd.h>
#include <algorithm>
#include <new>
#include "macros.hpp"
#include "kqueue.hpp"
#include "err.hpp"
#include "config.hpp"
#include "i_poll_events.hpp"
#include "likely.hpp"
// NetBSD defines (struct kevent).udata as intptr_t, everyone else
// as void *.
#if defined ZMQ_HAVE_NETBSD
#define kevent_udata_t intptr_t
#else
#define kevent_udata_t void *
#endif
zmq::kqueue_t::kqueue_t (const zmq::ctx_t &ctx_) :
ctx(ctx_),
stopping (false)
{
// Create event queue
kqueue_fd = kqueue ();
errno_assert (kqueue_fd != -1);
#ifdef HAVE_FORK
pid = getpid();
#endif
}
zmq::kqueue_t::~kqueue_t ()
{
worker.stop ();
close (kqueue_fd);
}
void zmq::kqueue_t::kevent_add (fd_t fd_, short filter_, void *udata_)
{
struct kevent ev;
EV_SET (&ev, fd_, filter_, EV_ADD, 0, 0, (kevent_udata_t)udata_);
int rc = kevent (kqueue_fd, &ev, 1, NULL, 0, NULL);
errno_assert (rc != -1);
}
void zmq::kqueue_t::kevent_delete (fd_t fd_, short filter_)
{
struct kevent ev;
EV_SET (&ev, fd_, filter_, EV_DELETE, 0, 0, 0);
int rc = kevent (kqueue_fd, &ev, 1, NULL, 0, NULL);
errno_assert (rc != -1);
}
zmq::kqueue_t::handle_t zmq::kqueue_t::add_fd (fd_t fd_,
i_poll_events *reactor_)
{
poll_entry_t *pe = new (std::nothrow) poll_entry_t;
alloc_assert (pe);
pe->fd = fd_;
pe->flag_pollin = 0;
pe->flag_pollout = 0;
pe->reactor = reactor_;
adjust_load (1);
return pe;
}
void zmq::kqueue_t::rm_fd (handle_t handle_)
{
poll_entry_t *pe = (poll_entry_t*) handle_;
if (pe->flag_pollin)
kevent_delete (pe->fd, EVFILT_READ);
if (pe->flag_pollout)
kevent_delete (pe->fd, EVFILT_WRITE);
pe->fd = retired_fd;
retired.push_back (pe);
adjust_load (-1);
}
void zmq::kqueue_t::set_pollin (handle_t handle_)
{
poll_entry_t *pe = (poll_entry_t*) handle_;
if (likely (!pe->flag_pollin)) {
pe->flag_pollin = true;
kevent_add (pe->fd, EVFILT_READ, pe);
}
}
void zmq::kqueue_t::reset_pollin (handle_t handle_)
{
poll_entry_t *pe = (poll_entry_t*) handle_;
if (likely (pe->flag_pollin)) {
pe->flag_pollin = false;
kevent_delete (pe->fd, EVFILT_READ);
}
}
void zmq::kqueue_t::set_pollout (handle_t handle_)
{
poll_entry_t *pe = (poll_entry_t*) handle_;
if (likely (!pe->flag_pollout)) {
pe->flag_pollout = true;
kevent_add (pe->fd, EVFILT_WRITE, pe);
}
}
void zmq::kqueue_t::reset_pollout (handle_t handle_)
{
poll_entry_t *pe = (poll_entry_t*) handle_;
if (likely (pe->flag_pollout)) {
pe->flag_pollout = false;
kevent_delete (pe->fd, EVFILT_WRITE);
}
}
void zmq::kqueue_t::start ()
{
ctx.start_thread (worker, worker_routine, this);
}
void zmq::kqueue_t::stop ()
{
stopping = true;
}
int zmq::kqueue_t::max_fds ()
{
return -1;
}
void zmq::kqueue_t::loop ()
{
while (!stopping) {
// Execute any due timers.
int timeout = (int) execute_timers ();
// Wait for events.
struct kevent ev_buf [max_io_events];
timespec ts = {timeout / 1000, (timeout % 1000) * 1000000};
int n = kevent (kqueue_fd, NULL, 0, &ev_buf [0], max_io_events,
timeout ? &ts: NULL);
#ifdef HAVE_FORK
if (unlikely(pid != getpid())) {
//printf("zmq::kqueue_t::loop aborting on forked child %d\n", (int)getpid());
// simply exit the loop in a forked process.
return;
}
#endif
if (n == -1) {
errno_assert (errno == EINTR);
continue;
}
for (int i = 0; i < n; i ++) {
poll_entry_t *pe = (poll_entry_t*) ev_buf [i].udata;
if (pe->fd == retired_fd)
continue;
if (ev_buf [i].flags & EV_EOF)
pe->reactor->in_event ();
if (pe->fd == retired_fd)
continue;
if (ev_buf [i].filter == EVFILT_WRITE)
pe->reactor->out_event ();
if (pe->fd == retired_fd)
continue;
if (ev_buf [i].filter == EVFILT_READ)
pe->reactor->in_event ();
}
// Destroy retired event sources.
for (retired_t::iterator it = retired.begin (); it != retired.end (); ++it) {
LIBZMQ_DELETE(*it);
}
retired.clear ();
}
}
void zmq::kqueue_t::worker_routine (void *arg_)
{
((kqueue_t*) arg_)->loop ();
}
#endif
-127
View File
@@ -1,127 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_KQUEUE_HPP_INCLUDED__
#define __ZMQ_KQUEUE_HPP_INCLUDED__
// poller.hpp decides which polling mechanism to use.
#include "poller.hpp"
#if defined ZMQ_USE_KQUEUE
#include <vector>
#include <unistd.h>
#include "ctx.hpp"
#include "fd.hpp"
#include "thread.hpp"
#include "poller_base.hpp"
namespace zmq
{
struct i_poll_events;
// Implements socket polling mechanism using the BSD-specific
// kqueue interface.
class kqueue_t : public poller_base_t
{
public:
typedef void* handle_t;
kqueue_t (const ctx_t &ctx_);
~kqueue_t ();
// "poller" concept.
handle_t add_fd (fd_t fd_, zmq::i_poll_events *events_);
void rm_fd (handle_t handle_);
void set_pollin (handle_t handle_);
void reset_pollin (handle_t handle_);
void set_pollout (handle_t handle_);
void reset_pollout (handle_t handle_);
void start ();
void stop ();
static int max_fds ();
private:
// Main worker thread routine.
static void worker_routine (void *arg_);
// Main event loop.
void loop ();
// Reference to ZMQ context.
const ctx_t &ctx;
// File descriptor referring to the kernel event queue.
fd_t kqueue_fd;
// Adds the event to the kqueue.
void kevent_add (fd_t fd_, short filter_, void *udata_);
// Deletes the event from the kqueue.
void kevent_delete (fd_t fd_, short filter_);
struct poll_entry_t
{
fd_t fd;
bool flag_pollin;
bool flag_pollout;
zmq::i_poll_events *reactor;
};
// List of retired event sources.
typedef std::vector <poll_entry_t*> retired_t;
retired_t retired;
// If true, thread is in the process of shutting down.
bool stopping;
// Handle of the physical thread doing the I/O work.
thread_t worker;
kqueue_t (const kqueue_t&);
const kqueue_t &operator = (const kqueue_t&);
#ifdef HAVE_FORK
// the process that created this context. Used to detect forking.
pid_t pid;
#endif
};
typedef kqueue_t poller_t;
}
#endif
#endif
-173
View File
@@ -1,173 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "lb.hpp"
#include "pipe.hpp"
#include "err.hpp"
#include "msg.hpp"
zmq::lb_t::lb_t () :
active (0),
current (0),
more (false),
dropping (false)
{
}
zmq::lb_t::~lb_t ()
{
zmq_assert (pipes.empty ());
}
void zmq::lb_t::attach (pipe_t *pipe_)
{
pipes.push_back (pipe_);
activated (pipe_);
}
void zmq::lb_t::pipe_terminated (pipe_t *pipe_)
{
pipes_t::size_type index = pipes.index (pipe_);
// If we are in the middle of multipart message and current pipe
// have disconnected, we have to drop the remainder of the message.
if (index == current && more)
dropping = true;
// Remove the pipe from the list; adjust number of active pipes
// accordingly.
if (index < active) {
active--;
pipes.swap (index, active);
if (current == active)
current = 0;
}
pipes.erase (pipe_);
}
void zmq::lb_t::activated (pipe_t *pipe_)
{
// Move the pipe to the list of active pipes.
pipes.swap (pipes.index (pipe_), active);
active++;
}
int zmq::lb_t::send (msg_t *msg_)
{
return sendpipe (msg_, NULL);
}
int zmq::lb_t::sendpipe (msg_t *msg_, pipe_t **pipe_)
{
// Drop the message if required. If we are at the end of the message
// switch back to non-dropping mode.
if (dropping) {
more = msg_->flags () & msg_t::more ? true : false;
dropping = more;
int rc = msg_->close ();
errno_assert (rc == 0);
rc = msg_->init ();
errno_assert (rc == 0);
return 0;
}
while (active > 0) {
if (pipes [current]->write (msg_))
{
if (pipe_)
*pipe_ = pipes [current];
break;
}
// If send fails for multi-part msg rollback other
// parts sent earlier and return EAGAIN.
// Application should handle this as suitable
if (more)
{
pipes [current]->rollback ();
more = 0;
errno = EAGAIN;
return -1;
}
active--;
if (current < active)
pipes.swap (current, active);
else
current = 0;
}
// If there are no pipes we cannot send the message.
if (active == 0) {
errno = EAGAIN;
return -1;
}
// If it's final part of the message we can flush it downstream and
// continue round-robining (load balance).
more = msg_->flags () & msg_t::more? true: false;
if (!more) {
pipes [current]->flush ();
if (++current >= active)
current = 0;
}
// Detach the message from the data buffer.
int rc = msg_->init ();
errno_assert (rc == 0);
return 0;
}
bool zmq::lb_t::has_out ()
{
// If one part of the message was already written we can definitely
// write the rest of the message.
if (more)
return true;
while (active > 0) {
// Check whether a pipe has room for another message.
if (pipes [current]->check_write ())
return true;
// Deactivate the pipe.
active--;
pipes.swap (current, active);
if (current == active)
current = 0;
}
return false;
}
-88
View File
@@ -1,88 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_LB_HPP_INCLUDED__
#define __ZMQ_LB_HPP_INCLUDED__
#include "array.hpp"
#include "pipe.hpp"
namespace zmq
{
// This class manages a set of outbound pipes. On send it load balances
// messages fairly among the pipes.
class lb_t
{
public:
lb_t ();
~lb_t ();
void attach (pipe_t *pipe_);
void activated (pipe_t *pipe_);
void pipe_terminated (pipe_t *pipe_);
int send (msg_t *msg_);
// Sends a message and stores the pipe that was used in pipe_.
// It is possible for this function to return success but keep pipe_
// unset if the rest of a multipart message to a terminated pipe is
// being dropped. For the first frame, this will never happen.
int sendpipe (msg_t *msg_, pipe_t **pipe_);
bool has_out ();
private:
// List of outbound pipes.
typedef array_t <pipe_t, 2> pipes_t;
pipes_t pipes;
// Number of active pipes. All the active pipes are located at the
// beginning of the pipes array.
pipes_t::size_type active;
// Points to the last pipe that the most recent message was sent to.
pipes_t::size_type current;
// True if last we are in the middle of a multipart message.
bool more;
// True if we are dropping current message.
bool dropping;
lb_t (const lb_t&);
const lb_t &operator = (const lb_t&);
};
}
#endif
-42
View File
@@ -1,42 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_LIKELY_HPP_INCLUDED__
#define __ZMQ_LIKELY_HPP_INCLUDED__
#if defined __GNUC__
#define likely(x) __builtin_expect ((x), 1)
#define unlikely(x) __builtin_expect ((x), 0)
#else
#define likely(x) (x)
#define unlikely(x) (x)
#endif
#endif
-12
View File
@@ -1,12 +0,0 @@
/******************************************************************************/
/* 0MQ Internal Use */
/******************************************************************************/
#define LIBZMQ_UNUSED(object) (void)object
#define LIBZMQ_DELETE(p_object) {\
delete p_object; \
p_object = 0; \
}
/******************************************************************************/
-101
View File
@@ -1,101 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "mailbox.hpp"
#include "err.hpp"
zmq::mailbox_t::mailbox_t ()
{
// Get the pipe into passive state. That way, if the users starts by
// polling on the associated file descriptor it will get woken up when
// new command is posted.
const bool ok = cpipe.read (NULL);
zmq_assert (!ok);
active = false;
}
zmq::mailbox_t::~mailbox_t ()
{
// TODO: Retrieve and deallocate commands inside the cpipe.
// Work around problem that other threads might still be in our
// send() method, by waiting on the mutex before disappearing.
sync.lock ();
sync.unlock ();
}
zmq::fd_t zmq::mailbox_t::get_fd () const
{
return signaler.get_fd ();
}
void zmq::mailbox_t::send (const command_t &cmd_)
{
sync.lock ();
cpipe.write (cmd_, false);
const bool ok = cpipe.flush ();
sync.unlock ();
if (!ok)
signaler.send ();
}
int zmq::mailbox_t::recv (command_t *cmd_, int timeout_)
{
// Try to get the command straight away.
if (active) {
if (cpipe.read (cmd_))
return 0;
// If there are no more commands available, switch into passive state.
active = false;
}
// Wait for signal from the command sender.
int rc = signaler.wait (timeout_);
if (rc == -1) {
errno_assert (errno == EAGAIN || errno == EINTR);
return -1;
}
// Receive the signal.
rc = signaler.recv_failable ();
if (rc == -1) {
errno_assert (errno == EAGAIN);
return -1;
}
// Switch into active state.
active = true;
// Get a command.
const bool ok = cpipe.read (cmd_);
zmq_assert (ok);
return 0;
}
-90
View File
@@ -1,90 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_MAILBOX_HPP_INCLUDED__
#define __ZMQ_MAILBOX_HPP_INCLUDED__
#include <stddef.h>
#include "signaler.hpp"
#include "fd.hpp"
#include "config.hpp"
#include "command.hpp"
#include "ypipe.hpp"
#include "mutex.hpp"
#include "i_mailbox.hpp"
namespace zmq
{
class mailbox_t : public i_mailbox
{
public:
mailbox_t ();
~mailbox_t ();
fd_t get_fd () const;
void send (const command_t &cmd_);
int recv (command_t *cmd_, int timeout_);
#ifdef HAVE_FORK
// close the file descriptors in the signaller. This is used in a forked
// child process to close the file descriptors so that they do not interfere
// with the context in the parent process.
void forked () { signaler.forked (); }
#endif
private:
// The pipe to store actual commands.
typedef ypipe_t <command_t, command_pipe_granularity> cpipe_t;
cpipe_t cpipe;
// Signaler to pass signals from writer thread to reader thread.
signaler_t signaler;
// There's only one thread receiving from the mailbox, but there
// is arbitrary number of threads sending. Given that ypipe requires
// synchronised access on both of its endpoints, we have to synchronise
// the sending side.
mutex_t sync;
// True if the underlying pipe is active, ie. when we are allowed to
// read commands from it.
bool active;
// Disable copying of mailbox_t object.
mailbox_t (const mailbox_t&);
const mailbox_t &operator = (const mailbox_t&);
};
}
#endif
-117
View File
@@ -1,117 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "mailbox_safe.hpp"
#include "clock.hpp"
#include "err.hpp"
zmq::mailbox_safe_t::mailbox_safe_t (mutex_t* sync_) :
sync (sync_)
{
// Get the pipe into passive state. That way, if the users starts by
// polling on the associated file descriptor it will get woken up when
// new command is posted.
const bool ok = cpipe.read (NULL);
zmq_assert (!ok);
}
zmq::mailbox_safe_t::~mailbox_safe_t ()
{
// TODO: Retrieve and deallocate commands inside the cpipe.
// Work around problem that other threads might still be in our
// send() method, by waiting on the mutex before disappearing.
sync->lock ();
sync->unlock ();
}
void zmq::mailbox_safe_t::add_signaler (signaler_t* signaler)
{
signalers.push_back(signaler);
}
void zmq::mailbox_safe_t::remove_signaler (signaler_t* signaler)
{
std::vector<signaler_t*>::iterator it = signalers.begin();
// TODO: make a copy of array and signal outside the lock
for (; it != signalers.end(); ++it){
if (*it == signaler)
break;
}
if (it != signalers.end())
signalers.erase(it);
}
void zmq::mailbox_safe_t::clear_signalers ()
{
signalers.clear ();
}
void zmq::mailbox_safe_t::send (const command_t &cmd_)
{
sync->lock ();
cpipe.write (cmd_, false);
const bool ok = cpipe.flush ();
if (!ok) {
cond_var.broadcast ();
for (std::vector<signaler_t*>::iterator it = signalers.begin(); it != signalers.end(); ++it){
(*it)->send();
}
}
sync->unlock ();
}
int zmq::mailbox_safe_t::recv (command_t *cmd_, int timeout_)
{
// Try to get the command straight away.
if (cpipe.read (cmd_))
return 0;
// Wait for signal from the command sender.
int rc = cond_var.wait (sync, timeout_);
if (rc == -1) {
errno_assert (errno == EAGAIN || errno == EINTR);
return -1;
}
// Another thread may already fetch the command
const bool ok = cpipe.read (cmd_);
if (!ok) {
errno = EAGAIN;
return -1;
}
return 0;
}
-94
View File
@@ -1,94 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_MAILBOX_SAFE_HPP_INCLUDED__
#define __ZMQ_MAILBOX_SAFE_HPP_INCLUDED__
#include <vector>
#include <stddef.h>
#include "signaler.hpp"
#include "fd.hpp"
#include "config.hpp"
#include "command.hpp"
#include "ypipe.hpp"
#include "mutex.hpp"
#include "i_mailbox.hpp"
#include "condition_variable.hpp"
namespace zmq
{
class mailbox_safe_t : public i_mailbox
{
public:
mailbox_safe_t (mutex_t* sync_);
~mailbox_safe_t ();
void send (const command_t &cmd_);
int recv (command_t *cmd_, int timeout_);
// Add signaler to mailbox which will be called when a message is ready
void add_signaler (signaler_t* signaler);
void remove_signaler (signaler_t* signaler);
void clear_signalers ();
#ifdef HAVE_FORK
// close the file descriptors in the signaller. This is used in a forked
// child process to close the file descriptors so that they do not interfere
// with the context in the parent process.
void forked ()
{
// TODO: call fork on the condition variable
}
#endif
private:
// The pipe to store actual commands.
typedef ypipe_t <command_t, command_pipe_granularity> cpipe_t;
cpipe_t cpipe;
// Condition variable to pass signals from writer thread to reader thread.
condition_variable_t cond_var;
// Synchronize access to the mailbox from receivers and senders
mutex_t* sync;
std::vector <zmq::signaler_t* > signalers;
// Disable copying of mailbox_t object.
mailbox_safe_t (const mailbox_safe_t&);
const mailbox_safe_t &operator = (const mailbox_safe_t&);
};
}
#endif
-285
View File
@@ -1,285 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include <string.h>
#include "mechanism.hpp"
#include "options.hpp"
#include "msg.hpp"
#include "err.hpp"
#include "wire.hpp"
#include "session_base.hpp"
zmq::mechanism_t::mechanism_t (const options_t &options_) :
options (options_)
{
}
zmq::mechanism_t::~mechanism_t ()
{
}
void zmq::mechanism_t::set_peer_routing_id (const void *id_ptr, size_t id_size)
{
routing_id.set (static_cast <const unsigned char*> (id_ptr), id_size);
}
void zmq::mechanism_t::peer_routing_id (msg_t *msg_)
{
const int rc = msg_->init_size (routing_id.size ());
errno_assert (rc == 0);
memcpy (msg_->data (), routing_id.data (), routing_id.size ());
msg_->set_flags (msg_t::routing_id);
}
void zmq::mechanism_t::set_user_id (const void *data_, size_t size_)
{
user_id.set (static_cast <const unsigned char*> (data_), size_);
zap_properties.ZMQ_MAP_INSERT_OR_EMPLACE (
ZMQ_MSG_PROPERTY_USER_ID, std::string ((char *) data_, size_));
}
const zmq::blob_t &zmq::mechanism_t::get_user_id () const
{
return user_id;
}
const char *zmq::mechanism_t::socket_type_string (int socket_type) const
{
static const char *names [] = {"PAIR", "PUB", "SUB", "REQ", "REP",
"DEALER", "ROUTER", "PULL", "PUSH",
"XPUB", "XSUB", "STREAM",
"SERVER", "CLIENT",
"RADIO", "DISH",
"GATHER", "SCATTER", "DGRAM"};
zmq_assert (socket_type >= 0 && socket_type <= 18);
return names [socket_type];
}
static size_t property_len (size_t name_len, size_t value_len)
{
return 1 + name_len + 4 + value_len;
}
static size_t name_len (const char *name)
{
const size_t name_len = strlen (name);
zmq_assert (name_len <= 255);
return name_len;
}
size_t zmq::mechanism_t::add_property (unsigned char *ptr,
size_t ptr_capacity,
const char *name,
const void *value,
size_t value_len)
{
const size_t name_len = ::name_len (name);
const size_t total_len = ::property_len (name_len, value_len);
zmq_assert (total_len <= ptr_capacity);
*ptr++ = static_cast <unsigned char> (name_len);
memcpy (ptr, name, name_len);
ptr += name_len;
zmq_assert (value_len <= 0x7FFFFFFF);
put_uint32 (ptr, static_cast <uint32_t> (value_len));
ptr += 4;
memcpy (ptr, value, value_len);
return total_len;
}
size_t zmq::mechanism_t::property_len (const char *name, size_t value_len)
{
return ::property_len (name_len (name), value_len);
}
#define ZMTP_PROPERTY_SOCKET_TYPE "Socket-Type"
#define ZMTP_PROPERTY_IDENTITY "Identity"
size_t zmq::mechanism_t::add_basic_properties (unsigned char *buf,
size_t buf_capacity) const
{
unsigned char *ptr = buf;
// Add socket type property
const char *socket_type = socket_type_string (options.type);
ptr += add_property (ptr, buf_capacity,
ZMTP_PROPERTY_SOCKET_TYPE, socket_type,
strlen (socket_type));
// Add identity (aka routing id) property
if (options.type == ZMQ_REQ || options.type == ZMQ_DEALER
|| options.type == ZMQ_ROUTER)
ptr += add_property (ptr, buf_capacity - (ptr - buf),
ZMTP_PROPERTY_IDENTITY, options.routing_id,
options.routing_id_size);
return ptr - buf;
}
size_t zmq::mechanism_t::basic_properties_len() const
{
const char *socket_type = socket_type_string (options.type);
return property_len (ZMTP_PROPERTY_SOCKET_TYPE, strlen (socket_type))
+ ((options.type == ZMQ_REQ || options.type == ZMQ_DEALER
|| options.type == ZMQ_ROUTER)
? property_len (ZMTP_PROPERTY_IDENTITY,
options.routing_id_size)
: 0);
}
void zmq::mechanism_t::make_command_with_basic_properties (
msg_t *msg_, const char *prefix, size_t prefix_len) const
{
const size_t command_size = prefix_len + basic_properties_len ();
const int rc = msg_->init_size (command_size);
errno_assert (rc == 0);
unsigned char *ptr = (unsigned char *) msg_->data ();
// Add prefix
memcpy (ptr, prefix, prefix_len);
ptr += prefix_len;
add_basic_properties (
ptr, command_size - (ptr - (unsigned char *) msg_->data ()));
}
int zmq::mechanism_t::parse_metadata (const unsigned char *ptr_,
size_t length_,
bool zap_flag)
{
size_t bytes_left = length_;
while (bytes_left > 1) {
const size_t name_length = static_cast <size_t> (*ptr_);
ptr_ += 1;
bytes_left -= 1;
if (bytes_left < name_length)
break;
const std::string name = std::string ((char *) ptr_, name_length);
ptr_ += name_length;
bytes_left -= name_length;
if (bytes_left < 4)
break;
const size_t value_length = static_cast <size_t> (get_uint32 (ptr_));
ptr_ += 4;
bytes_left -= 4;
if (bytes_left < value_length)
break;
const uint8_t *value = ptr_;
ptr_ += value_length;
bytes_left -= value_length;
if (name == ZMTP_PROPERTY_IDENTITY && options.recv_routing_id)
set_peer_routing_id (value, value_length);
else
if (name == ZMTP_PROPERTY_SOCKET_TYPE) {
const std::string socket_type ((char *) value, value_length);
if (!check_socket_type (socket_type)) {
errno = EINVAL;
return -1;
}
}
else {
const int rc = property (name, value, value_length);
if (rc == -1)
return -1;
}
if (zap_flag)
zap_properties.ZMQ_MAP_INSERT_OR_EMPLACE (
name, std::string ((char *) value, value_length));
else
zmtp_properties.ZMQ_MAP_INSERT_OR_EMPLACE (
name, std::string ((char *) value, value_length));
}
if (bytes_left > 0) {
errno = EPROTO;
return -1;
}
return 0;
}
int zmq::mechanism_t::property (const std::string& /* name_ */,
const void * /* value_ */, size_t /* length_ */)
{
// Default implementation does not check
// property values and returns 0 to signal success.
return 0;
}
bool zmq::mechanism_t::check_socket_type (const std::string& type_) const
{
switch (options.type) {
case ZMQ_REQ:
return type_ == "REP" || type_ == "ROUTER";
case ZMQ_REP:
return type_ == "REQ" || type_ == "DEALER";
case ZMQ_DEALER:
return type_ == "REP" || type_ == "DEALER" || type_ == "ROUTER";
case ZMQ_ROUTER:
return type_ == "REQ" || type_ == "DEALER" || type_ == "ROUTER";
case ZMQ_PUSH:
return type_ == "PULL";
case ZMQ_PULL:
return type_ == "PUSH";
case ZMQ_PUB:
return type_ == "SUB" || type_ == "XSUB";
case ZMQ_SUB:
return type_ == "PUB" || type_ == "XPUB";
case ZMQ_XPUB:
return type_ == "SUB" || type_ == "XSUB";
case ZMQ_XSUB:
return type_ == "PUB" || type_ == "XPUB";
case ZMQ_PAIR:
return type_ == "PAIR";
case ZMQ_SERVER:
return type_ == "CLIENT";
case ZMQ_CLIENT:
return type_ == "SERVER";
case ZMQ_RADIO:
return type_ == "DISH";
case ZMQ_DISH:
return type_ == "RADIO";
case ZMQ_GATHER:
return type_ == "SCATTER";
case ZMQ_SCATTER:
return type_ == "GATHER";
case ZMQ_DGRAM:
return type_ == "DGRAM";
default:
break;
}
return false;
}
-152
View File
@@ -1,152 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_MECHANISM_HPP_INCLUDED__
#define __ZMQ_MECHANISM_HPP_INCLUDED__
#include "stdint.hpp"
#include "options.hpp"
#include "blob.hpp"
#include "metadata.hpp"
namespace zmq
{
class msg_t;
class session_base_t;
// Abstract class representing security mechanism.
// Different mechanism extends this class.
class mechanism_t
{
public:
enum status_t {
handshaking,
ready,
error
};
mechanism_t (const options_t &options_);
virtual ~mechanism_t ();
// Prepare next handshake command that is to be sent to the peer.
virtual int next_handshake_command (msg_t *msg_) = 0;
// Process the handshake command received from the peer.
virtual int process_handshake_command (msg_t *msg_) = 0;
virtual int encode (msg_t *) { return 0; }
virtual int decode (msg_t *) { return 0; }
// Notifies mechanism about availability of ZAP message.
virtual int zap_msg_available () { return 0; }
// Returns the status of this mechanism.
virtual status_t status () const = 0;
void set_peer_routing_id (const void *id_ptr, size_t id_size);
void peer_routing_id (msg_t *msg_);
void set_user_id (const void *user_id, size_t size);
const blob_t &get_user_id () const;
const metadata_t::dict_t& get_zmtp_properties () {
return zmtp_properties;
}
const metadata_t::dict_t& get_zap_properties () {
return zap_properties;
}
protected:
// Only used to identify the socket for the Socket-Type
// property in the wire protocol.
const char *socket_type_string (int socket_type) const;
static size_t add_property (unsigned char *ptr,
size_t ptr_capacity,
const char *name,
const void *value,
size_t value_len);
static size_t property_len (const char *name,
size_t value_len);
size_t add_basic_properties (unsigned char *ptr, size_t ptr_capacity) const;
size_t basic_properties_len () const;
void make_command_with_basic_properties (msg_t *msg_,
const char *prefix,
size_t prefix_len) const;
// Parses a metadata.
// Metadata consists of a list of properties consisting of
// name and value as size-specified strings.
// Returns 0 on success and -1 on error, in which case errno is set.
int parse_metadata (
const unsigned char *ptr_, size_t length, bool zap_flag = false);
// This is called by parse_property method whenever it
// parses a new property. The function should return 0
// on success and -1 on error, in which case it should
// set errno. Signaling error prevents parser from
// parsing remaining data.
// Derived classes are supposed to override this
// method to handle custom processing.
virtual int property (const std::string& name_,
const void *value_, size_t length_);
// Properties received from ZMTP peer.
metadata_t::dict_t zmtp_properties;
// Properties received from ZAP server.
metadata_t::dict_t zap_properties;
options_t options;
private:
blob_t routing_id;
blob_t user_id;
// Returns true iff socket associated with the mechanism
// is compatible with a given socket type 'type_'.
bool check_socket_type (const std::string& type_) const;
};
}
#endif
-70
View File
@@ -1,70 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "mechanism_base.hpp"
#include "session_base.hpp"
zmq::mechanism_base_t::mechanism_base_t (session_base_t *const session_,
const options_t &options_) :
mechanism_t (options_),
session (session_)
{
}
int zmq::mechanism_base_t::check_basic_command_structure (msg_t *msg_)
{
if (msg_->size () <= 1 || msg_->size () <= ((uint8_t *) msg_->data ())[0]) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED);
errno = EPROTO;
return -1;
}
return 0;
}
void zmq::mechanism_base_t::handle_error_reason (const char *error_reason,
size_t error_reason_len)
{
if (error_reason_len == 3 && error_reason[1] == '0'
&& error_reason[2] == '0' && error_reason[0] >= '3'
&& error_reason[0] <= '5') {
// it is a ZAP status code, so emit an authentication failure event
session->get_socket ()->event_handshake_failed_auth (
session->get_endpoint (), (error_reason[0] - '0') * 100);
}
}
bool zmq::mechanism_base_t::zap_required() const
{
return !options.zap_domain.empty ();
}
-53
View File
@@ -1,53 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_MECHANISM_BASE_HPP_INCLUDED__
#define __ZMQ_MECHANISM_BASE_HPP_INCLUDED__
#include "mechanism.hpp"
namespace zmq
{
class mechanism_base_t : public mechanism_t
{
protected:
mechanism_base_t (session_base_t *const session_,
const options_t &options_);
session_base_t *const session;
int check_basic_command_structure (msg_t *msg_);
void handle_error_reason (const char *error_reason, size_t error_reason_len);
bool zap_required() const;
};
}
#endif
-62
View File
@@ -1,62 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "metadata.hpp"
zmq::metadata_t::metadata_t (const dict_t &dict) :
ref_cnt (1),
dict (dict)
{
}
const char *zmq::metadata_t::get (const std::string &property) const
{
dict_t::const_iterator it = dict.find (property);
if (it == dict.end())
{
/** \todo remove this when support for the deprecated name "Identity" is dropped */
if (property == "Identity")
return get (ZMQ_MSG_PROPERTY_ROUTING_ID);
return NULL;
}
else
return it->second.c_str ();
}
void zmq::metadata_t::add_ref ()
{
ref_cnt.add (1);
}
bool zmq::metadata_t::drop_ref ()
{
return !ref_cnt.sub (1);
}
-70
View File
@@ -1,70 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_METADATA_HPP_INCLUDED__
#define __ZMQ_METADATA_HPP_INCLUDED__
#include <map>
#include <string>
#include "atomic_counter.hpp"
namespace zmq
{
class metadata_t
{
public:
typedef std::map <std::string, std::string> dict_t;
metadata_t (const dict_t &dict);
// Returns pointer to property value or NULL if
// property is not found.
const char *get (const std::string &property) const;
void add_ref ();
// Drop reference. Returns true iff the reference
// counter drops to zero.
bool drop_ref ();
private:
metadata_t(const metadata_t&);
metadata_t & operator=(const metadata_t&);
// Reference counter.
atomic_counter_t ref_cnt;
// Dictionary holding metadata.
dict_t dict;
};
}
#endif
-578
View File
@@ -1,578 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#include "msg.hpp"
#include <string.h>
#include <stdlib.h>
#include <new>
#include "stdint.hpp"
#include "likely.hpp"
#include "metadata.hpp"
#include "err.hpp"
// Check whether the sizes of public representation of the message (zmq_msg_t)
// and private representation of the message (zmq::msg_t) match.
typedef char zmq_msg_size_check
[2 * ((sizeof (zmq::msg_t) == sizeof (zmq_msg_t)) != 0) - 1];
bool zmq::msg_t::check () const
{
return u.base.type >= type_min && u.base.type <= type_max;
}
int zmq::msg_t::init (void* data_, size_t size_,
msg_free_fn* ffn_, void* hint,
content_t* content_)
{
if (size_ < max_vsm_size) {
int const rc = init_size(size_);
if (rc != -1)
{
memcpy(data(), data_, size_);
return 0;
}
else
{
return -1;
}
}
else if(content_)
{
return init_external_storage(content_, data_, size_, ffn_, hint);
}
else
{
return init_data(data_, size_, ffn_, hint);
}
}
int zmq::msg_t::init ()
{
u.vsm.metadata = NULL;
u.vsm.type = type_vsm;
u.vsm.flags = 0;
u.vsm.size = 0;
u.vsm.group[0] = '\0';
u.vsm.routing_id = 0;
return 0;
}
int zmq::msg_t::init_size (size_t size_)
{
if (size_ <= max_vsm_size) {
u.vsm.metadata = NULL;
u.vsm.type = type_vsm;
u.vsm.flags = 0;
u.vsm.size = (unsigned char) size_;
u.vsm.group[0] = '\0';
u.vsm.routing_id = 0;
}
else {
u.lmsg.metadata = NULL;
u.lmsg.type = type_lmsg;
u.lmsg.flags = 0;
u.lmsg.group[0] = '\0';
u.lmsg.routing_id = 0;
u.lmsg.content = NULL;
if (sizeof (content_t) + size_ > size_)
u.lmsg.content = (content_t*) malloc (sizeof (content_t) + size_);
if (unlikely (!u.lmsg.content)) {
errno = ENOMEM;
return -1;
}
u.lmsg.content->data = u.lmsg.content + 1;
u.lmsg.content->size = size_;
u.lmsg.content->ffn = NULL;
u.lmsg.content->hint = NULL;
new (&u.lmsg.content->refcnt) zmq::atomic_counter_t ();
}
return 0;
}
int zmq::msg_t::init_external_storage(content_t* content_, void* data_, size_t size_,
msg_free_fn *ffn_, void* hint_)
{
zmq_assert(NULL != data_);
zmq_assert(NULL != content_);
u.zclmsg.metadata = NULL;
u.zclmsg.type = type_zclmsg;
u.zclmsg.flags = 0;
u.zclmsg.group[0] = '\0';
u.zclmsg.routing_id = 0;
u.zclmsg.content = content_;
u.zclmsg.content->data = data_;
u.zclmsg.content->size = size_;
u.zclmsg.content->ffn = ffn_;
u.zclmsg.content->hint = hint_;
new (&u.zclmsg.content->refcnt) zmq::atomic_counter_t();
return 0;
}
int zmq::msg_t::init_data (void *data_, size_t size_,
msg_free_fn *ffn_, void *hint_)
{
// If data is NULL and size is not 0, a segfault
// would occur once the data is accessed
zmq_assert (data_ != NULL || size_ == 0);
// Initialize constant message if there's no need to deallocate
if (ffn_ == NULL) {
u.cmsg.metadata = NULL;
u.cmsg.type = type_cmsg;
u.cmsg.flags = 0;
u.cmsg.data = data_;
u.cmsg.size = size_;
u.cmsg.group[0] = '\0';
u.cmsg.routing_id = 0;
}
else {
u.lmsg.metadata = NULL;
u.lmsg.type = type_lmsg;
u.lmsg.flags = 0;
u.lmsg.group[0] = '\0';
u.lmsg.routing_id = 0;
u.lmsg.content = (content_t*) malloc (sizeof (content_t));
if (!u.lmsg.content) {
errno = ENOMEM;
return -1;
}
u.lmsg.content->data = data_;
u.lmsg.content->size = size_;
u.lmsg.content->ffn = ffn_;
u.lmsg.content->hint = hint_;
new (&u.lmsg.content->refcnt) zmq::atomic_counter_t ();
}
return 0;
}
int zmq::msg_t::init_delimiter ()
{
u.delimiter.metadata = NULL;
u.delimiter.type = type_delimiter;
u.delimiter.flags = 0;
u.delimiter.group[0] = '\0';
u.delimiter.routing_id = 0;
return 0;
}
int zmq::msg_t::init_join ()
{
u.base.metadata = NULL;
u.base.type = type_join;
u.base.flags = 0;
u.base.group[0] = '\0';
u.base.routing_id = 0;
return 0;
}
int zmq::msg_t::init_leave ()
{
u.base.metadata = NULL;
u.base.type = type_leave;
u.base.flags = 0;
u.base.group[0] = '\0';
u.base.routing_id = 0;
return 0;
}
int zmq::msg_t::close ()
{
// Check the validity of the message.
if (unlikely (!check ())) {
errno = EFAULT;
return -1;
}
if (u.base.type == type_lmsg) {
// If the content is not shared, or if it is shared and the reference
// count has dropped to zero, deallocate it.
if (!(u.lmsg.flags & msg_t::shared) ||
!u.lmsg.content->refcnt.sub (1)) {
// We used "placement new" operator to initialize the reference
// counter so we call the destructor explicitly now.
u.lmsg.content->refcnt.~atomic_counter_t ();
if (u.lmsg.content->ffn)
u.lmsg.content->ffn (u.lmsg.content->data,
u.lmsg.content->hint);
free (u.lmsg.content);
}
}
if (is_zcmsg())
{
zmq_assert(u.zclmsg.content->ffn);
// If the content is not shared, or if it is shared and the reference
// count has dropped to zero, deallocate it.
if (!(u.zclmsg.flags & msg_t::shared) ||
!u.zclmsg.content->refcnt.sub (1)) {
// We used "placement new" operator to initialize the reference
// counter so we call the destructor explicitly now.
u.zclmsg.content->refcnt.~atomic_counter_t ();
u.zclmsg.content->ffn (u.zclmsg.content->data,
u.zclmsg.content->hint);
}
}
if (u.base.metadata != NULL) {
if (u.base.metadata->drop_ref ()) {
LIBZMQ_DELETE(u.base.metadata);
}
u.base.metadata = NULL;
}
// Make the message invalid.
u.base.type = 0;
return 0;
}
int zmq::msg_t::move (msg_t &src_)
{
// Check the validity of the source.
if (unlikely (!src_.check ())) {
errno = EFAULT;
return -1;
}
int rc = close ();
if (unlikely (rc < 0))
return rc;
*this = src_;
rc = src_.init ();
if (unlikely (rc < 0))
return rc;
return 0;
}
int zmq::msg_t::copy (msg_t &src_)
{
// Check the validity of the source.
if (unlikely (!src_.check ())) {
errno = EFAULT;
return -1;
}
int rc = close ();
if (unlikely (rc < 0))
return rc;
if (src_.u.base.type == type_lmsg ) {
// One reference is added to shared messages. Non-shared messages
// are turned into shared messages and reference count is set to 2.
if (src_.u.lmsg.flags & msg_t::shared)
src_.u.lmsg.content->refcnt.add (1);
else {
src_.u.lmsg.flags |= msg_t::shared;
src_.u.lmsg.content->refcnt.set (2);
}
}
if (src_.is_zcmsg()) {
// One reference is added to shared messages. Non-shared messages
// are turned into shared messages and reference count is set to 2.
if (src_.u.zclmsg.flags & msg_t::shared)
src_.refcnt()->add (1);
else {
src_.u.zclmsg.flags |= msg_t::shared;
src_.refcnt()->set (2);
}
}
if (src_.u.base.metadata != NULL)
src_.u.base.metadata->add_ref ();
*this = src_;
return 0;
}
void *zmq::msg_t::data ()
{
// Check the validity of the message.
zmq_assert (check ());
switch (u.base.type) {
case type_vsm:
return u.vsm.data;
case type_lmsg:
return u.lmsg.content->data;
case type_cmsg:
return u.cmsg.data;
case type_zclmsg:
return u.zclmsg.content->data;
default:
zmq_assert (false);
return NULL;
}
}
size_t zmq::msg_t::size () const
{
// Check the validity of the message.
zmq_assert (check ());
switch (u.base.type) {
case type_vsm:
return u.vsm.size;
case type_lmsg:
return u.lmsg.content->size;
case type_zclmsg:
return u.zclmsg.content->size;
case type_cmsg:
return u.cmsg.size;
default:
zmq_assert (false);
return 0;
}
}
unsigned char zmq::msg_t::flags () const
{
return u.base.flags;
}
void zmq::msg_t::set_flags (unsigned char flags_)
{
u.base.flags |= flags_;
}
void zmq::msg_t::reset_flags (unsigned char flags_)
{
u.base.flags &= ~flags_;
}
zmq::metadata_t *zmq::msg_t::metadata () const
{
return u.base.metadata;
}
void zmq::msg_t::set_metadata (zmq::metadata_t *metadata_)
{
assert (metadata_ != NULL);
assert (u.base.metadata == NULL);
metadata_->add_ref ();
u.base.metadata = metadata_;
}
void zmq::msg_t::reset_metadata ()
{
if (u.base.metadata) {
if (u.base.metadata->drop_ref ()) {
LIBZMQ_DELETE(u.base.metadata);
}
u.base.metadata = NULL;
}
}
bool zmq::msg_t::is_routing_id () const
{
return (u.base.flags & routing_id) == routing_id;
}
bool zmq::msg_t::is_credential () const
{
return (u.base.flags & credential) == credential;
}
bool zmq::msg_t::is_delimiter () const
{
return u.base.type == type_delimiter;
}
bool zmq::msg_t::is_vsm () const
{
return u.base.type == type_vsm;
}
bool zmq::msg_t::is_cmsg () const
{
return u.base.type == type_cmsg;
}
bool zmq::msg_t::is_zcmsg() const
{
return u.base.type == type_zclmsg;
}
bool zmq::msg_t::is_join() const
{
return u.base.type == type_join;
}
bool zmq::msg_t::is_leave() const
{
return u.base.type == type_leave;
}
void zmq::msg_t::add_refs (int refs_)
{
zmq_assert (refs_ >= 0);
// Operation not supported for messages with metadata.
zmq_assert (u.base.metadata == NULL);
// No copies required.
if (!refs_)
return;
// VSMs, CMSGS and delimiters can be copied straight away. The only
// message type that needs special care are long messages.
if (u.base.type == type_lmsg || is_zcmsg() ) {
if (u.base.flags & msg_t::shared)
refcnt()->add (refs_);
else {
refcnt()->set (refs_ + 1);
u.base.flags |= msg_t::shared;
}
}
}
bool zmq::msg_t::rm_refs (int refs_)
{
zmq_assert (refs_ >= 0);
// Operation not supported for messages with metadata.
zmq_assert (u.base.metadata == NULL);
// No copies required.
if (!refs_)
return true;
// If there's only one reference close the message.
if ( (u.base.type != type_zclmsg && u.base.type != type_lmsg) || !(u.base.flags & msg_t::shared)) {
close ();
return false;
}
// The only message type that needs special care are long and zcopy messages.
if (u.base.type == type_lmsg && !u.lmsg.content->refcnt.sub(refs_)) {
// We used "placement new" operator to initialize the reference
// counter so we call the destructor explicitly now.
u.lmsg.content->refcnt.~atomic_counter_t ();
if (u.lmsg.content->ffn)
u.lmsg.content->ffn (u.lmsg.content->data, u.lmsg.content->hint);
free (u.lmsg.content);
return false;
}
if (is_zcmsg() && !u.zclmsg.content->refcnt.sub(refs_)) {
// storage for rfcnt is provided externally
if (u.zclmsg.content->ffn) {
u.zclmsg.content->ffn(u.zclmsg.content->data, u.zclmsg.content->hint);
}
return false;
}
return true;
}
uint32_t zmq::msg_t::get_routing_id ()
{
return u.base.routing_id;
}
int zmq::msg_t::set_routing_id (uint32_t routing_id_)
{
if (routing_id_) {
u.base.routing_id = routing_id_;
return 0;
}
errno = EINVAL;
return -1;
}
int zmq::msg_t::reset_routing_id ()
{
u.base.routing_id = 0;
return 0;
}
const char * zmq::msg_t::group ()
{
return u.base.group;
}
int zmq::msg_t::set_group (const char * group_)
{
return set_group (group_, strlen (group_));
}
int zmq::msg_t::set_group (const char * group_, size_t length_)
{
if (length_> ZMQ_GROUP_MAX_LENGTH)
{
errno = EINVAL;
return -1;
}
strncpy (u.base.group, group_, length_);
u.base.group[length_] = '\0';
return 0;
}
zmq::atomic_counter_t *zmq::msg_t::refcnt()
{
switch(u.base.type)
{
case type_lmsg:
return &u.lmsg.content->refcnt;
case type_zclmsg:
return &u.zclmsg.content->refcnt;
default:
zmq_assert(false);
return NULL;
}
}
-268
View File
@@ -1,268 +0,0 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_MSG_HPP_INCLUDE__
#define __ZMQ_MSG_HPP_INCLUDE__
#include <stddef.h>
#include <stdio.h>
#include "config.hpp"
#include "err.hpp"
#include "fd.hpp"
#include "atomic_counter.hpp"
#include "metadata.hpp"
// Signature for free function to deallocate the message content.
// Note that it has to be declared as "C" so that it is the same as
// zmq_free_fn defined in zmq.h.
extern "C"
{
typedef void (msg_free_fn) (void *data, void *hint);
}
namespace zmq
{
// Note that this structure needs to be explicitly constructed
// (init functions) and destructed (close function).
class msg_t
{
public:
// Shared message buffer. Message data are either allocated in one
// continuous block along with this structure - thus avoiding one
// malloc/free pair or they are stored in user-supplied memory.
// In the latter case, ffn member stores pointer to the function to be
// used to deallocate the data. If the buffer is actually shared (there
// are at least 2 references to it) refcount member contains number of
// references.
struct content_t
{
void *data;
size_t size;
msg_free_fn *ffn;
void *hint;
zmq::atomic_counter_t refcnt;
};
// Message flags.
enum
{
more = 1, // Followed by more parts
command = 2, // Command frame (see ZMTP spec)
credential = 32,
routing_id = 64,
shared = 128
};
bool check () const;
int init();
int init (void* data, size_t size_,
msg_free_fn* ffn_, void* hint,
content_t* content_ = NULL);
int init_size (size_t size_);
int init_data (void *data_, size_t size_, msg_free_fn *ffn_,
void *hint_);
int init_external_storage(content_t* content_, void *data_, size_t size_,
msg_free_fn *ffn_, void *hint_);
int init_delimiter ();
int init_join ();
int init_leave ();
int close ();
int move (msg_t &src_);
int copy (msg_t &src_);
void *data ();
size_t size () const;
unsigned char flags () const;
void set_flags (unsigned char flags_);
void reset_flags (unsigned char flags_);
metadata_t *metadata () const;
void set_metadata (metadata_t *metadata_);
void reset_metadata ();
bool is_routing_id () const;
bool is_credential () const;
bool is_delimiter () const;
bool is_join () const;
bool is_leave () const;
bool is_vsm () const;
bool is_cmsg () const;
bool is_zcmsg() const;
uint32_t get_routing_id ();
int set_routing_id (uint32_t routing_id_);
int reset_routing_id ();
const char * group ();
int set_group (const char* group_);
int set_group (const char*, size_t length);
// After calling this function you can copy the message in POD-style
// refs_ times. No need to call copy.
void add_refs (int refs_);
// Removes references previously added by add_refs. If the number of
// references drops to 0, the message is closed and false is returned.
bool rm_refs (int refs_);
// Size in bytes of the largest message that is still copied around
// rather than being reference-counted.
enum { msg_t_size = 64 };
enum { max_vsm_size = msg_t_size - (sizeof (metadata_t *) +
3 +
16 +
sizeof (uint32_t))};
private:
zmq::atomic_counter_t* refcnt();
// Different message types.
enum type_t
{
type_min = 101,
// VSM messages store the content in the message itself
type_vsm = 101,
// LMSG messages store the content in malloc-ed memory
type_lmsg = 102,
// Delimiter messages are used in envelopes
type_delimiter = 103,
// CMSG messages point to constant data
type_cmsg = 104,
// zero-copy LMSG message for v2_decoder
type_zclmsg = 105,
// Join message for radio_dish
type_join = 106,
// Leave message for radio_dish
type_leave = 107,
type_max = 107
};
// Note that fields shared between different message types are not
// moved to the parent class (msg_t). This way we get tighter packing
// of the data. Shared fields can be accessed via 'base' member of
// the union.
union {
struct {
metadata_t *metadata;
unsigned char unused [msg_t_size - (sizeof (metadata_t *) +
2 +
16 +
sizeof (uint32_t))];
unsigned char type;
unsigned char flags;
char group [16];
uint32_t routing_id;
} base;
struct {
metadata_t *metadata;
unsigned char data [max_vsm_size];
unsigned char size;
unsigned char type;
unsigned char flags;
char group [16];
uint32_t routing_id;
} vsm;
struct {
metadata_t *metadata;
content_t *content;
unsigned char unused [msg_t_size - (sizeof (metadata_t *) +
sizeof (content_t*) +
2 +
16 +
sizeof (uint32_t))];
unsigned char type;
unsigned char flags;
char group [16];
uint32_t routing_id;
} lmsg;
struct {
metadata_t *metadata;
content_t *content;
unsigned char unused [msg_t_size - (sizeof (metadata_t *) +
sizeof (content_t*) +
2 +
16 +
sizeof (uint32_t))];
unsigned char type;
unsigned char flags;
char group [16];
uint32_t routing_id;
} zclmsg;
struct {
metadata_t *metadata;
void* data;
size_t size;
unsigned char unused [msg_t_size - (sizeof (metadata_t *) +
sizeof (void*) +
sizeof (size_t) +
2 +
16 +
sizeof (uint32_t))];
unsigned char type;
unsigned char flags;
char group [16];
uint32_t routing_id;
} cmsg;
struct {
metadata_t *metadata;
unsigned char unused [msg_t_size - (sizeof (metadata_t *) +
2 +
16 +
sizeof (uint32_t))];
unsigned char type;
unsigned char flags;
char group [16];
uint32_t routing_id;
} delimiter;
} u;
};
inline int close_and_return (zmq::msg_t *msg, int echo)
{
// Since we abort on close failure we preserve errno for success case.
int err = errno;
const int rc = msg->close ();
errno_assert (rc == 0);
errno = err;
return echo;
}
inline int close_and_return (zmq::msg_t msg [], int count, int echo)
{
for (int i = 0; i < count; i++)
close_and_return (&msg [i], 0);
return echo;
}
}
#endif
Loaded 100 of 413 files, more files were not shown because too many files have changed in this diff. Show more