2008-08-05 15:08:32 +00:00
|
|
|
|
2009-06-24 18:56:07 +00:00
|
|
|
#ifdef LIGHTY_OS_NETBSD
|
|
|
|
#define _NETBSD_SOURCE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef LIGHTY_OS_OPENBSD
|
|
|
|
#warning OpenBSD does net allow sending of file descriptors when _XOPEN_SOURCE is defined (needed for Solaris)
|
|
|
|
#else
|
|
|
|
#define _XOPEN_SOURCE
|
|
|
|
#define _XOPEN_SOURCE_EXTENDED 1
|
|
|
|
#endif
|
2008-10-02 19:46:06 +00:00
|
|
|
|
2009-06-16 21:16:07 +00:00
|
|
|
#include <lighttpd/utils.h>
|
2009-06-17 08:59:34 +00:00
|
|
|
#include <lighttpd/ip_parsers.h>
|
2008-08-05 15:08:32 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
2008-09-18 07:14:57 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
|
2009-06-24 18:56:07 +00:00
|
|
|
#if 0
|
2009-06-23 21:40:13 +00:00
|
|
|
#include <stropts.h>
|
2009-06-24 18:56:07 +00:00
|
|
|
#endif
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
/* for send/li_receive_fd */
|
2009-06-24 18:56:07 +00:00
|
|
|
union fdmsg {
|
|
|
|
struct cmsghdr h;
|
|
|
|
gchar buf[1000];
|
|
|
|
};
|
|
|
|
|
2009-06-23 21:40:13 +00:00
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_fatal(const gchar* msg) {
|
2008-08-05 15:08:32 +00:00
|
|
|
fprintf(stderr, "%s\n", msg);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_fd_no_block(int fd) {
|
2009-06-23 21:40:13 +00:00
|
|
|
#ifdef O_NONBLOCK
|
|
|
|
fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
|
|
|
|
#elif defined _WIN32
|
2008-08-05 15:08:32 +00:00
|
|
|
int i = 1;
|
2009-06-23 21:40:13 +00:00
|
|
|
ioctlsocket(fd, FIONBIO, &i);
|
|
|
|
#else
|
|
|
|
#error No way found to set non-blocking mode for fds.
|
2008-08-05 15:08:32 +00:00
|
|
|
#endif
|
2009-06-23 21:40:13 +00:00
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_fd_block(int fd) {
|
2008-08-05 15:08:32 +00:00
|
|
|
#ifdef O_NONBLOCK
|
2009-06-23 21:40:13 +00:00
|
|
|
fcntl(fd, F_SETFL, O_RDWR);
|
2008-08-05 15:08:32 +00:00
|
|
|
#elif defined _WIN32
|
2009-06-23 21:40:13 +00:00
|
|
|
int i = 0;
|
2008-08-05 15:08:32 +00:00
|
|
|
ioctlsocket(fd, FIONBIO, &i);
|
2009-06-23 21:40:13 +00:00
|
|
|
#else
|
|
|
|
#error No way found to set blocking mode for fds.
|
2008-08-05 15:08:32 +00:00
|
|
|
#endif
|
|
|
|
}
|
2008-08-06 18:46:42 +00:00
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_fd_init(int fd) {
|
2009-06-23 21:40:13 +00:00
|
|
|
#ifdef FD_CLOEXEC
|
|
|
|
/* close fd on exec (cgi) */
|
|
|
|
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
|
|
|
#endif
|
2009-07-09 20:17:24 +00:00
|
|
|
li_fd_no_block(fd);
|
2009-06-23 21:40:13 +00:00
|
|
|
}
|
|
|
|
|
2009-06-24 18:56:07 +00:00
|
|
|
#if 0
|
2009-06-23 21:40:13 +00:00
|
|
|
#ifndef _WIN32
|
2009-07-09 20:17:24 +00:00
|
|
|
int li_send_fd(int s, int fd) { /* write fd to unix socket s */
|
2009-06-23 21:40:13 +00:00
|
|
|
for ( ;; ) {
|
|
|
|
if (-1 == ioctl(s, I_SENDFD, fd)) {
|
|
|
|
switch (errno) {
|
|
|
|
case EINTR: break;
|
|
|
|
case EAGAIN: return -2;
|
|
|
|
default: return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
int li_receive_fd(int s, int *fd) { /* read fd from unix socket s */
|
2009-06-23 21:40:13 +00:00
|
|
|
struct strrecvfd res;
|
|
|
|
memset(&res, 0, sizeof(res));
|
|
|
|
for ( ;; ) {
|
|
|
|
if (-1 == ioctl(s, I_RECVFD, &res)) {
|
|
|
|
switch (errno) {
|
|
|
|
case EINTR: break;
|
|
|
|
case EAGAIN: return -2;
|
|
|
|
default: return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
*fd = res.fd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2009-06-24 18:56:07 +00:00
|
|
|
#endif
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
gint li_send_fd(gint s, gint fd) { /* write fd to unix socket s */
|
2009-06-24 18:56:07 +00:00
|
|
|
struct msghdr msg;
|
|
|
|
struct iovec iov;
|
|
|
|
#ifdef CMSG_FIRSTHDR
|
|
|
|
struct cmsghdr *cmsg;
|
|
|
|
#ifndef CMSG_SPACE
|
|
|
|
#define CMSG_SPACE(x) x+100
|
|
|
|
#endif
|
|
|
|
gchar buf[CMSG_SPACE(sizeof(gint))];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
iov.iov_len = 1;
|
|
|
|
iov.iov_base = "x";
|
|
|
|
msg.msg_iov = &iov;
|
|
|
|
msg.msg_iovlen = 1;
|
|
|
|
msg.msg_name = 0;
|
|
|
|
msg.msg_namelen = 0;
|
|
|
|
#ifdef CMSG_FIRSTHDR
|
|
|
|
msg.msg_control = buf;
|
|
|
|
msg.msg_controllen = sizeof(buf);
|
|
|
|
cmsg = CMSG_FIRSTHDR(&msg);
|
|
|
|
cmsg->cmsg_level = SOL_SOCKET;
|
|
|
|
cmsg->cmsg_type = SCM_RIGHTS;
|
|
|
|
#ifndef CMSG_LEN
|
|
|
|
#define CMSG_LEN(x) x
|
|
|
|
#endif
|
|
|
|
cmsg->cmsg_len = CMSG_LEN(sizeof(gint));
|
|
|
|
msg.msg_controllen = cmsg->cmsg_len;
|
|
|
|
*((gint*)CMSG_DATA(cmsg)) = fd;
|
|
|
|
#else
|
|
|
|
msg.msg_accrights = (gchar*)&fd;
|
|
|
|
msg.msg_accrightslen = sizeof(fd);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if (sendmsg(s, &msg, 0) < 0) {
|
|
|
|
switch (errno) {
|
2009-07-07 20:24:52 +00:00
|
|
|
case EINTR: continue;
|
|
|
|
#if EAGAIN != EWOULDBLOCK
|
2009-06-24 18:56:07 +00:00
|
|
|
case EWOULDBLOCK:
|
2009-07-07 20:24:52 +00:00
|
|
|
#endif
|
2009-06-24 18:56:07 +00:00
|
|
|
case EAGAIN: return -2;
|
|
|
|
default: return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
gint li_receive_fd(gint s, gint *fd) { /* read fd from unix socket s */
|
2009-06-24 18:56:07 +00:00
|
|
|
struct iovec iov;
|
|
|
|
struct msghdr msg;
|
|
|
|
#ifdef CMSG_FIRSTHDR
|
|
|
|
union fdmsg cmsg;
|
|
|
|
struct cmsghdr* h;
|
|
|
|
#else
|
|
|
|
gint _fd;
|
|
|
|
#endif
|
|
|
|
gchar x[100];
|
|
|
|
gchar name[100];
|
|
|
|
|
|
|
|
iov.iov_base = x;
|
|
|
|
iov.iov_len = 100;
|
|
|
|
msg.msg_name = name;
|
|
|
|
msg.msg_namelen = 100;
|
|
|
|
#ifdef CMSG_FIRSTHDR
|
|
|
|
msg.msg_control = cmsg.buf;
|
|
|
|
msg.msg_controllen = sizeof(union fdmsg);
|
|
|
|
#else
|
|
|
|
msg.msg_accrights = (gchar*)&_fd;
|
|
|
|
msg.msg_accrightslen = sizeof(_fd);
|
|
|
|
#endif
|
|
|
|
msg.msg_iov = &iov;
|
|
|
|
msg.msg_iovlen = 1;
|
|
|
|
#ifdef CMSG_FIRSTHDR
|
|
|
|
msg.msg_flags = 0;
|
|
|
|
h = CMSG_FIRSTHDR(&msg);
|
|
|
|
#ifndef CMSG_LEN
|
|
|
|
#define CMSG_LEN(x) x
|
|
|
|
#endif
|
|
|
|
h->cmsg_len = CMSG_LEN(sizeof(gint));
|
|
|
|
h->cmsg_level = SOL_SOCKET;
|
|
|
|
h->cmsg_type = SCM_RIGHTS;
|
|
|
|
*((gint*)CMSG_DATA(h)) = -1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if (recvmsg(s, &msg, 0) == -1) {
|
|
|
|
switch (errno) {
|
2009-07-07 20:24:52 +00:00
|
|
|
case EINTR: continue;
|
|
|
|
#if EAGAIN != EWOULDBLOCK
|
2009-06-24 18:56:07 +00:00
|
|
|
case EWOULDBLOCK:
|
2009-07-07 20:24:52 +00:00
|
|
|
#endif
|
2009-06-24 18:56:07 +00:00
|
|
|
case EAGAIN: return -2;
|
|
|
|
default: return -1;
|
|
|
|
}
|
|
|
|
}
|
2009-07-07 20:24:52 +00:00
|
|
|
|
|
|
|
break;
|
2009-06-24 18:56:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CMSG_FIRSTHDR
|
|
|
|
h = CMSG_FIRSTHDR(&msg);
|
|
|
|
|
|
|
|
if (!h || h->cmsg_len != CMSG_LEN(sizeof(gint)) || h->cmsg_level != SOL_SOCKET || h->cmsg_type != SCM_RIGHTS) {
|
|
|
|
#ifdef EPROTO
|
|
|
|
errno = EPROTO;
|
|
|
|
#else
|
|
|
|
errno = EINVAL;
|
|
|
|
#endif
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*fd = *((gint*)CMSG_DATA(h));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
if (msg.msg_accrightslen != sizeof(fd))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
*fd = _fd;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2009-06-23 21:40:13 +00:00
|
|
|
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_ev_io_add_events(struct ev_loop *loop, ev_io *watcher, int events) {
|
2008-08-06 18:46:42 +00:00
|
|
|
if ((watcher->events & events) == events) return;
|
|
|
|
ev_io_stop(loop, watcher);
|
|
|
|
ev_io_set(watcher, watcher->fd, watcher->events | events);
|
|
|
|
ev_io_start(loop, watcher);
|
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_ev_io_rem_events(struct ev_loop *loop, ev_io *watcher, int events) {
|
2008-08-06 18:46:42 +00:00
|
|
|
if (0 == (watcher->events & events)) return;
|
|
|
|
ev_io_stop(loop, watcher);
|
|
|
|
ev_io_set(watcher, watcher->fd, watcher->events & ~events);
|
|
|
|
ev_io_start(loop, watcher);
|
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_ev_io_set_events(struct ev_loop *loop, ev_io *watcher, int events) {
|
2008-08-06 18:46:42 +00:00
|
|
|
if (events == (watcher->events & (EV_READ | EV_WRITE))) return;
|
|
|
|
ev_io_stop(loop, watcher);
|
|
|
|
ev_io_set(watcher, watcher->fd, (watcher->events & ~(EV_READ | EV_WRITE)) | events);
|
|
|
|
ev_io_start(loop, watcher);
|
|
|
|
}
|
2008-08-09 15:20:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* converts hex char (0-9, A-Z, a-z) to decimal.
|
|
|
|
* returns -1 on invalid input.
|
|
|
|
*/
|
|
|
|
static int hex2int(unsigned char hex) {
|
|
|
|
int res;
|
|
|
|
if (hex >= 'A') { /* 'A' < 'a': hex >= 'A' --> hex >= 'a' */
|
|
|
|
if (hex >= 'a') {
|
|
|
|
res = hex - 'a' + 10;
|
|
|
|
} else {
|
|
|
|
res = hex - 'A' + 10;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
res = hex - '0';
|
|
|
|
}
|
|
|
|
if (res > 15)
|
|
|
|
res = -1;
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_url_decode(GString *path) {
|
2008-08-09 15:20:12 +00:00
|
|
|
char *src, *dst, c;
|
|
|
|
src = dst = path->str;
|
|
|
|
for ( ; *src; src++) {
|
|
|
|
c = *src;
|
|
|
|
if (c == '%') {
|
|
|
|
if (src[1] && src[2]) {
|
|
|
|
int a = hex2int(src[1]), b = hex2int(src[2]);
|
|
|
|
if (a != -1 && b != -1) {
|
|
|
|
c = (a << 4) | b;
|
|
|
|
if (c < 32 || c == 127) c = '_';
|
|
|
|
*(dst++) = c;
|
|
|
|
}
|
|
|
|
src += 2;
|
|
|
|
} else {
|
|
|
|
/* end of string */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (c < 32 || c == 127) c = '_';
|
|
|
|
*(dst++) = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_string_set_size(path, dst - path->str);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove "/../", "//", "/./" parts from path.
|
|
|
|
*
|
|
|
|
* /blah/.. gets /
|
|
|
|
* /blah/../foo gets /foo
|
|
|
|
* /abc/./xyz gets /abc/xyz
|
|
|
|
* /abc//xyz gets /abc/xyz
|
|
|
|
*
|
|
|
|
* NOTE: src and dest can point to the same buffer, in which case
|
|
|
|
* the operation is performed in-place.
|
|
|
|
*/
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_path_simplify(GString *path) {
|
2008-08-09 15:20:12 +00:00
|
|
|
int toklen;
|
|
|
|
char c, pre1;
|
|
|
|
char *start, *slash, *walk, *out;
|
|
|
|
unsigned short pre;
|
|
|
|
|
|
|
|
if (path == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
walk = start = out = slash = path->str;
|
|
|
|
while (*walk == ' ') {
|
|
|
|
walk++;
|
|
|
|
}
|
|
|
|
|
|
|
|
pre1 = *(walk++);
|
|
|
|
c = *(walk++);
|
|
|
|
pre = pre1;
|
|
|
|
if (pre1 != '/') {
|
|
|
|
pre = ('/' << 8) | pre1;
|
|
|
|
*(out++) = '/';
|
|
|
|
}
|
|
|
|
*(out++) = pre1;
|
|
|
|
|
|
|
|
if (pre1 == '\0') {
|
|
|
|
g_string_set_size(path, out - start);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if (c == '/' || c == '\0') {
|
|
|
|
toklen = out - slash;
|
|
|
|
if (toklen == 3 && pre == (('.' << 8) | '.')) {
|
|
|
|
out = slash;
|
|
|
|
if (out > start) {
|
|
|
|
out--;
|
|
|
|
while (out > start && *out != '/') {
|
|
|
|
out--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == '\0')
|
|
|
|
out++;
|
|
|
|
} else if (toklen == 1 || pre == (('/' << 8) | '.')) {
|
|
|
|
out = slash;
|
|
|
|
if (c == '\0')
|
|
|
|
out++;
|
|
|
|
}
|
|
|
|
|
|
|
|
slash = out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == '\0')
|
|
|
|
break;
|
|
|
|
|
|
|
|
pre1 = c;
|
|
|
|
pre = (pre << 8) | pre1;
|
|
|
|
c = *walk;
|
|
|
|
*out = pre1;
|
|
|
|
|
|
|
|
out++;
|
|
|
|
walk++;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_string_set_size(path, out - start);
|
|
|
|
}
|
2008-08-13 00:18:35 +00:00
|
|
|
|
2008-08-13 23:05:15 +00:00
|
|
|
|
2009-10-08 12:33:47 +00:00
|
|
|
gboolean li_querystring_find(const GString *querystring, const gchar *key, const guint key_len, gchar **val, guint *val_len) {
|
2009-08-13 16:38:30 +00:00
|
|
|
gchar delim = '\0';
|
|
|
|
gchar *end = querystring->str + querystring->len;
|
|
|
|
gchar *start = querystring->str;
|
|
|
|
gchar *c = querystring->str;
|
|
|
|
|
|
|
|
/* search for key */
|
|
|
|
for (c = querystring->str; c != end; c++) {
|
|
|
|
if ((*c == '&' || *c == ';') && delim == '\0')
|
|
|
|
delim = *c;
|
|
|
|
|
|
|
|
if (*c == '=' || (*c == delim && delim != '\0')) {
|
|
|
|
if ((c - start) == (gint)key_len && memcmp(start, key, key_len) == 0) {
|
|
|
|
/* key found */
|
|
|
|
c++;
|
|
|
|
*val = c;
|
|
|
|
|
|
|
|
/* get length of val */
|
|
|
|
for (; c != end; c++) {
|
|
|
|
if ((*c == '&' || *c == ';') && (delim == '\0' || *c == delim))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
*val_len = c - *val;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = c + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
GString *li_counter_format(guint64 count, liCounterType t, GString *dest) {
|
2009-03-15 23:32:46 +00:00
|
|
|
guint64 rest;
|
|
|
|
|
2009-03-13 22:16:21 +00:00
|
|
|
if (!dest)
|
|
|
|
dest = g_string_sized_new(10);
|
|
|
|
else
|
|
|
|
g_string_truncate(dest, 0);
|
|
|
|
|
|
|
|
switch (t) {
|
|
|
|
case COUNTER_TIME:
|
|
|
|
/* 123 days 12 hours 32 min 5 s */
|
|
|
|
if (count > (3600*24)) {
|
|
|
|
g_string_append_printf(dest, "%"G_GUINT64_FORMAT" days", count / (3600*24));
|
|
|
|
count %= (3600*24);
|
2008-08-13 23:05:15 +00:00
|
|
|
}
|
2009-03-13 22:16:21 +00:00
|
|
|
if (count > 3600) {
|
|
|
|
g_string_append_printf(dest, "%s%"G_GUINT64_FORMAT" hours", dest->len ? " ":"", count / 3600);
|
2008-11-03 14:10:25 +00:00
|
|
|
count %= 3600;
|
|
|
|
}
|
2009-03-13 22:16:21 +00:00
|
|
|
if (count > 60) {
|
|
|
|
g_string_append_printf(dest, "%s%"G_GUINT64_FORMAT" min", dest->len ? " ":"", count / 60);
|
2008-11-03 14:10:25 +00:00
|
|
|
count %= 60;
|
|
|
|
}
|
2009-03-14 00:40:58 +00:00
|
|
|
if (count || !dest->len) {
|
2009-03-13 22:16:21 +00:00
|
|
|
g_string_append_printf(dest, "%s%"G_GUINT64_FORMAT" s", dest->len ? " ":"", count);
|
2008-11-03 14:10:25 +00:00
|
|
|
}
|
2009-03-13 22:16:21 +00:00
|
|
|
break;
|
|
|
|
case COUNTER_BYTES:
|
|
|
|
/* B KB MB GB TB PB */
|
|
|
|
if (count >> 50) {
|
|
|
|
/* PB */
|
2009-03-15 23:32:46 +00:00
|
|
|
rest = (((count >> 40) & 1023) * 100) / 1024;
|
|
|
|
g_string_append_printf(dest, "%"G_GUINT64_FORMAT".%02"G_GUINT64_FORMAT" PB", count >> 50, rest);
|
2009-03-13 22:16:21 +00:00
|
|
|
} else if (count >> 40) {
|
|
|
|
/* TB */
|
2009-03-15 23:32:46 +00:00
|
|
|
rest = (((count >> 30) & 1023) * 100) / 1024;
|
|
|
|
g_string_append_printf(dest, "%"G_GUINT64_FORMAT".%02"G_GUINT64_FORMAT" TB", count >> 40, rest);
|
2009-03-13 22:16:21 +00:00
|
|
|
} else if (count >> 30) {
|
|
|
|
/* GB */
|
2009-03-15 23:32:46 +00:00
|
|
|
rest = (((count >> 20) & 1023) * 100) / 1024;
|
|
|
|
g_string_append_printf(dest, "%"G_GUINT64_FORMAT".%02"G_GUINT64_FORMAT" GB", count >> 30, rest);
|
2009-03-13 22:16:21 +00:00
|
|
|
} else if (count >> 20) {
|
|
|
|
/* MB */
|
2009-03-15 23:32:46 +00:00
|
|
|
rest = (((count >> 10) & 1023) * 100) / 1024;
|
|
|
|
g_string_append_printf(dest, "%"G_GUINT64_FORMAT".%02"G_GUINT64_FORMAT" MB", count >> 20, rest);
|
2009-03-13 22:16:21 +00:00
|
|
|
} else if (count >> 10) {
|
|
|
|
/* KB */
|
2009-03-15 23:32:46 +00:00
|
|
|
rest = ((count & 1023) * 100) / 1024;
|
|
|
|
g_string_append_printf(dest, "%"G_GUINT64_FORMAT".%02"G_GUINT64_FORMAT" KB", count >> 10, rest);
|
2009-03-13 22:16:21 +00:00
|
|
|
} else {
|
|
|
|
/* B */
|
|
|
|
g_string_append_printf(dest, "%"G_GUINT64_FORMAT" B", count);
|
2008-11-03 14:10:25 +00:00
|
|
|
}
|
2009-03-13 22:16:21 +00:00
|
|
|
break;
|
|
|
|
case COUNTER_UNITS:
|
|
|
|
/* m k */
|
|
|
|
if (count < 1000) {
|
|
|
|
g_string_append_printf(dest, "%"G_GUINT64_FORMAT, count);
|
|
|
|
} else if (count < 1000*1000) {
|
2009-03-16 01:52:01 +00:00
|
|
|
g_string_append_printf(dest, "%"G_GUINT64_FORMAT".%02"G_GUINT64_FORMAT" k", count / (guint64)1000, (count % (guint64)1000) / 10);
|
2009-03-13 22:16:21 +00:00
|
|
|
} else {
|
2009-03-16 01:52:01 +00:00
|
|
|
g_string_append_printf(dest, "%"G_GUINT64_FORMAT".%02"G_GUINT64_FORMAT" m", count / (guint64)(1000*1000), (count % (guint64)(1000*1000)) / 10000);
|
2008-11-03 14:10:25 +00:00
|
|
|
}
|
2009-03-13 22:16:21 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-11-03 14:10:25 +00:00
|
|
|
|
2009-03-13 22:16:21 +00:00
|
|
|
return dest;
|
2008-11-03 14:10:25 +00:00
|
|
|
}
|
|
|
|
|
2009-01-06 22:25:07 +00:00
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
gchar *li_ev_backend_string(guint backend) {
|
2008-08-15 16:21:21 +00:00
|
|
|
switch (backend) {
|
2009-10-17 21:50:21 +00:00
|
|
|
case EVBACKEND_SELECT: return "select";
|
|
|
|
case EVBACKEND_POLL: return "poll";
|
|
|
|
case EVBACKEND_EPOLL: return "epoll";
|
|
|
|
case EVBACKEND_KQUEUE: return "kqueue";
|
|
|
|
case EVBACKEND_DEVPOLL: return "devpoll";
|
|
|
|
case EVBACKEND_PORT: return "port";
|
|
|
|
default: return "unknown";
|
2008-08-15 16:21:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_string_destroy_notify(gpointer str) {
|
2008-09-24 21:55:20 +00:00
|
|
|
g_string_free((GString*)str, TRUE);
|
|
|
|
}
|
2008-10-02 00:33:51 +00:00
|
|
|
|
2009-10-17 21:50:21 +00:00
|
|
|
guint li_hash_binary_len(gconstpointer data, gsize len) {
|
|
|
|
GString str = li_const_gstring(data, len);
|
|
|
|
return g_string_hash(&str);
|
|
|
|
}
|
2008-10-02 00:33:51 +00:00
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
guint li_hash_ipv4(gconstpointer key) {
|
2009-01-06 22:25:07 +00:00
|
|
|
return *((guint*)key) * 2654435761;
|
2008-10-02 00:33:51 +00:00
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
guint li_hash_ipv6(gconstpointer key) {
|
2009-10-17 21:50:21 +00:00
|
|
|
return li_hash_binary_len(key, 16);
|
2008-10-02 00:33:51 +00:00
|
|
|
}
|
2008-10-02 19:46:06 +00:00
|
|
|
|
2009-10-17 21:50:21 +00:00
|
|
|
guint li_hash_sockaddr(gconstpointer key) {
|
|
|
|
const liSocketAddress *addr = key;
|
|
|
|
return li_hash_binary_len(addr->addr, addr->len);
|
|
|
|
}
|
|
|
|
gboolean li_equal_sockaddr(gconstpointer key1, gconstpointer key2) {
|
|
|
|
const liSocketAddress *addr1 = key1, *addr2 = key2;
|
|
|
|
if (addr1->len != addr2->len) return FALSE;
|
|
|
|
if (addr1->addr == addr2->addr) return TRUE;
|
|
|
|
if (!addr1->addr || !addr2->addr) return FALSE;
|
|
|
|
return 0 == memcmp(addr1->addr, addr2->addr, addr1->len);
|
|
|
|
}
|
2008-10-02 19:46:06 +00:00
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
GString *li_sockaddr_to_string(liSocketAddress addr, GString *dest, gboolean showport) {
|
2008-11-03 14:10:25 +00:00
|
|
|
gchar *p;
|
|
|
|
guint8 len = 0;
|
|
|
|
guint8 tmp;
|
|
|
|
guint8 tmplen;
|
|
|
|
guint8 oct;
|
2009-07-08 19:06:07 +00:00
|
|
|
liSockAddr *saddr = addr.addr;
|
2008-11-03 14:10:25 +00:00
|
|
|
|
|
|
|
switch (saddr->plain.sa_family) {
|
|
|
|
case AF_INET:
|
|
|
|
/* ipv4 */
|
|
|
|
if (!dest)
|
2009-03-01 16:15:52 +00:00
|
|
|
dest = g_string_sized_new(16+6);
|
2008-11-03 14:10:25 +00:00
|
|
|
else
|
2009-03-01 16:15:52 +00:00
|
|
|
g_string_set_size(dest, 16+6);
|
2008-11-03 14:10:25 +00:00
|
|
|
|
|
|
|
p = dest->str;
|
|
|
|
|
|
|
|
for (guint i = 0; i < 4; i++) {
|
|
|
|
oct = ((guint8*)&saddr->ipv4.sin_addr.s_addr)[i];
|
|
|
|
for (tmplen = 1, tmp = oct; tmp > 9; tmp /= 10)
|
|
|
|
tmplen++;
|
|
|
|
|
|
|
|
len += tmplen + 1;
|
|
|
|
tmp = tmplen;
|
|
|
|
|
|
|
|
p[tmplen] = '.';
|
|
|
|
|
|
|
|
for (p += tmplen-1; tmplen; tmplen--) {
|
|
|
|
*p = '0' + (oct % 10);
|
|
|
|
p--;
|
|
|
|
oct /= 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
p += tmp + 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
dest->str[len-1] = 0;
|
|
|
|
dest->len = len-1;
|
2009-03-01 16:15:52 +00:00
|
|
|
if (showport) g_string_append_printf(dest, ":%u", (unsigned int) ntohs(saddr->ipv4.sin_port));
|
2008-11-03 14:10:25 +00:00
|
|
|
break;
|
2008-11-20 02:15:40 +00:00
|
|
|
#ifdef HAVE_IPV6
|
2008-11-03 14:10:25 +00:00
|
|
|
case AF_INET6:
|
|
|
|
/* ipv6 - not yet implemented with own function */
|
|
|
|
if (!dest)
|
2009-03-01 16:15:52 +00:00
|
|
|
dest = g_string_sized_new(INET6_ADDRSTRLEN+6);
|
2008-11-03 14:10:25 +00:00
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
li_ipv6_tostring(dest, saddr->ipv6.sin6_addr.s6_addr);
|
2009-03-01 16:15:52 +00:00
|
|
|
if (showport) g_string_append_printf(dest, ":%u", (unsigned int) ntohs(saddr->ipv6.sin6_port));
|
2009-04-02 20:29:09 +00:00
|
|
|
break;
|
2009-03-01 16:15:52 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_UN_H
|
|
|
|
case AF_UNIX:
|
|
|
|
if (!dest)
|
|
|
|
dest = g_string_sized_new(0);
|
|
|
|
else
|
|
|
|
g_string_truncate(dest, 0);
|
|
|
|
g_string_append_len(dest, CONST_STR_LEN("unix:"));
|
|
|
|
g_string_append(dest, saddr->un.sun_path);
|
|
|
|
break;
|
2008-11-20 02:15:40 +00:00
|
|
|
#endif
|
2009-01-01 15:44:42 +00:00
|
|
|
default:
|
2009-03-01 16:15:52 +00:00
|
|
|
if (!dest)
|
|
|
|
dest = g_string_new_len(CONST_STR_LEN("unknown sockaddr family"));
|
|
|
|
else
|
2009-07-09 20:17:24 +00:00
|
|
|
li_string_assign_len(dest, CONST_STR_LEN("unknown sockaddr family"));
|
2008-11-03 14:10:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return dest;
|
|
|
|
}
|
2008-12-10 15:36:38 +00:00
|
|
|
|
2009-10-08 12:33:47 +00:00
|
|
|
liSocketAddress li_sockaddr_from_string(const GString *str, guint tcp_default_port) {
|
2009-01-01 15:44:42 +00:00
|
|
|
guint32 ipv4;
|
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
guint8 ipv6[16];
|
|
|
|
#endif
|
2009-09-04 13:56:52 +00:00
|
|
|
guint16 port;
|
2009-07-08 19:06:07 +00:00
|
|
|
liSocketAddress saddr = { 0, NULL };
|
2009-01-01 15:44:42 +00:00
|
|
|
|
2009-01-10 14:09:42 +00:00
|
|
|
#ifdef HAVE_SYS_UN_H
|
|
|
|
if (0 == strncmp(str->str, "unix:/", 6)) {
|
2009-01-10 14:22:35 +00:00
|
|
|
saddr.len = str->len + 1 - 5 + sizeof(saddr.addr->un.sun_family);
|
2009-07-08 19:06:07 +00:00
|
|
|
saddr.addr = (liSockAddr*) g_slice_alloc0(saddr.len);
|
2009-01-10 14:09:42 +00:00
|
|
|
saddr.addr->un.sun_family = AF_UNIX;
|
2009-01-10 14:22:35 +00:00
|
|
|
strcpy(saddr.addr->un.sun_path, str->str + 5);
|
2009-01-10 14:09:42 +00:00
|
|
|
} else
|
|
|
|
#endif
|
2009-07-09 20:17:24 +00:00
|
|
|
if (li_parse_ipv4(str->str, &ipv4, NULL, &port)) {
|
2009-09-04 13:56:52 +00:00
|
|
|
if (!port) port = tcp_default_port;
|
2009-01-01 15:44:42 +00:00
|
|
|
saddr.len = sizeof(struct sockaddr_in);
|
2009-07-08 19:06:07 +00:00
|
|
|
saddr.addr = (liSockAddr*) g_slice_alloc0(saddr.len);
|
2009-01-01 15:44:42 +00:00
|
|
|
saddr.addr->ipv4.sin_family = AF_INET;
|
|
|
|
saddr.addr->ipv4.sin_addr.s_addr = ipv4;
|
|
|
|
saddr.addr->ipv4.sin_port = htons(port);
|
|
|
|
#ifdef HAVE_IPV6
|
2009-01-10 14:09:42 +00:00
|
|
|
} else
|
2009-07-09 20:17:24 +00:00
|
|
|
if (li_parse_ipv6(str->str, ipv6, NULL, &port)) {
|
2009-09-04 13:56:52 +00:00
|
|
|
if (!port) port = tcp_default_port;
|
2009-01-01 15:44:42 +00:00
|
|
|
saddr.len = sizeof(struct sockaddr_in6);
|
2009-07-08 19:06:07 +00:00
|
|
|
saddr.addr = (liSockAddr*) g_slice_alloc0(saddr.len);
|
2009-01-01 15:44:42 +00:00
|
|
|
saddr.addr->ipv6.sin6_family = AF_INET6;
|
|
|
|
memcpy(&saddr.addr->ipv6.sin6_addr, ipv6, 16);
|
|
|
|
saddr.addr->ipv6.sin6_port = htons(port);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return saddr;
|
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
liSocketAddress li_sockaddr_local_from_socket(gint fd) {
|
2009-04-03 12:29:55 +00:00
|
|
|
socklen_t l = 0;
|
|
|
|
static struct sockaddr sa;
|
2009-07-08 19:06:07 +00:00
|
|
|
liSocketAddress saddr = { 0, NULL };
|
2009-04-03 12:29:55 +00:00
|
|
|
|
|
|
|
if (-1 == getsockname(fd, &sa, &l)) {
|
|
|
|
return saddr;
|
|
|
|
}
|
|
|
|
|
2009-07-08 19:06:07 +00:00
|
|
|
saddr.addr = (liSockAddr*) g_slice_alloc0(l);
|
2009-04-03 12:29:55 +00:00
|
|
|
saddr.len = l;
|
|
|
|
getsockname(fd, (struct sockaddr*) saddr.addr, &l);
|
|
|
|
|
|
|
|
return saddr;
|
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
liSocketAddress li_sockaddr_remote_from_socket(gint fd) {
|
2009-04-03 12:29:55 +00:00
|
|
|
socklen_t l = 0;
|
|
|
|
static struct sockaddr sa;
|
2009-07-08 19:06:07 +00:00
|
|
|
liSocketAddress saddr = { 0, NULL };
|
2009-04-03 12:29:55 +00:00
|
|
|
|
|
|
|
if (-1 == getpeername(fd, &sa, &l)) {
|
|
|
|
return saddr;
|
|
|
|
}
|
|
|
|
|
2009-07-08 19:06:07 +00:00
|
|
|
saddr.addr = (liSockAddr*) g_slice_alloc0(l);
|
2009-04-03 12:29:55 +00:00
|
|
|
saddr.len = l;
|
|
|
|
getpeername(fd, (struct sockaddr*) saddr.addr, &l);
|
|
|
|
|
|
|
|
return saddr;
|
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_sockaddr_clear(liSocketAddress *saddr) {
|
2009-04-03 12:29:55 +00:00
|
|
|
if (saddr->addr) g_slice_free1(saddr->len, saddr->addr);
|
|
|
|
saddr->addr = NULL;
|
|
|
|
saddr->len = 0;
|
2009-01-01 15:44:42 +00:00
|
|
|
}
|
|
|
|
|
2009-10-09 13:38:12 +00:00
|
|
|
gboolean li_ipv4_in_ipv4_net(guint32 target, guint32 match, guint32 networkmask) {
|
2009-09-04 13:56:52 +00:00
|
|
|
return (target & networkmask) == (match & networkmask);
|
|
|
|
}
|
|
|
|
|
2009-10-09 13:38:12 +00:00
|
|
|
gboolean li_ipv6_in_ipv6_net(const unsigned char *target, const guint8 *match, guint network) {
|
2009-09-04 13:56:52 +00:00
|
|
|
guint8 mask = network % 8;
|
|
|
|
if (0 != memcmp(target, match, network / 8)) return FALSE;
|
|
|
|
if (!mask) return TRUE;
|
|
|
|
mask = ~(((guint) 1 << (8-mask)) - 1);
|
|
|
|
return (target[network / 8] & mask) == (match[network / 8] & mask);
|
|
|
|
}
|
|
|
|
|
2009-10-09 13:38:12 +00:00
|
|
|
gboolean li_ipv6_in_ipv4_net(const unsigned char *target, guint32 match, guint32 networkmask) {
|
2009-09-04 13:56:52 +00:00
|
|
|
static const guint8 ipv6match[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
|
2009-10-09 13:38:12 +00:00
|
|
|
if (!li_ipv6_in_ipv6_net(target, ipv6match, 96)) return FALSE;
|
|
|
|
return li_ipv4_in_ipv4_net(*(guint32*)(target+12), match, networkmask);
|
2009-09-04 13:56:52 +00:00
|
|
|
}
|
|
|
|
|
2009-10-09 13:38:12 +00:00
|
|
|
gboolean li_ipv4_in_ipv6_net(guint32 target, const guint8 *match, guint network) {
|
2009-09-04 13:56:52 +00:00
|
|
|
guint8 ipv6[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
|
|
|
|
*(guint32*) (ipv6+12) = target;
|
2009-10-09 13:38:12 +00:00
|
|
|
return li_ipv6_in_ipv6_net(ipv6, match, network);
|
2009-09-04 13:56:52 +00:00
|
|
|
}
|
|
|
|
|
2009-01-01 15:44:42 +00:00
|
|
|
/* unused */
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_gstring_replace_char_with_str_len(GString *gstr, gchar c, gchar *str, guint len) {
|
2008-12-10 15:36:38 +00:00
|
|
|
for (guint i = 0; i < gstr->len; i++) {
|
|
|
|
if (gstr->str[i] == c) {
|
|
|
|
/* char found, replace */
|
|
|
|
gstr->str[i] = str[0];
|
|
|
|
if (len > 1)
|
|
|
|
g_string_insert_len(gstr, i, &str[1], len-1);
|
|
|
|
i += len - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-01-10 12:30:58 +00:00
|
|
|
|
2009-10-08 12:33:47 +00:00
|
|
|
gboolean li_strncase_equal(const GString *str, const gchar *s, guint len) {
|
2009-01-10 12:30:58 +00:00
|
|
|
if (str->len != len) return FALSE;
|
|
|
|
return 0 == g_ascii_strncasecmp(str->str, s, len);
|
|
|
|
}
|
2009-03-01 20:22:15 +00:00
|
|
|
|
2009-10-08 12:33:47 +00:00
|
|
|
gboolean li_string_suffix(const GString *str, const gchar *s, gsize len) {
|
2009-03-08 15:45:50 +00:00
|
|
|
if (str->len < len)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return (strcmp(str->str + str->len - len, s) == 0);
|
|
|
|
}
|
|
|
|
|
2009-10-08 12:33:47 +00:00
|
|
|
gboolean li_string_prefix(const GString *str, const gchar *s, gsize len) {
|
2009-03-08 15:45:50 +00:00
|
|
|
if (str->len < len)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return (strncmp(str->str, s, len) == 0);
|
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
GString *li_string_assign_len(GString *string, const gchar *val, gssize len) {
|
2009-03-01 20:22:15 +00:00
|
|
|
g_string_truncate(string, 0);
|
|
|
|
g_string_append_len(string, val, len);
|
2009-03-01 20:27:34 +00:00
|
|
|
return string;
|
2009-03-01 20:22:15 +00:00
|
|
|
}
|
2009-03-04 01:48:55 +00:00
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_string_append_int(GString *dest, gint64 v) {
|
2009-03-16 21:24:14 +00:00
|
|
|
gchar *buf, *end, swap;
|
2009-03-19 16:59:30 +00:00
|
|
|
gsize len;
|
2009-03-16 21:24:14 +00:00
|
|
|
guint64 val;
|
|
|
|
|
2009-03-17 10:44:44 +00:00
|
|
|
len = dest->len + 1;
|
|
|
|
g_string_set_size(dest, dest->len + 21);
|
2009-03-19 16:59:30 +00:00
|
|
|
buf = dest->str + len - 1;
|
2009-03-16 21:24:14 +00:00
|
|
|
|
|
|
|
if (v < 0) {
|
|
|
|
len++;
|
|
|
|
*(buf++) = '-';
|
|
|
|
/* -v maybe < 0 for signed types, so just cast it to unsigned to get the correct value */
|
|
|
|
val = -v;
|
|
|
|
} else {
|
|
|
|
val = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
end = buf;
|
|
|
|
while (val > 9) {
|
|
|
|
*(end++) = '0' + (val % 10);
|
|
|
|
val = val / 10;
|
|
|
|
}
|
|
|
|
*(end) = '0' + val;
|
|
|
|
*(end + 1) = '\0';
|
|
|
|
len += end - buf;
|
|
|
|
|
|
|
|
while (buf < end) {
|
|
|
|
swap = *end;
|
|
|
|
*end = *buf;
|
|
|
|
*buf = swap;
|
|
|
|
|
|
|
|
buf++;
|
|
|
|
end--;
|
|
|
|
}
|
|
|
|
|
|
|
|
dest->len = len;
|
|
|
|
}
|
|
|
|
|
2009-03-04 01:48:55 +00:00
|
|
|
/* http://womble.decadentplace.org.uk/readdir_r-advisory.html */
|
2009-07-09 20:17:24 +00:00
|
|
|
gsize li_dirent_buf_size(DIR * dirp) {
|
2009-03-04 01:48:55 +00:00
|
|
|
glong name_max;
|
|
|
|
gsize name_end;
|
|
|
|
|
|
|
|
# if !defined(HAVE_DIRFD)
|
|
|
|
UNUSED(dirp);
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# if defined(HAVE_FPATHCONF) && defined(HAVE_DIRFD) && defined(_PC_NAME_MAX)
|
|
|
|
name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
|
|
|
|
if (name_max == -1)
|
|
|
|
# if defined(NAME_MAX)
|
|
|
|
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
|
|
|
# else
|
|
|
|
return (gsize)(-1);
|
|
|
|
# endif
|
|
|
|
# else
|
|
|
|
# if defined(NAME_MAX)
|
|
|
|
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
|
|
|
# else
|
|
|
|
# error "buffer size for readdir_r cannot be determined"
|
|
|
|
# endif
|
|
|
|
# endif
|
|
|
|
|
|
|
|
name_end = (gsize)offsetof(struct dirent, d_name) + name_max + 1;
|
|
|
|
|
|
|
|
return (name_end > sizeof(struct dirent) ? name_end : sizeof(struct dirent));
|
|
|
|
}
|
2009-07-17 10:19:25 +00:00
|
|
|
|
|
|
|
const char *li_remove_path(const char *path) {
|
|
|
|
char *p = strrchr(path, DIR_SEPERATOR);
|
|
|
|
if (NULL != p && *(p) != '\0') {
|
|
|
|
return (p + 1);
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
GQuark li_sys_error_quark() {
|
|
|
|
return g_quark_from_static_string("li-sys-error-quark");
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean _li_set_sys_error(GError **error, const gchar *msg, const gchar *file, int lineno) {
|
|
|
|
int code = errno;
|
|
|
|
g_set_error(error, LI_SYS_ERROR, code, "(%s:%d): %s: %s", file, lineno, msg, g_strerror(code));
|
|
|
|
return FALSE;
|
|
|
|
}
|
2009-10-10 17:27:42 +00:00
|
|
|
|
|
|
|
void li_apr_sha1_base64(GString *dest, const GString *passwd) {
|
|
|
|
GChecksum *sha1sum;
|
|
|
|
gsize digestlen = g_checksum_type_get_length(G_CHECKSUM_SHA1);
|
|
|
|
guint8 digest[digestlen+1];
|
|
|
|
gchar *digest_base64;
|
|
|
|
|
|
|
|
sha1sum = g_checksum_new(G_CHECKSUM_SHA1);
|
|
|
|
g_checksum_update(sha1sum, GUSTR_LEN(passwd));
|
|
|
|
g_checksum_get_digest(sha1sum, digest, &digestlen);
|
|
|
|
g_checksum_free(sha1sum);
|
|
|
|
|
|
|
|
digest_base64 = g_base64_encode(digest, digestlen);
|
|
|
|
|
|
|
|
li_string_assign_len(dest, CONST_STR_LEN("{SHA}"));
|
|
|
|
g_string_append(dest, digest_base64);
|
|
|
|
|
|
|
|
g_free(digest_base64);
|
|
|
|
}
|