26#include <sys/socket.h>
32void MsgQueue::writeToFd()
37 std::vector<int> sharedBuffers;
43 log(
"Unexpected write notification");
50 if (!mp->getContent(nsent, data, nsend, sharedBuffers))
69 if (nsend >
static_cast<ssize_t
>(maxWriteBufferLength))
70 nsend =
static_cast<ssize_t
>(maxWriteBufferLength);
74 nw = write(wFd, data, nsend);
81 struct cmsghdr * cmsgh;
83 size_t fdCount = sharedBuffers.size();
86 if (fdCount > maxFDPerMessage)
88 log(
fmt(
"attempt to send too many FD\n"));
93 cmsghdrlength = CMSG_SPACE((fdCount *
sizeof(
int)));
95 cmsgh = (
struct cmsghdr*)malloc(cmsghdrlength);
96 memset(cmsgh, 0, cmsghdrlength);
99 cmsgh->cmsg_len = CMSG_LEN(fdCount *
sizeof(
int));
100 cmsgh->cmsg_level = SOL_SOCKET;
101 cmsgh->cmsg_type = SCM_RIGHTS;
102 msgh.msg_control = cmsgh;
103 msgh.msg_controllen = cmsghdrlength;
104 for(
size_t i = 0; i < fdCount; ++i)
106 ((
int *) CMSG_DATA(CMSG_FIRSTHDR(&msgh)))[i] = sharedBuffers[i];
113 msgh.msg_control = cmsgh;
114 msgh.msg_controllen = cmsghdrlength;
117 iov[0].iov_base = data;
118 iov[0].iov_len = nsend;
121 msgh.msg_name = NULL;
122 msgh.msg_namelen = 0;
126 nw = sendmsg(wFd, &msgh, MSG_NOSIGNAL);
135 log(
"write returned 0\n");
147 log(
fmt(
"sending msg nq %ld:\n%.*s\n",
148 msgq.size(), (
int)nw, data));
152 log(
fmt(
"sending %.*s\n", (
int)nw, data));
158 mp->advance(nsent, nw);
166 std::string logLine =
"Dying Connection ";
176 if (!strcmp(enableBLOB,
"Also"))
178 else if (!strcmp(enableBLOB,
"Only"))
180 else if (!strcmp(enableBLOB,
"Never"))
190 static const char *prtags[] =
192 "defNumber",
"oneNumber",
"defText",
"oneText",
"defSwitch",
"oneSwitch",
"defLight",
"oneLight",
195 const char *msg, *perm, *pcd;
203 fprintf(stderr,
" %s", pcd);
206 fprintf(stderr,
" %s", perm);
209 fprintf(stderr,
" '%s'", msg);
213 for (i = 0; i <
sizeof(prtags) /
sizeof(prtags[0]); i++)
214 if (strcmp(prtags[i],
tagXMLEle(e)) == 0)
217 fprintf(stderr,
"\n");
223 rio.set<
MsgQueue, &MsgQueue::ioCb>(
this);
224 wio.set<
MsgQueue, &MsgQueue::ioCb>(
this);
243 for(
auto mp : msgqcp)
265 if (shutdown(oldWFd, SHUT_WR) == -1)
267 if (
errno != ENOTCONN)
269 log(
fmt(
"socket shutdown failed: %s\n", strerror(
errno)));
278 log(
fmt(
"socket close failed: %s\n", strerror(
errno)));
291 if (this->rFd != this->wFd)
296 else if (this->wFd != -1)
308 fcntl(rFd, F_SETFL, fcntl(rFd, F_GETFL, 0) | O_NONBLOCK);
311 fcntl(wFd, F_SETFL, fcntl(wFd, F_GETFL, 0) | O_NONBLOCK);
314 rio.set(rFd, ev::READ);
315 wio.set(wFd, ev::WRITE);
322 if (msgq.empty())
return nullptr;
323 return *(msgq.begin());
346 msgq.push_back(serialized);
347 serialized->addAwaiter(
this);
353void MsgQueue::updateIos()
357 if (msgq.empty() || !msgq.front()->requestContent(nsent))
374 if ((!msgq.empty()) && (msgq.front() == msg))
384 auto queueCopy = msgq;
385 for(
auto mp : queueCopy)
403 l += mp->queueSize();
409void MsgQueue::ioCb(ev::io &,
int revents)
411 if (EV_ERROR & revents)
414 if ((!sockErrno) && this->wFd != this->rFd)
421 log(
fmt(
"Communication error: %s\n", strerror(sockErrno)));
427 if (revents & EV_READ)
430 if (revents & EV_WRITE)
434size_t MsgQueue::doRead(
char * buf,
size_t nr)
439 return read(rFd, buf, nr);
449 struct cmsghdr cmsgh;
451 char control[CMSG_SPACE(maxFDPerMessage *
sizeof(
int))];
457 msgh.msg_name = NULL;
458 msgh.msg_namelen = 0;
462 msgh.msg_control = control_un.control;
463 msgh.msg_controllen =
sizeof(control_un.control);
467 recvflag = MSG_CMSG_CLOEXEC;
471 int size = recvmsg(rFd, &msgh, recvflag);
477 for (
struct cmsghdr * cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg))
479 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
482 while(cmsg->cmsg_len >= CMSG_LEN((fdCount + 1) *
sizeof(
int)))
487 int * fds = (
int*)CMSG_DATA(cmsg);
488 for(
int i = 0; i < fdCount; ++i)
491 fcntl(fds[i], F_SETFD, FD_CLOEXEC);
493 incomingSharedBuffers.push_back(fds[i]);
498 log(
fmt(
"Ignoring ancillary data level %d, type %d\n", cmsg->cmsg_level, cmsg->cmsg_type));
505void MsgQueue::readFromFd()
507 char buf[maxReadBufferLength];
511 nr = doRead(buf,
sizeof(buf));
514 if (
errno == EAGAIN ||
errno == EWOULDBLOCK)
return;
529 log(
fmt(
"XML error: %s\n", err));
530 log(
fmt(
"XML read: %.*s\n", (
int)nr, buf));
537 XMLEle *root = nodes[inode];
548 log(
fmt(
"read <%s device='%s' name='%s'>\n",
CommandLineArgs * userConfigurableArguments
std::string fmt(const char *fmt,...)
HeartBeat heartBeat() const
static void crackBLOB(const char *enableBLOB, BLOBHandling *bp)
void messageMayHaveProgressed(const SerializedMsg *msg)
MsgQueue(bool useSharedBuffer)
virtual void onMessage(XMLEle *root, std::list< int > &sharedBuffers)=0
void traceMsg(const std::string &log, XMLEle *root)
virtual void closeWritePart()
unsigned long msgQSize() const
virtual void log(const std::string &log) const
SerializedMsg * headMsg() const
void setFds(int rFd, int wFd)
SerializedMsg * serialize(MsgQueue *from)
BLOBHandling
How drivers handle BLOBs incoming from snooping drivers.
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
LilXML * newLilXML()
Create a new lilxml parser.
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
XMLEle ** parseXMLChunk(LilXML *lp, char *buf, int size, char ynot[])
Process an XML chunk.
void delXMLEle(XMLEle *ep)
delXMLEle Delete XML element.
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
void delLilXML(LilXML *lp)
Delete a lilxml parser.