1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
/* Copyright 2010 Stefan Tomanek <stefan.tomanek+th@wertarbyte.de>
* You have permission to copy, modify, and redistribute under the
* terms of the GPLv3 or any later version.
* For full license terms, see COPYING.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "devtag.h"
#include "devices.h"
#include "command.h"
#include "cmdsocket.h"
int bind_cmdsocket( char *name ) {
int cmd_fd;
struct sockaddr_un addr;
/* remove any stale files */
struct stat sb;
int serr = stat(name, &sb);
if ( !serr && S_ISSOCK(sb.st_mode)) {
unlink(name);
}
cmd_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
strcpy(addr.sun_path, name);
addr.sun_family = AF_UNIX;
bind (cmd_fd, (struct sockaddr *) &addr,
strlen(addr.sun_path) + sizeof (addr.sun_family));
return cmd_fd;
}
int connect_cmdsocket( char *name ) {
int fd;
struct sockaddr_un server;
fd = socket(AF_UNIX, SOCK_DGRAM, 0);
strcpy(server.sun_path, name);
server.sun_family = AF_UNIX;
connect(fd, (struct sockaddr *) &server,
strlen(server.sun_path) + sizeof (server.sun_family));
return fd;
}
struct command *read_command( int cmd_fd ) {
struct command *cmd = malloc(sizeof(struct command));
if (! cmd) {
fprintf(stderr, "Unable to allocate memory for command!\n");
return NULL;
}
int fd[1] = {-1};
char buffer[CMSG_SPACE(sizeof fd)];
struct iovec v = {
.iov_base = cmd,
.iov_len = sizeof(*cmd)
};
struct msghdr msg = {
.msg_iov = &v,
.msg_iovlen = 1,
.msg_control = buffer,
.msg_controllen = sizeof(buffer)
};
int done = recvmsg( cmd_fd, &msg, 0 );
if (done == -1) {
fprintf(stderr, "Error reading command.");
free(cmd);
return NULL;
}
struct cmsghdr *cmessage = CMSG_FIRSTHDR(&msg);
if (cmessage) {
memcpy(fd, CMSG_DATA(cmessage), sizeof fd);
/* place FD back in the command message */
cmd->fd = (int) fd[0];
}
return cmd;
}
int send_command( int cmd_fd, enum command_type type, char *param, int passfd, int exclusive, char *tag ) {
if (type == CMD_ADD && passfd == 1) {
type = CMD_PASSFD;
}
struct command cmd = {
.fd = -1,
.exclusive = exclusive,
.type = type,
.param = {0},
.tag = {0}
};
if (param != NULL) {
strncpy(cmd.param, param, TH_COMMAND_PARAM_LENGTH);
cmd.param[TH_COMMAND_PARAM_LENGTH-1] = '\0';
}
if (tag != NULL) {
strncpy(cmd.tag, tag, TH_DEVICE_TAG_LENGTH);
cmd.tag[TH_DEVICE_TAG_LENGTH-1] = '\0';
}
struct iovec v = {
.iov_base = &cmd,
.iov_len = sizeof(cmd)
};
struct msghdr m = {
.msg_iov = &v,
.msg_iovlen = 1
};
/* add FD */
int dev_fd[1] = { -1 };
char buffer[CMSG_SPACE(sizeof(dev_fd))];
if (passfd) {
int fd = open( param, O_RDONLY );
if (fd < 0) {
perror("open");
return 1;
}
dev_fd[0] = fd ;
m.msg_control = buffer;
m.msg_controllen = sizeof(buffer);
struct cmsghdr *cmessage = CMSG_FIRSTHDR(&m);
cmessage->cmsg_level = SOL_SOCKET;
cmessage->cmsg_type = SCM_RIGHTS;
cmessage->cmsg_len = CMSG_LEN(sizeof(dev_fd));
m.msg_controllen = cmessage->cmsg_len;
memcpy(CMSG_DATA(cmessage), dev_fd, sizeof dev_fd);
}
int done = sendmsg( cmd_fd, &m, 0 );
return (done == -1);
}
|