summaryrefslogtreecommitdiffstats
path: root/sbin/devd/devd.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/devd/devd.cc')
-rw-r--r--sbin/devd/devd.cc83
1 files changed, 54 insertions, 29 deletions
diff --git a/sbin/devd/devd.cc b/sbin/devd/devd.cc
index ce2a4f3..c770204 100644
--- a/sbin/devd/devd.cc
+++ b/sbin/devd/devd.cc
@@ -100,7 +100,8 @@ __FBSDID("$FreeBSD$");
#include "devd.h" /* C compatible definitions */
#include "devd.hh" /* C++ class definitions */
-#define PIPE "/var/run/devd.pipe"
+#define STREAMPIPE "/var/run/devd.pipe"
+#define SEQPACKETPIPE "/var/run/devd.seqpacket.pipe"
#define CF "/etc/devd.conf"
#define SYSCTL "hw.bus.devctl_queue"
@@ -119,6 +120,11 @@ __FBSDID("$FreeBSD$");
using namespace std;
+typedef struct client {
+ int fd;
+ int socktype;
+} client_t;
+
extern FILE *yyin;
extern int lineno;
@@ -822,12 +828,12 @@ process_event(char *buffer)
}
int
-create_socket(const char *name)
+create_socket(const char *name, int socktype)
{
int fd, slen;
struct sockaddr_un sun;
- if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0)
+ if ((fd = socket(PF_LOCAL, socktype, 0)) < 0)
err(1, "socket");
bzero(&sun, sizeof(sun));
sun.sun_family = AF_UNIX;
@@ -846,12 +852,13 @@ create_socket(const char *name)
unsigned int max_clients = 10; /* Default, can be overriden on cmdline. */
unsigned int num_clients;
-list<int> clients;
+
+list<client_t> clients;
void
notify_clients(const char *data, int len)
{
- list<int>::iterator i;
+ list<client_t>::iterator i;
/*
* Deliver the data to all clients. Throw clients overboard at the
@@ -861,11 +868,17 @@ notify_clients(const char *data, int len)
* kernel memory or tie up the limited number of available connections).
*/
for (i = clients.begin(); i != clients.end(); ) {
- if (write(*i, data, len) != len) {
+ int flags;
+ if (i->socktype == SOCK_SEQPACKET)
+ flags = MSG_EOR;
+ else
+ flags = 0;
+
+ if (send(i->fd, data, len, flags) != len) {
--num_clients;
- close(*i);
+ close(i->fd);
i = clients.erase(i);
- devdlog(LOG_WARNING, "notify_clients: write() failed; "
+ devdlog(LOG_WARNING, "notify_clients: send() failed; "
"dropping unresponsive client\n");
} else
++i;
@@ -877,7 +890,7 @@ check_clients(void)
{
int s;
struct pollfd pfd;
- list<int>::iterator i;
+ list<client_t>::iterator i;
/*
* Check all existing clients to see if any of them have disappeared.
@@ -888,12 +901,12 @@ check_clients(void)
*/
pfd.events = 0;
for (i = clients.begin(); i != clients.end(); ) {
- pfd.fd = *i;
+ pfd.fd = i->fd;
s = poll(&pfd, 1, 0);
if ((s < 0 && s != EINTR ) ||
(s > 0 && (pfd.revents & POLLHUP))) {
--num_clients;
- close(*i);
+ close(i->fd);
i = clients.erase(i);
devdlog(LOG_NOTICE, "check_clients: "
"dropping disconnected client\n");
@@ -903,9 +916,9 @@ check_clients(void)
}
void
-new_client(int fd)
+new_client(int fd, int socktype)
{
- int s;
+ client_t s;
int sndbuf_size;
/*
@@ -914,13 +927,14 @@ new_client(int fd)
* by sending large buffers full of data we'll never read.
*/
check_clients();
- s = accept(fd, NULL, NULL);
- if (s != -1) {
+ s.socktype = socktype;
+ s.fd = accept(fd, NULL, NULL);
+ if (s.fd != -1) {
sndbuf_size = CLIENT_BUFSIZE;
- if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_size,
+ if (setsockopt(s.fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_size,
sizeof(sndbuf_size)))
err(1, "setsockopt");
- shutdown(s, SHUT_RD);
+ shutdown(s.fd, SHUT_RD);
clients.push_back(s);
++num_clients;
} else
@@ -934,7 +948,7 @@ event_loop(void)
int fd;
char buffer[DEVCTL_MAXBUF];
int once = 0;
- int server_fd, max_fd;
+ int stream_fd, seqpacket_fd, max_fd;
int accepting;
timeval tv;
fd_set fds;
@@ -942,9 +956,10 @@ event_loop(void)
fd = open(PATH_DEVCTL, O_RDONLY | O_CLOEXEC);
if (fd == -1)
err(1, "Can't open devctl device %s", PATH_DEVCTL);
- server_fd = create_socket(PIPE);
+ stream_fd = create_socket(STREAMPIPE, SOCK_STREAM);
+ seqpacket_fd = create_socket(SEQPACKETPIPE, SOCK_SEQPACKET);
accepting = 1;
- max_fd = max(fd, server_fd) + 1;
+ max_fd = max(fd, max(stream_fd, seqpacket_fd)) + 1;
while (!romeo_must_die) {
if (!once && !no_daemon && !daemonize_quick) {
// Check to see if we have any events pending.
@@ -965,24 +980,28 @@ event_loop(void)
}
/*
* When we've already got the max number of clients, stop
- * accepting new connections (don't put server_fd in the set),
- * shrink the accept() queue to reject connections quickly, and
- * poll the existing clients more often, so that we notice more
- * quickly when any of them disappear to free up client slots.
+ * accepting new connections (don't put the listening sockets in
+ * the set), shrink the accept() queue to reject connections
+ * quickly, and poll the existing clients more often, so that we
+ * notice more quickly when any of them disappear to free up
+ * client slots.
*/
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (num_clients < max_clients) {
if (!accepting) {
- listen(server_fd, max_clients);
+ listen(stream_fd, max_clients);
+ listen(seqpacket_fd, max_clients);
accepting = 1;
}
- FD_SET(server_fd, &fds);
+ FD_SET(stream_fd, &fds);
+ FD_SET(seqpacket_fd, &fds);
tv.tv_sec = 60;
tv.tv_usec = 0;
} else {
if (accepting) {
- listen(server_fd, 0);
+ listen(stream_fd, 0);
+ listen(seqpacket_fd, 0);
accepting = 0;
}
tv.tv_sec = 2;
@@ -1022,8 +1041,14 @@ event_loop(void)
break;
}
}
- if (FD_ISSET(server_fd, &fds))
- new_client(server_fd);
+ if (FD_ISSET(stream_fd, &fds))
+ new_client(stream_fd, SOCK_STREAM);
+ /*
+ * Aside from the socket type, both sockets use the same
+ * protocol, so we can process clients the same way.
+ */
+ if (FD_ISSET(seqpacket_fd, &fds))
+ new_client(seqpacket_fd, SOCK_SEQPACKET);
}
close(fd);
}
OpenPOWER on IntegriCloud