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