zmq_utils.cpp 7.15 KB
Newer Older
1
/*
2
    Copyright (c) 2007-2015 Contributors as noted in the AUTHORS file
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

    This file is part of 0MQ.

    0MQ is free software; you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    0MQ 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 "platform.hpp"

#include "clock.hpp"
#include "err.hpp"
24
#include "thread.hpp"
25 26
#include "atomic_counter.hpp"
#include "atomic_ptr.hpp"
27 28
#include <assert.h>
#include "../include/zmq_utils.h"
29 30 31 32 33 34

#if !defined ZMQ_HAVE_WINDOWS
#include <unistd.h>
#else
#include "windows.hpp"
#endif
Frank's avatar
Frank committed
35

36
#ifdef HAVE_LIBSODIUM
Frank's avatar
Frank committed
37 38 39 40 41
#ifdef HAVE_TWEETNACL
#include "tweetnacl_base.h"
#else
#include "sodium.h"
#endif
42 43
#endif

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68

void zmq_sleep (int seconds_)
{
#if defined ZMQ_HAVE_WINDOWS
    Sleep (seconds_ * 1000);
#else
    sleep (seconds_);
#endif
}

void *zmq_stopwatch_start ()
{
    uint64_t *watch = (uint64_t*) malloc (sizeof (uint64_t));
    alloc_assert (watch);
    *watch = zmq::clock_t::now_us ();
    return (void*) watch;
}

unsigned long zmq_stopwatch_stop (void *watch_)
{
    uint64_t end = zmq::clock_t::now_us ();
    uint64_t start = *(uint64_t*) watch_;
    free (watch_);
    return (unsigned long) (end - start);
}
69

70
void *zmq_threadstart(zmq_thread_fn* func, void* arg)
71 72
{
    zmq::thread_t* thread = new zmq::thread_t;
73
    thread->start(func, arg);
74 75 76 77 78 79 80 81 82
    return thread;
}

void zmq_threadclose(void* thread)
{
    zmq::thread_t* pThread = static_cast<zmq::thread_t*>(thread);
    pThread->stop();
    delete pThread;
}
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113

//  Z85 codec, taken from 0MQ RFC project, implements RFC32 Z85 encoding

//  Maps base 256 to base 85
static char encoder [85 + 1] = {
    "0123456789" "abcdefghij" "klmnopqrst" "uvwxyzABCD"
    "EFGHIJKLMN" "OPQRSTUVWX" "YZ.-:+=^!/" "*?&<>()[]{" 
    "}@%$#"
};

//  Maps base 85 to base 256
//  We chop off lower 32 and higher 128 ranges
static uint8_t decoder [96] = {
    0x00, 0x44, 0x00, 0x54, 0x53, 0x52, 0x48, 0x00, 
    0x4B, 0x4C, 0x46, 0x41, 0x00, 0x3F, 0x3E, 0x45, 
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
    0x08, 0x09, 0x40, 0x00, 0x49, 0x42, 0x4A, 0x47, 
    0x51, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 
    0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 
    0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 
    0x3B, 0x3C, 0x3D, 0x4D, 0x00, 0x4E, 0x43, 0x00, 
    0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 
    0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 
    0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 
    0x21, 0x22, 0x23, 0x4F, 0x00, 0x50, 0x00, 0x00
};

//  --------------------------------------------------------------------------
//  Encode a binary frame as a string; destination string MUST be at least
//  size * 5 / 4 bytes long plus 1 byte for the null terminator. Returns
//  dest. Size must be a multiple of 4.
114
//  Returns NULL and sets errno = EINVAL for invalid input.
115

116
char *zmq_z85_encode (char *dest, const uint8_t *data, size_t size)
117
{
118 119 120 121
    if (size % 4 != 0) {
        errno = EINVAL;
        return NULL;
    }
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
    unsigned int char_nbr = 0;
    unsigned int byte_nbr = 0;
    uint32_t value = 0;
    while (byte_nbr < size) {
        //  Accumulate value in base 256 (binary)
        value = value * 256 + data [byte_nbr++];
        if (byte_nbr % 4 == 0) {
            //  Output value in base 85
            unsigned int divisor = 85 * 85 * 85 * 85;
            while (divisor) {
                dest [char_nbr++] = encoder [value / divisor % 85];
                divisor /= 85;
            }
            value = 0;
        }
    }
    assert (char_nbr == size * 5 / 4);
    dest [char_nbr] = 0;
    return dest;
}

143

144 145 146 147
//  --------------------------------------------------------------------------
//  Decode an encoded string into a binary frame; dest must be at least
//  strlen (string) * 4 / 5 bytes long. Returns dest. strlen (string) 
//  must be a multiple of 5.
148
//  Returns NULL and sets errno = EINVAL for invalid input.
149

150
uint8_t *zmq_z85_decode (uint8_t *dest, const char *string)
151
{
152 153 154 155
    if (strlen (string) % 5 != 0) {
        errno = EINVAL;
        return NULL;
    }
156 157
    unsigned int byte_nbr = 0;
    unsigned int char_nbr = 0;
158
    unsigned int string_len = strlen (string);
159
    uint32_t value = 0;
Pieter Hintjens's avatar
Pieter Hintjens committed
160
    while (char_nbr < string_len) {
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
        //  Accumulate value in base 85
        value = value * 85 + decoder [(uint8_t) string [char_nbr++] - 32];
        if (char_nbr % 5 == 0) {
            //  Output value in base 256
            unsigned int divisor = 256 * 256 * 256;
            while (divisor) {
                dest [byte_nbr++] = value / divisor % 256;
                divisor /= 256;
            }
            value = 0;
        }
    }
    assert (byte_nbr == strlen (string) * 4 / 5);
    return dest;
}
176 177 178 179 180 181 182

//  --------------------------------------------------------------------------
//  Generate a public/private keypair with libsodium.
//  Generated keys will be 40 byte z85-encoded strings.
//  Returns 0 on success, -1 on failure, setting errno.
//  Sets errno = ENOTSUP in the absence of libsodium.

Pieter Hintjens's avatar
Pieter Hintjens committed
183
int zmq_curve_keypair (char *z85_public_key, char *z85_secret_key)
184 185 186 187 188 189 190 191 192 193 194
{
#ifdef HAVE_LIBSODIUM
#   if crypto_box_PUBLICKEYBYTES != 32 \
    || crypto_box_SECRETKEYBYTES != 32
#       error "libsodium not built correctly"
#   endif

    uint8_t public_key [32];
    uint8_t secret_key [32];

    int rc = crypto_box_keypair (public_key, secret_key);
Pieter Hintjens's avatar
Pieter Hintjens committed
195 196 197
    //  Is there a sensible errno to set here?
    if (rc)
        return rc;
198

199 200
    zmq_z85_encode (z85_public_key, public_key, 32);
    zmq_z85_encode (z85_secret_key, secret_key, 32);
201

202 203
    return 0;
#else // requires libsodium
204
    (void) z85_public_key, (void) z85_secret_key;
205 206 207 208
    errno = ENOTSUP;
    return -1;
#endif
}
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234


//  --------------------------------------------------------------------------
//  Initialize a new atomic counter, which is set to zero

void *zmq_atomic_counter_new (void)
{
    zmq::atomic_counter_t *counter = new zmq::atomic_counter_t;
    alloc_assert (counter);
    return counter;
}

//  Se the value of the atomic counter

void zmq_atomic_counter_set (void *counter_, int value_)
{
    ((zmq::atomic_counter_t *) counter_)->set (value_);
}

//  Increment the atomic counter, and return the old value

int zmq_atomic_counter_inc (void *counter_)
{
    return ((zmq::atomic_counter_t *) counter_)->add (1);
}

235 236
//  Decrement the atomic counter and return 1 (if counter >= 1), or
//  0 if counter hit zero.
237

238
int zmq_atomic_counter_dec (void *counter_)
239
{
240
    return ((zmq::atomic_counter_t *) counter_)->sub (1)? 1: 0;
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
}

//  Return actual value of atomic counter

int zmq_atomic_counter_value (void *counter_)
{
    return ((zmq::atomic_counter_t *) counter_)->get ();
}

//  Destroy atomic counter, and set reference to NULL

void zmq_atomic_counter_destroy (void **counter_p_)
{
    delete ((zmq::atomic_counter_t *) *counter_p_);
    *counter_p_ = NULL;
}