From 8af6b12ee8716d2004d13bbfc81281953975b466 Mon Sep 17 00:00:00 2001
From: open-license-manager <rillf@maildrop.cc>
Date: 周一, 04 8月 2014 00:15:33 +0800
Subject: [PATCH] new identifier strategy (to be reverted

---
 test/scratch/stackoverflow.cpp  |  187 +++++++++++++
 test/functional/CMakeLists.txt  |   14 +
 test/scratch/base62.c           |  131 +++++++++
 src/library/os/linux/os-linux.c |   24 +
 test/scratch/pc-identifiers.c   |  415 +++++++++++++++++++++++++++++
 test/functional/volid_test.cpp  |   10 
 src/library/pc-identifiers.c    |   22 +
 7 files changed, 791 insertions(+), 12 deletions(-)

diff --git a/src/library/os/linux/os-linux.c b/src/library/os/linux/os-linux.c
index b791859..af828bd 100644
--- a/src/library/os/linux/os-linux.c
+++ b/src/library/os/linux/os-linux.c
@@ -31,6 +31,9 @@
 #include <dirent.h>
 #include <stdio.h>
 
+#include <dbus-1.0/dbus/dbus.h>
+#include <sys/utsname.h>
+
 static int ifname_position(char *ifnames, char * ifname, int ifnames_max) {
 	int i, position;
 	position = -1;
@@ -49,7 +52,7 @@
 
 	FUNCTION_RETURN f_return = OK;
 	struct ifaddrs *ifaddr, *ifa;
-	int family, i,  n, if_name_position;
+	int family, i, n, if_name_position;
 	unsigned int if_num, if_max;
 	//char host[NI_MAXHOST];
 	char *ifnames;
@@ -408,3 +411,22 @@
 	return NONE;
 }
 
+FUNCTION_RETURN getMachineName(unsigned char identifier[6]) {
+	static struct utsname u;
+
+	if (uname(&u) < 0) {
+		return ERROR;
+	}
+	memcpy(identifier, u.nodename, 6);
+	return OK;
+}
+
+FUNCTION_RETURN getOsSpecificIdentifier(unsigned char identifier[6]) {
+	char* dbus_id = dbus_get_local_machine_id();
+	if (dbus_id == NULL) {
+		return ERROR;
+	}
+	memcpy(identifier, dbus_id, 6);
+	dbus_free(dbus_id);
+	return OK;
+}
diff --git a/src/library/pc-identifiers.c b/src/library/pc-identifiers.c
index e674d77..07a362a 100644
--- a/src/library/pc-identifiers.c
+++ b/src/library/pc-identifiers.c
@@ -13,6 +13,14 @@
 #include "base/base64.h"
 #include <valgrind/memcheck.h>
 
+FUNCTION_RETURN generate_ethernet_pc_id(PcIdentifier * identifiers,
+		unsigned int * num_identifiers, bool use_mac);
+static void encodeStrategy(PcIdentifier * identifier,
+		IDENTIFICATION_STRATEGY strategy);
+static FUNCTION_RETURN generate_platform_specific_pc_id(
+		PcIdentifier * identifiers, unsigned int * num_identifiers);
+
+
 static FUNCTION_RETURN generate_default_pc_id(PcIdentifier * identifiers,
 		unsigned int * num_identifiers) {
 	size_t adapter_num, disk_num, plat_spec_id;
@@ -64,18 +72,20 @@
 					identifiers[current_identifier][k] = diskInfos[i].disk_sn[k
 							+ 2] ^ adapterInfos[j].mac_address[k + 2];
 				}
-				encodeStrategy(identifiers[current_identifier], DEFAULT);
+				encodeStrategy(&identifiers[current_identifier], DEFAULT);
 				current_identifier++;
 			}
 		}
 		free(diskInfos);
 		free(adapterInfos);
 	} else if (result_adapterInfos == OK) {
+		i=defined_identifiers-current_identifier;
 		return generate_ethernet_pc_id(&identifiers[current_identifier],
-				defined_identifiers-current_identifier, true);
+				&i, true);
 	} else if (result_diskinfos == OK) {
+		i=defined_identifiers-current_identifier;
 		return generate_disk_pc_id(&identifiers[current_identifier],
-				defined_identifiers-current_identifier, false);
+				&i, false);
 	}
 
 	return OK;
@@ -84,12 +94,14 @@
 static void encodeStrategy(PcIdentifier * identifier,
 		IDENTIFICATION_STRATEGY strategy) {
 	unsigned char strategy_num = strategy << 5;
-	identifier[0] = (identifier[0] & 15) | strategy_num;
+	identifier[0][0] = (identifier[0][0] & 15)
+
+					++     | strategy_num;
 
 }
 
 static FUNCTION_RETURN generate_platform_specific_pc_id(
-		PcIdentifier * identifiers, unsigned int * num_identifiers) {
+		   * identifiers, unsigned int * num_identifiers) {
 
 }
 
diff --git a/test/functional/CMakeLists.txt b/test/functional/CMakeLists.txt
index 66c8195..86296ab 100644
--- a/test/functional/CMakeLists.txt
+++ b/test/functional/CMakeLists.txt
@@ -44,3 +44,17 @@
 ADD_TEST(standard_license_test ${EXECUTABLE_OUTPUT_PATH}/standard_license_test)
 ADD_TEST(date_test ${EXECUTABLE_OUTPUT_PATH}/date_test)
 ADD_TEST(volid_test ${EXECUTABLE_OUTPUT_PATH}/volid_test)
+
+
+
+add_executable(
+ stackoverflow
+ stackoverflow.cpp
+)
+
+target_link_libraries(
+    stackoverflow
+    license_generator_lib
+)
+
+SET_TARGET_PROPERTIES(stackoverflow PROPERTIES LINK_SEARCH_START_STATIC ON)
\ No newline at end of file
diff --git a/test/functional/volid_test.cpp b/test/functional/volid_test.cpp
index 501c815..4e1e847 100644
--- a/test/functional/volid_test.cpp
+++ b/test/functional/volid_test.cpp
@@ -11,12 +11,12 @@
 #include "../../src/library/ini/SimpleIni.h"
 #include "generate-license.h"
 #include "../../src/library/pc-identifiers.h"
-#include <dbus/dbus.h>
+#include <dbus-1.0/dbus/dbus.h>
 
 namespace fs = boost::filesystem;
 using namespace license;
 using namespace std;
-/*
+
  BOOST_AUTO_TEST_CASE( default_volid_lic_file ) {
  const string licLocation(PROJECT_TEST_TEMP_DIR "/volid_license.lic");
  PcSignature identifier_out;
@@ -99,7 +99,5 @@
  }
  }
  }
- */
-BOOST_AUTO_TEST_CASE( ciiii ) {
-	cout << dbus_get_local_machine_id() << endl;
-}
+
+
diff --git a/test/scratch/base62.c b/test/scratch/base62.c
new file mode 100644
index 0000000..7fae217
--- /dev/null
+++ b/test/scratch/base62.c
@@ -0,0 +1,131 @@
+
+
+/* Division by 62 on an arbitrary length input.
+   (TODO: Note: the cast will segfault on some systems, so you will need
+   to use a memcpy instead).
+   Also TODO: Optimisation: use >32 bit integers if available.
+ */
+static void b62_divide(const unsigned char* dividend, int dividend_len,
+					   unsigned char* quotient, unsigned int* remainder)
+{
+	unsigned int quantity;
+	int i;
+
+	quantity = 0;
+	for (i=dividend_len-2;i>=0;i-=2) {
+		quantity |= *((unsigned short*)&dividend[i]);
+		*((unsigned short *)&quotient[i]) = (unsigned short)(quantity/62);
+		quantity = (quantity%62)<<16;
+	}
+	*remainder = quantity>>16;
+}
+
+/* pseudo-base62 encode
+	base62 encoding is not a very nice mapping to character data.  The only
+	way that we can properly do this is to divide by 62 each time and get
+	the remainder, this will ensure full use of the base62 space.  This is
+	/not/ very performant.  So instead we operate the base62 encoding on
+	56 bit (7 byte) chunks.  This gives a pretty good usage, with far less
+	lengthy division operations on moderately sized input.  I only did this
+	for completeness as I got interested in it, but we can prove that you have
+	to do the full division each time (although you may find a better way of
+	implementing it!) as follows.  We want to encode data as a bitstream, so
+	we want to find N,M s.t. 62^M = 2^N, and M,N are integers.  There are
+	no such M,N (proof on request).  For base64 encoding we get 64^M = 2^N,
+	obviously we can fit M=1,N=6 which equates to sucking up 6 bits each time
+	for the encoding algorithm.  So instead we try to find a comprise between
+	the the block size, and the number of bits wasted by the conversion to
+	base62 space.  The constraints here are
+
+	(1) we want to deal with whole numbers of bytes to simplify the code
+	(2) we want to waste as little of the encoding space as possible
+	(3) we want to keep the division operations restricted to a reasonable
+	number of bits as the running time of the division operation depends
+	on the length of the input bit string.
+
+	The ratio of the length of the bit strings in the two bases will be
+	log2(256)/log2(62)
+	For base64 encoding we get 4/3 exactly.  So to minimize waste here we
+	want to take chunks of 3 bytes, then there is no wastage between blocks.
+	For base62 encoding we get ~1.34.  Picking 5 as the block size wastes
+	some 30% of the encoding space for the last byte.  Let me know if you
+	think another pick is better.  This one means that we are operating
+	on 40-bit strings, so the division isn't too strenuous to compute, and
+	on a 64-bit platform can be done all in a register.
+ */
+#define msg_id_length (((134359*(sizeof(time_t)+sizeof(int)*2))/100000)+2)
+
+static char base62_tab[62] = {
+	'A','B','C','D','E','F','G','H',
+	'I','J','K','L','M','N','O','P',
+	'Q','R','S','T','U','V','W','X',
+	'Y','Z','a','b','c','d','e','f',
+	'g','h','i','j','k','l','m','n',
+	'o','p','q','r','s','t','u','v',
+	'w','x','y','z','0','1','2','3',
+	'4','5','6','7','8','9'
+};
+
+int b62_encode(char* out, const unsigned char* data, int length, int linelength)
+{
+	int i,j;
+	char *start = out;
+	uint64_t bitstring;
+
+	linelength;
+	for (i=0;i<length-4;i+=5) {
+		bitstring =
+			(uint64_t)data[i]<<32|(uint64_t)data[i+1]<<24|(uint64_t)data[i+2]<<16|
+			(uint64_t)data[i+3]<<8|(uint64_t)data[i+4];
+
+		for (j=0;j<7;++j) {
+			*out++ = base62_tab[bitstring%62];
+			bitstring /= 62;
+		}
+/*
+		b62_divide(quotient,len,quotient,&rem);
+		*out++ = base62_tab[rem];
+		for (j=1;j<len;++j) {
+			b62_divide(quotient,len,quotient,&rem);
+			*out++ = base62_tab[rem];
+		}*/
+	}
+	switch (length-i) {
+	case 1:
+		*out++ = base62_tab[data[i]%62];
+		*out++ = base62_tab[data[i]/62];
+		break;
+	case 2:
+		bitstring = data[i]<<8|data[i+1];
+		*out++ = base62_tab[bitstring%62];
+		bitstring /= 62;
+		*out++ = base62_tab[bitstring%62];
+		*out++ = base62_tab[bitstring/62];
+		break;
+	case 3:
+		bitstring = data[i]<<16|data[i+1]<<8|data[i];
+		*out++ = base62_tab[bitstring%62];
+		bitstring /= 62;
+		*out++ = base62_tab[bitstring%62];
+		bitstring /= 62;
+		*out++ = base62_tab[bitstring%62];
+		bitstring /= 62;
+		*out++ = base62_tab[bitstring%62];
+		*out++ = base62_tab[bitstring/62];
+		break;
+	case 4:
+		bitstring = data[i]<<24|data[i+1]<<16|data[i+2]<<8|data[i];
+		*out++ = base62_tab[bitstring%62];
+		bitstring /= 62;
+		*out++ = base62_tab[bitstring%62];
+		bitstring /= 62;
+		*out++ = base62_tab[bitstring%62];
+		bitstring /= 62;
+		*out++ = base62_tab[bitstring%62];
+		bitstring /= 62;
+		*out++ = base62_tab[bitstring%62];
+		*out++ = base62_tab[bitstring/62];
+		break;
+	}
+	return (int)(out-start);
+}
diff --git a/test/scratch/pc-identifiers.c b/test/scratch/pc-identifiers.c
new file mode 100644
index 0000000..07a362a
--- /dev/null
+++ b/test/scratch/pc-identifiers.c
@@ -0,0 +1,415 @@
+/*
+ * pc-identifiers.c
+ *
+ *  Created on: Apr 16, 2014
+ *      Author: devel
+ */
+
+#include "os/os.h"
+#include "pc-identifiers.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include "base/base64.h"
+#include <valgrind/memcheck.h>
+
+FUNCTION_RETURN generate_ethernet_pc_id(PcIdentifier * identifiers,
+		unsigned int * num_identifiers, bool use_mac);
+static void encodeStrategy(PcIdentifier * identifier,
+		IDENTIFICATION_STRATEGY strategy);
+static FUNCTION_RETURN generate_platform_specific_pc_id(
+		PcIdentifier * identifiers, unsigned int * num_identifiers);
+
+
+static FUNCTION_RETURN generate_default_pc_id(PcIdentifier * identifiers,
+		unsigned int * num_identifiers) {
+	size_t adapter_num, disk_num, plat_spec_id;
+	FUNCTION_RETURN result_adapterInfos, result_diskinfos, result_plat_spec;
+	unsigned int required_id_size, current_identifier, i, j, k;
+	DiskInfo * diskInfos;
+	AdapterInfo *adapterInfos;
+	required_id_size = 0;
+
+	//just calculate the number of required identifiers
+	result_plat_spec = generate_platform_specific_pc_id(NULL, &plat_spec_id);
+	if (result_plat_spec == OK) {
+		required_id_size += 1;
+	}
+	result_adapterInfos = getAdapterInfos(NULL, &adapter_num);
+	result_diskinfos = getDiskInfos(NULL, &disk_num);
+	if (result_diskinfos == OK && result_adapterInfos == OK) {
+		required_id_size += disk_num * adapter_num;
+	} else if (result_adapterInfos == OK) {
+		required_id_size += adapter_num;
+	} else if (result_diskinfos == OK) {
+		required_id_size += disk_num;
+	}
+	int defined_identifiers = *num_identifiers;
+	if (identifiers == NULL) {
+		*num_identifiers = required_id_size;
+		return OK;
+	} else if (required_id_size > defined_identifiers) {
+		return BUFFER_TOO_SMALL;
+	}
+
+	//calculate the identifiers
+	current_identifier = 0;
+	if (result_plat_spec == OK) {
+		generate_platform_specific_pc_id(identifiers, 1);
+		current_identifier += 1;
+	}
+	if (result_diskinfos == OK && result_adapterInfos == OK) {
+		diskInfos = (DiskInfo*) malloc(disk_num * sizeof(DiskInfo));
+		result_diskinfos = getDiskInfos(diskInfos, &disk_num);
+		adapterInfos = (AdapterInfo*) malloc(adapter_num * sizeof(AdapterInfo));
+		result_adapterInfos = getAdapterInfos(adapterInfos, &adapter_num);
+		for (i = 0; i < disk_num; i++) {
+			for (j = 0; j < adapter_num; j++) {
+				if (current_identifier > defined_identifiers) {
+					break;
+				}
+				for (k = 0; k < 6; k++) {
+					identifiers[current_identifier][k] = diskInfos[i].disk_sn[k
+							+ 2] ^ adapterInfos[j].mac_address[k + 2];
+				}
+				encodeStrategy(&identifiers[current_identifier], DEFAULT);
+				current_identifier++;
+			}
+		}
+		free(diskInfos);
+		free(adapterInfos);
+	} else if (result_adapterInfos == OK) {
+		i=defined_identifiers-current_identifier;
+		return generate_ethernet_pc_id(&identifiers[current_identifier],
+				&i, true);
+	} else if (result_diskinfos == OK) {
+		i=defined_identifiers-current_identifier;
+		return generate_disk_pc_id(&identifiers[current_identifier],
+				&i, false);
+	}
+
+	return OK;
+}
+
+static void encodeStrategy(PcIdentifier * identifier,
+		IDENTIFICATION_STRATEGY strategy) {
+	unsigned char strategy_num = strategy << 5;
+	identifier[0][0] = (identifier[0][0] & 15)
+
+					++     | strategy_num;
+
+}
+
+static FUNCTION_RETURN generate_platform_specific_pc_id(
+		   * identifiers, unsigned int * num_identifiers) {
+
+}
+
+static FUNCTION_RETURN generate_ethernet_pc_id(PcIdentifier * identifiers,
+		unsigned int * num_identifiers, bool use_mac) {
+	size_t adapters;
+	FUNCTION_RETURN result_adapterInfos;
+	unsigned int j, k;
+	AdapterInfo *adapterInfos;
+
+	result_adapterInfos = getAdapterInfos(NULL, &adapters);
+	if (result_adapterInfos != OK) {
+		return result_adapterInfos;
+	}
+
+	int defined_adapters = *num_identifiers;
+	*num_identifiers = adapters;
+	if (identifiers == NULL) {
+		return OK;
+	} else if (adapters > defined_adapters) {
+		return BUFFER_TOO_SMALL;
+	}
+
+	adapterInfos = (AdapterInfo*) malloc(adapters * sizeof(AdapterInfo));
+	result_adapterInfos = getAdapterInfos(adapterInfos, &adapters);
+	for (j = 0; j < adapters; j++) {
+		for (k = 0; k < 6; k++)
+			if (use_mac) {
+				identifiers[j][k] = adapterInfos[j].mac_address[k + 2];
+			} else {
+				//use ip
+				if (k < 4) {
+					identifiers[j][k] = adapterInfos[j].ipv4_address[k];
+				} else {
+					//padding
+					identifiers[j][k] = 42;
+				}
+			}
+	}
+	free(adapterInfos);
+	return OK;
+}
+
+static FUNCTION_RETURN generate_disk_pc_id(PcIdentifier * identifiers,
+		unsigned int * num_identifiers, bool use_label) {
+	size_t disk_num, available_disk_info = 0;
+	FUNCTION_RETURN result_diskinfos;
+	unsigned int i, j;
+	char firstChar;
+	DiskInfo * diskInfos;
+
+	result_diskinfos = getDiskInfos(NULL, &disk_num);
+	if (result_diskinfos != OK) {
+		return result_diskinfos;
+	}
+	diskInfos = (DiskInfo*) malloc(disk_num * sizeof(DiskInfo));
+//memset(diskInfos,0,disk_num * sizeof(DiskInfo));
+	result_diskinfos = getDiskInfos(diskInfos, &disk_num);
+	if (result_diskinfos != OK) {
+		free(diskInfos);
+		return result_diskinfos;
+	}
+	for (i = 0; i < disk_num; i++) {
+		firstChar = use_label ? diskInfos[i].label[0] : diskInfos[i].disk_sn[0];
+		available_disk_info += firstChar == 0 ? 0 : 1;
+	}
+
+	int defined_identifiers = *num_identifiers;
+	*num_identifiers = available_disk_info;
+	if (identifiers == NULL) {
+		free(diskInfos);
+		return OK;
+	} else if (available_disk_info > defined_identifiers) {
+		free(diskInfos);
+		return BUFFER_TOO_SMALL;
+	}
+
+	j = 0;
+	for (i = 0; i < disk_num; i++) {
+		if (use_label) {
+			if (diskInfos[i].label[0] != 0) {
+				memset(identifiers[j], 0, sizeof(PcIdentifier)); //!!!!!!!
+				strncpy(identifiers[j], diskInfos[i].label,
+						sizeof(PcIdentifier));
+				j++;
+			}
+		} else {
+			if (diskInfos[i].disk_sn[0] != 0) {
+				memcpy(identifiers[j], &diskInfos[i].disk_sn[2],
+						sizeof(PcIdentifier));
+				j++;
+			}
+		}
+	}
+	free(diskInfos);
+	return OK;
+}
+
+/**
+ *
+ * Calculates all the possible identifiers for the current machine, for the
+ * given calculation strategy requested. Pc identifiers are more than one,
+ * for instance a machine with more than one disk and one network interface has
+ * usually multiple identifiers.
+ *
+ * First 4 bit of each pc identifier are reserved 3 for the type of strategy
+ * used in calculation and 1 for parity checks (not implemented here)
+ *
+ * @param identifiers
+ * @param array_size
+ * @param
+ * @return
+ */
+FUNCTION_RETURN generate_pc_id(PcIdentifier * identifiers,
+		unsigned int * array_size, IDENTIFICATION_STRATEGY strategy) {
+	FUNCTION_RETURN result;
+	unsigned int i, j;
+	const unsigned int original_array_size = *array_size;
+	unsigned char strategy_num;
+	switch (strategy) {
+	case DEFAULT:
+		result = generate_default_pc_id(identifiers, array_size);
+		break;
+	case ETHERNET:
+		result = generate_ethernet_pc_id(identifiers, array_size, true);
+		break;
+	case IP_ADDRESS:
+		result = generate_ethernet_pc_id(identifiers, array_size, false);
+		break;
+	case DISK_NUM:
+		result = generate_disk_pc_id(identifiers, array_size, false);
+		break;
+	case PLATFORM_SPECIFIC:
+		result = generate_platform_specific_pc_id(identifiers, array_size);
+		break;
+	default:
+		return ERROR;
+	}
+
+	if (result == OK && identifiers != NULL) {
+		//fill array if larger
+		for (i = *array_size; i < original_array_size; i++) {
+			identifiers[i][0] = STRATEGY_UNKNOWN << 5;
+			for (j = 1; j < sizeof(PcIdentifier); j++) {
+				identifiers[i][j] = 42; //padding
+			}
+		}
+	}
+	return result;
+}
+
+char *MakeCRC(char *BitString) {
+	static char Res[3];                                 // CRC Result
+	char CRC[2];
+	int i;
+	char DoInvert;
+
+	for (i = 0; i < 2; ++i)
+		CRC[i] = 0;                    // Init before calculation
+
+	for (i = 0; i < strlen(BitString); ++i) {
+		DoInvert = ('1' == BitString[i]) ^ CRC[1];         // XOR required?
+
+		CRC[1] = CRC[0];
+		CRC[0] = DoInvert;
+	}
+
+	for (i = 0; i < 2; ++i)
+		Res[1 - i] = CRC[i] ? '1' : '0'; // Convert binary to ASCII
+	Res[2] = 0;                                         // Set string terminator
+
+	return (Res);
+}
+
+FUNCTION_RETURN encode_pc_id(PcIdentifier identifier1, PcIdentifier identifier2,
+		PcSignature pc_identifier_out) {
+//TODO base62 encoding, now uses base64
+	PcIdentifier concat_identifiers[2];
+	int b64_size = 0;
+	size_t concatIdentifiersSize = sizeof(PcIdentifier) * 2;
+//concat_identifiers = (PcIdentifier *) malloc(concatIdentifiersSize);
+	memcpy(&concat_identifiers[0], identifier1, sizeof(PcIdentifier));
+	memcpy(&concat_identifiers[1], identifier2, sizeof(PcIdentifier));
+	char* b64_data = base64(concat_identifiers, concatIdentifiersSize,
+			&b64_size);
+	if (b64_size > sizeof(PcSignature)) {
+		return BUFFER_TOO_SMALL;
+	}
+	sprintf(pc_identifier_out, "%.4s-%.4s-%.4s-%.4s", &b64_data[0],
+			&b64_data[4], &b64_data[8], &b64_data[12]);
+//free(concat_identifiers);
+	free(b64_data);
+	return OK;
+}
+
+FUNCTION_RETURN parity_check_id(PcSignature pc_identifier) {
+	return OK;
+}
+
+FUNCTION_RETURN generate_user_pc_signature(PcSignature identifier_out,
+		IDENTIFICATION_STRATEGY strategy) {
+	FUNCTION_RETURN result;
+	PcIdentifier* identifiers;
+	unsigned int req_buffer_size = 0;
+	result = generate_pc_id(NULL, &req_buffer_size, strategy);
+	if (result != OK) {
+		return result;
+	}
+	if (req_buffer_size == 0) {
+		return ERROR;
+	}
+	req_buffer_size = req_buffer_size < 2 ? 2 : req_buffer_size;
+	identifiers = (PcIdentifier *) malloc(
+			sizeof(PcIdentifier) * req_buffer_size);
+	result = generate_pc_id(identifiers, &req_buffer_size, strategy);
+	if (result != OK) {
+		free(identifiers);
+		return result;
+	}
+	VALGRIND_CHECK_VALUE_IS_DEFINED(identifiers[0]);
+	VALGRIND_CHECK_VALUE_IS_DEFINED(identifiers[1]);
+	result = encode_pc_id(identifiers[0], identifiers[1], identifier_out);
+	VALGRIND_CHECK_VALUE_IS_DEFINED(identifier_out);
+	free(identifiers);
+	return result;
+}
+
+/**
+ * Extract the two pc identifiers from the user provided code.
+ * @param identifier1_out
+ * @param identifier2_out
+ * @param str_code: the code in the string format XXXX-XXXX-XXXX-XXXX
+ * @return
+ */
+static FUNCTION_RETURN decode_pc_id(PcIdentifier identifier1_out,
+		PcIdentifier identifier2_out, PcSignature pc_signature_in) {
+//TODO base62 encoding, now uses base64
+
+	unsigned char * concat_identifiers;
+	char base64ids[17];
+	int identifiers_size;
+
+	sscanf(pc_signature_in, "%4s-%4s-%4s-%4s", &base64ids[0], &base64ids[4],
+			&base64ids[8], &base64ids[12]);
+	concat_identifiers = unbase64(base64ids, 16, &identifiers_size);
+	if (identifiers_size > sizeof(PcIdentifier) * 2) {
+		return BUFFER_TOO_SMALL;
+	}
+	memcpy(identifier1_out, concat_identifiers, sizeof(PcIdentifier));
+	memcpy(identifier2_out, concat_identifiers + sizeof(PcIdentifier),
+			sizeof(PcIdentifier));
+	free(concat_identifiers);
+	return OK;
+}
+
+static IDENTIFICATION_STRATEGY strategy_from_pc_id(PcIdentifier identifier) {
+	return (IDENTIFICATION_STRATEGY) identifier[0] >> 5;
+}
+
+EVENT_TYPE validate_pc_signature(PcSignature str_code) {
+	PcIdentifier user_identifiers[2];
+	FUNCTION_RETURN result;
+	IDENTIFICATION_STRATEGY previous_strategy_id, current_strategy_id;
+	PcIdentifier* calculated_identifiers = NULL;
+	unsigned int calc_identifiers_size = 0;
+	int i = 0, j = 0;
+//bool found;
+#ifdef _DEBUG
+	printf("Comparing pc identifiers: \n");
+#endif
+	result = decode_pc_id(user_identifiers[0], user_identifiers[1], str_code);
+	if (result != OK) {
+		return result;
+	}
+	previous_strategy_id = STRATEGY_UNKNOWN;
+//found = false;
+	for (i = 0; i < 2; i++) {
+		current_strategy_id = strategy_from_pc_id(user_identifiers[i]);
+		if (current_strategy_id == STRATEGY_UNKNOWN) {
+			return LICENSE_MALFORMED;
+		}
+		if (current_strategy_id != previous_strategy_id) {
+			if (calculated_identifiers != NULL) {
+				free(calculated_identifiers);
+			}
+			previous_strategy_id = current_strategy_id;
+			generate_pc_id(NULL, &calc_identifiers_size, current_strategy_id);
+			calculated_identifiers = (PcIdentifier *) malloc(
+					sizeof(PcIdentifier) * calc_identifiers_size);
+			generate_pc_id(calculated_identifiers, &calc_identifiers_size,
+					current_strategy_id);
+		}
+		//maybe skip the byte 0
+		for (j = 0; j < calc_identifiers_size; j++) {
+#ifdef _DEBUG
+			printf("generated id: %02x%02x%02x%02x%02x%02x index %d, user_supplied id %02x%02x%02x%02x%02x%02x idx: %d\n",
+					calculated_identifiers[j][0],calculated_identifiers[j][1],calculated_identifiers[j][2],
+					calculated_identifiers[j][3],calculated_identifiers[j][4],calculated_identifiers[j][5],j,
+					user_identifiers[i][0],user_identifiers[i][1],user_identifiers[i][2],user_identifiers[i][3],user_identifiers[i][4],user_identifiers[i][5],i);
+
+#endif
+			if (!memcmp(user_identifiers[i], calculated_identifiers[j],
+					sizeof(PcIdentifier))) {
+				free(calculated_identifiers);
+				return LICENSE_OK;
+			}
+		}
+	}
+	free(calculated_identifiers);
+	return IDENTIFIERS_MISMATCH;
+}
diff --git a/test/scratch/stackoverflow.cpp b/test/scratch/stackoverflow.cpp
new file mode 100644
index 0000000..198bfc8
--- /dev/null
+++ b/test/scratch/stackoverflow.cpp
@@ -0,0 +1,187 @@
+//http://stackoverflow.com/questions/16858782/how-to-obtain-almost-unique-system-identifier-in-a-cross-platform-way
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/utsname.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <assert.h>
+#include <stdbool.h>
+
+#ifdef DARWIN
+#include <net/if_dl.h>
+#include <ifaddrs.h>
+#include <net/if_types.h>
+#else //!DARWIN
+#include <linux/if.h>
+#include <linux/sockios.h>
+#endif //!DARWIN
+
+const char* getMachineName() {
+	static struct utsname u;
+
+	if (uname(&u) < 0) {
+		assert(0);
+		return "unknown";
+	}
+
+	return u.nodename;
+}
+
+//---------------------------------get MAC addresses ------------------------------------unsigned short-unsigned short----------
+// we just need this for purposes of unique machine id. So any one or two mac's is fine.
+unsigned short hashMacAddress(unsigned char* mac) {
+	unsigned short hash = 0;
+
+	for (unsigned int i = 0; i < 6; i++) {
+		hash += (mac[i] << ((i & 1) * 8));
+	}
+	return hash;
+}
+
+void getMacHash(unsigned short *mac1, unsigned short *mac2) {
+	*mac1 = 0;
+	*mac2 = 0;
+
+#ifdef DARWIN
+
+	struct ifaddrs* ifaphead;
+	if ( getifaddrs( &ifaphead ) != 0 )
+	return;
+
+	// iterate over the net interfaces
+	bool foundMac1 = false;
+	struct ifaddrs* ifap;
+	for ( ifap = ifaphead; ifap; ifap = ifap->ifa_next )
+	{
+		struct sockaddr_dl* sdl = (struct sockaddr_dl*)ifap->ifa_addr;
+		if ( sdl && ( sdl->sdl_family == AF_LINK ) && ( sdl->sdl_type == IFT_ETHER ))
+		{
+			if ( !foundMac1 )
+			{
+				foundMac1 = true;
+				mac1 = hashMacAddress( (unsigned char*)(LLADDR(sdl))); //sdl->sdl_data) + sdl->sdl_nlen) );
+			} else {
+				mac2 = hashMacAddress( (unsigned char*)(LLADDR(sdl))); //sdl->sdl_data) + sdl->sdl_nlen) );
+				break;
+			}
+		}
+	}
+
+	freeifaddrs( ifaphead );
+
+#else // !DARWIN
+
+	int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+	if (sock < 0)
+		return;
+
+	// enumerate all IP addresses of the system
+	struct ifconf conf;
+	char ifconfbuf[128 * sizeof(struct ifreq)];
+	memset(ifconfbuf, 0, sizeof(ifconfbuf));
+	conf.ifc_buf = ifconfbuf;
+	conf.ifc_len = sizeof(ifconfbuf);
+	if (ioctl(sock, SIOCGIFCONF, &conf)) {
+		assert(0);
+		return;
+	}
+
+	// get MAC address
+	bool foundMac1 = false;
+	struct ifreq* ifr;
+	for (ifr = conf.ifc_req; (char*) ifr < (char*) conf.ifc_req + conf.ifc_len;
+			ifr++) {
+		if (ifr->ifr_addr.sa_data == (ifr + 1)->ifr_addr.sa_data)
+			continue;  // duplicate, skip it
+
+		if (ioctl(sock, SIOCGIFFLAGS, ifr))
+			continue;  // failed to get flags, skip it
+		if (ioctl(sock, SIOCGIFHWADDR, ifr) == 0) {
+			if (!foundMac1) {
+				foundMac1 = true;
+				*mac1 = hashMacAddress(
+						(unsigned char*) &(ifr->ifr_addr.sa_data));
+			} else {
+				*mac2 = hashMacAddress(
+						(unsigned char*) &(ifr->ifr_addr.sa_data));
+				break;
+			}
+		}
+	}
+
+	close(sock);
+
+#endif // !DARWIN
+
+	// sort the mac addresses. We don't want to invalidate
+	// both macs if they just change order.
+	if (*mac1 > *mac2) {
+		unsigned short tmp = *mac2;
+		*mac2 = *mac1;
+		*mac1 = tmp;
+	}
+}
+
+unsigned short getVolumeHash() {
+	// we don't have a 'volume serial number' like on windows. Lets hash the system name instead.
+	unsigned char* sysname = (unsigned char*) getMachineName();
+	unsigned short hash = 0;
+
+	for (unsigned int i = 0; sysname[i]; i++)
+		hash += (sysname[i] << ((i & 1) * 8));
+
+	return hash;
+}
+
+#ifdef DARWIN
+#include <mach-o/arch.h>
+unsigned short getCpuHash()
+{
+	const NXArchInfo* info = NXGetLocalArchInfo();
+	unsigned short val = 0;
+	val += (unsigned short)info->cputype;
+	val += (unsigned short)info->cpusubtype;
+	return val;
+}
+
+#else // !DARWIN
+
+static void getCpuid(unsigned int* p, unsigned int ax) {
+	__asm __volatile
+	( "movl %%ebx, %%esi\n\t"
+			"cpuid\n\t"
+			"xchgl %%ebx, %%esi"
+			: "=a" (p[0]), "=S" (p[1]),
+			"=c" (p[2]), "=d" (p[3])
+			: "0" (ax)
+	);
+}
+
+unsigned short getCpuHash() {
+	unsigned int cpuinfo[4] = { 0, 0, 0, 0 };
+	getCpuid(cpuinfo, 0);
+	unsigned short hash = 0;
+	unsigned int* ptr = (&cpuinfo[0]);
+	for (unsigned int i = 0; i < 4; i++)
+		hash += (ptr[i] & 0xFFFF) + (ptr[i] >> 16);
+
+	return hash;
+}
+#endif // !DARWIN
+
+int main() {
+
+	printf("Machine: %s\n", getMachineName());
+	printf("CPU: %d\n", getCpuHash());
+	printf("Volume: %d\n", getVolumeHash());
+	return 0;
+}

--
Gitblit v1.9.1