Statistics
| Branch: | Tag: | Revision:

root / src / libstrongswan / utils.c @ 098466039fff91bbff9ff28f463087188e5605b6

History | View | Annotate | Download (7.4 KB)

1
/*
2
 * Copyright (C) 2008-2009 Tobias Brunner
3
 * Copyright (C) 2005-2008 Martin Willi
4
 * Hochschule fuer Technik Rapperswil
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License as published by the
8
 * Free Software Foundation; either version 2 of the License, or (at your
9
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
10
 *
11
 * This program is distributed in the hope that it will be useful, but
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14
 * for more details.
15
 */
16
17
#include "utils.h"
18
19
#include <sys/stat.h>
20
#include <string.h>
21
#include <stdio.h>
22
#include <unistd.h>
23
#include <stdint.h>
24
#include <limits.h>
25
#include <dirent.h>
26
#include <time.h>
27
28
#include <enum.h>
29
#include <debug.h>
30
31
ENUM(status_names, SUCCESS, DESTROY_ME,
32
    "SUCCESS",
33
    "FAILED",
34
    "OUT_OF_RES",
35
    "ALREADY_DONE",
36
    "NOT_SUPPORTED",
37
    "INVALID_ARG",
38
    "NOT_FOUND",
39
    "PARSE_ERROR",
40
    "VERIFY_ERROR",
41
    "INVALID_STATE",
42
    "DESTROY_ME",
43
    "NEED_MORE",
44
);
45
46
/**
47
 * Described in header.
48
 */
49
void *clalloc(void * pointer, size_t size)
50
{
51
    void *data;
52
    data = malloc(size);
53
54
    memcpy(data, pointer, size);
55
56
    return (data);
57
}
58
59
/**
60
 * Described in header.
61
 */
62
void memxor(u_int8_t dst[], u_int8_t src[], size_t n)
63
{
64
    int m, i;
65
66
    /* byte wise XOR until dst aligned */
67
    for (i = 0; (uintptr_t)&dst[i] % sizeof(long) && i < n; i++)
68
    {
69
        dst[i] ^= src[i];
70
    }
71
    /* try to use words if src shares an aligment with dst */
72
    switch (((uintptr_t)&src[i] % sizeof(long)))
73
    {
74
        case 0:
75
            for (m = n - sizeof(long); i <= m; i += sizeof(long))
76
            {
77
                *(long*)&dst[i] ^= *(long*)&src[i];
78
            }
79
            break;
80
        case sizeof(int):
81
            for (m = n - sizeof(int); i <= m; i += sizeof(int))
82
            {
83
                *(int*)&dst[i] ^= *(int*)&src[i];
84
            }
85
            break;
86
        case sizeof(short):
87
            for (m = n - sizeof(short); i <= m; i += sizeof(short))
88
            {
89
                *(short*)&dst[i] ^= *(short*)&src[i];
90
            }
91
            break;
92
        default:
93
            break;
94
    }
95
    /* byte wise XOR of the rest */
96
    for (; i < n; i++)
97
    {
98
        dst[i] ^= src[i];
99
    }
100
}
101
102
/**
103
 * Described in header.
104
 */
105
void *memstr(const void *haystack, const char *needle, size_t n)
106
{
107
    unsigned const char *pos = haystack;
108
    size_t l = strlen(needle);
109
    for (; n >= l; ++pos, --n)
110
    {
111
        if (memeq(pos, needle, l))
112
        {
113
            return (void*)pos;
114
        }
115
    }
116
    return NULL;
117
}
118
119
/**
120
 * Described in header.
121
 */
122
bool mkdir_p(const char *path, mode_t mode)
123
{
124
    size_t len;
125
    char *pos, full[PATH_MAX];
126
    pos = full;
127
    if (!path || *path == '\0')
128
    {
129
        return TRUE;
130
    }
131
    len = snprintf(full, sizeof(full)-1, "%s", path);
132
    if (len < 0 || len >= sizeof(full)-1)
133
    {
134
        DBG1("path string %s too long", path);
135
        return FALSE;
136
    }
137
    /* ensure that the path ends with a '/' */
138
    if (full[len-1] != '/')
139
    {
140
        full[len++] = '/';
141
        full[len] = '\0';
142
    }
143
    /* skip '/' at the beginning */
144
    while (*pos == '/')
145
    {
146
        pos++;
147
    }
148
    while ((pos = strchr(pos, '/')))
149
    {
150
        *pos = '\0';
151
        if (access(full, F_OK) < 0)
152
        {
153
            if (mkdir(full, mode) < 0)
154
            {
155
                DBG1("failed to create directory %s", full);
156
                return FALSE;
157
            }
158
        }
159
        *pos = '/';
160
        pos++;
161
    }
162
    return TRUE;
163
}
164
165
/**
166
 * Return monotonic time
167
 */
168
time_t time_monotonic(timeval_t *tv)
169
{
170
#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CONDATTR_CLOCK_MONOTONIC)
171
    /* as we use time_monotonic() for condvar operations, we use the
172
     * monotonic time source only if it is also supported by pthread. */
173
    timespec_t ts;
174
175
    if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
176
    {
177
        if (tv)
178
        {
179
            tv->tv_sec = ts.tv_sec;
180
            tv->tv_usec = ts.tv_nsec / 1000;
181
        }
182
        return ts.tv_sec;
183
    }
184
#endif /* HAVE_CLOCK_MONOTONIC && HAVE_CONDATTR_CLOCK_MONOTONIC */
185
    /* Fallback to non-monotonic timestamps:
186
     * On MAC OS X, creating monotonic timestamps is rather difficult. We
187
     * could use mach_absolute_time() and catch sleep/wakeup notifications.
188
     * We stick to the simpler (non-monotonic) gettimeofday() for now.
189
     * But keep in mind: we need the same time source here as in condvar! */
190
    if (!tv)
191
    {
192
        return time(NULL);
193
    }
194
    if (gettimeofday(tv, NULL) != 0)
195
    {    /* should actually never fail if passed pointers are valid */
196
        return -1;
197
    }
198
    return tv->tv_sec;
199
}
200
201
/**
202
 * return null
203
 */
204
void *return_null()
205
{
206
    return NULL;
207
}
208
209
/**
210
 * returns TRUE
211
 */
212
bool return_true()
213
{
214
    return TRUE;
215
}
216
217
/**
218
 * returns FALSE
219
 */
220
bool return_false()
221
{
222
    return FALSE;
223
}
224
225
/**
226
 * nop operation
227
 */
228
void nop()
229
{
230
}
231
232
#ifndef HAVE_GCC_ATOMIC_OPERATIONS
233
#include <pthread.h>
234
235
/**
236
 * We use a single mutex for all refcount variables.
237
 */
238
static pthread_mutex_t ref_mutex = PTHREAD_MUTEX_INITIALIZER;
239
240
/**
241
 * Increase refcount
242
 */
243
void ref_get(refcount_t *ref)
244
{
245
    pthread_mutex_lock(&ref_mutex);
246
    (*ref)++;
247
    pthread_mutex_unlock(&ref_mutex);
248
}
249
250
/**
251
 * Decrease refcount
252
 */
253
bool ref_put(refcount_t *ref)
254
{
255
    bool more_refs;
256
257
    pthread_mutex_lock(&ref_mutex);
258
    more_refs = --(*ref);
259
    pthread_mutex_unlock(&ref_mutex);
260
    return !more_refs;
261
}
262
#endif /* HAVE_GCC_ATOMIC_OPERATIONS */
263
264
/**
265
 * Described in header.
266
 */
267
int time_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
268
                     const void *const *args)
269
{
270
    static const char* months[] = {
271
        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
272
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
273
    };
274
    time_t *time = *((time_t**)(args[0]));
275
    bool utc = *((bool*)(args[1]));;
276
    struct tm t;
277
278
    if (time == UNDEFINED_TIME)
279
    {
280
        return print_in_hook(dst, len, "--- -- --:--:--%s----",
281
                             utc ? " UTC " : " ");
282
    }
283
    if (utc)
284
    {
285
        gmtime_r(time, &t);
286
    }
287
    else
288
    {
289
        localtime_r(time, &t);
290
    }
291
    return print_in_hook(dst, len, "%s %02d %02d:%02d:%02d%s%04d",
292
                         months[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min,
293
                         t.tm_sec, utc ? " UTC " : " ", t.tm_year + 1900);
294
}
295
296
/**
297
 * Described in header.
298
 */
299
int time_delta_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
300
                           const void *const *args)
301
{
302
    char* unit = "second";
303
    time_t *arg1 = *((time_t**)(args[0]));
304
    time_t *arg2 = *((time_t**)(args[1]));
305
    time_t delta = abs(*arg1 - *arg2);
306
307
    if (delta > 2 * 60 * 60 * 24)
308
    {
309
        delta /= 60 * 60 * 24;
310
        unit = "day";
311
    }
312
    else if (delta > 2 * 60 * 60)
313
    {
314
        delta /= 60 * 60;
315
        unit = "hour";
316
    }
317
    else if (delta > 2 * 60)
318
    {
319
        delta /= 60;
320
        unit = "minute";
321
    }
322
    return print_in_hook(dst, len, "%d %s%s", delta, unit, (delta == 1)? "":"s");
323
}
324
325
/**
326
 * Number of bytes per line to dump raw data
327
 */
328
#define BYTES_PER_LINE 16
329
330
static char hexdig_upper[] = "0123456789ABCDEF";
331
332
/**
333
 * Described in header.
334
 */
335
int mem_printf_hook(char *dst, size_t dstlen,
336
                    printf_hook_spec_t *spec, const void *const *args)
337
{
338
    char *bytes = *((void**)(args[0]));
339
    int len = *((size_t*)(args[1]));
340
341
    char buffer[BYTES_PER_LINE * 3];
342
    char ascii_buffer[BYTES_PER_LINE + 1];
343
    char *buffer_pos = buffer;
344
    char *bytes_pos  = bytes;
345
    char *bytes_roof = bytes + len;
346
    int line_start = 0;
347
    int i = 0;
348
    int written = 0;
349
350
    written += print_in_hook(dst, dstlen, "=> %d bytes @ %p", len, bytes);
351
352
    while (bytes_pos < bytes_roof)
353
    {
354
        *buffer_pos++ = hexdig_upper[(*bytes_pos >> 4) & 0xF];
355
        *buffer_pos++ = hexdig_upper[ *bytes_pos       & 0xF];
356
357
        ascii_buffer[i++] =
358
                (*bytes_pos > 31 && *bytes_pos < 127) ? *bytes_pos : '.';
359
360
        if (++bytes_pos == bytes_roof || i == BYTES_PER_LINE)
361
        {
362
            int padding = 3 * (BYTES_PER_LINE - i);
363
364
            while (padding--)
365
            {
366
                *buffer_pos++ = ' ';
367
            }
368
            *buffer_pos++ = '\0';
369
            ascii_buffer[i] = '\0';
370
371
            written += print_in_hook(dst, dstlen, "\n%4d: %s  %s",
372
                                     line_start, buffer, ascii_buffer);
373
374
            buffer_pos = buffer;
375
            line_start += BYTES_PER_LINE;
376
            i = 0;
377
        }
378
        else
379
        {
380
            *buffer_pos++ = ' ';
381
        }
382
    }
383
    return written;
384
}