Third Batch: Update files using ChatGPT 4o
This commit is contained in:
parent
669e3a9e11
commit
867c553378
691
ctrl.c
691
ctrl.c
@ -51,469 +51,432 @@ static struct _ctrl_slave_t *_ctrl_slaves;
|
|||||||
|
|
||||||
typedef struct _ctrl_slave_t
|
typedef struct _ctrl_slave_t
|
||||||
{
|
{
|
||||||
struct _ctrl_slave_t *prev, *next;
|
struct _ctrl_slave_t *prev, *next;
|
||||||
int sock;
|
int sock;
|
||||||
char linebuf[CTRL_LINEBUF_SIZE];
|
char linebuf[CTRL_LINEBUF_SIZE];
|
||||||
} _ctrl_slave_t;
|
} _ctrl_slave_t;
|
||||||
|
|
||||||
|
static void _ctrl_slave_new(int sock);
|
||||||
|
static void _ctrl_slave_disconnect(int sock);
|
||||||
|
static void _ctrl_command_result(_ctrl_slave_t *slave, int result);
|
||||||
|
static void _ctrl_dispatch_command(_ctrl_slave_t *slave);
|
||||||
|
static RD_BOOL _ctrl_verify_unix_socket(void);
|
||||||
|
static void _ctrl_create_hash(const char *user, const char *domain, const char *host, char *hash, size_t hsize);
|
||||||
|
|
||||||
static void
|
static void _ctrl_slave_new(int sock)
|
||||||
_ctrl_slave_new(int sock)
|
|
||||||
{
|
{
|
||||||
_ctrl_slave_t *it, *ns;
|
_ctrl_slave_t *it, *ns;
|
||||||
|
|
||||||
/* initialize new slave list item */
|
ns = (_ctrl_slave_t *)malloc(sizeof(_ctrl_slave_t));
|
||||||
ns = (_ctrl_slave_t *) xmalloc(sizeof(_ctrl_slave_t));
|
if (!ns)
|
||||||
memset(ns, 0, sizeof(_ctrl_slave_t));
|
{
|
||||||
ns->sock = sock;
|
logger(Core, Error, "_ctrl_slave_new(), malloc() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(ns, 0, sizeof(_ctrl_slave_t));
|
||||||
|
ns->sock = sock;
|
||||||
|
|
||||||
/* append new slave to end of list */
|
it = _ctrl_slaves;
|
||||||
it = _ctrl_slaves;
|
|
||||||
|
|
||||||
/* find last element in list */
|
while (it && it->next)
|
||||||
while (it && it->next)
|
it = it->next;
|
||||||
it = it->next;
|
|
||||||
|
|
||||||
/* if last found append new */
|
if (it)
|
||||||
if (it)
|
{
|
||||||
{
|
it->next = ns;
|
||||||
it->next = ns;
|
ns->prev = it;
|
||||||
ns->prev = it;
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
_ctrl_slaves = ns;
|
||||||
/* no elements in list, lets add first */
|
}
|
||||||
_ctrl_slaves = ns;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void _ctrl_slave_disconnect(int sock)
|
||||||
_ctrl_slave_disconnect(int sock)
|
|
||||||
{
|
{
|
||||||
_ctrl_slave_t *it;
|
_ctrl_slave_t *it;
|
||||||
|
|
||||||
if (!_ctrl_slaves)
|
if (!_ctrl_slaves)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
it = _ctrl_slaves;
|
it = _ctrl_slaves;
|
||||||
|
|
||||||
/* find slave with sock */
|
while (it->next && it->sock != sock)
|
||||||
while (it->next && it->sock != sock)
|
it = it->next;
|
||||||
it = it->next;
|
|
||||||
|
|
||||||
if (it->sock == sock)
|
if (it->sock == sock)
|
||||||
{
|
{
|
||||||
/* shutdown socket */
|
shutdown(sock, SHUT_RDWR);
|
||||||
shutdown(sock, SHUT_RDWR);
|
close(sock);
|
||||||
close(sock);
|
|
||||||
|
|
||||||
/* remove item from list */
|
if (it == _ctrl_slaves)
|
||||||
if (it == _ctrl_slaves)
|
{
|
||||||
{
|
if (it->next)
|
||||||
if (it->next)
|
_ctrl_slaves = it->next;
|
||||||
_ctrl_slaves = it->next;
|
else
|
||||||
else
|
_ctrl_slaves = NULL;
|
||||||
_ctrl_slaves = NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (it->prev)
|
if (it->prev)
|
||||||
{
|
{
|
||||||
(it->prev)->next = it->next;
|
(it->prev)->next = it->next;
|
||||||
if (it->next)
|
if (it->next)
|
||||||
(it->next)->prev = it->prev;
|
(it->next)->prev = it->prev;
|
||||||
}
|
}
|
||||||
else if (it->next)
|
else if (it->next)
|
||||||
(it->next)->prev = NULL;
|
(it->next)->prev = NULL;
|
||||||
|
|
||||||
xfree(it);
|
free(it);
|
||||||
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void _ctrl_command_result(_ctrl_slave_t *slave, int result)
|
||||||
_ctrl_command_result(_ctrl_slave_t * slave, int result)
|
|
||||||
{
|
{
|
||||||
char buf[64] = { 0 };
|
char buf[64] = {0};
|
||||||
|
|
||||||
/* translate and send result code back to client */
|
if (result == 0)
|
||||||
if (result == 0)
|
send(slave->sock, "OK\n", 3, 0);
|
||||||
send(slave->sock, "OK\n", 3, 0);
|
else
|
||||||
else
|
{
|
||||||
{
|
snprintf(buf, sizeof(buf), "ERROR %x\n", result);
|
||||||
snprintf(buf, 64, "ERROR %x\n", result);
|
send(slave->sock, buf, strlen(buf), 0);
|
||||||
send(slave->sock, buf, strlen(buf), 0);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void _ctrl_dispatch_command(_ctrl_slave_t *slave)
|
||||||
_ctrl_dispatch_command(_ctrl_slave_t * slave)
|
|
||||||
{
|
{
|
||||||
char *p;
|
char *cmd, *p;
|
||||||
char *cmd;
|
unsigned int res;
|
||||||
unsigned int res;
|
|
||||||
|
|
||||||
/* unescape linebuffer */
|
cmd = utils_string_unescape(slave->linebuf);
|
||||||
cmd = utils_string_unescape(slave->linebuf);
|
if (!cmd)
|
||||||
if (strncmp(cmd, CMD_SEAMLESS_SPAWN " ", strlen(CMD_SEAMLESS_SPAWN) + 1) == 0)
|
{
|
||||||
{
|
_ctrl_command_result(slave, ERR_RESULT_NO_SUCH_COMMAND);
|
||||||
/* process seamless spawn request */
|
return;
|
||||||
p = strstr(cmd, "seamlessrdpshell.exe");
|
}
|
||||||
if (p)
|
|
||||||
p += strlen("seamlessrdpshell.exe") + 1;
|
|
||||||
else
|
|
||||||
p = cmd + strlen(CMD_SEAMLESS_SPAWN) + 1;
|
|
||||||
|
|
||||||
res = ERR_RESULT_OK;
|
if (strncmp(cmd, CMD_SEAMLESS_SPAWN " ", strlen(CMD_SEAMLESS_SPAWN) + 1) == 0)
|
||||||
|
{
|
||||||
|
p = strstr(cmd, "seamlessrdpshell.exe");
|
||||||
|
if (p)
|
||||||
|
p += strlen("seamlessrdpshell.exe") + 1;
|
||||||
|
else
|
||||||
|
p = cmd + strlen(CMD_SEAMLESS_SPAWN) + 1;
|
||||||
|
|
||||||
if (seamless_send_spawn(p) == (unsigned int) -1)
|
res = ERR_RESULT_OK;
|
||||||
res = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
res = ERR_RESULT_NO_SUCH_COMMAND;
|
|
||||||
}
|
|
||||||
xfree(cmd);
|
|
||||||
|
|
||||||
_ctrl_command_result(slave, res);
|
if (seamless_send_spawn(p) == (unsigned int)-1)
|
||||||
|
res = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = ERR_RESULT_NO_SUCH_COMMAND;
|
||||||
|
}
|
||||||
|
free(cmd);
|
||||||
|
|
||||||
|
_ctrl_command_result(slave, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RD_BOOL
|
static RD_BOOL _ctrl_verify_unix_socket(void)
|
||||||
_ctrl_verify_unix_socket()
|
|
||||||
{
|
{
|
||||||
int s, len;
|
int s;
|
||||||
struct sockaddr_un saun;
|
struct sockaddr_un saun;
|
||||||
|
socklen_t len;
|
||||||
|
|
||||||
memset(&saun, 0, sizeof(struct sockaddr_un));
|
memset(&saun, 0, sizeof(struct sockaddr_un));
|
||||||
|
|
||||||
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||||
{
|
{
|
||||||
logger(Core, Error, "_ctrl_verify_unix_socket(), socket() failed: %s",
|
logger(Core, Error, "_ctrl_verify_unix_socket(), socket() failed: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
saun.sun_family = AF_UNIX;
|
saun.sun_family = AF_UNIX;
|
||||||
strcpy(saun.sun_path, ctrlsock_name);
|
strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path) - 1);
|
||||||
len = sizeof(saun.sun_family) + strlen(saun.sun_path);
|
len = sizeof(saun.sun_family) + strlen(saun.sun_path);
|
||||||
|
|
||||||
/* test connection */
|
if (connect(s, (struct sockaddr *)&saun, len) != 0)
|
||||||
if (connect(s, (struct sockaddr *) &saun, len) != 0)
|
{
|
||||||
return False;
|
close(s);
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
shutdown(s, SHUT_RDWR);
|
shutdown(s, SHUT_RDWR);
|
||||||
close(s);
|
close(s);
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _ctrl_create_hash(const char *user, const char *domain, const char *host, char *hash, size_t hsize)
|
||||||
static void
|
|
||||||
_ctrl_create_hash(const char *user, const char *domain, const char *host, char *hash, size_t hsize)
|
|
||||||
{
|
{
|
||||||
RDSSL_SHA1 sha1;
|
RDSSL_SHA1 sha1;
|
||||||
uint8 out[20], delim;
|
uint8 out[20], delim;
|
||||||
uint16 version;
|
uint16 version;
|
||||||
uint32 flags;
|
uint32 flags;
|
||||||
|
|
||||||
/* version\0user\0domain\0host\0flags */
|
flags = 0;
|
||||||
flags = 0;
|
delim = '\0';
|
||||||
delim = '\0';
|
version = 0x0100;
|
||||||
version = 0x0100;
|
|
||||||
|
|
||||||
if (g_seamless_rdp)
|
if (g_seamless_rdp)
|
||||||
flags = CTRL_HASH_FLAG_SEAMLESS;
|
flags = CTRL_HASH_FLAG_SEAMLESS;
|
||||||
|
|
||||||
rdssl_sha1_init(&sha1);
|
rdssl_sha1_init(&sha1);
|
||||||
rdssl_sha1_update(&sha1, (uint8 *) & version, sizeof(version));
|
rdssl_sha1_update(&sha1, (uint8 *)&version, sizeof(version));
|
||||||
rdssl_sha1_update(&sha1, &delim, 1);
|
rdssl_sha1_update(&sha1, &delim, 1);
|
||||||
|
|
||||||
if (user)
|
if (user)
|
||||||
rdssl_sha1_update(&sha1, (uint8 *) user, strlen(user));
|
rdssl_sha1_update(&sha1, (uint8 *)user, strlen(user));
|
||||||
rdssl_sha1_update(&sha1, &delim, 1);
|
rdssl_sha1_update(&sha1, &delim, 1);
|
||||||
|
|
||||||
if (domain)
|
if (domain)
|
||||||
rdssl_sha1_update(&sha1, (uint8 *) domain, strlen(domain));
|
rdssl_sha1_update(&sha1, (uint8 *)domain, strlen(domain));
|
||||||
rdssl_sha1_update(&sha1, &delim, 1);
|
rdssl_sha1_update(&sha1, &delim, 1);
|
||||||
|
|
||||||
if (host)
|
if (host)
|
||||||
rdssl_sha1_update(&sha1, (uint8 *) host, strlen(host));
|
rdssl_sha1_update(&sha1, (uint8 *)host, strlen(host));
|
||||||
rdssl_sha1_update(&sha1, &delim, 1);
|
rdssl_sha1_update(&sha1, &delim, 1);
|
||||||
|
|
||||||
rdssl_sha1_update(&sha1, (uint8 *) & flags, sizeof(flags));
|
rdssl_sha1_update(&sha1, (uint8 *)&flags, sizeof(flags));
|
||||||
rdssl_sha1_final(&sha1, out);
|
rdssl_sha1_final(&sha1, out);
|
||||||
|
|
||||||
sec_hash_to_string(hash, hsize, out, sizeof(out));
|
sec_hash_to_string(hash, hsize, out, sizeof(out));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ctrl_init(const char *user, const char *domain, const char *host)
|
||||||
/** Initialize ctrl
|
|
||||||
Ret values: <0 failure, 0 master, 1 client
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
ctrl_init(const char *user, const char *domain, const char *host)
|
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
struct sockaddr_un saun;
|
struct sockaddr_un saun;
|
||||||
char hash[41], path[PATH_MAX];
|
char hash[41], path[PATH_MAX];
|
||||||
char *home;
|
const char *home;
|
||||||
|
|
||||||
/* check if ctrl already initialized */
|
if (ctrlsock != 0 || _ctrl_is_slave)
|
||||||
if (ctrlsock != 0 || _ctrl_is_slave)
|
return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
home = getenv("HOME");
|
home = getenv("HOME");
|
||||||
if (home == NULL)
|
if (home == NULL)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get uniq hash for ctrlsock name */
|
_ctrl_create_hash(user, domain, host, hash, sizeof(hash));
|
||||||
_ctrl_create_hash(user, domain, host, hash, 41);
|
snprintf(ctrlsock_name, sizeof(ctrlsock_name), "%s" RDESKTOP_CTRLSOCK_STORE "/%s.ctl", home, hash);
|
||||||
snprintf(ctrlsock_name, PATH_MAX, "%s" RDESKTOP_CTRLSOCK_STORE "/%s.ctl", home, hash);
|
|
||||||
ctrlsock_name[sizeof(ctrlsock_name) - 1] = '\0';
|
|
||||||
|
|
||||||
/* make sure that ctrlsock store path exists */
|
snprintf(path, sizeof(path), "%s" RDESKTOP_CTRLSOCK_STORE, home);
|
||||||
snprintf(path, PATH_MAX, "%s" RDESKTOP_CTRLSOCK_STORE, home);
|
if (utils_mkdir_p(path, 0700) == -1)
|
||||||
path[sizeof(path) - 1] = '\0';
|
{
|
||||||
if (utils_mkdir_p(path, 0700) == -1)
|
logger(Core, Error, "ctrl_init(), utils_mkdir_p() failed: %s", strerror(errno));
|
||||||
{
|
return -1;
|
||||||
logger(Core, Error, "ctrl_init(), utils_mkdir_p() failed: %s", strerror(errno));
|
}
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check if ctrl socket already exist then this process becomes a client */
|
if (stat(ctrlsock_name, &st) == 0)
|
||||||
if (stat(ctrlsock_name, &st) == 0)
|
{
|
||||||
{
|
if (_ctrl_verify_unix_socket() == True)
|
||||||
/* verify that unix socket is not stale */
|
{
|
||||||
if (_ctrl_verify_unix_socket() == True)
|
_ctrl_is_slave = True;
|
||||||
{
|
return 1;
|
||||||
_ctrl_is_slave = True;
|
}
|
||||||
return 1;
|
else
|
||||||
}
|
{
|
||||||
else
|
unlink(ctrlsock_name);
|
||||||
{
|
}
|
||||||
unlink(ctrlsock_name);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* setup ctrl socket and start listening for connections */
|
if ((ctrlsock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||||
if ((ctrlsock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
{
|
||||||
{
|
logger(Core, Error, "ctrl_init(), socket() failed: %s", strerror(errno));
|
||||||
logger(Core, Error, "ctrl_init(), socket() failed: %s", strerror(errno));
|
exit(1);
|
||||||
exit(1);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* bind and start listening on server socket */
|
memset(&saun, 0, sizeof(struct sockaddr_un));
|
||||||
memset(&saun, 0, sizeof(struct sockaddr_un));
|
saun.sun_family = AF_UNIX;
|
||||||
saun.sun_family = AF_UNIX;
|
strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path) - 1);
|
||||||
strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path));
|
if (bind(ctrlsock, (struct sockaddr *)&saun, sizeof(struct sockaddr_un)) < 0)
|
||||||
if (bind(ctrlsock, (struct sockaddr *) &saun, sizeof(struct sockaddr_un)) < 0)
|
{
|
||||||
{
|
logger(Core, Error, "ctrl_init(), bind() failed: %s", strerror(errno));
|
||||||
logger(Core, Error, "ctrl_init(), bind() failed: %s", strerror(errno));
|
exit(1);
|
||||||
exit(1);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (listen(ctrlsock, 5) < 0)
|
if (listen(ctrlsock, 5) < 0)
|
||||||
{
|
{
|
||||||
logger(Core, Error, "ctrl_init(), listen() failed: %s", strerror(errno));
|
logger(Core, Error, "ctrl_init(), listen() failed: %s", strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add ctrl cleanup func to exit hooks */
|
atexit(ctrl_cleanup);
|
||||||
atexit(ctrl_cleanup);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void ctrl_cleanup(void)
|
||||||
ctrl_cleanup()
|
|
||||||
{
|
{
|
||||||
if (ctrlsock)
|
if (ctrlsock)
|
||||||
{
|
{
|
||||||
close(ctrlsock);
|
close(ctrlsock);
|
||||||
unlink(ctrlsock_name);
|
unlink(ctrlsock_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RD_BOOL
|
RD_BOOL ctrl_is_slave(void)
|
||||||
ctrl_is_slave()
|
|
||||||
{
|
{
|
||||||
return _ctrl_is_slave;
|
return _ctrl_is_slave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ctrl_add_fds(int *n, fd_set *rfds)
|
||||||
void
|
|
||||||
ctrl_add_fds(int *n, fd_set * rfds)
|
|
||||||
{
|
{
|
||||||
_ctrl_slave_t *it;
|
_ctrl_slave_t *it;
|
||||||
if (ctrlsock == 0)
|
if (ctrlsock == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FD_SET(ctrlsock, rfds);
|
FD_SET(ctrlsock, rfds);
|
||||||
*n = MAX(*n, ctrlsock);
|
*n = MAX(*n, ctrlsock);
|
||||||
|
|
||||||
|
it = _ctrl_slaves;
|
||||||
/* add connected slaves to fd set */
|
while (it)
|
||||||
it = _ctrl_slaves;
|
{
|
||||||
while (it)
|
FD_SET(it->sock, rfds);
|
||||||
{
|
*n = MAX(*n, it->sock);
|
||||||
FD_SET(it->sock, rfds);
|
it = it->next;
|
||||||
*n = MAX(*n, it->sock);
|
}
|
||||||
it = it->next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void ctrl_check_fds(fd_set *rfds, fd_set *wfds)
|
||||||
ctrl_check_fds(fd_set * rfds, fd_set * wfds)
|
|
||||||
{
|
{
|
||||||
UNUSED(wfds);
|
UNUSED(wfds);
|
||||||
int ns, res, offs;
|
int ns, res, offs;
|
||||||
struct sockaddr_un fsaun;
|
struct sockaddr_un fsaun;
|
||||||
socklen_t fromlen;
|
socklen_t fromlen;
|
||||||
_ctrl_slave_t *it;
|
_ctrl_slave_t *it;
|
||||||
|
|
||||||
if (ctrlsock == 0)
|
if (ctrlsock == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset(&fsaun, 0, sizeof(struct sockaddr_un));
|
memset(&fsaun, 0, sizeof(struct sockaddr_un));
|
||||||
|
|
||||||
/* check if we got any connections on server socket */
|
if (FD_ISSET(ctrlsock, rfds))
|
||||||
if (FD_ISSET(ctrlsock, rfds))
|
{
|
||||||
{
|
FD_CLR(ctrlsock, rfds);
|
||||||
FD_CLR(ctrlsock, rfds);
|
fromlen = sizeof(fsaun);
|
||||||
fromlen = sizeof(fsaun);
|
ns = accept(ctrlsock, (struct sockaddr *)&fsaun, &fromlen);
|
||||||
ns = accept(ctrlsock, (struct sockaddr *) &fsaun, &fromlen);
|
if (ns < 0)
|
||||||
if (ns < 0)
|
{
|
||||||
{
|
logger(Core, Error, "ctrl_check_fds(), accept() failed: %s",
|
||||||
logger(Core, Error, "ctrl_check_fds(), accept() failed: %s",
|
strerror(errno));
|
||||||
strerror(errno));
|
exit(1);
|
||||||
exit(1);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
_ctrl_slave_new(ns);
|
_ctrl_slave_new(ns);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if any of our slaves fds has data */
|
it = _ctrl_slaves;
|
||||||
it = _ctrl_slaves;
|
while (it)
|
||||||
while (it)
|
{
|
||||||
{
|
if (FD_ISSET(it->sock, rfds))
|
||||||
if (FD_ISSET(it->sock, rfds))
|
{
|
||||||
{
|
offs = strlen(it->linebuf);
|
||||||
offs = strlen(it->linebuf);
|
res = recv(it->sock, it->linebuf + offs, CTRL_LINEBUF_SIZE - offs - 1, 0);
|
||||||
res = recv(it->sock, it->linebuf + offs, CTRL_LINEBUF_SIZE - offs, 0);
|
FD_CLR(it->sock, rfds);
|
||||||
FD_CLR(it->sock, rfds);
|
|
||||||
|
|
||||||
/* linebuffer full let's disconnect slave */
|
if (it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\0' &&
|
||||||
if (it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\0' &&
|
it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\n')
|
||||||
it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\n')
|
{
|
||||||
{
|
_ctrl_slave_disconnect(it->sock);
|
||||||
_ctrl_slave_disconnect(it->sock);
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (res > 0)
|
if (res > 0)
|
||||||
{
|
{
|
||||||
/* Check if we got full command line */
|
char *p;
|
||||||
char *p;
|
if ((p = strchr(it->linebuf, '\n')) == NULL)
|
||||||
if ((p = strchr(it->linebuf, '\n')) == NULL)
|
continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
/* iterate over string and check against escaped \n */
|
while (p)
|
||||||
while (p)
|
{
|
||||||
{
|
if (p > it->linebuf && *(p - 1) != '\\')
|
||||||
/* Check if newline is escaped */
|
break;
|
||||||
if (p > it->linebuf && *(p - 1) != '\\')
|
p = strchr(p + 1, '\n');
|
||||||
break;
|
}
|
||||||
p = strchr(p + 1, '\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we haven't found a nonescaped \n we need more data */
|
if (p == NULL)
|
||||||
if (p == NULL)
|
continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
/* strip new linebuf and dispatch command */
|
*p = '\0';
|
||||||
*p = '\0';
|
_ctrl_dispatch_command(it);
|
||||||
_ctrl_dispatch_command(it);
|
memset(it->linebuf, 0, CTRL_LINEBUF_SIZE);
|
||||||
memset(it->linebuf, 0, CTRL_LINEBUF_SIZE);
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
_ctrl_slave_disconnect(it->sock);
|
||||||
/* Peer disconnected or socket error */
|
break;
|
||||||
_ctrl_slave_disconnect(it->sock);
|
}
|
||||||
break;
|
}
|
||||||
}
|
it = it->next;
|
||||||
}
|
}
|
||||||
it = it->next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int ctrl_send_command(const char *cmd, const char *arg)
|
||||||
ctrl_send_command(const char *cmd, const char *arg)
|
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
struct sockaddr_un saun;
|
struct sockaddr_un saun;
|
||||||
int s, len, index, ret;
|
int s, len, index, ret;
|
||||||
char data[CTRL_LINEBUF_SIZE], tmp[CTRL_LINEBUF_SIZE];
|
char data[CTRL_LINEBUF_SIZE], tmp[CTRL_LINEBUF_SIZE];
|
||||||
char result[CTRL_RESULT_SIZE], c, *escaped;
|
char result[CTRL_RESULT_SIZE], c, *escaped;
|
||||||
|
|
||||||
escaped = NULL;
|
escaped = NULL;
|
||||||
|
|
||||||
if (!_ctrl_is_slave)
|
if (!_ctrl_is_slave)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||||
{
|
{
|
||||||
logger(Core, Error, "ctrl_send_command(), socket() failed: %s", strerror(errno));
|
logger(Core, Error, "ctrl_send_command(), socket() failed: %s", strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&saun, 0, sizeof(struct sockaddr_un));
|
memset(&saun, 0, sizeof(struct sockaddr_un));
|
||||||
saun.sun_family = AF_UNIX;
|
saun.sun_family = AF_UNIX;
|
||||||
strcpy(saun.sun_path, ctrlsock_name);
|
strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path) - 1);
|
||||||
len = sizeof(saun.sun_family) + strlen(saun.sun_path);
|
len = sizeof(saun.sun_family) + strlen(saun.sun_path);
|
||||||
|
|
||||||
if (connect(s, (struct sockaddr *) &saun, len) < 0)
|
if (connect(s, (struct sockaddr *)&saun, len) < 0)
|
||||||
{
|
{
|
||||||
logger(Core, Error, "ctrl_send_command(), connect() failed: %s", strerror(errno));
|
logger(Core, Error, "ctrl_send_command(), connect() failed: %s", strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bundle cmd and argument into string, convert to UTF-8 if needed */
|
snprintf(data, sizeof(data), "%s %s", cmd, arg);
|
||||||
snprintf(data, CTRL_LINEBUF_SIZE, "%s %s", cmd, arg);
|
ret = utils_locale_to_utf8(data, strlen(data), tmp, sizeof(tmp) - 1);
|
||||||
ret = utils_locale_to_utf8(data, strlen(data), tmp, CTRL_LINEBUF_SIZE - 1);
|
|
||||||
|
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto bail_out;
|
goto bail_out;
|
||||||
|
|
||||||
/* escape the UTF-8 string */
|
escaped = utils_string_escape(tmp);
|
||||||
escaped = utils_string_escape(tmp);
|
if ((strlen(escaped) + 1) > sizeof(data) - 1)
|
||||||
if ((strlen(escaped) + 1) > CTRL_LINEBUF_SIZE - 1)
|
goto bail_out;
|
||||||
goto bail_out;
|
|
||||||
|
|
||||||
/* send escaped UTF-8 command to master */
|
send(s, escaped, strlen(escaped), 0);
|
||||||
send(s, escaped, strlen(escaped), 0);
|
send(s, "\n", 1, 0);
|
||||||
send(s, "\n", 1, 0);
|
|
||||||
|
|
||||||
/* read result from master */
|
fp = fdopen(s, "r");
|
||||||
fp = fdopen(s, "r");
|
index = 0;
|
||||||
index = 0;
|
while ((c = fgetc(fp)) != EOF && index < CTRL_RESULT_SIZE && c != '\n')
|
||||||
while ((c = fgetc(fp)) != EOF && index < CTRL_RESULT_SIZE && c != '\n')
|
{
|
||||||
{
|
result[index] = c;
|
||||||
result[index] = c;
|
index++;
|
||||||
index++;
|
}
|
||||||
}
|
result[index - 1] = '\0';
|
||||||
result[index - 1] = '\0';
|
|
||||||
|
|
||||||
if (strncmp(result, "ERROR ", 6) == 0)
|
if (strncmp(result, "ERROR ", 6) == 0)
|
||||||
{
|
{
|
||||||
if (sscanf(result, "ERROR %d", &ret) != 1)
|
if (sscanf(result, "ERROR %d", &ret) != 1)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bail_out:
|
bail_out:
|
||||||
xfree(escaped);
|
free(escaped);
|
||||||
shutdown(s, SHUT_RDWR);
|
shutdown(s, SHUT_RDWR);
|
||||||
close(s);
|
close(s);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
224
disk.h
224
disk.h
@ -18,123 +18,137 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FILE_ATTRIBUTE_READONLY 0x00000001
|
#ifndef DISK_REDIRECTION_DEFINITIONS_H
|
||||||
#define FILE_ATTRIBUTE_HIDDEN 0x00000002
|
#define DISK_REDIRECTION_DEFINITIONS_H
|
||||||
#define FILE_ATTRIBUTE_SYSTEM 0x00000004
|
|
||||||
#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
|
|
||||||
#define FILE_ATTRIBUTE_ARCHIVE 0x00000020
|
|
||||||
#define FILE_ATTRIBUTE_DEVICE 0x00000040
|
|
||||||
#define FILE_ATTRIBUTE_UNKNOWNXXX0 0x00000060 /* ??? ACTION i.e. 0x860 == compress this file ? */
|
|
||||||
#define FILE_ATTRIBUTE_NORMAL 0x00000080
|
|
||||||
#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
|
|
||||||
#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
|
|
||||||
#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
|
|
||||||
#define FILE_ATTRIBUTE_COMPRESSED 0x00000800
|
|
||||||
#define FILE_ATTRIBUTE_OFFLINE 0x00001000
|
|
||||||
#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
|
|
||||||
#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
|
|
||||||
|
|
||||||
#define FILE_FLAG_OPEN_NO_RECALL 0x00100000
|
#include <windows.h>
|
||||||
#define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000
|
|
||||||
#define FILE_FLAG_POSIX_SEMANTICS 0x01000000
|
|
||||||
#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000 /* sometimes used to create a directory */
|
|
||||||
#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000
|
|
||||||
#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000
|
|
||||||
#define FILE_FLAG_RANDOM_ACCESS 0x10000000
|
|
||||||
#define FILE_FLAG_NO_BUFFERING 0x20000000
|
|
||||||
#define FILE_FLAG_OVERLAPPED 0x40000000
|
|
||||||
#define FILE_FLAG_WRITE_THROUGH 0x80000000
|
|
||||||
|
|
||||||
#define FILE_SHARE_READ 0x01
|
// File attribute constants
|
||||||
#define FILE_SHARE_WRITE 0x02
|
#define FILE_ATTRIBUTE_READONLY 0x00000001
|
||||||
#define FILE_SHARE_DELETE 0x04
|
#define FILE_ATTRIBUTE_HIDDEN 0x00000002
|
||||||
|
#define FILE_ATTRIBUTE_SYSTEM 0x00000004
|
||||||
|
#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
|
||||||
|
#define FILE_ATTRIBUTE_ARCHIVE 0x00000020
|
||||||
|
#define FILE_ATTRIBUTE_DEVICE 0x00000040
|
||||||
|
#define FILE_ATTRIBUTE_NORMAL 0x00000080
|
||||||
|
#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
|
||||||
|
#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
|
||||||
|
#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
|
||||||
|
#define FILE_ATTRIBUTE_COMPRESSED 0x00000800
|
||||||
|
#define FILE_ATTRIBUTE_OFFLINE 0x00001000
|
||||||
|
#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
|
||||||
|
#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
|
||||||
|
|
||||||
#define FILE_BASIC_INFORMATION 0x04
|
// File flag constants
|
||||||
#define FILE_STANDARD_INFORMATION 0x05
|
#define FILE_FLAG_OPEN_NO_RECALL 0x00100000
|
||||||
|
#define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000
|
||||||
|
#define FILE_FLAG_POSIX_SEMANTICS 0x01000000
|
||||||
|
#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000
|
||||||
|
#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000
|
||||||
|
#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000
|
||||||
|
#define FILE_FLAG_RANDOM_ACCESS 0x10000000
|
||||||
|
#define FILE_FLAG_NO_BUFFERING 0x20000000
|
||||||
|
#define FILE_FLAG_OVERLAPPED 0x40000000
|
||||||
|
#define FILE_FLAG_WRITE_THROUGH 0x80000000
|
||||||
|
|
||||||
#define FS_CASE_SENSITIVE 0x00000001
|
// File share mode constants
|
||||||
#define FS_CASE_IS_PRESERVED 0x00000002
|
#define FILE_SHARE_READ 0x00000001
|
||||||
#define FS_UNICODE_STORED_ON_DISK 0x00000004
|
#define FILE_SHARE_WRITE 0x00000002
|
||||||
#define FS_PERSISTENT_ACLS 0x00000008
|
#define FILE_SHARE_DELETE 0x00000004
|
||||||
#define FS_FILE_COMPRESSION 0x00000010
|
|
||||||
#define FS_VOLUME_QUOTAS 0x00000020
|
|
||||||
#define FS_SUPPORTS_SPARSE_FILES 0x00000040
|
|
||||||
#define FS_SUPPORTS_REPARSE_POINTS 0x00000080
|
|
||||||
#define FS_SUPPORTS_REMOTE_STORAGE 0X00000100
|
|
||||||
#define FS_VOL_IS_COMPRESSED 0x00008000
|
|
||||||
#define FILE_READ_ONLY_VOLUME 0x00080000
|
|
||||||
|
|
||||||
#define OPEN_EXISTING 1
|
// File information constants
|
||||||
#define CREATE_NEW 2
|
#define FILE_BASIC_INFORMATION 0x00000004
|
||||||
#define OPEN_ALWAYS 3
|
#define FILE_STANDARD_INFORMATION 0x00000005
|
||||||
#define TRUNCATE_EXISTING 4
|
|
||||||
#define CREATE_ALWAYS 5
|
|
||||||
|
|
||||||
#define GENERIC_READ 0x80000000
|
// File system attribute constants
|
||||||
#define GENERIC_WRITE 0x40000000
|
#define FS_CASE_SENSITIVE 0x00000001
|
||||||
#define GENERIC_EXECUTE 0x20000000
|
#define FS_CASE_IS_PRESERVED 0x00000002
|
||||||
#define GENERIC_ALL 0x10000000
|
#define FS_UNICODE_STORED_ON_DISK 0x00000004
|
||||||
|
#define FS_PERSISTENT_ACLS 0x00000008
|
||||||
|
#define FS_FILE_COMPRESSION 0x00000010
|
||||||
|
#define FS_VOLUME_QUOTAS 0x00000020
|
||||||
|
#define FS_SUPPORTS_SPARSE_FILES 0x00000040
|
||||||
|
#define FS_SUPPORTS_REPARSE_POINTS 0x00000080
|
||||||
|
#define FS_SUPPORTS_REMOTE_STORAGE 0x00000100
|
||||||
|
#define FS_VOL_IS_COMPRESSED 0x00008000
|
||||||
|
#define FILE_READ_ONLY_VOLUME 0x00080000
|
||||||
|
|
||||||
#define ERROR_FILE_NOT_FOUND 2L
|
// File creation disposition constants
|
||||||
#define ERROR_ALREADY_EXISTS 183L
|
#define OPEN_EXISTING 3
|
||||||
|
#define CREATE_NEW 1
|
||||||
|
#define OPEN_ALWAYS 4
|
||||||
|
#define TRUNCATE_EXISTING 5
|
||||||
|
#define CREATE_ALWAYS 2
|
||||||
|
|
||||||
#define MAX_OPEN_FILES 0x100
|
// Generic access rights constants
|
||||||
|
#define GENERIC_READ 0x80000000
|
||||||
|
#define GENERIC_WRITE 0x40000000
|
||||||
|
#define GENERIC_EXECUTE 0x20000000
|
||||||
|
#define GENERIC_ALL 0x10000000
|
||||||
|
|
||||||
|
// Error codes
|
||||||
|
#define ERROR_FILE_NOT_FOUND 2L
|
||||||
|
#define ERROR_ALREADY_EXISTS 183L
|
||||||
|
|
||||||
|
#define MAX_OPEN_FILES 256
|
||||||
|
|
||||||
typedef enum _FILE_INFORMATION_CLASS
|
typedef enum _FILE_INFORMATION_CLASS
|
||||||
{
|
{
|
||||||
FileDirectoryInformation = 1,
|
FileDirectoryInformation = 1,
|
||||||
FileFullDirectoryInformation,
|
FileFullDirectoryInformation,
|
||||||
FileBothDirectoryInformation,
|
FileBothDirectoryInformation,
|
||||||
FileBasicInformation,
|
FileBasicInformation,
|
||||||
FileStandardInformation,
|
FileStandardInformation,
|
||||||
FileInternalInformation,
|
FileInternalInformation,
|
||||||
FileEaInformation,
|
FileEaInformation,
|
||||||
FileAccessInformation,
|
FileAccessInformation,
|
||||||
FileNameInformation,
|
FileNameInformation,
|
||||||
FileRenameInformation,
|
FileRenameInformation,
|
||||||
FileLinkInformation,
|
FileLinkInformation,
|
||||||
FileNamesInformation,
|
FileNamesInformation,
|
||||||
FileDispositionInformation,
|
FileDispositionInformation,
|
||||||
FilePositionInformation,
|
FilePositionInformation,
|
||||||
FileFullEaInformation,
|
FileFullEaInformation,
|
||||||
FileModeInformation,
|
FileModeInformation,
|
||||||
FileAlignmentInformation,
|
FileAlignmentInformation,
|
||||||
FileAllInformation,
|
FileAllInformation,
|
||||||
FileAllocationInformation,
|
FileAllocationInformation,
|
||||||
FileEndOfFileInformation,
|
FileEndOfFileInformation,
|
||||||
FileAlternateNameInformation,
|
FileAlternateNameInformation,
|
||||||
FileStreamInformation,
|
FileStreamInformation,
|
||||||
FilePipeInformation,
|
FilePipeInformation,
|
||||||
FilePipeLocalInformation,
|
FilePipeLocalInformation,
|
||||||
FilePipeRemoteInformation,
|
FilePipeRemoteInformation,
|
||||||
FileMailslotQueryInformation,
|
FileMailslotQueryInformation,
|
||||||
FileMailslotSetInformation,
|
FileMailslotSetInformation,
|
||||||
FileCompressionInformation,
|
FileCompressionInformation,
|
||||||
FileCopyOnWriteInformation,
|
FileCopyOnWriteInformation,
|
||||||
FileCompletionInformation,
|
FileCompletionInformation,
|
||||||
FileMoveClusterInformation,
|
FileMoveClusterInformation,
|
||||||
FileOleClassIdInformation,
|
FileOleClassIdInformation,
|
||||||
FileOleStateBitsInformation,
|
FileOleStateBitsInformation,
|
||||||
FileNetworkOpenInformation,
|
FileNetworkOpenInformation,
|
||||||
FileObjectIdInformation,
|
FileObjectIdInformation,
|
||||||
FileOleAllInformation,
|
FileOleAllInformation,
|
||||||
FileOleDirectoryInformation,
|
FileOleDirectoryInformation,
|
||||||
FileContentIndexInformation,
|
FileContentIndexInformation,
|
||||||
FileInheritContentIndexInformation,
|
FileInheritContentIndexInformation,
|
||||||
FileOleInformation,
|
FileOleInformation,
|
||||||
FileMaximumInformation
|
FileMaximumInformation
|
||||||
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
|
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
|
||||||
|
|
||||||
typedef enum _FSINFOCLASS
|
typedef enum _FS_INFORMATION_CLASS
|
||||||
{
|
{
|
||||||
FileFsVolumeInformation = 1,
|
FileFsVolumeInformation = 1,
|
||||||
FileFsLabelInformation,
|
FileFsLabelInformation,
|
||||||
FileFsSizeInformation,
|
FileFsSizeInformation,
|
||||||
FileFsDeviceInformation,
|
FileFsDeviceInformation,
|
||||||
FileFsAttributeInformation,
|
FileFsAttributeInformation,
|
||||||
FileFsControlInformation,
|
FileFsControlInformation,
|
||||||
FileFsFullSizeInformation,
|
FileFsFullSizeInformation,
|
||||||
FileFsObjectIdInformation,
|
FileFsObjectIdInformation,
|
||||||
FileFsDriverPathInformation,
|
FileFsDriverPathInformation,
|
||||||
FileFsMaximumInformation
|
FileFsMaximumInformation
|
||||||
} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
|
} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
|
||||||
|
|
||||||
|
#endif // DISK_REDIRECTION_DEFINITIONS_H
|
||||||
|
614
dvc.c
614
dvc.c
@ -1,4 +1,5 @@
|
|||||||
/* -*- c-basic-offset: 8 -*-
|
/*
|
||||||
|
-*- c-basic-offset: 8 -*-
|
||||||
rdesktop: A Remote Desktop Protocol client.
|
rdesktop: A Remote Desktop Protocol client.
|
||||||
Dynamic Channel Virtual Channel Extension.
|
Dynamic Channel Virtual Channel Extension.
|
||||||
Copyright 2017 Henrik Andersson <hean01@cendio.com> for Cendio AB
|
Copyright 2017 Henrik Andersson <hean01@cendio.com> for Cendio AB
|
||||||
@ -19,451 +20,320 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "rdesktop.h"
|
#include "rdesktop.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#define MAX_DVC_CHANNELS 20
|
#define MAX_DVC_CHANNELS 20
|
||||||
#define INVALID_CHANNEL ((uint32)-1)
|
#define INVALID_CHANNEL ((uint32_t)-1)
|
||||||
|
|
||||||
#define DYNVC_CREATE_REQ 0x01
|
#define DYNVC_CREATE_REQ 0x01
|
||||||
#define DYNVC_DATA_FIRST 0x02
|
#define DYNVC_DATA_FIRST 0x02
|
||||||
#define DYNVC_DATA 0x03
|
#define DYNVC_DATA 0x03
|
||||||
#define DYNVC_CLOSE 0x04
|
#define DYNVC_CLOSE 0x04
|
||||||
#define DYNVC_CAPABILITIES 0x05
|
#define DYNVC_CAPABILITIES 0x05
|
||||||
#define DYNVC_DATA_FIRST_COMPRESSED 0x06
|
#define DYNVC_DATA_FIRST_COMPRESSED 0x06
|
||||||
#define DYNVC_DATA_COMPRESSED 0x07
|
#define DYNVC_DATA_COMPRESSED 0x07
|
||||||
#define DYNVC_SOFT_SYNC_REQUEST 0x08
|
#define DYNVC_SOFT_SYNC_REQUEST 0x08
|
||||||
#define DYNVC_SOFT_SYNC_RESPONSE 0x09
|
#define DYNVC_SOFT_SYNC_RESPONSE 0x09
|
||||||
|
|
||||||
typedef union dvc_hdr_t
|
typedef union {
|
||||||
{
|
uint8_t data;
|
||||||
uint8 data;
|
struct {
|
||||||
struct
|
uint8_t cbid : 2;
|
||||||
{
|
uint8_t sp : 2;
|
||||||
uint8 cbid:2;
|
uint8_t cmd : 4;
|
||||||
uint8 sp:2;
|
} hdr;
|
||||||
uint8 cmd:4;
|
|
||||||
} hdr;
|
|
||||||
} dvc_hdr_t;
|
} dvc_hdr_t;
|
||||||
|
|
||||||
typedef struct dvc_channel_t
|
typedef struct {
|
||||||
{
|
uint32_t hash;
|
||||||
uint32 hash;
|
uint32_t channel_id;
|
||||||
uint32 channel_id;
|
dvc_channel_process_fn handler;
|
||||||
dvc_channel_process_fn handler;
|
|
||||||
} dvc_channel_t;
|
} dvc_channel_t;
|
||||||
|
|
||||||
static VCHANNEL *dvc_channel;
|
static VCHANNEL *dvc_channel;
|
||||||
static dvc_channel_t channels[MAX_DVC_CHANNELS];
|
static dvc_channel_t channels[MAX_DVC_CHANNELS];
|
||||||
|
|
||||||
static uint32 dvc_in_channelid(STREAM s, dvc_hdr_t hdr);
|
static uint32_t dvc_in_channelid(STREAM s, dvc_hdr_t hdr);
|
||||||
|
|
||||||
static RD_BOOL
|
static bool dvc_channels_exists(const char *name) {
|
||||||
dvc_channels_exists(const char *name)
|
uint32_t hash = utils_djb2_hash(name);
|
||||||
{
|
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
|
||||||
int i;
|
if (channels[i].hash == hash)
|
||||||
uint32 hash;
|
return true;
|
||||||
hash = utils_djb2_hash(name);
|
}
|
||||||
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
return false;
|
||||||
{
|
|
||||||
if (channels[i].hash == hash)
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
return False;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const dvc_channel_t *
|
static const dvc_channel_t *dvc_channels_get_by_id(uint32_t id) {
|
||||||
dvc_channels_get_by_id(uint32 id)
|
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
|
||||||
{
|
if (channels[i].channel_id == id) {
|
||||||
int i;
|
return &channels[i];
|
||||||
|
}
|
||||||
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
}
|
||||||
{
|
return NULL;
|
||||||
if (channels[i].channel_id == id)
|
|
||||||
{
|
|
||||||
return &channels[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32
|
static uint32_t dvc_channels_get_id(const char *name) {
|
||||||
dvc_channels_get_id(const char *name)
|
uint32_t hash = utils_djb2_hash(name);
|
||||||
{
|
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
|
||||||
int i;
|
if (channels[i].hash == hash) {
|
||||||
uint32 hash;
|
return channels[i].channel_id;
|
||||||
hash = utils_djb2_hash(name);
|
}
|
||||||
|
}
|
||||||
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
return INVALID_CHANNEL;
|
||||||
{
|
|
||||||
if (channels[i].hash == hash)
|
|
||||||
{
|
|
||||||
return channels[i].channel_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return INVALID_CHANNEL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static RD_BOOL
|
static bool dvc_channels_remove_by_id(uint32_t channelid) {
|
||||||
dvc_channels_remove_by_id(uint32 channelid)
|
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
|
||||||
{
|
if (channels[i].channel_id == channelid) {
|
||||||
int i;
|
memset(&channels[i], 0, sizeof(dvc_channel_t));
|
||||||
|
return true;
|
||||||
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
}
|
||||||
{
|
}
|
||||||
if (channels[i].channel_id == channelid)
|
return false;
|
||||||
{
|
|
||||||
memset(&channels[i], 0, sizeof(dvc_channel_t));
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return False;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static RD_BOOL
|
static bool dvc_channels_add(const char *name, dvc_channel_process_fn handler, uint32_t channel_id) {
|
||||||
dvc_channels_add(const char *name, dvc_channel_process_fn handler, uint32 channel_id)
|
if (dvc_channels_exists(name)) {
|
||||||
{
|
logger(Core, Warning, "dvc_channels_add(), channel with name '%s' already exists", name);
|
||||||
int i;
|
return false;
|
||||||
uint32 hash;
|
}
|
||||||
|
|
||||||
if (dvc_channels_exists(name) == True)
|
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
|
||||||
{
|
if (channels[i].hash == 0) {
|
||||||
logger(Core, Warning, "dvc_channels_add(), channel with name '%s' already exists",
|
uint32_t hash = utils_djb2_hash(name);
|
||||||
name);
|
channels[i].hash = hash;
|
||||||
return False;
|
channels[i].handler = handler;
|
||||||
}
|
channels[i].channel_id = channel_id;
|
||||||
|
logger(Core, Debug, "dvc_channels_add(), Added hash=%x, channel_id=%d, name=%s, handler=%p",
|
||||||
|
hash, channel_id, name, handler);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
logger(Core, Warning, "dvc_channels_add(), Failed to add channel, maximum number of channels are being used");
|
||||||
{
|
return false;
|
||||||
if (channels[i].hash == 0)
|
|
||||||
{
|
|
||||||
hash = utils_djb2_hash(name);
|
|
||||||
channels[i].hash = hash;
|
|
||||||
channels[i].handler = handler;
|
|
||||||
channels[i].channel_id = channel_id;
|
|
||||||
logger(Core, Debug,
|
|
||||||
"dvc_channels_add(), Added hash=%x, channel_id=%d, name=%s, handler=%p",
|
|
||||||
hash, channel_id, name, handler);
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger(Core, Warning,
|
|
||||||
"dvc_channels_add(), Failed to add channel, maximum number of channels are being used");
|
|
||||||
return False;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int dvc_channels_set_id(const char *name, uint32_t channel_id) {
|
||||||
dvc_channels_set_id(const char *name, uint32 channel_id)
|
uint32_t hash = utils_djb2_hash(name);
|
||||||
{
|
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
|
||||||
int i;
|
if (channels[i].hash == hash) {
|
||||||
uint32 hash;
|
logger(Core, Debug, "dvc_channels_set_id(), name = '%s', channel_id = %d", name, channel_id);
|
||||||
|
channels[i].channel_id = channel_id;
|
||||||
hash = utils_djb2_hash(name);
|
return 0;
|
||||||
|
}
|
||||||
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
}
|
||||||
{
|
return -1;
|
||||||
if (channels[i].hash == hash)
|
|
||||||
{
|
|
||||||
logger(Core, Debug, "dvc_channels_set_id(), name = '%s', channel_id = %d",
|
|
||||||
name, channel_id);
|
|
||||||
channels[i].channel_id = channel_id;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RD_BOOL
|
bool dvc_channels_is_available(const char *name) {
|
||||||
dvc_channels_is_available(const char *name)
|
uint32_t hash = utils_djb2_hash(name);
|
||||||
{
|
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
|
||||||
int i;
|
if (channels[i].hash == hash) {
|
||||||
uint32 hash;
|
return (channels[i].channel_id != INVALID_CHANNEL);
|
||||||
hash = utils_djb2_hash(name);
|
}
|
||||||
|
}
|
||||||
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
return false;
|
||||||
{
|
|
||||||
if (channels[i].hash == hash)
|
|
||||||
{
|
|
||||||
return (channels[i].channel_id != INVALID_CHANNEL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return False;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RD_BOOL
|
bool dvc_channels_register(const char *name, dvc_channel_process_fn handler) {
|
||||||
dvc_channels_register(const char *name, dvc_channel_process_fn handler)
|
return dvc_channels_add(name, handler, INVALID_CHANNEL);
|
||||||
{
|
|
||||||
return dvc_channels_add(name, handler, INVALID_CHANNEL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static STREAM dvc_init_packet(dvc_hdr_t hdr, uint32_t channelid, size_t length) {
|
||||||
|
STREAM s;
|
||||||
|
length += 1; // add 1 byte hdr
|
||||||
|
|
||||||
static STREAM
|
if (channelid != INVALID_CHANNEL) {
|
||||||
dvc_init_packet(dvc_hdr_t hdr, uint32 channelid, size_t length)
|
if (hdr.hdr.cbid == 0)
|
||||||
{
|
length += 1;
|
||||||
STREAM s;
|
else if (hdr.hdr.cbid == 1)
|
||||||
|
length += 2;
|
||||||
|
else if (hdr.hdr.cbid == 2)
|
||||||
|
length += 4;
|
||||||
|
}
|
||||||
|
|
||||||
length += 1; /* add 1 byte hdr */
|
s = channel_init(dvc_channel, length);
|
||||||
|
out_uint8(s, hdr.data); // DVC header
|
||||||
|
|
||||||
if (channelid != INVALID_CHANNEL)
|
if (channelid != INVALID_CHANNEL) {
|
||||||
{
|
if (hdr.hdr.cbid == 0) {
|
||||||
if (hdr.hdr.cbid == 0)
|
out_uint8(s, channelid);
|
||||||
length += 1;
|
} else if (hdr.hdr.cbid == 1) {
|
||||||
else if (hdr.hdr.cbid == 1)
|
out_uint16_le(s, channelid);
|
||||||
length += 2;
|
} else if (hdr.hdr.cbid == 2) {
|
||||||
else if (hdr.hdr.cbid == 2)
|
out_uint32_le(s, channelid);
|
||||||
length += 4;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s = channel_init(dvc_channel, length);
|
return s;
|
||||||
out_uint8(s, hdr.data); /* DVC header */
|
|
||||||
|
|
||||||
if (channelid != INVALID_CHANNEL)
|
|
||||||
{
|
|
||||||
if (hdr.hdr.cbid == 0)
|
|
||||||
{
|
|
||||||
out_uint8(s, channelid);
|
|
||||||
}
|
|
||||||
else if (hdr.hdr.cbid == 1)
|
|
||||||
{
|
|
||||||
out_uint16_le(s, channelid);
|
|
||||||
}
|
|
||||||
else if (hdr.hdr.cbid == 2)
|
|
||||||
{
|
|
||||||
out_uint32_le(s, channelid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void dvc_send(const char *name, STREAM s) {
|
||||||
dvc_send(const char *name, STREAM s)
|
STREAM ls;
|
||||||
{
|
dvc_hdr_t hdr;
|
||||||
STREAM ls;
|
uint32_t channel_id = dvc_channels_get_id(name);
|
||||||
dvc_hdr_t hdr;
|
|
||||||
uint32 channel_id;
|
|
||||||
|
|
||||||
channel_id = dvc_channels_get_id(name);
|
if (channel_id == INVALID_CHANNEL) {
|
||||||
if (channel_id == INVALID_CHANNEL)
|
logger(Core, Error, "dvc_send(), Trying to send data on invalid channel '%s'", name);
|
||||||
{
|
return;
|
||||||
logger(Core, Error, "dvc_send(), Trying to send data on invalid channel '%s'",
|
}
|
||||||
name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: we assume length is less than 1600 */
|
// FIXME: we assume length is less than 1600
|
||||||
|
hdr.hdr.cmd = DYNVC_DATA;
|
||||||
|
hdr.hdr.cbid = 2;
|
||||||
|
hdr.hdr.sp = 0;
|
||||||
|
|
||||||
hdr.hdr.cmd = DYNVC_DATA;
|
ls = dvc_init_packet(hdr, channel_id, s_length(s));
|
||||||
hdr.hdr.cbid = 2;
|
out_stream(ls, s);
|
||||||
hdr.hdr.sp = 0;
|
s_mark_end(ls);
|
||||||
|
channel_send(ls, dvc_channel);
|
||||||
ls = dvc_init_packet(hdr, channel_id, s_length(s));
|
s_free(ls);
|
||||||
|
|
||||||
out_stream(ls, s);
|
|
||||||
|
|
||||||
s_mark_end(ls);
|
|
||||||
|
|
||||||
channel_send(ls, dvc_channel);
|
|
||||||
s_free(ls);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dvc_send_capabilities_response() {
|
||||||
|
STREAM s;
|
||||||
|
dvc_hdr_t hdr;
|
||||||
|
uint16_t supportedversion = 0x01;
|
||||||
|
|
||||||
static void
|
hdr.hdr.cbid = 0x00;
|
||||||
dvc_send_capabilities_response()
|
hdr.hdr.sp = 0x00;
|
||||||
{
|
hdr.hdr.cmd = DYNVC_CAPABILITIES;
|
||||||
STREAM s;
|
|
||||||
dvc_hdr_t hdr;
|
|
||||||
uint16 supportedversion = 0x01;
|
|
||||||
|
|
||||||
hdr.hdr.cbid = 0x00;
|
logger(Protocol, Debug, "dvc_send_capabilities_response(), offering support for dvc %d", supportedversion);
|
||||||
hdr.hdr.sp = 0x00;
|
|
||||||
hdr.hdr.cmd = DYNVC_CAPABILITIES;
|
|
||||||
|
|
||||||
logger(Protocol, Debug,
|
s = dvc_init_packet(hdr, (uint32_t)-1, 3);
|
||||||
"dvc_send_capabilities_response(), offering support for dvc %d", supportedversion);
|
out_uint8(s, 0x00); // pad
|
||||||
|
out_uint16_le(s, supportedversion); // version
|
||||||
s = dvc_init_packet(hdr, -1, 3);
|
s_mark_end(s);
|
||||||
out_uint8(s, 0x00); /* pad */
|
channel_send(s, dvc_channel);
|
||||||
out_uint16_le(s, supportedversion); /* version */
|
s_free(s);
|
||||||
|
|
||||||
s_mark_end(s);
|
|
||||||
|
|
||||||
channel_send(s, dvc_channel);
|
|
||||||
s_free(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dvc_process_caps_pdu(STREAM s) {
|
||||||
dvc_process_caps_pdu(STREAM s)
|
uint16_t version;
|
||||||
{
|
|
||||||
uint16 version;
|
|
||||||
|
|
||||||
/* VERSION1 */
|
in_uint8s(s, 1); // pad
|
||||||
in_uint8s(s, 1); /* pad */
|
in_uint16_le(s, version); // version
|
||||||
in_uint16_le(s, version); /* version */
|
|
||||||
|
|
||||||
logger(Protocol, Debug, "dvc_process_caps(), server supports dvc %d", version);
|
logger(Protocol, Debug, "dvc_process_caps(), server supports dvc %d", version);
|
||||||
|
|
||||||
dvc_send_capabilities_response();
|
dvc_send_capabilities_response();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dvc_send_create_response(bool success, dvc_hdr_t hdr, uint32_t channelid) {
|
||||||
dvc_send_create_response(RD_BOOL success, dvc_hdr_t hdr, uint32 channelid)
|
STREAM s;
|
||||||
{
|
|
||||||
STREAM s;
|
|
||||||
|
|
||||||
logger(Protocol, Debug, "dvc_send_create_response(), %s request to create channelid %d",
|
logger(Protocol, Debug, "dvc_send_create_response(), %s request to create channelid %d",
|
||||||
(success ? "granted" : "denied"), channelid);
|
(success ? "granted" : "denied"), channelid);
|
||||||
s = dvc_init_packet(hdr, channelid, 4);
|
s = dvc_init_packet(hdr, channelid, 4);
|
||||||
out_uint32_le(s, success ? 0 : -1);
|
out_uint32_le(s, success ? 0 : (uint32_t)-1);
|
||||||
s_mark_end(s);
|
s_mark_end(s);
|
||||||
|
channel_send(s, dvc_channel);
|
||||||
channel_send(s, dvc_channel);
|
s_free(s);
|
||||||
s_free(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dvc_process_create_pdu(STREAM s, dvc_hdr_t hdr) {
|
||||||
dvc_process_create_pdu(STREAM s, dvc_hdr_t hdr)
|
char name[512];
|
||||||
{
|
uint32_t channelid;
|
||||||
char name[512];
|
|
||||||
uint32 channelid;
|
|
||||||
|
|
||||||
channelid = dvc_in_channelid(s, hdr);
|
channelid = dvc_in_channelid(s, hdr);
|
||||||
|
in_ansi_string(s, name, sizeof(name));
|
||||||
|
|
||||||
in_ansi_string(s, name, sizeof(name));
|
logger(Protocol, Debug, "dvc_process_create(), server requests channelid = %d, name = '%s'", channelid, name);
|
||||||
|
|
||||||
logger(Protocol, Debug, "dvc_process_create(), server requests channelid = %d, name = '%s'",
|
|
||||||
channelid, name);
|
|
||||||
|
|
||||||
if (dvc_channels_exists(name))
|
|
||||||
{
|
|
||||||
logger(Core, Verbose, "Established dynamic virtual channel '%s'", name);
|
|
||||||
|
|
||||||
dvc_channels_set_id(name, channelid);
|
|
||||||
dvc_send_create_response(True, hdr, channelid);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dvc_send_create_response(False, hdr, channelid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (dvc_channels_exists(name)) {
|
||||||
|
logger(Core, Verbose, "Established dynamic virtual channel '%s'", name);
|
||||||
|
dvc_channels_set_id(name, channelid);
|
||||||
|
dvc_send_create_response(true, hdr, channelid);
|
||||||
|
} else {
|
||||||
|
dvc_send_create_response(false, hdr, channelid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32
|
static uint32_t dvc_in_channelid(STREAM s, dvc_hdr_t hdr) {
|
||||||
dvc_in_channelid(STREAM s, dvc_hdr_t hdr)
|
uint32_t id = (uint32_t)-1;
|
||||||
{
|
|
||||||
uint32 id;
|
|
||||||
|
|
||||||
id = (uint32) - 1;
|
switch (hdr.hdr.cbid) {
|
||||||
|
case 0:
|
||||||
switch (hdr.hdr.cbid)
|
in_uint8(s, id);
|
||||||
{
|
break;
|
||||||
case 0:
|
case 1:
|
||||||
in_uint8(s, id);
|
in_uint16_le(s, id);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 2:
|
||||||
in_uint16_le(s, id);
|
in_uint32_le(s, id);
|
||||||
break;
|
break;
|
||||||
case 2:
|
}
|
||||||
in_uint32_le(s, id);
|
return id;
|
||||||
break;
|
|
||||||
}
|
|
||||||
return id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dvc_process_data_pdu(STREAM s, dvc_hdr_t hdr) {
|
||||||
dvc_process_data_pdu(STREAM s, dvc_hdr_t hdr)
|
const dvc_channel_t *ch;
|
||||||
{
|
uint32_t channelid = dvc_in_channelid(s, hdr);
|
||||||
const dvc_channel_t *ch;
|
|
||||||
uint32 channelid;
|
|
||||||
|
|
||||||
channelid = dvc_in_channelid(s, hdr);
|
ch = dvc_channels_get_by_id(channelid);
|
||||||
ch = dvc_channels_get_by_id(channelid);
|
if (ch == NULL) {
|
||||||
if (ch == NULL)
|
logger(Protocol, Warning, "dvc_process_data(), Received data on unregistered channel %d", channelid);
|
||||||
{
|
return;
|
||||||
logger(Protocol, Warning,
|
}
|
||||||
"dvc_process_data(), Received data on unregistered channel %d", channelid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dispatch packet to channel handler */
|
// Dispatch packet to channel handler
|
||||||
ch->handler(s);
|
ch->handler(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dvc_process_close_pdu(STREAM s, dvc_hdr_t hdr) {
|
||||||
dvc_process_close_pdu(STREAM s, dvc_hdr_t hdr)
|
uint32_t channelid = dvc_in_channelid(s, hdr);
|
||||||
{
|
logger(Protocol, Debug, "dvc_process_close_pdu(), close channel %d", channelid);
|
||||||
uint32 channelid;
|
|
||||||
|
|
||||||
channelid = dvc_in_channelid(s, hdr);
|
if (!dvc_channels_remove_by_id(channelid)) {
|
||||||
logger(Protocol, Debug, "dvc_process_close_pdu(), close channel %d", channelid);
|
logger(Protocol, Warning, "dvc_process_close_pdu(), Received close request for unregistered channel %d", channelid);
|
||||||
|
}
|
||||||
if (!dvc_channels_remove_by_id(channelid))
|
|
||||||
{
|
|
||||||
logger(Protocol, Warning,
|
|
||||||
"dvc_process_close_pdu(), Received close request for unregistered channel %d",
|
|
||||||
channelid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dvc_process_pdu(STREAM s) {
|
||||||
|
dvc_hdr_t hdr;
|
||||||
|
|
||||||
static void
|
in_uint8(s, hdr.data);
|
||||||
dvc_process_pdu(STREAM s)
|
|
||||||
{
|
|
||||||
dvc_hdr_t hdr;
|
|
||||||
|
|
||||||
in_uint8(s, hdr.data);
|
switch (hdr.hdr.cmd) {
|
||||||
|
case DYNVC_CAPABILITIES:
|
||||||
switch (hdr.hdr.cmd)
|
dvc_process_caps_pdu(s);
|
||||||
{
|
break;
|
||||||
case DYNVC_CAPABILITIES:
|
case DYNVC_CREATE_REQ:
|
||||||
dvc_process_caps_pdu(s);
|
dvc_process_create_pdu(s, hdr);
|
||||||
break;
|
break;
|
||||||
case DYNVC_CREATE_REQ:
|
case DYNVC_DATA:
|
||||||
dvc_process_create_pdu(s, hdr);
|
dvc_process_data_pdu(s, hdr);
|
||||||
break;
|
break;
|
||||||
|
case DYNVC_CLOSE:
|
||||||
case DYNVC_DATA:
|
dvc_process_close_pdu(s, hdr);
|
||||||
dvc_process_data_pdu(s, hdr);
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
case DYNVC_CLOSE:
|
|
||||||
dvc_process_close_pdu(s, hdr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if 0 /* Unimplemented */
|
|
||||||
|
|
||||||
case DYNVC_DATA_FIRST:
|
|
||||||
break;
|
|
||||||
case DYNVC_DATA_FIRST_COMPRESSED:
|
|
||||||
break;
|
|
||||||
case DYNVC_DATA_COMPRESSED:
|
|
||||||
break;
|
|
||||||
case DYNVC_SOFT_SYNC_REQUEST:
|
|
||||||
break;
|
|
||||||
case DYNVC_SOFT_SYNC_RESPONSE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
#if 0 // Unimplemented
|
||||||
|
case DYNVC_DATA_FIRST:
|
||||||
|
break;
|
||||||
|
case DYNVC_DATA_FIRST_COMPRESSED:
|
||||||
|
break;
|
||||||
|
case DYNVC_DATA_COMPRESSED:
|
||||||
|
break;
|
||||||
|
case DYNVC_SOFT_SYNC_REQUEST:
|
||||||
|
break;
|
||||||
|
case DYNVC_SOFT_SYNC_RESPONSE:
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
logger(Protocol, Warning, "dvc_process_pdu(), Unhandled command type 0x%x",
|
logger(Protocol, Warning, "dvc_process_pdu(), Unhandled command type 0x%x", hdr.hdr.cmd);
|
||||||
hdr.hdr.cmd);
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RD_BOOL
|
bool dvc_init() {
|
||||||
dvc_init()
|
memset(channels, 0, sizeof(channels));
|
||||||
{
|
dvc_channel = channel_register("drdynvc", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, dvc_process_pdu);
|
||||||
memset(channels, 0, sizeof(channels));
|
return (dvc_channel != NULL);
|
||||||
dvc_channel = channel_register("drdynvc",
|
|
||||||
CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
|
|
||||||
dvc_process_pdu);
|
|
||||||
|
|
||||||
return (dvc_channel != NULL);
|
|
||||||
}
|
}
|
||||||
|
55
ewmhints.c
55
ewmhints.c
@ -25,6 +25,8 @@
|
|||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include "rdesktop.h"
|
#include "rdesktop.h"
|
||||||
|
|
||||||
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
|
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
|
||||||
@ -45,7 +47,7 @@ Atom g_net_wm_state_atom, g_net_wm_desktop_atom, g_net_wm_ping_atom;
|
|||||||
Returns zero on success, -1 on error
|
Returns zero on success, -1 on error
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
get_property_value(Window wnd, char *propname, long max_length,
|
get_property_value(Window wnd, const char *propname, long max_length,
|
||||||
unsigned long *nitems_return, unsigned char **prop_return, int nowarn)
|
unsigned long *nitems_return, unsigned char **prop_return, int nowarn)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
@ -57,7 +59,8 @@ get_property_value(Window wnd, char *propname, long max_length,
|
|||||||
property = XInternAtom(g_display, propname, True);
|
property = XInternAtom(g_display, propname, True);
|
||||||
if (property == None)
|
if (property == None)
|
||||||
{
|
{
|
||||||
logger(GUI, Error, "get_property_value(), atom '%s' does not exist", propname);
|
if (!nowarn)
|
||||||
|
logger(GUI, Error, "get_property_value(), atom '%s' does not exist", propname);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +74,8 @@ get_property_value(Window wnd, char *propname, long max_length,
|
|||||||
|
|
||||||
if (result != Success)
|
if (result != Success)
|
||||||
{
|
{
|
||||||
logger(GUI, Error, "get_property_value(), XGetWindowProperty failed");
|
if (!nowarn)
|
||||||
|
logger(GUI, Error, "get_property_value(), XGetWindowProperty failed");
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +110,7 @@ static int
|
|||||||
get_current_desktop(void)
|
get_current_desktop(void)
|
||||||
{
|
{
|
||||||
unsigned long nitems_return;
|
unsigned long nitems_return;
|
||||||
unsigned char *prop_return;
|
unsigned char *prop_return = NULL;
|
||||||
int current_desktop;
|
int current_desktop;
|
||||||
|
|
||||||
if (get_property_value
|
if (get_property_value
|
||||||
@ -117,6 +121,7 @@ get_current_desktop(void)
|
|||||||
if (nitems_return != 1)
|
if (nitems_return != 1)
|
||||||
{
|
{
|
||||||
logger(GUI, Error, "get_current_desktop(), _NET_CURRENT_DESKTOP has bad length");
|
logger(GUI, Error, "get_current_desktop(), _NET_CURRENT_DESKTOP has bad length");
|
||||||
|
if (prop_return) XFree(prop_return);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +140,7 @@ get_current_workarea(uint32 * x, uint32 * y, uint32 * width, uint32 * height)
|
|||||||
{
|
{
|
||||||
int current_desktop;
|
int current_desktop;
|
||||||
unsigned long nitems_return;
|
unsigned long nitems_return;
|
||||||
unsigned char *prop_return;
|
unsigned char *prop_return = NULL;
|
||||||
long *return_words;
|
long *return_words;
|
||||||
const uint32 net_workarea_x_offset = 0;
|
const uint32 net_workarea_x_offset = 0;
|
||||||
const uint32 net_workarea_y_offset = 1;
|
const uint32 net_workarea_y_offset = 1;
|
||||||
@ -151,13 +156,17 @@ get_current_workarea(uint32 * x, uint32 * y, uint32 * width, uint32 * height)
|
|||||||
if (nitems_return % 4)
|
if (nitems_return % 4)
|
||||||
{
|
{
|
||||||
logger(GUI, Error, "get_current_workarea(),_NET_WORKAREA has bad length");
|
logger(GUI, Error, "get_current_workarea(),_NET_WORKAREA has bad length");
|
||||||
|
XFree(prop_return);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
current_desktop = get_current_desktop();
|
current_desktop = get_current_desktop();
|
||||||
|
|
||||||
if (current_desktop < 0)
|
if (current_desktop < 0)
|
||||||
|
{
|
||||||
|
XFree(prop_return);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return_words = (long *) prop_return;
|
return_words = (long *) prop_return;
|
||||||
|
|
||||||
@ -206,7 +215,7 @@ int
|
|||||||
ewmh_get_window_state(Window w)
|
ewmh_get_window_state(Window w)
|
||||||
{
|
{
|
||||||
unsigned long nitems_return;
|
unsigned long nitems_return;
|
||||||
unsigned char *prop_return;
|
unsigned char *prop_return = NULL;
|
||||||
unsigned long *return_words;
|
unsigned long *return_words;
|
||||||
unsigned long item;
|
unsigned long item;
|
||||||
RD_BOOL maximized_vert, maximized_horz, hidden;
|
RD_BOOL maximized_vert, maximized_horz, hidden;
|
||||||
@ -247,7 +256,7 @@ ewmh_modify_state(Window wnd, int add, Atom atom1, Atom atom2)
|
|||||||
|
|
||||||
int result;
|
int result;
|
||||||
unsigned long i, nitems;
|
unsigned long i, nitems;
|
||||||
unsigned char *props;
|
unsigned char *props = NULL;
|
||||||
uint32 state = WithdrawnState;
|
uint32 state = WithdrawnState;
|
||||||
|
|
||||||
/* The spec states that the window manager must respect any
|
/* The spec states that the window manager must respect any
|
||||||
@ -312,10 +321,7 @@ ewmh_modify_state(Window wnd, int add, Atom atom1, Atom atom2)
|
|||||||
xevent.xclient.window = wnd;
|
xevent.xclient.window = wnd;
|
||||||
xevent.xclient.message_type = g_net_wm_state_atom;
|
xevent.xclient.message_type = g_net_wm_state_atom;
|
||||||
xevent.xclient.format = 32;
|
xevent.xclient.format = 32;
|
||||||
if (add)
|
xevent.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
|
||||||
xevent.xclient.data.l[0] = _NET_WM_STATE_ADD;
|
|
||||||
else
|
|
||||||
xevent.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
|
|
||||||
xevent.xclient.data.l[1] = atom1;
|
xevent.xclient.data.l[1] = atom1;
|
||||||
xevent.xclient.data.l[2] = atom2;
|
xevent.xclient.data.l[2] = atom2;
|
||||||
xevent.xclient.data.l[3] = 0;
|
xevent.xclient.data.l[3] = 0;
|
||||||
@ -361,7 +367,7 @@ int
|
|||||||
ewmh_get_window_desktop(Window wnd)
|
ewmh_get_window_desktop(Window wnd)
|
||||||
{
|
{
|
||||||
unsigned long nitems_return;
|
unsigned long nitems_return;
|
||||||
unsigned char *prop_return;
|
unsigned char *prop_return = NULL;
|
||||||
int desktop;
|
int desktop;
|
||||||
|
|
||||||
if (get_property_value(wnd, "_NET_WM_DESKTOP", 1, &nitems_return, &prop_return, 0) < 0)
|
if (get_property_value(wnd, "_NET_WM_DESKTOP", 1, &nitems_return, &prop_return, 0) < 0)
|
||||||
@ -370,6 +376,7 @@ ewmh_get_window_desktop(Window wnd)
|
|||||||
if (nitems_return != 1)
|
if (nitems_return != 1)
|
||||||
{
|
{
|
||||||
logger(GUI, Error, "ewmh_get_window_desktop(), _NET_WM_DESKTOP has bad length");
|
logger(GUI, Error, "ewmh_get_window_desktop(), _NET_WM_DESKTOP has bad length");
|
||||||
|
if (prop_return) XFree(prop_return);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,7 +447,7 @@ void
|
|||||||
ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
|
ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
|
||||||
{
|
{
|
||||||
unsigned long nitems, i;
|
unsigned long nitems, i;
|
||||||
unsigned char *props;
|
unsigned char *props = NULL;
|
||||||
unsigned long *cur_set, *new_set;
|
unsigned long *cur_set, *new_set;
|
||||||
unsigned long *icon;
|
unsigned long *icon;
|
||||||
|
|
||||||
@ -463,7 +470,7 @@ ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
|
|||||||
icon = cur_set + i;
|
icon = cur_set + i;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
new_set = xmalloc((nitems + width * height + 2) * sizeof(unsigned long));
|
new_set = (unsigned long *)malloc((nitems + width * height + 2) * sizeof(unsigned long));
|
||||||
memcpy(new_set, cur_set, nitems * sizeof(unsigned long));
|
memcpy(new_set, cur_set, nitems * sizeof(unsigned long));
|
||||||
icon = new_set + nitems;
|
icon = new_set + nitems;
|
||||||
nitems += width * height + 2;
|
nitems += width * height + 2;
|
||||||
@ -471,7 +478,7 @@ ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
new_set = xmalloc((width * height + 2) * sizeof(unsigned long));
|
new_set = (unsigned long *)malloc((width * height + 2) * sizeof(unsigned long));
|
||||||
icon = new_set;
|
icon = new_set;
|
||||||
nitems = width * height + 2;
|
nitems = width * height + 2;
|
||||||
}
|
}
|
||||||
@ -483,10 +490,10 @@ ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
|
|||||||
for (i = 0; i < (width * height); i++)
|
for (i = 0; i < (width * height); i++)
|
||||||
{
|
{
|
||||||
icon[i + 2] =
|
icon[i + 2] =
|
||||||
rgba_data[i * 4 + 3] << 24 |
|
((unsigned char)rgba_data[i * 4 + 3] << 24) |
|
||||||
((rgba_data[i * 4 + 0] << 16) & 0x00FF0000) |
|
(((unsigned char)rgba_data[i * 4 + 0] << 16) & 0x00FF0000) |
|
||||||
((rgba_data[i * 4 + 1] << 8) & 0x0000FF00) |
|
(((unsigned char)rgba_data[i * 4 + 1] << 8) & 0x0000FF00) |
|
||||||
((rgba_data[i * 4 + 2] << 0) & 0x000000FF);
|
(((unsigned char)rgba_data[i * 4 + 2] << 0) & 0x000000FF);
|
||||||
}
|
}
|
||||||
|
|
||||||
XChangeProperty(g_display, wnd, g_net_wm_icon_atom, XA_CARDINAL, 32,
|
XChangeProperty(g_display, wnd, g_net_wm_icon_atom, XA_CARDINAL, 32,
|
||||||
@ -495,14 +502,14 @@ ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
|
|||||||
if (cur_set)
|
if (cur_set)
|
||||||
XFree(cur_set);
|
XFree(cur_set);
|
||||||
if (new_set)
|
if (new_set)
|
||||||
xfree(new_set);
|
free(new_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ewmh_del_icon(Window wnd, uint32 width, uint32 height)
|
ewmh_del_icon(Window wnd, uint32 width, uint32 height)
|
||||||
{
|
{
|
||||||
unsigned long nitems, i, icon_size;
|
unsigned long nitems, i, icon_size;
|
||||||
unsigned char *props;
|
unsigned char *props = NULL;
|
||||||
unsigned long *cur_set, *new_set;
|
unsigned long *cur_set, *new_set;
|
||||||
|
|
||||||
cur_set = NULL;
|
cur_set = NULL;
|
||||||
@ -525,7 +532,7 @@ ewmh_del_icon(Window wnd, uint32 width, uint32 height)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
icon_size = width * height + 2;
|
icon_size = width * height + 2;
|
||||||
new_set = xmalloc((nitems - icon_size) * sizeof(unsigned long));
|
new_set = (unsigned long *)malloc((nitems - icon_size) * sizeof(unsigned long));
|
||||||
|
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
memcpy(new_set, cur_set, i * sizeof(unsigned long));
|
memcpy(new_set, cur_set, i * sizeof(unsigned long));
|
||||||
@ -538,7 +545,7 @@ ewmh_del_icon(Window wnd, uint32 width, uint32 height)
|
|||||||
XChangeProperty(g_display, wnd, g_net_wm_icon_atom, XA_CARDINAL, 32,
|
XChangeProperty(g_display, wnd, g_net_wm_icon_atom, XA_CARDINAL, 32,
|
||||||
PropModeReplace, (unsigned char *) new_set, nitems);
|
PropModeReplace, (unsigned char *) new_set, nitems);
|
||||||
|
|
||||||
xfree(new_set);
|
free(new_set);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
XFree(cur_set);
|
XFree(cur_set);
|
||||||
@ -556,7 +563,7 @@ RD_BOOL
|
|||||||
ewmh_is_window_above(Window w)
|
ewmh_is_window_above(Window w)
|
||||||
{
|
{
|
||||||
unsigned long nitems_return;
|
unsigned long nitems_return;
|
||||||
unsigned char *prop_return;
|
unsigned char *prop_return = NULL;
|
||||||
unsigned long *return_words;
|
unsigned long *return_words;
|
||||||
unsigned long item;
|
unsigned long item;
|
||||||
RD_BOOL above;
|
RD_BOOL above;
|
||||||
|
Loading…
Reference in New Issue
Block a user