blob: 137bdeabe5aa916d99aa8c2f6ebb07ac5c5b9533 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "pegasus_utils.h"
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <errno.h>
namespace pegasus {
namespace utils {
void addr2host(const ::dsn::rpc_address &addr, char *str, int len /* = 100*/)
{
struct sockaddr_in addr2;
addr2.sin_addr.s_addr = htonl(addr.ip());
addr2.sin_family = AF_INET;
if (getnameinfo((struct sockaddr *)&addr2,
sizeof(sockaddr),
str,
sizeof(char *) * len,
nullptr,
0,
NI_NAMEREQD)) {
inet_ntop(AF_INET, &(addr2.sin_addr), str, 100);
}
}
size_t
c_escape_string(const char *src, size_t src_len, char *dest, size_t dest_len, bool always_escape)
{
const char *src_end = src + src_len;
size_t used = 0;
for (; src < src_end; src++) {
unsigned char c = *src;
if (always_escape) {
if (dest_len - used < 5) // space for four-character escape + \0
return (size_t)-1;
snprintf(dest + used, 5, "\\x%02X", c);
used += 4;
continue;
}
if (dest_len - used < 2) // space for two-character escape
return (size_t)-1;
switch (c) {
case '\n':
dest[used++] = '\\';
dest[used++] = 'n';
break;
case '\r':
dest[used++] = '\\';
dest[used++] = 'r';
break;
case '\t':
dest[used++] = '\\';
dest[used++] = 't';
break;
case '\"':
dest[used++] = '\\';
dest[used++] = '\"';
break;
case '\'':
dest[used++] = '\\';
dest[used++] = '\'';
break;
case '\\':
dest[used++] = '\\';
dest[used++] = '\\';
break;
default:
// Note that if we emit \xNN and the src character after that is a hex
// digit then that digit must be escaped too to prevent it being
// interpreted as part of the character code by C.
if (c < ' ' || c > '~') {
if (dest_len - used < 5) // space for four-character escape + \0
return (size_t)-1;
snprintf(dest + used, 5, "\\x%02X", c);
used += 4;
} else {
dest[used++] = c;
break;
}
}
}
if (dest_len - used < 1) // make sure that there is room for \0
return (size_t)-1;
dest[used] = '\0'; // doesn't count towards return value though
return used;
}
inline unsigned int hex_digit_to_int(char c)
{
/* Assume ASCII. */
assert('0' == 0x30 && 'A' == 0x41 && 'a' == 0x61);
assert(isxdigit(c));
unsigned int x = static_cast<unsigned char>(c);
if (x > '9') {
x += 9;
}
return x & 0xf;
}
// return < 0 means failed
static int c_unescape_sequences(const char *source, char *dest)
{
char *d = dest;
const char *p = source;
// Small optimization for case where source = dest and there's no escaping
while (p == d && *p >= ' ' && *p <= '~' && *p != '\\') {
p++;
d++;
}
while (*p != '\0') {
if (*p == '\\') {
switch (*++p) { // skip past the '\\'
case 'n':
*d++ = '\n';
break;
case 'r':
*d++ = '\r';
break;
case 't':
*d++ = '\t';
break;
case '"':
*d++ = '\"';
break;
case '\'':
*d++ = '\'';
break;
case '\\':
*d++ = '\\';
break;
case 'x':
case 'X': {
if (!isxdigit(p[1]) || !isxdigit(p[2])) {
return source - p - 1;
}
unsigned int ch = hex_digit_to_int(p[1]);
ch = (ch << 4) + hex_digit_to_int(p[2]);
*d++ = ch;
p += 2;
break;
}
default:
return source - p - 1;
}
p++; // read past letter we escaped
} else if (*p >= ' ' && *p <= '~') {
*d++ = *p++;
} else {
return source - p - 1;
}
}
*d = '\0';
return d - dest;
}
int c_unescape_string(const std::string &src, std::string &dest)
{
dest = src;
int len = c_unescape_sequences(dest.c_str(), &dest[0]);
if (len >= 0 && len < dest.length())
dest.resize(len);
return len;
}
} // namespace utils
} // namespace pegasus