Add base64 encoder/decoder at anna core functions
[anna.git] / source / core / functions.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #include <stdarg.h>
10 #include <ctype.h>
11 #include <poll.h>
12 #include <time.h>
13 #include <sys/time.h>
14 #include <pthread.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <sys/types.h>
18 #include <regex.h>
19 #include <sys/utsname.h>
20 #include <arpa/inet.h>
21 #include <sys/socket.h> // extraccion de IP del hostname
22 #include <netinet/in.h> // extraccion de IP del hostname
23 #include <netdb.h> // extraccion de IP del hostname
24 #include <unistd.h> // gethostname
25
26 #include <anna/core/functions.hpp>
27 #include <anna/core/DataBlock.hpp>
28 #include <anna/core/tracing/Logger.hpp>
29 #include <anna/core/util/Second.hpp>
30 #include <anna/core/util/Tokenizer.hpp>
31
32 #include <algorithm>
33
34
35 using namespace anna;
36 using namespace std;
37
38 #define PAGE_WIDTH_LENGTH      80
39
40 static const std::string base64_chars =
41              "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
42              "abcdefghijklmnopqrstuvwxyz"
43              "0123456789+/";
44
45
46 string functions::getVersion() throw() {
47   static const int version = ANNA_VERSION;
48   string result;
49   int mainVersion = (version & 0xff00) >> 8;
50   int subVersion = (version & 0xff);
51   char aux [32];
52   sprintf(aux, "%d.%d", mainVersion, subVersion);
53   result = aux;
54   return result += getArchitecture();
55 }
56
57 /*
58 (1) Solo coge los dos primeros digitos del numero de release
59 */
60 string functions::getArchitecture() throw() {
61   string result;
62   WHEN_MULTITHREAD(result = "/MT");
63   WHEN_SINGLETHREAD(result = "/ST");
64 #ifdef _DEBUG
65   result += "/D";
66 #else
67   result += "/O";
68 #endif
69 #ifdef _PROFILE
70   result += 'P';
71 #endif
72   struct utsname un;
73   uname(&un);
74   result += '/';
75   result += un.sysname;
76   result += ' ';
77   char* release = anna_strchr(un.release, '.');               // (1)
78
79   if(release != NULL)
80     if((release = anna_strchr(release + 1, '.')) != NULL)
81       * release = 0;
82
83   result += un.release;
84   result += " (";
85   result += un.machine;
86   result += ")";
87   return result;
88 }
89
90 string functions::asString(const int number)
91 throw() {
92   char aux [16];
93   sprintf(aux, "%d", number);
94   return string(aux);
95 }
96
97 string functions::asString(const S64 number)
98 throw() {
99   char aux [24];
100   //sprintf(aux, "%lld", number);
101   #ifdef __anna64__
102      sprintf (aux, "%ld", number);
103   #else
104      sprintf (aux, "%lld", number);
105   #endif
106   return string(aux);
107 }
108
109 string functions::asString(const unsigned int number)
110 throw() {
111   char aux [16];
112   sprintf(aux, "%u", number);
113   return string(aux);
114 }
115
116 string functions::asString(const U64 number)
117 throw() {
118   char aux [16];
119   //sprintf(aux, "%llu", number);
120   #ifdef __anna64__
121      sprintf (aux, "%lu", number);
122   #else
123      sprintf (aux, "%llu", number);
124   #endif
125   return string(aux);
126 }
127
128 string functions::asString(const float number, const char* format)
129 throw() {
130   char aux [64];
131   sprintf(aux, format, number);
132   return string(aux);
133 }
134
135 string functions::asString(const double number, const char* format)
136 throw() {
137   char aux [64];
138   sprintf(aux, format, number);
139   return string(aux);
140 }
141
142 string functions::asDateTime(const Second &second)
143 throw() {
144   char aux [DateTimeSizeString];
145   return std::string(asDateTime(second, aux));
146 }
147
148 const char* functions::asDateTime(const Second &second, char* result)
149 throw() {
150   struct tm* tt = localtime((time_t*) & second);
151   sprintf(
152     result, "%02d/%02d/%4d %02d:%02d:%02d",
153     tt->tm_mday, tt->tm_mon + 1, tt->tm_year + 1900,
154     tt->tm_hour, tt->tm_min, tt->tm_sec
155   );
156   return result;
157 }
158
159 std::string functions::asString(const DataBlock& dataBlock, const int characterByLine)
160 throw() {
161   return dataBlock.asString(characterByLine);
162 }
163
164 string functions::asHexString(const int number)
165 throw() {
166   char aux [16];
167   sprintf(aux, "0x%x", number);
168   return string(aux);
169 }
170
171 string functions::asHexString(const S64 number)
172 throw() {
173   char aux [32];
174   //sprintf(aux, "0x%llx", number);
175   #ifdef __anna64__
176      sprintf (aux, "0x%lx", number);
177   #else
178      sprintf (aux, "0x%llx", number);
179   #endif
180   return string(aux);
181 }
182
183 // from a version by Allen Holub (see Andrew Binstock, "Hashing Revisited"
184 // Dr. Dobb's Journal, April 1996)
185 S64 functions::hash(const char* p)
186 throw() {
187   static const int long_bits = sizeof(S64) << 3;
188   static const int one_eighth = long_bits >> 3;
189   static const int three_fourths = long_bits * 3 / 4;
190   static const S64 high_bits = ((S64)(~0L)) << (long_bits - one_eighth);
191   S64 result = 0;
192   S64 temp;
193
194   while(*p != 0) {
195     result = (result << one_eighth) + *p ++;
196
197     if((temp = result & high_bits) != 0)
198       result = (result ^(temp >> three_fourths)) &~ high_bits;
199   }
200
201   return result;
202 }
203
204 //static
205 std::string functions::asHexString(const DataBlock& dataBlock)
206 throw() {
207   const char* buffer = dataBlock.getData();
208   const int size = dataBlock.getSize();
209   string result;
210   int byte;
211
212   for(int ii = 0; ii < size; ii ++) {
213     byte = (buffer [ii] & 0xf0) >> 4;
214     result += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
215     byte = (buffer [ii] & 0x0f);
216     result += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
217   }
218
219   return result;
220 }
221
222 /**
223  * Gets the original value obtained with #asHexString (const DataBlock&).
224  * \param hexString String which contains the buffer. The format is an hexadecimal octet sequence representation (i.e. 'af012fb3', with even number of digits).
225  * The input shall be preprocessed to comply with that format (e.g. colon or any other non-hex digit must be removed).
226  * \param target DataBlock for string decode.
227  * \return DataBlock corresponding to the provided string.
228  */
229 //static
230 DataBlock& functions::fromHexString(const std::string& hexString, DataBlock& target)
231 throw(RuntimeException) {
232
233   if((hexString.length() % 2) != 0)
234     throw RuntimeException("functions::fromHexString | Invalid string length", ANNA_FILE_LOCATION);
235
236   target.clear();
237   const char* src = hexString.data();
238   unsigned char hex;
239   int aux;
240
241   for(int ii = 1, maxii = hexString.length(); ii < maxii; ii += 2) {
242     if(isxdigit(aux = src [ii - 1]) == 0)
243       throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
244
245     hex = ((aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a)) << 4;
246
247     if(isxdigit(aux = src [ii]) == 0)
248       throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
249
250     hex |= (aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a);
251     target += hex;
252   }
253
254   return target;
255 }
256
257 string functions::asString(const char* format, ...)
258 throw() {
259   va_list ap;
260   char aux [1024];
261   va_start(ap, format);
262   vsnprintf(aux, sizeof(aux), format, ap);
263   va_end(ap);
264   return string(aux);
265 }
266
267 void functions::sleep(const Millisecond &millisecond)
268 throw() {
269   timespec req;
270   timespec rem;
271   req.tv_sec = millisecond.getValue() / 1000;                          // segundos
272   req.tv_nsec = (millisecond.getValue() % 1000);                       // milisegundos
273   req.tv_nsec *= 1000000;                                   // mili = 10e-3, nano=10-9
274   int r;
275
276   while((r = nanosleep(&req, &rem)) != 0) {
277     if(errno == EINTR)
278       req = rem;
279     else {
280       string msg(asText("functions::sleep | timespec { sec: ", (int) req.tv_sec));
281       msg += functions::asText("| nsec: ", (int) req.tv_nsec);
282       msg += " }";
283       RuntimeException ex(msg, errno, ANNA_FILE_LOCATION);
284       ex.trace();
285       break;
286     }
287   }
288 }
289
290 bool functions::asBool(const char* str)
291 throw(RuntimeException) {
292   if(str == NULL)
293     return false;
294
295   if(strcasecmp(str, "true") == 0 || anna_strcmp(str, "1") == 0)
296     return true;
297
298   if(strcasecmp(str, "false") == 0 || anna_strcmp(str, "0") == 0)
299     return false;
300
301   string msg("anna::funcions::asBool | Cannot interpret '");
302   msg += str;
303   msg += "' as boolean";
304   throw RuntimeException(msg, ANNA_FILE_LOCATION);
305 }
306
307 S64 functions::asInteger64(const char* str)
308 throw() {
309   S64 number = 0;
310   //sscanf(str, "%lld", &number);
311   #ifdef __anna64__
312     sscanf (str, "%ld", &number);
313   #else
314      sscanf (str, "%lld", &number);
315   #endif
316   return number;
317 }
318
319 pthread_t functions::getCurrentThread()
320 throw() {
321   WHEN_MULTITHREAD(return pthread_self());
322   WHEN_SINGLETHREAD(return 0);
323 }
324
325 bool functions::isLike(const char* pattern, const std::string& _value)
326 throw(RuntimeException) {
327   const char* value = _value.c_str();
328   regex_t preg;
329   int ret;
330
331   if((ret = regcomp(&preg, pattern, REG_EXTENDED)) != 0) {
332     char err[256];
333     string msg("anna::functions::isLike | ");
334     msg += " | Pattern: ";
335     msg += pattern;
336     msg += " | Value: ";
337     msg += value;
338     msg += " | ";
339
340     if(regerror(ret, &preg, err, sizeof(err)))
341       msg += err;
342     else
343       msg += "Invalid pattern";
344
345     throw RuntimeException(msg, ANNA_FILE_LOCATION);
346   }
347
348   const bool result = (regexec(&preg, value, 0, NULL, 0) == 0) ? true : false;
349
350   regfree(&preg);
351   return result;
352 }
353
354 /*static*/
355 S64 functions::merge(const char* whatis, const int n1, const int n2, const int bitShift)
356 throw(RuntimeException) {
357   if(bitShift > intBitSize) {
358     string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | bitShift must be less than %d", whatis, n1, n2, bitShift, intBitSize));
359     throw RuntimeException(msg, ANNA_FILE_LOCATION);
360   }
361
362   if((bitsize(n1) + bitShift) > int64BitSize) {
363     string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N1 overload", whatis, n1, n2, bitShift));
364     throw RuntimeException(msg, ANNA_FILE_LOCATION);
365   }
366
367   if(bitsize(n2) > bitShift) {
368     string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N2 overload", whatis, n1, n2, bitShift));
369     throw RuntimeException(msg, ANNA_FILE_LOCATION);
370   }
371
372   S64 result = n1;
373   result <<= bitShift;
374   result |= n2;
375
376   if(bitShift == intBitSize) {
377     LOGINFORMATION(
378       string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | ", whatis, n1, n2, bitShift));
379       msg += functions::asHexString(result);
380       Logger::information(msg, ANNA_FILE_LOCATION);
381     );
382   }
383
384   return result;
385 }
386
387 /*static*/
388 /*
389  * Basado en el algoritmo de http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
390  */
391 int functions::log2(const unsigned int v)
392 throw() {
393   static const signed char LogTable256[] = {
394     -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
395     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
396     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
397     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
398     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
399     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
400     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
401     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
402     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
403     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
404     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
405     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
406     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
407     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
408     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
409     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
410   };
411   int r = -1;     // r will be lg(v)
412   unsigned int t, tt; // temporaries
413
414   if((tt = v >> 16)) {
415     r = ((t = tt >> 8)) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
416   } else {
417     r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
418   }
419
420   return r;
421 }
422
423 std::string functions::entriesAsString(int number, const char * wordForSingular, const char * wordForPlural) throw() {
424   std::string result;
425   std::string singular = (wordForSingular ? wordForSingular : "entry");
426   std::string plural = (wordForPlural ? wordForPlural : "entries");
427
428   if(wordForSingular && !wordForPlural)
429     plural = singular + "s";
430
431   result += ((number != 0) ? anna::functions::asString(number) : "no");
432   result += " ";
433   result += ((number != 1) ? plural : singular);
434   return result;
435 }
436
437
438 std::string functions::justify(const std::string & title, TextJustifyMode::_v mode, char filler) throw() {
439   std::string result;
440   int d_size = title.size();
441   int repeat = PAGE_WIDTH_LENGTH - d_size - 1;
442   bool adjust = false;
443
444   if(mode == TextJustifyMode::Center) {
445     repeat = (repeat - 1) / 2;
446     adjust = (2 * (repeat + 1) + d_size != PAGE_WIDTH_LENGTH);
447   }
448
449   if((mode == TextJustifyMode::Right) || (mode == TextJustifyMode::Center)) {
450     for(int k = 0; k < (repeat + (adjust ? 1 : 0)); k++) result += filler;
451
452     result += " ";
453   }
454
455   result += title;
456
457   if((mode == TextJustifyMode::Left) || (mode == TextJustifyMode::Center)) {
458     result += " ";
459
460     for(int k = 0; k < repeat; k++) result += filler;
461   }
462
463   return result;
464 }
465
466
467 std::string functions::highlight(const std::string & title, TextHighlightMode::_v mode, char filler, bool appendCR) throw() {
468   std::string result;
469   int ou_repeat = title.size();
470   int lr_repeat = PAGE_WIDTH_LENGTH - ou_repeat - 1;
471   bool adjust = false;
472
473   if(mode == TextHighlightMode::LeftAndRightline) {
474     lr_repeat = (lr_repeat - 1) / 2;
475     adjust = (2 * (lr_repeat + 1) + ou_repeat != PAGE_WIDTH_LENGTH);
476   }
477
478   if((mode == TextHighlightMode::Leftline) || (mode == TextHighlightMode::LeftAndRightline)) {
479     for(int k = 0; k < (lr_repeat + (adjust ? 1 : 0)); k++) result += filler;
480
481     result += " ";
482   }
483
484   if((mode == TextHighlightMode::Overline) || (mode == TextHighlightMode::OverAndUnderline)) {
485     for(int k = 0; k < ou_repeat; k++) result += filler;
486
487     result += "\n";
488   }
489
490   result += title;
491
492   if((mode == TextHighlightMode::Underline) || (mode == TextHighlightMode::OverAndUnderline)) {
493     result += "\n";
494
495     for(int k = 0; k < ou_repeat; k++) result += filler;
496   }
497
498   if((mode == TextHighlightMode::Rightline) || (mode == TextHighlightMode::LeftAndRightline)) {
499     result += " ";
500
501     for(int k = 0; k < lr_repeat; k++) result += filler;
502   }
503
504   if(appendCR) result += "\n";
505
506   return result;
507 }
508
509
510 std::string functions::tab(const std::string & text, int tabSpaces) throw() {
511   std::string result;
512   size_t pos, from = 0;
513   std::string tab, crTab = "\n";
514
515   for(int k = 0; k < tabSpaces; k++) tab += " ";
516
517   crTab += tab;
518   result = tab;
519   result += text;
520
521   while(((pos = result.find('\n', from)) != std::string::npos) && (pos != (result.size() - 1)/*exclude last CR if exists*/)) {
522     result.replace(pos, 1, crTab);
523     from = pos + 1;
524   }
525
526   return result;
527 }
528
529
530 bool functions::endsWith(const std::string & pattern, const std::string & suffix, std::string & preffix) throw() {
531   preffix = "";
532
533   if(pattern.size() < suffix.size()) return false;
534
535   size_t pos = pattern.rfind(suffix);
536
537   if(pos == std::string::npos) return false;
538
539   preffix.assign(pattern.c_str(), pos);
540   return (pos == (pattern.size() - suffix.size()));
541 }
542
543
544 bool functions::startsWith(const std::string & pattern, const std::string & preffix, std::string & suffix) throw() {
545   suffix = "";
546
547   if(pattern.size() < preffix.size()) return false;
548
549   if(pattern.find(preffix) != 0) return false;
550
551   suffix.assign(pattern.c_str(), preffix.size(), pattern.size() - preffix.size());
552   return true;
553 }
554
555
556 std::string functions::replace(const std::string & text, const char *item, const char *target, bool all) throw() {
557   std::string result = text;
558
559   if(!item || !target) return result;  // protection for NULL strings provided
560
561   size_t lengthReplaced = strlen(item);
562   size_t pos = result.find(item);
563
564   while(pos != std::string::npos) {
565     result.replace(pos, lengthReplaced, target);
566
567     if(!all) break;
568
569     pos = result.find(item);
570   }
571
572   return result;
573 }
574
575
576 std::string functions::addQuotationMarks(const std::string & str) throw() {
577   std::string result = "'";
578   result += str;
579   result += "'";
580   return (result);
581 }
582
583
584 std::string functions::addQuotationMarks(const char * str) throw() {
585   std::string result = "'";
586   result += (str ? str : "<null>");
587   result += "'";
588   return (result);
589 }
590
591
592 std::string functions::addQuotationMarks(const int & integer) throw() {
593   std::string result = "'";
594   result += anna::functions::asString(integer);
595   result += "'";
596   return (result);
597 }
598
599
600 std::string functions::vectorToStringRepresentation(const std::vector<int> & v, const char separator) throw() {
601   std::string result = "";
602
603   if(v.size() != 0) {
604     std::vector<int>::const_iterator iter;
605     std::vector<int>::const_iterator iter_min(v.begin());
606     std::vector<int>::const_iterator iter_max(v.end());
607
608     for(iter = iter_min; iter != iter_max; iter++) {
609       result += anna::functions::asString(*iter);
610       result += separator;
611     }
612
613     // Delete the last space: starts at 'size()-1', take 1 caracter:
614     result.erase(result.size() - 1, 1);
615   }
616
617   return (result);
618 }
619
620
621 std::string functions::vectorToStringRepresentation(const std::vector<std::string> & v, const char separator) throw() {
622   std::string result = "";
623
624   if(v.size() != 0) {
625     std::vector<std::string>::const_iterator iter;
626     std::vector<std::string>::const_iterator iter_min(v.begin());
627     std::vector<std::string>::const_iterator iter_max(v.end());
628
629     for(iter = iter_min; iter != iter_max; iter++) {
630       result += (*iter);
631       result += separator;
632     }
633
634     // Delete the last space: starts at 'size()-1', take 1 caracter:
635     result.erase(result.size() - 1, 1);
636   }
637
638   return (result);
639 }
640
641
642 std::string functions::socketLiteralAsString(const std::string & address, int port) throw() {
643   std::string result = address;
644   result += ":";
645   result += anna::functions::asString(port);
646   return result;
647 }
648
649
650 std::string functions::asAsciiString(const char * buffer, int size, bool & isFullyPrintable) throw() {
651   std::string result;
652   // Supposed printable by default:
653   isFullyPrintable = true;
654
655   if(size == 0 || !buffer) {
656     result = "<null>";
657     isFullyPrintable = false;
658     return result;
659   }
660
661   for(int k = 0; k < size; k ++) {
662     unsigned char c = (unsigned char) buffer [k];
663     int printable = isprint(c);
664     result += (printable ? (char) c : '.');
665
666     if(!printable) isFullyPrintable = false;
667   }
668
669   return result;
670 }
671
672
673 std::string functions::getHostname() throw() {
674   char aux[255];
675   std::string result = "<hostname>";
676
677   if(gethostname(aux, sizeof aux) == 0 /*success*/)
678     result = aux;
679
680   return result;
681 }
682
683 std::string functions::getDomainname() throw() {
684   char aux[256];
685   std::string result = "<domainname>";
686
687   if(getdomainname(aux, sizeof aux) == 0 /*success*/)
688     result = aux;
689
690   return result;
691 }
692
693 std::string functions::getFQDN(const char *hostname, const char *domainname) throw() {
694   std::string hn = hostname ? hostname : (functions::getHostname());
695   std::string dn = domainname ? domainname : (functions::getDomainname());
696   // FQDN is limited to 255 bytes, with aditional restriction: 63 bytes label within a domain name.
697
698   if(hn == "") return dn;
699
700   if(dn == "") return hn;
701
702   std::string label(hn, 0, 63);
703   std::string fqdn(label + "." + dn, 0, 255);
704   return fqdn;
705 }
706
707 std::string functions::getHostnameIP() throw() {
708   std::string result = "";
709   struct hostent *he;
710   struct in_addr **addr_list;
711   char hostname[128];
712   gethostname(hostname, sizeof hostname);
713
714   if((he = gethostbyname(hostname)) != NULL) {
715     // Official name: he->h_name
716     // IP addresses:
717     addr_list = (struct in_addr **)he->h_addr_list;
718
719     for(int i = 0; addr_list[i] != NULL; i++) {
720       //printf("%s ", inet_ntoa(*addr_list[i]));
721       result = inet_ntoa(*addr_list[i]);
722       return result;
723     }
724   }
725
726   return result;
727 }
728
729
730 anna::DataBlock functions::rawIpPresentationAsRaw(const std::string & rawPresentation) throw(anna::RuntimeException) {
731   int length = rawPresentation.size();
732
733   if(length != 8 && length != 32)
734     throw anna::RuntimeException("functions::rawIpPresentationAsRaw | Expected 8 or 32-sized raw IP presentation provided", ANNA_FILE_LOCATION);
735
736   anna::DataBlock result(true);
737   int byte;
738   char rByte[3]; // readable byte
739   rByte[2] = 0;
740
741   for(int k = 0; k < length; k += 2) {
742     rByte[0] =  rawPresentation[k];
743     rByte[1] = rawPresentation[k + 1];
744     sscanf(rByte, "%x", &byte);
745     result += byte;
746   }
747
748   return result;
749 }
750
751
752 std::string functions::rawIpAsRawIpPresentation(const anna::DataBlock & db) throw(anna::RuntimeException) {
753   int length = db.getSize();
754
755   if(length != 4 && length != 16)
756     throw anna::RuntimeException("functions::rawIpAsRawIpPresentation | Expected 4 or 16-sized raw IP DataBlock provided", ANNA_FILE_LOCATION);
757
758   std::string result = "";
759   int byte;
760   char rByte[3]; // readable byte
761   rByte[2] = 0;
762
763   for(int k = 0; k < length; k++) {
764     byte = (unsigned char)db[k];
765     sprintf(rByte, "%.2X", byte);
766     result += rByte;
767   }
768
769   return result;
770 }
771
772
773
774 ////////////////////
775 // Address Format //
776 ////////////////////
777 //   IPv6 addresses have two logical parts: a 64-bit network prefix, and a 64-bit host address part. (The host address is often automatically generated from the interface MAC address.[34]) An IPv6 address is represented by 8 groups of 16-bit hexadecimal values separated by colons (:) shown as follows:
778 //   A typical example of an IPv6 address is
779 //   2001:0db8:85a3:0000:0000:8a2e:0370:7334
780 //   The hexadecimal digits are case-insensitive.
781 //
782 //   The 128-bit IPv6 address can be abbreviated with the following rules:
783 //   -Rule one: Leading zeroes within a 16-bit value may be omitted. For example, the address fe80:0000:0000:0000:0202:b3ff:fe1e:8329 may be written as fe80:0:0:0:202:b3ff:fe1e:8329
784 //   -Rule two: A single occurrence of consecutive groups of zeroes within an address may be replaced by a double colon. For example, fe80:0:0:0:202:b3ff:fe1e:8329 becomes fe80::202:b3ff:fe1e:8329
785 //   A single IPv6 address can be represented in several different ways, such as 2001:db8::1:0:0:1 and 2001:0DB8:0:0:1::1. RFC 5952 recommends a canonical textual representation.
786
787 //      Si la dirección tiene más de una serie de grupos nulos consecutivos la compresión sólo se permite en uno de ellos.
788 //      Así, las siguientes son representaciones posibles de una misma dirección:
789 //
790 //      2001:0DB8:0000:0000:0000:0000:1428:57ab
791 //      2001:0DB8:0000:0000:0000::1428:57ab
792 //      2001:0DB8:0:0:0:0:1428:57ab
793 //      2001:0DB8:0::0:1428:57ab
794 //      2001:0DB8::1428:57ab
795 //      son todas válidas y significan lo mismo, pero
796 //      2001::25de::cade
797 //          --    --
798 //      no es válida porque no queda claro cuántos grupos nulos hay en cada lado.
799 //
800 //      Los ceros iniciales en un grupo también se pueden omitir:
801 //      2001:0DB8:02de::0e13
802 //      2001:DB8:2de::e13
803 //
804 //      Si la dirección es una dirección IPv4 empotrada (mapped), los Ãºltimos 32 bits pueden escribirse en base decimal, así:
805 //      ::ffff:192.168.89.9
806 //      ::ffff:c0a8:5909
807 //
808 //      No se debe confundir con:
809 //      ::192.168.89.9
810 //      ::c0a8:5909
811 //
812 //      El formato ::ffff:1.2.3.4 se denomina dirección IPv4 mapeada, y el formato ::1.2.3.4 dirección IPv4 compatible.
813 //      Las direcciones IPv4 pueden ser transformadas fácilmente al formato IPv6. Por ejemplo, si la dirección decimal IPv4 es 135.75.43.52
814 //       (en hexadecimal, 0x874B2B34), puede ser convertida a 0000:0000:0000:0000:0000:0000:874B:2B34 o ::874B:2B34. Entonces, uno puede usar
815 //       la notación mixta dirección IPv4 compatible, en cuyo caso la dirección debería ser ::135.75.43.52. Este tipo de dirección IPv4 compatible
816 //       casi no está siendo utilizada en la práctica, aunque los estándares no la han declarado obsoleta.
817 //
818 // http://tools.ietf.org/html/rfc5952: canonical text representation recommendation
819
820 bool functions::isIPv4(const std::string & ip, IPv4Type::_v ipv4Type) throw() {
821   if(ipv4Type == IPv4Type::Estrict) {
822     // La expresión regular no controla si hay mas de 3 puntos:
823     int n_dot = 0;
824
825     for(int k = 0; k < ip.length(); k++)
826       if(ip[k] == '.') n_dot++;
827
828     if(n_dot > 3)
829       return (false);
830
831     bool ipv4 = anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, ip);
832     bool colon = (ip.find(":") != std::string::npos);
833     return (ipv4 && !colon);
834   }
835
836   if(ipv4Type == IPv4Type::Compatible) {
837     std::string pureIPv4 = ip;
838     bool firstDoubleColon = (ip.find("::") == 0);
839
840     if(firstDoubleColon) {
841       pureIPv4.erase(0, 2);
842       bool anotherColon = (pureIPv4.find(":") != std::string::npos);
843
844       if(anotherColon) return (false);
845
846       return (anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, pureIPv4));
847     }
848   }
849
850   if(ipv4Type == IPv4Type::Mapped) {
851     size_t posLastColon = ip.rfind(":");
852
853     if(posLastColon == std::string::npos)
854       return (false);
855
856     if(!isIPv4(ip.substr(posLastColon + 1)))
857       return (false);
858
859     unsigned char buf[sizeof(struct in6_addr)];
860     int s = inet_pton(AF_INET6, ip.c_str(), buf);
861
862     if(s > 0)
863       return (true);
864   }
865
866   return false;
867 }
868
869
870 bool functions::isIPv6(const std::string & ip) throw() {
871   // Chequeo de digitos permitidos:
872   for(int k = 0; k < ip.length(); k++) {
873     bool digit = isdigit(ip[k]);
874     bool hex = ((ip[k] == 'a') ||
875                 (ip[k] == 'b') ||
876                 (ip[k] == 'c') ||
877                 (ip[k] == 'd') ||
878                 (ip[k] == 'e') ||
879                 (ip[k] == 'f') ||
880                 (ip[k] == 'A') ||
881                 (ip[k] == 'B') ||
882                 (ip[k] == 'C') ||
883                 (ip[k] == 'D') ||
884                 (ip[k] == 'E') ||
885                 (ip[k] == 'F'));
886     bool colon = (ip[k] == ':');
887
888     if(!digit && !hex && !colon)
889       return false;
890   }
891
892   return (anna::functions::isLike(s_REGEXP_IPv6_ADDRESSES, ip));
893 }
894
895
896 std::string functions::IPv4To6(const std::string & ip) throw(anna::RuntimeException) {
897   if(!isIPv4(ip, IPv4Type::Estrict) && !isIPv4(ip, IPv4Type::Compatible) && !isIPv4(ip, IPv4Type::Mapped))
898     throw anna::RuntimeException("functions::IPv4To6 | Expected IPv4, IPv4-compatible or IPv4-mapped address format", ANNA_FILE_LOCATION);
899
900   std::string result, pureIPv4;
901   bool firstDoubleColon = (ip.find("::") == 0);
902
903   if(firstDoubleColon) {
904     // Clean '::'
905     size_t ipv4_pos = ip.rfind(":") /* last ocurrence */ + 1;
906     pureIPv4 = ip.substr(ipv4_pos);
907   } else {
908     if(!isIPv4(ip)) {
909       size_t posColon = ip.find(":");
910
911       if(posColon == 0)  // first colon
912         throw anna::RuntimeException("functions::IPv4To6 | Invalid IPv4 address format", ANNA_FILE_LOCATION);
913
914       if(posColon != std::string::npos)  // any colon
915         return ip; // seems to be IPv6 already?
916
917       throw anna::RuntimeException("functions::IPv4To6 | Unreconized IPv4 address format", ANNA_FILE_LOCATION);
918     }
919
920     pureIPv4 = ip;
921   }
922
923   // Number of ocurrences for '.'
924   int n_dot = 0;
925
926   for(int k = 0; k < pureIPv4.length(); k++)
927     if(pureIPv4[k] == '.') n_dot++;
928
929   if(n_dot > 3)
930     throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (more than three dots!)", ANNA_FILE_LOCATION);
931
932   anna::Tokenizer tok;
933   anna::Tokenizer::const_iterator tok_it;
934   std::string token;
935   tok.apply(pureIPv4, ".");
936   int v[4];
937   int cnt = 0;
938
939   for(tok_it = tok.begin(); tok_it != tok.end(); tok_it ++) {
940     token = anna::Tokenizer::data(tok_it);
941     v[cnt] = atoi(anna::Tokenizer::data(tok_it));
942
943     if(v[cnt] < 0 || v[cnt] > 255)
944       throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (any value out of range 0-255)", ANNA_FILE_LOCATION);
945
946     cnt++;
947   }
948
949   if(isIPv4(ip, IPv4Type::Compatible))
950     result = anna::functions::asString("::%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
951   else
952     result = anna::functions::asString("::ffff:%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
953
954   return result;
955 }
956
957
958 std::string functions::normalizeIP(const std::string & ip) throw(anna::RuntimeException) {
959   std::string result = ip;
960 //   std::transform(result.begin(), result.end(), result.begin(), (int (*)(int))std::tolower);
961   std::transform(result.begin(), result.end(), result.begin(), ::tolower);
962
963   if(isIPv4(ip, IPv4Type::Estrict) || isIPv4(ip, IPv4Type::Compatible) || isIPv4(ip, IPv4Type::Mapped))
964     result = IPv4To6(result);
965
966   size_t pos = result.find("::"); // zeroes simplification group
967   size_t rpos = result.rfind("::"); // zeroes simplification group
968
969   if(pos != rpos)
970     throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (more than one simplification group '::')", ANNA_FILE_LOCATION);
971
972   if(pos != std::string::npos) {  // zeroes exists
973     // string ( size_t n, char c ) -> content is initialized as a string formed by a repetition of character c, n times.
974     // Number of ocurrences for ':'
975     int n_colon = 0;
976
977     for(int k = 0; k < result.length(); k++)
978       if(result[k] == ':') n_colon++;
979
980     // Generate equivalent to '::'
981     std::string equiv_str;
982
983     for(int k = 0; k < (8 - n_colon); k++)
984       equiv_str += ":0";
985
986     equiv_str += ":";
987     // Replace with equivalent:
988     result.replace(pos, 2, equiv_str);
989
990     // Special case: IP began with '::'
991     if(result[0] == ':') {
992       result.insert(0, "0");
993     }
994
995     // Special case: IP was only '::'
996     if(result[result.length() - 1] == ':') {
997       result += "0";
998     }
999   }
1000
1001   // Protection: it must be seven colons:
1002   int n_colon = 0;
1003
1004   for(int k = 0; k < result.length(); k++)
1005     if(result[k] == ':') n_colon++;
1006
1007   if(n_colon != 7)
1008     throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (missing any 16-bit group)", ANNA_FILE_LOCATION);
1009
1010   // Padding with zeroes at left
1011   anna::Tokenizer ipStr;
1012   anna::Tokenizer::const_iterator ipStr_it;
1013   std::string token;
1014   ipStr.apply(result, ":");
1015   result = "";
1016
1017   for(ipStr_it = ipStr.begin(); ipStr_it != ipStr.end(); ipStr_it ++) {
1018     token = anna::Tokenizer::data(ipStr_it);
1019
1020     while(token.length() < 4) token.insert(0, "0");
1021
1022     result += token;
1023     result += ":";
1024   }
1025
1026   // Remove last ':'
1027   size_t lastPos = result.length() - 1;
1028   result.erase(lastPos, 1);
1029
1030   // Chequeo de digitos permitidos:
1031   for(int k = 0; k < result.length(); k++) {
1032     bool digit = isdigit(result[k]);
1033     bool hex = ((result[k] == 'a') ||
1034                 (result[k] == 'b') ||
1035                 (result[k] == 'c') ||
1036                 (result[k] == 'd') ||
1037                 (result[k] == 'e') ||
1038                 (result[k] == 'f'));
1039     bool colon = (result[k] == ':');
1040
1041     if(!digit && !hex && !colon) {
1042       throw anna::RuntimeException("functions::normalizeIP | Invalid address format (only digits (0-9) and hex digits are allowed)", ANNA_FILE_LOCATION);
1043     }
1044   }
1045
1046   return result;
1047 }
1048
1049
1050 bool functions::sameIP(const std::string & ip1, const std::string & ip2) throw(anna::RuntimeException) {
1051   //if (ip1 == ip2) return true; it should validate wrong-format addresses
1052   return (normalizeIP(ip1) == normalizeIP(ip2));
1053 }
1054
1055
1056 bool functions::matchIPv6(const std::string & _ipv6, const std::string & preffixedIpv6) throw(anna::RuntimeException) {
1057   size_t preffixPos = preffixedIpv6.find("/");
1058
1059   if(preffixPos == std::string::npos)
1060     return (sameIP(_ipv6, preffixedIpv6));
1061
1062   std::string ipv6 = _ipv6;
1063
1064   if(isIPv4(_ipv6, IPv4Type::Estrict) || isIPv4(_ipv6, IPv4Type::Compatible) || isIPv4(_ipv6, IPv4Type::Mapped)) ipv6 = IPv4To6(_ipv6);
1065
1066   std::string _ipv6_2 = preffixedIpv6.substr(0, preffixPos);
1067   std::string ipv6_2 = _ipv6_2;
1068
1069   if(isIPv4(_ipv6_2, IPv4Type::Estrict) || isIPv4(_ipv6_2, IPv4Type::Compatible) || isIPv4(_ipv6_2, IPv4Type::Mapped)) ipv6_2 = IPv4To6(_ipv6_2);
1070
1071   std::string preffix = preffixedIpv6.substr(preffixPos + 1);
1072   int ipv6_2_preffixLength = atoi(preffix.c_str());
1073
1074   if(ipv6_2_preffixLength < 0 || ipv6_2_preffixLength > 128)
1075     throw anna::RuntimeException("functions::matchIPv6 | Invalid Ipv6 preffix length: out of range [0,128]", ANNA_FILE_LOCATION);
1076
1077   // No restriction, all ipv6_2 ignored (special and not usual case)
1078   if(ipv6_2_preffixLength == 0) return true;
1079
1080   // Auxiliary data:
1081   int spare = ipv6_2_preffixLength /* bits */ % 8; // bytes
1082   int incompletedRestrictionBytes = ipv6_2_preffixLength / 8;
1083   int completedRestrictionBytes = incompletedRestrictionBytes + ((spare != 0) ? 1 : 0);
1084   char mask = 0xFF << (8 - spare);
1085   // Limit ipv6
1086   anna::DataBlock rawIP1 = ipAsRaw(ipv6);
1087   anna::DataBlock restrictedIP1(true);
1088   restrictedIP1.assign(rawIP1.getData(), incompletedRestrictionBytes);
1089
1090   if(spare != 0) restrictedIP1 += rawIP1[incompletedRestrictionBytes] & mask;
1091
1092   // Limit ipv6_2
1093   anna::DataBlock rawIP2 = ipAsRaw(ipv6_2);
1094   anna::DataBlock realIP2(true);
1095   realIP2.assign(rawIP2.getData(), incompletedRestrictionBytes);
1096
1097   if(spare != 0) realIP2 += rawIP2[incompletedRestrictionBytes] & mask;
1098
1099   // Comparison
1100   int n = memcmp(restrictedIP1.getData(), realIP2.getData(), completedRestrictionBytes);
1101   return (n == 0);
1102 }
1103
1104
1105 anna::DataBlock functions::ipAsRaw(const std::string & ip) throw(anna::RuntimeException) {
1106   anna::DataBlock result(true);
1107
1108   if(isIPv4(ip)) {
1109     unsigned char buf[sizeof(struct in6_addr)];
1110     int s = inet_pton(AF_INET, ip.c_str(), buf);
1111
1112     if(s > 0) {
1113       result += (S8)buf[0];
1114       result += (S8)buf[1];
1115       result += (S8)buf[2];
1116       result += (S8)buf[3];
1117     } else {
1118       if(s < 0) perror("inet_pton");
1119
1120       throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv4 address format", ANNA_FILE_LOCATION);
1121     }
1122   } else {
1123     unsigned char buf[sizeof(struct in6_addr)];
1124     int s = inet_pton(AF_INET6, ip.c_str(), buf);
1125
1126     if(s > 0) {
1127       result += (S8)buf[0];
1128       result += (S8)buf[1];
1129       result += (S8)buf[2];
1130       result += (S8)buf[3];
1131       result += (S8)buf[4];
1132       result += (S8)buf[5];
1133       result += (S8)buf[6];
1134       result += (S8)buf[7];
1135       result += (S8)buf[8];
1136       result += (S8)buf[9];
1137       result += (S8)buf[10];
1138       result += (S8)buf[11];
1139       result += (S8)buf[12];
1140       result += (S8)buf[13];
1141       result += (S8)buf[14];
1142       result += (S8)buf[15];
1143     } else {
1144       if(s < 0) perror("inet_pton");
1145
1146       throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv6 address format", ANNA_FILE_LOCATION);
1147     }
1148   }
1149
1150   return result;
1151   // Alternativa
1152   //   anna::DataBlock result(true);
1153   //
1154   //
1155   //   if (isIPv4(ip)) {
1156   //
1157   //      int dec1, dec2, dec3, dec4; // U32 type is valid, 'int' better: argument for %d must be 'int *' (http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/)
1158   //      sscanf(ip.c_str(), "%d.%d.%d.%d", &dec1, &dec2, &dec3, &dec4);
1159   //      result += (S8)dec1;
1160   //      result += (S8)dec2;
1161   //      result += (S8)dec3;
1162   //      result += (S8)dec4;
1163   //   }
1164   //   else {
1165   //
1166   //      int hex1, hex2, hex3, hex4, hex5, hex6, hex7, hex8; // U16 type is not valid: argument for %X must be 'int *' (http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/)
1167   //      sscanf(normalizeIP(ip).c_str(), "%X:%X:%X:%X:%X:%X:%X:%X", &hex1, &hex2, &hex3, &hex4, &hex5, &hex6, &hex7, &hex8);
1168   //      result += ((S8)(hex1 >> 8));
1169   //      result += ((S8)(hex1 & 0x00FF));
1170   //      result += ((S8)(hex2 >> 8));
1171   //      result += ((S8)(hex2 & 0x00FF));
1172   //      result += ((S8)(hex3 >> 8));
1173   //      result += ((S8)(hex3 & 0x00FF));
1174   //      result += ((S8)(hex4 >> 8));
1175   //      result += ((S8)(hex4 & 0x00FF));
1176   //      result += ((S8)(hex5 >> 8));
1177   //      result += ((S8)(hex5 & 0x00FF));
1178   //      result += ((S8)(hex6 >> 8));
1179   //      result += ((S8)(hex6 & 0x00FF));
1180   //      result += ((S8)(hex7 >> 8));
1181   //      result += ((S8)(hex7 & 0x00FF));
1182   //      result += ((S8)(hex8 >> 8));
1183   //      result += ((S8)(hex8 & 0x00FF));
1184   //   }
1185   //
1186   //
1187   //   return result;
1188 }
1189
1190
1191 std::string functions::rawIpAsString(const char *buffer, int bufferLength, bool normalize) throw(anna::RuntimeException) {
1192   std::string result = "";
1193   char str[INET6_ADDRSTRLEN];
1194
1195   if(bufferLength == 4) {
1196     if(inet_ntop(AF_INET, buffer, str, INET_ADDRSTRLEN) != NULL)
1197       result = str;
1198   } else if(bufferLength == 16) {
1199     if(inet_ntop(AF_INET6, buffer, str, INET6_ADDRSTRLEN) != NULL)
1200       result = str;
1201   } else
1202     throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1203
1204   if(result == "")
1205     throw anna::RuntimeException("functions::rawIpAsString | Wrong IP address serialization (check range value)", ANNA_FILE_LOCATION);
1206
1207   return (normalize ? normalizeIP(result) : result);
1208   // Alternativa:
1209   //   std::string result;
1210   //
1211   //
1212   //   if (bufferLength == 4) { // IPv4
1213   //      result = anna::functions::asString("%d.%d.%d.%d", (U8)buffer[0], (U8)buffer[1], (U8)buffer[2], (U8)buffer[3]);
1214   //   }
1215   //   else if (bufferLength == 16) { // IPv6
1216   //      result = anna::functions::asString("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
1217   //                       ((((U8)buffer[0]) << 8) & 0xFF00 /* same as (U16 cast)*/) +
1218   //                       (((U8)buffer[1])        & 0x00FF),
1219   //                       ((((U8)buffer[2]) << 8) & 0xFF00) +
1220   //                       (((U8)buffer[3])        & 0x00FF),
1221   //                       ((((U8)buffer[4]) << 8) & 0xFF00) +
1222   //                       (((U8)buffer[5])        & 0x00FF),
1223   //                       ((((U8)buffer[6]) << 8) & 0xFF00) +
1224   //                       (((U8)buffer[7])        & 0x00FF),
1225   //                       ((((U8)buffer[8]) << 8) & 0xFF00) +
1226   //                       (((U8)buffer[9])        & 0x00FF),
1227   //                       ((((U8)buffer[10]) << 8) & 0xFF00) +
1228   //                       (((U8)buffer[11])        & 0x00FF),
1229   //                       ((((U8)buffer[12]) << 8) & 0xFF00) +
1230   //                       (((U8)buffer[13])        & 0x00FF),
1231   //                       ((((U8)buffer[14]) << 8) & 0xFF00) +
1232   //                       (((U8)buffer[15])        & 0x00FF));
1233   //   }
1234   //   else
1235   //      throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1236   //
1237   //
1238   //   return (normalize ? normalizeIP(result):result);
1239 }
1240
1241
1242 void functions::getAddressAndPortFromSocketLiteral(const std::string &literal, std::string &address, int &port) throw() {
1243   size_t pos = literal.find_last_of(":");
1244   size_t lastPos = literal.size() - 1;
1245   address = ""; port = -1; // assume error
1246
1247   if((pos != std::string::npos) && (pos != lastPos)) {
1248     address = literal.substr(0, pos);
1249     port = atoi(literal.substr(pos + 1, lastPos).c_str());
1250   }
1251 }
1252
1253
1254 socket_v functions::getSocketVectorFromString(const std::string & list) throw() {
1255   socket_v result;
1256   std::string address;
1257   int port;
1258   anna::Tokenizer lst;
1259   lst.apply(list, ",");
1260
1261   if(lst.size() < 1) return result;
1262
1263   anna::Tokenizer::const_iterator tok_min(lst.begin());
1264   anna::Tokenizer::const_iterator tok_max(lst.end());
1265   anna::Tokenizer::const_iterator tok_iter;
1266
1267   for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) {
1268     getAddressAndPortFromSocketLiteral(anna::Tokenizer::data(tok_iter), address, port);
1269
1270     if(port == -1) { result.clear(); return result; }
1271
1272     result.push_back(socket_t(address, port));
1273   }
1274
1275   return result;
1276 }
1277
1278 std::string functions::socketVectorAsString(const socket_v & socketVector) throw() {
1279   std::string result;
1280   socket_v_it it;
1281   socket_v_it it_min(socketVector.begin());
1282   socket_v_it it_max(socketVector.end());
1283
1284   for(it = it_min; it != it_max; it++) {
1285     result += anna::functions::asString("%s:%d,", (*it).first.c_str(), (*it).second);
1286   }
1287
1288   result.erase(result.size() - 1, 1);  // remove last comma
1289   return result;
1290 }
1291
1292 bool functions::littleEndian()
1293 throw() {
1294   int i = 1;
1295   char *p = (char *) &i;
1296   if (p[0] == 1) return true;
1297   return false;
1298 }
1299
1300 const char* functions::codeInteger(char* result, const int n)
1301 throw() {
1302   int aux(htonl(n));
1303   char* w((char*) &aux);
1304   *result = *w;
1305   *(result + 1) = *(w + 1);
1306   *(result + 2) = *(w + 2);
1307   *(result + 3) = *(w + 3);
1308   return result;
1309 }
1310
1311 const char* functions::codeShort(char* result, const short int n)
1312 throw() {
1313   short int aux(htons(n));
1314   char* w((char*) &aux);
1315   *result = *w;
1316   *(result + 1) = *(w + 1);
1317   return result;
1318 }
1319
1320 const char* functions::codeInteger64(char* result, const S64 n)
1321 throw() {
1322   S64 aux(0xffffffff);
1323   int n2;
1324   aux <<= 32;
1325   aux &= n;
1326   n2 = (aux >> 32) & 0xffffffff;
1327   codeInteger(result, n2);
1328   n2 = n & 0xffffffff;
1329   codeInteger(result + sizeof(int), n2);
1330   return result;
1331 }
1332
1333 /*static*/
1334 const char* functions::codeFloat(char* result, const float n)
1335 throw() {
1336   int ii;
1337   anna_memcpy(&ii, &n, sizeof(n));
1338   return functions::codeInteger(result, ii);
1339 }
1340
1341 /*static*/
1342 const char* functions::codeDouble(char* result, const double n)
1343 throw() {
1344   S64 ii;
1345   anna_memcpy(&ii, &n, sizeof(n));
1346   return functions::codeInteger64(result, ii);
1347 }
1348
1349 int functions::decodeInteger(const char* data)
1350 throw() {
1351   int result;
1352   char* w((char*) &result);
1353   *w  = *data;
1354   *(w + 1) = *(data + 1);
1355   *(w + 2) = *(data + 2);
1356   *(w + 3) = *(data + 3);
1357   return ntohl(result);
1358 }
1359
1360 short int functions::decodeShort(const char* data)
1361 throw() {
1362   short int result;
1363   char* w((char*) &result);
1364   *w  = *data;
1365   *(w + 1) = *(data + 1);
1366   return ntohs(result);
1367 }
1368
1369 S64 functions::decodeInteger64(const char* data)
1370 throw() {
1371   S64 result(decodeInteger(data));
1372   result <<= 32;
1373   return result |= (decodeInteger(data + sizeof(int)) & 0xffffffff);
1374 }
1375
1376 /*static*/
1377 float functions::decodeFloat(const char* data)
1378 throw() {
1379   float result;
1380   int ii = functions::decodeInteger(data);
1381   anna_memcpy(&result, &ii, sizeof(result));
1382   return result;
1383 }
1384
1385 /*static*/
1386 double functions::decodeDouble(const char* data)
1387 throw() {
1388   double result;
1389   S64 ii = functions::decodeInteger64(data);
1390   anna_memcpy(&result, &ii, sizeof(result));
1391   return result;
1392 }
1393
1394
1395
1396 void functions::decodeIsupNumber(const char *buffer, int length, isup_number_t & isupNumber, bool calledOrCalling) throw(anna::RuntimeException) {
1397 #define DECODE2BYTES_INDX_VALUETYPE(buffer,indx,value_type) ((((value_type)buffer[indx] << 8) & 0xFF00) + ((value_type)buffer[indx+1] & 0x00FF))
1398   isupNumber.reset();
1399   isupNumber.OddEven = (short)((buffer[0] >> 7) & 0x01);
1400   bool filler = isupNumber.OddEven;
1401
1402   if(filler && ((buffer [length - 1] & 0xf0) != 0x00))
1403     throw anna::RuntimeException("functions::decodeIsupNumber | Isup number filler must be '0000'", ANNA_FILE_LOCATION);
1404
1405   isupNumber.NatureOfAddress = (short)(buffer[0] & 0x7F);
1406   isupNumber.NumberingPlan = (short)((buffer[1] >> 4) & 0x07);
1407
1408   if(calledOrCalling) {
1409     isupNumber.InternalNetworkNumber = (short)((buffer[1] >> 7) & 0x01);
1410   } else {
1411     isupNumber.NumberIncomplete = (short)((buffer[1] >> 7) & 0x01);
1412     isupNumber.AddressPresentationRestricted = (short)((buffer[1] >> 2) & 0x03);
1413     isupNumber.Screening = (short)(buffer[1] & 0x03);
1414   }
1415
1416   // Digits:
1417   isupNumber.Digits = "";
1418   int byte;
1419
1420   for(int k = 2; k < length; k ++) {
1421     byte = (buffer [k] & 0x0f);
1422     isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1423     byte = (buffer [k] & 0xf0) >> 4;
1424     isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1425   }
1426
1427   if(filler) isupNumber.Digits.erase(isupNumber.Digits.size() - 1, 1);   // remove filler
1428 }
1429
1430
1431 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, std::string & target) throw(anna::RuntimeException) {
1432   // Checkings:
1433   if(isupNumber.OddEven < 0 || isupNumber.OddEven > 1)
1434     throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field out of range [0,1]", ANNA_FILE_LOCATION);
1435
1436   bool odd = isupNumber.OddEven;
1437   bool oddDigits = (isupNumber.Digits.size() % 2);
1438
1439   if(odd != oddDigits)
1440     throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field doesn't correspond to the number of digits on 'Digits' field", ANNA_FILE_LOCATION);
1441
1442   if(isupNumber.NatureOfAddress < 0 || isupNumber.NatureOfAddress > 127)
1443     throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NatureOfAddress' field out of range [0,127]", ANNA_FILE_LOCATION);
1444
1445   if(isupNumber.NumberingPlan < 0 || isupNumber.NumberingPlan > 7)
1446     throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberingPlan' field out of range [0,7]", ANNA_FILE_LOCATION);
1447
1448   if(calledOrCalling) {
1449     if(isupNumber.NumberIncomplete != 0)
1450       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field present on Called Party Number !", ANNA_FILE_LOCATION);
1451
1452     if(isupNumber.AddressPresentationRestricted != 0)
1453       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field present on Called Party Number !", ANNA_FILE_LOCATION);
1454
1455     if(isupNumber.Screening != 0)
1456       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field present on Called Party Number !", ANNA_FILE_LOCATION);
1457
1458     if(isupNumber.InternalNetworkNumber < 0 || isupNumber.InternalNetworkNumber > 1)
1459       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field out of range [0,1]", ANNA_FILE_LOCATION);
1460   } else {
1461     if(isupNumber.InternalNetworkNumber != 0)
1462       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field present on Calling Party Number !", ANNA_FILE_LOCATION);
1463
1464     if(isupNumber.NumberIncomplete < 0 || isupNumber.NumberIncomplete > 1)
1465       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field out of range [0,1]", ANNA_FILE_LOCATION);
1466
1467     if(isupNumber.AddressPresentationRestricted < 0 || isupNumber.AddressPresentationRestricted > 3)
1468       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field out of range [0,3]", ANNA_FILE_LOCATION);
1469
1470     if(isupNumber.Screening < 0 || isupNumber.Screening > 3)
1471       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field out of range [0,3]", ANNA_FILE_LOCATION);
1472   }
1473
1474   char byte;
1475   target = "";
1476   bool filler = isupNumber.OddEven;
1477   bool hasDigits = (isupNumber.Digits.size() > 0);
1478   byte = filler ? 0x80 : 0x00;
1479   byte |= isupNumber.NatureOfAddress;
1480   target += byte;
1481
1482   if(calledOrCalling) {
1483     byte = isupNumber.InternalNetworkNumber << 7;
1484     byte |= (isupNumber.NumberingPlan << 4);
1485   } else {
1486     byte = isupNumber.NumberIncomplete << 7;
1487     byte |= (isupNumber.NumberingPlan << 4);
1488     byte |= (isupNumber.AddressPresentationRestricted << 2);
1489     byte |= isupNumber.Screening;
1490   }
1491
1492   target += byte;
1493   //int byte;
1494   unsigned char hex;
1495   std::string dtlc = isupNumber.Digits; // digits to lower case
1496   //std::transform(dtlc.begin(), dtlc.end(), dtlc.begin(), std::tolower);
1497   const char *digits = dtlc.c_str();
1498
1499   for(int k = 1; k < isupNumber.Digits.size(); k += 2) {
1500     if(isxdigit(byte = digits [k - 1]) == 0)
1501       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1502
1503     hex = (byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a);
1504
1505     if(isxdigit(byte = digits [k]) == 0)
1506       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1507
1508     hex |= ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a)) << 4;
1509     target += hex;
1510   }
1511
1512   if(hasDigits && filler) {
1513     if(isxdigit(byte = digits [isupNumber.Digits.size() - 1]) == 0)
1514       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1515
1516     target += ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a));
1517   }
1518 }
1519
1520
1521 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, char * buffer, int & length) throw(anna::RuntimeException) {
1522   std::string target;
1523   codeIsupNumber(isupNumber, calledOrCalling, target);
1524   length = target.size();
1525   memcpy(buffer, target.c_str(), length);
1526 }
1527
1528
1529 static inline bool is_base64(U8 c) {
1530   return (isalnum(c) || (c == '+') || (c == '/'));
1531 }
1532
1533 std::string functions::encodeBase64(const U8* buf, unsigned int bufLen) {
1534   std::string ret;
1535   int i = 0;
1536   int j = 0;
1537   U8 char_array_3[3];
1538   U8 char_array_4[4];
1539
1540   while (bufLen--) {
1541     char_array_3[i++] = *(buf++);
1542     if (i == 3) {
1543       char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
1544       char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
1545       char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
1546       char_array_4[3] = char_array_3[2] & 0x3f;
1547
1548       for(i = 0; (i <4) ; i++)
1549         ret += base64_chars[char_array_4[i]];
1550       i = 0;
1551     }
1552   }
1553
1554   if (i)
1555   {
1556     for(j = i; j < 3; j++)
1557       char_array_3[j] = '\0';
1558
1559     char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
1560     char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
1561     char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
1562     char_array_4[3] = char_array_3[2] & 0x3f;
1563
1564     for (j = 0; (j < i + 1); j++)
1565       ret += base64_chars[char_array_4[j]];
1566
1567     while((i++ < 3))
1568       ret += '=';
1569   }
1570
1571   return ret;
1572 }
1573
1574 std::string functions::decodeBase64(const std::string & encodedString) {
1575   int in_len = encodedString.size();
1576   int i = 0;
1577   int j = 0;
1578   int in_ = 0;
1579   U8 char_array_4[4], char_array_3[3];
1580   std::string ret;
1581
1582   while (in_len-- && ( encodedString[in_] != '=') && is_base64(encodedString[in_])) {
1583     char_array_4[i++] = encodedString[in_]; in_++;
1584     if (i ==4) {
1585       for (i = 0; i <4; i++)
1586         char_array_4[i] = base64_chars.find(char_array_4[i]);
1587
1588       char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
1589       char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
1590       char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
1591
1592       for (i = 0; (i < 3); i++)
1593           ret += char_array_3[i];
1594       i = 0;
1595     }
1596   }
1597
1598   if (i) {
1599     for (j = i; j <4; j++)
1600       char_array_4[j] = 0;
1601
1602     for (j = 0; j <4; j++)
1603       char_array_4[j] = base64_chars.find(char_array_4[j]);
1604
1605     char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
1606     char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
1607     char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
1608
1609     for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
1610   }
1611
1612   return ret;
1613 }
1614