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