/**
- * Convert a given fancy human-readable size to bytes.
+ * Unit conversion table entry for 'convert_with_table'.
+ */
+struct ConversionTable
+{
+ /**
+ * Name of the unit (or NULL for end of table).
+ */
+ const char *name;
+
+ /**
+ * Factor to apply for this unit.
+ */
+ unsigned long long value;
+};
+
+
+/**
+ * Convert a string of the form "4 X 5 Y" into a numeric value
+ * by interpreting "X" and "Y" as units and then multiplying
+ * the numbers with the values associated with the respective
+ * unit from the conversion table.
*
- * @param fancy_size human readable string (i.e. 1 MB)
- * @param size set to the size in bytes
+ * @param input input string to parse
+ * @param table table with the conversion of unit names to numbers
+ * @param output where to store the result
* @return GNUNET_OK on success, GNUNET_SYSERR on error
*/
-int
-GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size,
- unsigned long long *size)
+static int
+convert_with_table (const char *input,
+ const struct ConversionTable *table,
+ unsigned long long *output)
{
- struct
- {
- const char *name;
- unsigned long long value;
- } table[] =
- {
- {
- "B", 1},
- {
- "KiB", 1024},
- {
- "kB", 1000},
- {
- "MiB", 1024 * 1024},
- {
- "MB", 1000 * 1000},
- {
- "GiB", 1024 * 1024 * 1024},
- {
- "GB", 1000 * 1000 * 1000},
- {
- "TiB", 1024LL * 1024LL * 1024LL * 1024LL},
- {
- "TB", 1000LL * 1000LL * 1000LL * 1024LL},
- {
- "PiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL},
- {
- "PB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL},
- {
- "EiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * 1024LL},
- {
- "EB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL * 1000LL},
- {
- NULL, 0}
- };
unsigned long long ret;
char *in;
const char *tok;
ret = 0;
last = 0;
- in = GNUNET_strdup (fancy_size);
+ in = GNUNET_strdup (input);
for (tok = strtok (in, " "); tok != NULL; tok = strtok (NULL, " "))
{
i = 0;
{
ret += last;
last = 0;
- if (1 != sscanf (tok, "%llu", &last))
+ if (1 != SSCANF (tok, "%llu", &last))
{
GNUNET_free (in);
return GNUNET_SYSERR; /* expected number */
}
}
ret += last;
- *size = ret;
+ *output = ret;
GNUNET_free (in);
return GNUNET_OK;
}
+/**
+ * Convert a given fancy human-readable size to bytes.
+ *
+ * @param fancy_size human readable string (i.e. 1 MB)
+ * @param size set to the size in bytes
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ */
+int
+GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size,
+ unsigned long long *size)
+{
+ static const struct ConversionTable table[] =
+ {
+ { "B", 1},
+ { "KiB", 1024},
+ { "kB", 1000},
+ { "MiB", 1024 * 1024},
+ { "MB", 1000 * 1000},
+ { "GiB", 1024 * 1024 * 1024},
+ { "GB", 1000 * 1000 * 1000},
+ { "TiB", 1024LL * 1024LL * 1024LL * 1024LL},
+ { "TB", 1000LL * 1000LL * 1000LL * 1024LL},
+ { "PiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL},
+ { "PB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL},
+ { "EiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * 1024LL},
+ { "EB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL * 1000LL},
+ { NULL, 0}
+ };
+
+ return convert_with_table (fancy_size,
+ table,
+ size);
+}
+
+
/**
* Convert a given fancy human-readable time to our internal
* representation.
*
- * @param fancy_size human readable string (i.e. 1 minute)
+ * @param fancy_time human readable string (i.e. 1 minute)
* @param rtime set to the relative time
* @return GNUNET_OK on success, GNUNET_SYSERR on error
*/
int
-GNUNET_STRINGS_fancy_time_to_relative (const char *fancy_size,
+GNUNET_STRINGS_fancy_time_to_relative (const char *fancy_time,
struct GNUNET_TIME_Relative *rtime)
{
- struct
- {
- const char *name;
- unsigned long long value;
- } table[] =
+ static const struct ConversionTable table[] =
{
- {
- "ms", 1},
- {
- "s", 1000},
- {
- "\"", 1000},
- {
- "min", 60 * 1000},
- {
- "minutes", 60 * 1000},
- {
- "'", 60 * 1000},
- {
- "h", 60 * 60 * 1000},
- {
- "d", 24 * 60 * 60 * 1000},
- {
- "a", 31557600 /* year */ },
- {
- NULL, 0}
+ { "ms", 1},
+ { "s", 1000},
+ { "\"", 1000},
+ { "min", 60 * 1000},
+ { "minutes", 60 * 1000},
+ { "'", 60 * 1000},
+ { "h", 60 * 60 * 1000},
+ { "d", 24 * 60 * 60 * 1000},
+ { "a", 31536000000LL /* year */ },
+ { NULL, 0}
};
- unsigned long long ret;
- char *in;
- const char *tok;
- unsigned long long last;
- unsigned int i;
+ int ret;
+ unsigned long long val;
- if ((0 == strcasecmp (fancy_size, "infinity")) ||
- (0 == strcasecmp (fancy_size, "forever")))
- {
- *rtime = GNUNET_TIME_UNIT_FOREVER_REL;
- return GNUNET_OK;
- }
- ret = 0;
- last = 0;
- in = GNUNET_strdup (fancy_size);
- for (tok = strtok (in, " "); tok != NULL; tok = strtok (NULL, " "))
- {
- i = 0;
- while ((table[i].name != NULL) && (0 != strcasecmp (table[i].name, tok)))
- i++;
- if (table[i].name != NULL)
- last *= table[i].value;
- else
- {
- ret += last;
- last = 0;
- if (1 != sscanf (tok, "%llu", &last))
- {
- GNUNET_free (in);
- return GNUNET_SYSERR; /* expected number */
- }
- }
- }
- ret += last;
- rtime->rel_value = (uint64_t) ret;
- GNUNET_free (in);
- return GNUNET_OK;
+ ret = convert_with_table (fancy_time,
+ table,
+ &val);
+ rtime->rel_value = (uint64_t) val;
+ return ret;
}
/**
* @return pointer to the next byte in 'out' or NULL on error.
*/
char *
-GNUNET_STRINGS_data_to_string (unsigned char *data, size_t size, char *out, size_t out_size)
+GNUNET_STRINGS_data_to_string (const unsigned char *data, size_t size, char *out, size_t out_size)
{
/**
- * 32 characters for encoding (GNUNET_CRYPTO_hash => 32 characters)
+ * 32 characters for encoding
*/
static char *encTable__ = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
unsigned int wpos;
GNUNET_assert (data != NULL);
GNUNET_assert (out != NULL);
- GNUNET_assert (out_size >= (((size*8) + ((size*8) % 5)) % 5));
+ if (out_size < (((size*8) + ((size*8) % 5)) % 5))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
vbit = 0;
wpos = 0;
rpos = 0;
vbit = 5;
}
if (wpos >= out_size)
+ {
+ GNUNET_break (0);
return NULL;
+ }
out[wpos++] = encTable__[(bits >> (vbit - 5)) & 31];
vbit -= 5;
}
if (wpos != out_size)
+ {
+ GNUNET_break (0);
return NULL;
+ }
GNUNET_assert (vbit == 0);
return &out[wpos];
}
/**
- * Check whether @filename is absolute or not, and if it's an URI
+ * Check whether 'filename' is absolute or not, and if it's an URI
*
* @param filename filename to check
* @param can_be_uri GNUNET_YES to check for being URI, GNUNET_NO - to
* assume it's not URI
- * @param r_is_uri a pointer to an int that is set to GNUNET_YES if @filename
- * is URI and to GNUNET_NO otherwise. Can be NULL. If @can_be_uri is
+ * @param r_is_uri a pointer to an int that is set to GNUNET_YES if 'filename'
+ * is URI and to GNUNET_NO otherwise. Can be NULL. If 'can_be_uri' is
* not GNUNET_YES, *r_is_uri is set to GNUNET_NO.
- * @param r_uri a pointer to a char * that is set to a pointer to URI scheme.
+ * @param r_uri_scheme a pointer to a char * that is set to a pointer to URI scheme.
* The string is allocated by the function, and should be freed with
* GNUNET_free (). Can be NULL.
- * @return GNUNET_YES if @filaneme is absolute, GNUNET_NO otherwise.
+ * @return GNUNET_YES if 'filename' is absolute, GNUNET_NO otherwise.
*/
int
GNUNET_STRINGS_path_is_absolute (const char *filename, int can_be_uri,
#endif
/**
- * Perform @checks on @filename
+ * Perform 'checks' on 'filename'
*
* @param filename file to check
* @param checks checks to perform
- * @return GNUNET_YES if all @checks pass, GNUNET_NO if at least one of them
+ * @return GNUNET_YES if all checks pass, GNUNET_NO if at least one of them
* fails, GNUNET_SYSERR when a check can't be performed
*/
int
GNUNET_STRINGS_check_filename (const char *filename,
- enum GNUNET_STRINGS_FilenameCheck checks)
+ enum GNUNET_STRINGS_FilenameCheck checks)
{
struct stat st;
if (filename == NULL || filename[0] == '\0')
return GNUNET_YES;
}
+#define MAX_IPV6_ADDRLEN 47
+#define MAX_IPV4_ADDRLEN 21
+#define MAX_IP_ADDRLEN MAX_IPV6_ADDRLEN
+
+
+/**
+ * Tries to convert 'zt_addr' string to an IPv6 address.
+ *
+ * @param zt_addr 0-terminated string. May be mangled by the function.
+ * @param addrlen length of zt_addr (not counting 0-terminator).
+ * @param r_buf a buffer to fill. Initially gets filled with zeroes,
+ * then its sin6_port, sin6_family and sin6_addr are set appropriately.
+ * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which
+ * case the contents of r_buf are undefined.
+ */
+int
+GNUNET_STRINGS_to_address_ipv6 (const char *zt_addr,
+ uint16_t addrlen,
+ struct sockaddr_in6 *r_buf)
+{
+ int ret;
+ char *port_colon;
+ unsigned int port;
+
+ if (addrlen < 6)
+ return GNUNET_SYSERR;
+
+ port_colon = strrchr (zt_addr, ':');
+ if (port_colon == NULL)
+ return GNUNET_SYSERR;
+ ret = SSCANF (port_colon, ":%u", &port);
+ if (ret != 1 || port > 65535)
+ return GNUNET_SYSERR;
+ port_colon[0] = '\0';
+ memset (r_buf, 0, sizeof (struct sockaddr_in6));
+ ret = inet_pton (AF_INET6, zt_addr, &r_buf->sin6_addr);
+ if (ret <= 0)
+ return GNUNET_SYSERR;
+ r_buf->sin6_port = htonl (port);
+ r_buf->sin6_family = AF_INET6;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Tries to convert 'zt_addr' string to an IPv4 address.
+ *
+ * @param zt_addr 0-terminated string. May be mangled by the function.
+ * @param addrlen length of zt_addr (not counting 0-terminator).
+ * @param r_buf a buffer to fill.
+ * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which case
+ * the contents of r_buf are undefined.
+ */
+int
+GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr, uint16_t addrlen,
+ struct sockaddr_in *r_buf)
+{
+ unsigned int temps[5];
+ unsigned int port;
+ int cnt;
+
+ if (addrlen < 9)
+ return GNUNET_SYSERR;
+
+ cnt = SSCANF (zt_addr, "%u.%u.%u.%u:%u", &temps[0], &temps[1], &temps[2], &temps[3], &port);
+ if (cnt != 5)
+ return GNUNET_SYSERR;
+
+ for (cnt = 0; cnt < 4; cnt++)
+ if (temps[cnt] > 0xFF)
+ return GNUNET_SYSERR;
+ if (port > 65535)
+ return GNUNET_SYSERR;
+
+ r_buf->sin_family = AF_INET;
+ r_buf->sin_port = htonl (port);
+ r_buf->sin_addr.s_addr = htonl ((temps[0] << 24) + (temps[1] << 16) +
+ (temps[2] << 8) + temps[3]);
+ return GNUNET_OK;
+}
+
+/**
+ * Tries to convert 'addr' string to an IP (v4 or v6) address.
+ * IPv6 address must have its address part enclosed in '()' parens
+ * instead of '[]'.
+ * Will automatically decide whether to treat 'addr' as v4 or v6 address.
+ *
+ * @param addr a string, may not be 0-terminated.
+ * @param addrlen number of bytes in addr (if addr is 0-terminated,
+ * 0-terminator should not be counted towards addrlen).
+ * @param r_buf a buffer to fill.
+ * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which
+ * case the contents of r_buf are undefined.
+ */
+int
+GNUNET_STRINGS_to_address_ip (const char *addr,
+ uint16_t addrlen,
+ struct sockaddr_storage *r_buf)
+{
+ uint16_t i;
+ char zt_addr[MAX_IP_ADDRLEN + 1];
+ uint16_t zt_len = addrlen <= MAX_IP_ADDRLEN ? addrlen : MAX_IP_ADDRLEN;
+
+ if (addrlen < 1)
+ return GNUNET_SYSERR;
+
+ memset (zt_addr, 0, MAX_IP_ADDRLEN + 1);
+ strncpy (zt_addr, addr, zt_len);
+
+ /* For URIs we use '(' and ')' instead of '[' and ']'. Do the substitution
+ * now, as GNUNET_STRINGS_to_address_ipv6() takes a proper []-enclosed IPv6
+ * address.
+ */
+ if (zt_addr[0] == '(')
+ {
+ for (i = 0; i < zt_len; i++)
+ {
+ switch (zt_addr[i])
+ {
+ case '(':
+ zt_addr[i] = '[';
+ break;
+ case ')':
+ zt_addr[i] = ']';
+ break;
+ default:
+ break;
+ }
+ }
+ return GNUNET_STRINGS_to_address_ipv6 (zt_addr, zt_len, (struct sockaddr_in6 *) r_buf);
+ }
+ return GNUNET_STRINGS_to_address_ipv4 (zt_addr, zt_len, (struct sockaddr_in *) r_buf);
+}
+
/* end of strings.c */