📄 su_uniqueid.c
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library 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 2.1 of * the License, or (at your option) any later version. * * This library 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@defgroup su_uniqueid GloballyUniqueIDs * * Globally unique IDs and random integers. * * GloballyUniqueID or #su_guid_t is a 128-bit identifier based on current * time and MAC address of the node generating the ID. A new ID is generated * each time su_guid_generate() is called. Please note that such IDs are @b * not unique if multiple processes are run on the same node. * * Use su_guid_sprintf() to convert #su_guid_t to printable format. * * The random integers can be generated with functions * - su_randint(), * - su_randmem(), or * - su_random(). *//**@ingroup su_uniqueid * * @CFILE su_uniqueid.c Construct a GloballyUniqueID as per H.225.0 v2. * * @author Pekka Pessi <pessi@research.nokia.com> * * @date Created: Tue Apr 15 06:31:41 1997 pessi */#include "config.h"#if defined(_WIN32)int _getpid(void);#define getpid _getpid#endif#include <string.h>#include <stdio.h>#include <stdlib.h>#include <time.h>#if HAVE_UNISTD_H#include <sys/types.h>#include <unistd.h>#endif#include "sofia-sip/su.h"#include "sofia-sip/su_time.h"#include "sofia-sip/su_uniqueid.h"/* For random number generator */static int initialized = 0;static void init(void);static void init_node(void);/* Constants */static const unsigned version = 1; /* Current version */static const unsigned reserved = 128; /* DCE variant */#define granularity (10000000UL)static const uint64_t mask60 = SU_U64_C(0xfffFFFFffffFFFF);#define MAGIC (16384)/* 100-nanosecond intervals between 15 October 1582 and 1 January 1900 */static const uint64_t ntp_epoch = (uint64_t)(141427) * (24 * 60 * 60L) * granularity;/* State */static uint64_t timestamp0 = 0;static unsigned clock_sequence = MAGIC;static unsigned char node[6];FILE *urandom;/* * Get current timestamp */static uint64_t timestamp(void){ uint64_t tl = su_ntp_now(); uint64_t hi = su_ntp_hi(tl), lo = su_ntp_lo(tl); lo *= granularity; hi *= granularity; tl = hi + (lo >> 32) + ntp_epoch;#ifdef TESTING printf("timestamp %08x-%08x\n", (unsigned)(tl >>32), (unsigned)tl);#endif tl &= mask60; if (tl <= timestamp0) clock_sequence = (clock_sequence + 1) & (MAGIC - 1); timestamp0 = tl; return tl;}#if !HAVE_RANDOM#define random() rand()#define srandom(x) srand(x)#endif/* * Initialize clock_sequence and timestamp0 */static void init(void){ int i; static uint32_t seed[32] = { 0 }; su_time_t now; initialized = 1; /* Initialize our random number generator */#if HAVE_DEV_URANDOM if (!urandom) urandom = fopen("/dev/urandom", "rb");#endif /* HAVE_DEV_URANDOM */ if (urandom) { fread(seed, sizeof seed, 1, urandom); } else { for (i = 0; i < 16; i++) {#if HAVE_CLOCK_GETTIME struct timespec ts; (void)clock_gettime(CLOCK_REALTIME, &ts); seed[2*i] ^= ts.tv_sec; seed[2*i+1] ^= ts.tv_nsec;#endif su_time(&now); seed[2*i] ^= now.tv_sec; seed[2*i+1] ^= now.tv_sec; } seed[30] ^= getuid(); seed[31] ^= getpid(); }#if HAVE_INITSTATE initstate(seed[0] ^ seed[1], (char *)&seed, sizeof(seed));#else srand(seed[0] ^ seed[1]);#endif clock_sequence = su_randint(0, MAGIC - 1); (void)timestamp(); init_node();}#if HAVE_GETIFADDRS#include <ifaddrs.h>#if HAVE_NETPACKET_PACKET_H#define HAVE_SOCKADDR_LL 1#include <netpacket/packet.h>#include <net/if_arp.h>#endif#endifstaticvoid init_node(void){ int i;#if HAVE_GETIFADDRS && HAVE_SOCKADDR_LL struct ifaddrs *ifa, *results; if (getifaddrs(&results) == 0) { for (ifa = results; ifa; ifa = ifa->ifa_next) {#if HAVE_SOCKADDR_LL struct sockaddr_ll const *sll = (void *)ifa->ifa_addr; if (sll->sll_family != AF_PACKET) continue; switch (sll->sll_hatype) { case ARPHRD_ETHER: case ARPHRD_EETHER: case ARPHRD_IEEE802: break; default: continue; } memcpy(node, sll->sll_addr, sizeof node); break;#endif } freeifaddrs(results); if (ifa) return; /* Success */ }#endif if (urandom) { fread(node, sizeof node, 1, urandom); } else for (i = 0; i < sizeof(node); i++) { unsigned r = random(); node[i] = (r >> 24) ^ (r >> 16) ^ (r >> 8) ^ r; } node[0] |= 1; /* "multicast" address */}size_t su_node_identifier(void *address, size_t addrlen){ if (addrlen > sizeof node) addrlen = sizeof node; if (!initialized) init(); memcpy(address, node, addrlen); return addrlen;}void su_guid_generate(su_guid_t *v){ uint64_t time; unsigned clock; if (!initialized) init(); time = timestamp(); clock = clock_sequence; v->s.time_high_and_version = htons((unsigned short)(((time >> 48) & 0x0fff) | (version << 12))); v->s.time_mid = htons((unsigned short)((time >> 32) & 0xffff)); v->s.time_low = htonl((unsigned long)(time & 0xffffffffUL)); v->s.clock_seq_low = clock & 0xff; v->s.clock_seq_hi_and_reserved = (clock >> 8) | reserved; memcpy(v->s.node, node, sizeof(v->s.node));}/* * Human-readable form of GloballyUniqueID */int su_guid_sprintf(char* buf, size_t len, su_guid_t const *v){ char mybuf[su_guid_strlen + 1]; sprintf(mybuf, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", (unsigned long)ntohl(v->s.time_low), ntohs(v->s.time_mid), ntohs(v->s.time_high_and_version), v->s.clock_seq_low, v->s.clock_seq_hi_and_reserved, v->s.node[0], v->s.node[1], v->s.node[2], v->s.node[3], v->s.node[4], v->s.node[5]); memcpy(buf, mybuf, len > sizeof(mybuf) ? sizeof(mybuf) : len); return su_guid_strlen;}/* * Generate random integer in range [lb, ub] (inclusive) */int su_randint(int lb, int ub){ unsigned rnd = 0; if (!initialized) init(); rnd = random(); if (ub - lb + 1 != 0) rnd %= (ub - lb + 1); return rnd + lb;}void *su_randmem(void *mem, size_t siz){ size_t i; if (!initialized) init(); for (i = 0; i < siz; i++) { unsigned r = random(); ((char *)mem)[i] = (r >> 24) ^ (r >> 16) ^ (r >> 8) ^ r; } return mem;}/** Get random number for RTP timestamps. * * This function returns a 32-bit random integer. It also initializes the * random number generator, if needed. */uint32_t su_random(void){ if (!initialized) init(); return (uint32_t)random();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -