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