Squid Web Cache master
Loading...
Searching...
No Matches
UdsOp.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/* DEBUG: section 54 Interprocess Communication */
10
11#include "squid.h"
12#include "base/TextException.h"
13#include "comm.h"
14#include "comm/Connection.h"
15#include "comm/Write.h"
16#include "CommCalls.h"
17#include "compat/socket.h"
18#include "ipc/UdsOp.h"
19
20Ipc::UdsOp::UdsOp(const String& pathAddr):
21 AsyncJob("Ipc::UdsOp"),
22 address(PathToAddress(pathAddr)),
23 options(COMM_NONBLOCKING)
24{
25 debugs(54, 5, '[' << this << "] pathAddr=" << pathAddr);
26}
27
29{
30 debugs(54, 5, '[' << this << ']');
31 if (Comm::IsConnOpen(conn_))
32 conn_->close();
33 conn_ = nullptr;
34}
35
36void Ipc::UdsOp::setOptions(int newOptions)
37{
38 options = newOptions;
39}
40
43{
44 if (!Comm::IsConnOpen(conn_)) {
45 if (options & COMM_DOBIND)
46 unlink(address.sun_path);
47 if (conn_ == nullptr)
48 conn_ = new Comm::Connection;
49 conn_->fd = comm_open_uds(SOCK_DGRAM, 0, &address, options);
50 Must(Comm::IsConnOpen(conn_));
51 }
52 return conn_;
53}
54
55void Ipc::UdsOp::setTimeout(time_t seconds, const char *handlerName)
56{
58 AsyncCall::Pointer handler = asyncCall(54,5, handlerName,
60 commSetConnTimeout(conn(), seconds, handler);
61}
62
67
69{
70 timedout(); // our kid handles communication timeout
71}
72
73struct sockaddr_un
74Ipc::PathToAddress(const String& pathAddr) {
75 assert(pathAddr.size() != 0);
76 struct sockaddr_un unixAddr;
77 memset(&unixAddr, 0, sizeof(unixAddr));
78 unixAddr.sun_family = AF_LOCAL;
79 xstrncpy(unixAddr.sun_path, pathAddr.termedBuf(), sizeof(unixAddr.sun_path));
80 return unixAddr;
81}
82
84
85Ipc::UdsSender::UdsSender(const String& pathAddr, const TypedMsgHdr& aMessage):
86 UdsOp(pathAddr),
87 codeContext(CodeContext::Current()),
88 message(aMessage),
89 retries(10), // TODO: make configurable?
90 timeout(10), // TODO: make configurable?
91 sleeping(false),
92 writing(false)
93{
95}
96
98{
99 // did we abort while waiting between retries?
100 if (sleeping)
101 cancelSleep();
102
104}
105
107{
108 UdsOp::start();
109 write();
110 if (timeout > 0)
111 setTimeout(timeout, "Ipc::UdsSender::noteTimeout");
112}
113
115{
116 return !writing && !sleeping && UdsOp::doneAll();
117}
118
120{
121 debugs(54, 5, MYNAME);
123 AsyncCall::Pointer writeHandler = JobCallback(54, 5,
124 Dialer, this, UdsSender::wrote);
125 Comm::Write(conn(), message.raw(), message.size(), writeHandler, nullptr);
126 writing = true;
127}
128
130{
131 debugs(54, 5, params.conn << " flag " << params.flag << " retries " << retries << " [" << this << ']');
132 writing = false;
133 if (params.flag != Comm::OK && retries-- > 0) {
134 // perhaps a fresh connection and more time will help?
135 conn()->close();
136 startSleep();
137 }
138}
139
142{
143 Must(!sleeping);
144 sleeping = true;
145 eventAdd("Ipc::UdsSender::DelayedRetry",
147 new Pointer(this), 1, 0, false); // TODO: Use Fibonacci increments
148}
149
152{
153 if (sleeping) {
154 // Why not delete the event? See Comm::ConnOpener::cancelSleep().
155 sleeping = false;
156 debugs(54, 9, "stops sleeping");
157 }
158}
159
162{
163 Pointer *ptr = static_cast<Pointer*>(data);
164 assert(ptr);
165 if (UdsSender *us = dynamic_cast<UdsSender*>(ptr->valid())) {
166 CallBack(us->codeContext, [&us] {
167 CallJobHere(54, 4, us, UdsSender, delayedRetry);
168 });
169 }
170 delete ptr;
171}
172
175{
176 debugs(54, 5, sleeping);
177 if (sleeping) {
178 sleeping = false;
179 write(); // reopens the connection if needed
180 }
181}
182
184{
185 debugs(54, 5, MYNAME);
186 mustStop("timedout");
187}
188
189void Ipc::SendMessage(const String& toAddress, const TypedMsgHdr &message)
190{
191 AsyncJob::Start(new UdsSender(toAddress, message));
192}
193
195Ipc::ImportFdIntoComm(const Comm::ConnectionPointer &conn, int socktype, int protocol, Ipc::FdNoteId noteId)
196{
197 struct sockaddr_storage addr;
198 socklen_t len = sizeof(addr);
199 if (xgetsockname(conn->fd, reinterpret_cast<sockaddr*>(&addr), &len) == 0) {
200 conn->remote = addr;
201 struct addrinfo* addr_info = nullptr;
202 conn->remote.getAddrInfo(addr_info);
203 addr_info->ai_socktype = socktype;
204 addr_info->ai_protocol = protocol;
205 comm_import_opened(conn, Ipc::FdNote(noteId), addr_info);
206 Ip::Address::FreeAddr(addr_info);
207 } else {
208 int xerrno = errno;
209 debugs(54, DBG_CRITICAL, "ERROR: Ipc::ImportFdIntoComm: " << conn << ' ' << xstrerr(xerrno));
210 conn->close();
211 }
212 return conn;
213}
214
RefCount< AsyncCallT< Dialer > > asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition AsyncCall.h:156
#define JobCallback(dbgSection, dbgLevel, Dialer, job, method)
Convenience macro to create a Dialer-based job callback.
void CallBack(const CodeContext::Pointer &callbackContext, Fun &&callback)
#define COMM_DOBIND
Definition Connection.h:49
#define COMM_NONBLOCKING
Definition Connection.h:46
#define Must(condition)
#define assert(EX)
Definition assert.h:17
static int retries
#define CBDATA_NAMESPACED_CLASS_INIT(namespace, type)
Definition cbdata.h:333
static void Start(const Pointer &job)
Definition AsyncJob.cc:37
virtual bool doneAll() const
whether positive goal has been reached
Definition AsyncJob.cc:112
virtual void start()
called by AsyncStart; do not call directly
Definition AsyncJob.cc:59
virtual void swanSong()
Definition AsyncJob.h:61
Comm::Flag flag
comm layer result status.
Definition CommCalls.h:82
Comm::ConnectionPointer conn
Definition CommCalls.h:80
Ip::Address remote
Definition Connection.h:152
static void FreeAddr(struct addrinfo *&ai)
Definition Address.cc:698
void getAddrInfo(struct addrinfo *&ai, int force=AF_UNSPEC) const
Definition Address.cc:619
struct msghdr with a known type, fixed-size I/O and control buffers
Definition TypedMsgHdr.h:35
void address(const struct sockaddr_un &addr)
sets [dest.] address
void setTimeout(time_t seconds, const char *handlerName)
call timedout() if no UDS messages in a given number of seconds
Definition UdsOp.cc:55
~UdsOp() override
Definition UdsOp.cc:28
void noteTimeout(const CommTimeoutCbParams &p)
Comm timeout callback; calls timedout()
Definition UdsOp.cc:68
UdsOp(const String &pathAddr)
Definition UdsOp.cc:20
void setOptions(int newOptions)
changes socket options
Definition UdsOp.cc:36
void clearTimeout()
remove previously set timeout, if any
Definition UdsOp.cc:63
Comm::ConnectionPointer & conn()
creates if needed and returns raw UDS socket descriptor
Definition UdsOp.cc:42
struct sockaddr_un address
UDS address from path; treat as read-only.
Definition UdsOp.h:37
attempts to send an IPC message a few times, with a timeout
Definition UdsOp.h:69
void cancelSleep()
stop sleeping (or do nothing if we were not)
Definition UdsOp.cc:151
void start() override
called by AsyncStart; do not call directly
Definition UdsOp.cc:106
static void DelayedRetry(void *data)
legacy wrapper for Ipc::UdsSender::delayedRetry()
Definition UdsOp.cc:161
void delayedRetry()
make another sending attempt after a pause
Definition UdsOp.cc:174
void startSleep()
pause for a while before resending the message
Definition UdsOp.cc:141
void wrote(const CommIoCbParams &params)
done writing or error
Definition UdsOp.cc:129
void timedout() override
called after setTimeout() if timed out
Definition UdsOp.cc:183
void write()
schedule writing
Definition UdsOp.cc:119
bool doneAll() const override
whether positive goal has been reached
Definition UdsOp.cc:114
void swanSong() override
Definition UdsOp.cc:97
TypedMsgHdr message
what to send
Definition UdsOp.h:93
UdsSender(const String &pathAddr, const TypedMsgHdr &aMessage)
Definition UdsOp.cc:85
#define AF_LOCAL
Definition cmsg.h:128
void commUnsetConnTimeout(const Comm::ConnectionPointer &conn)
Definition comm.cc:618
void commSetConnTimeout(const Comm::ConnectionPointer &conn, time_t timeout, AsyncCall::Pointer &callback)
Definition comm.cc:594
int comm_open_uds(int sock_type, int proto, struct sockaddr_un *addr, int flags)
Create a unix-domain socket (UDS) that only supports FD_MSGHDR I/O.
Definition comm.cc:1677
void comm_import_opened(const Comm::ConnectionPointer &conn, const char *note, struct addrinfo *AI)
update Comm state after getting a comm_open() FD from another process
Definition comm.cc:551
#define MYNAME
Definition Stream.h:219
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
#define DBG_CRITICAL
Definition Stream.h:37
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition event.cc:107
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition Connection.cc:27
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Definition Write.cc:33
@ OK
Definition Flag.h:16
FdNoteId
We cannot send char* FD notes to other processes. Pass int IDs and convert.
Definition FdNotes.h:20
void SendMessage(const String &toAddress, const TypedMsgHdr &message)
Definition UdsOp.cc:189
struct sockaddr_un PathToAddress(const String &pathAddr)
converts human-readable filename path into UDS address
Definition UdsOp.cc:74
const Comm::ConnectionPointer & ImportFdIntoComm(const Comm::ConnectionPointer &conn, int socktype, int protocol, FdNoteId noteId)
import socket fd from another strand into our Comm state
Definition UdsOp.cc:195
const char * FdNote(int fdNodeId)
converts FdNoteId into a string
Definition FdNotes.cc:16
int xgetsockname(int socketFd, struct sockaddr *sa, socklen_t *saLength)
POSIX getsockname(2) equivalent.
Definition socket.h:80
char sun_family
Definition cmsg.h:107
char sun_path[256]
Definition cmsg.h:108
int socklen_t
Definition types.h:137
const char * xstrerr(int error)
Definition xstrerror.cc:83
char * xstrncpy(char *dst, const char *src, size_t n)
Definition xstring.cc:37