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