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 
20 Ipc::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 
36 void 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 
55 void Ipc::UdsOp::setTimeout(time_t seconds, const char *handlerName)
56 {
58  AsyncCall::Pointer handler = asyncCall(54,5, handlerName,
59  Dialer(CbcPointer<UdsOp>(this), &UdsOp::noteTimeout));
60  commSetConnTimeout(conn(), seconds, handler);
61 }
62 
64 {
65  commUnsetConnTimeout(conn());
66 }
67 
69 {
70  timedout(); // our kid handles communication timeout
71 }
72 
73 struct sockaddr_un
74 Ipc::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 
85 Ipc::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 
103  UdsOp::swanSong();
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 
189 void Ipc::SendMessage(const String& toAddress, const TypedMsgHdr &message)
190 {
191  AsyncJob::Start(new UdsSender(toAddress, message));
192 }
193 
195 Ipc::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 
const char * xstrerr(int error)
Definition: xstrerror.cc:83
void commUnsetConnTimeout(const Comm::ConnectionPointer &conn)
Definition: comm.cc:618
void write()
schedule writing
Definition: UdsOp.cc:119
void delayedRetry()
make another sending attempt after a pause
Definition: UdsOp.cc:174
#define DBG_CRITICAL
Definition: Stream.h:37
struct sockaddr_un address
UDS address from path; treat as read-only.
Definition: UdsOp.h:37
#define AF_LOCAL
Definition: cmsg.h:128
void setOptions(int newOptions)
changes socket options
Definition: UdsOp.cc:36
virtual void swanSong()
Definition: AsyncJob.h:61
void timedout() override
Definition: UdsOp.cc:183
static void FreeAddr(struct addrinfo *&ai)
Definition: Address.cc:698
~UdsOp() override
Definition: UdsOp.cc:28
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
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:27
@ OK
Definition: Flag.h:16
void CallBack(const CodeContext::Pointer &callbackContext, Fun &&callback)
Definition: CodeContext.h:126
char sun_family
Definition: cmsg.h:107
const char * FdNote(int fdNodeId)
converts FdNoteId into a string
Definition: FdNotes.cc:16
int socklen_t
Definition: types.h:137
RefCount< AsyncCallT< Dialer > > asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition: AsyncCall.h:156
#define COMM_NONBLOCKING
Definition: Connection.h:46
CBDATA_NAMESPACED_CLASS_INIT(Ipc, UdsSender)
char sun_path[256]
Definition: cmsg.h:108
void noteTimeout(const CommTimeoutCbParams &p)
Comm timeout callback; calls timedout()
Definition: UdsOp.cc:68
int xgetsockname(int socketFd, struct sockaddr *sa, socklen_t *saLength)
POSIX getsockname(2) equivalent.
Definition: socket.h:80
virtual bool doneAll() const
whether positive goal has been reached
Definition: AsyncJob.cc:112
attempts to send an IPC message a few times, with a timeout
Definition: UdsOp.h:68
TypedMsgHdr message
what to send
Definition: UdsOp.h:93
void wrote(const CommIoCbParams &params)
done writing or error
Definition: UdsOp.cc:129
FdNoteId
We cannot send char* FD notes to other processes. Pass int IDs and convert.
Definition: FdNotes.h:20
Comm::ConnectionPointer conn
Definition: CommCalls.h:80
Ip::Address remote
Definition: Connection.h:152
void SendMessage(const String &toAddress, const TypedMsgHdr &message)
Definition: UdsOp.cc:189
#define assert(EX)
Definition: assert.h:17
SSL Connection
Definition: Session.h:49
Comm::Flag flag
comm layer result status.
Definition: CommCalls.h:82
#define JobCallback(dbgSection, dbgLevel, Dialer, job, method)
Convenience macro to create a Dialer-based job callback.
Definition: AsyncJobCalls.h:70
void startSleep()
pause for a while before resending the message
Definition: UdsOp.cc:141
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Definition: Write.cc:33
void clearTimeout()
remove previously set timeout, if any
Definition: UdsOp.cc:63
UdsSender(const String &pathAddr, const TypedMsgHdr &aMessage)
Definition: UdsOp.cc:85
bool doneAll() const override
whether positive goal has been reached
Definition: UdsOp.cc:114
void cancelSleep()
stop sleeping (or do nothing if we were not)
Definition: UdsOp.cc:151
void swanSong() override
Definition: UdsOp.cc:97
void setTimeout(time_t seconds, const char *handlerName)
call timedout() if no UDS messages in a given number of seconds
Definition: UdsOp.cc:55
#define COMM_DOBIND
Definition: Connection.h:49
void getAddrInfo(struct addrinfo *&ai, int force=AF_UNSPEC) const
Definition: Address.cc:619
void commSetConnTimeout(const Comm::ConnectionPointer &conn, time_t timeout, AsyncCall::Pointer &callback)
Definition: comm.cc:594
static int retries
virtual void start()
called by AsyncStart; do not call directly
Definition: AsyncJob.cc:59
#define Must(condition)
Definition: TextException.h:75
struct msghdr with a known type, fixed-size I/O and control buffers
Definition: TypedMsgHdr.h:34
#define MYNAME
Definition: Stream.h:219
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
struct sockaddr_un PathToAddress(const String &pathAddr)
converts human-readable filename path into UDS address
Definition: UdsOp.cc:74
void start() override
called by AsyncStart; do not call directly
Definition: UdsOp.cc:106
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
UdsOp(const String &pathAddr)
Definition: UdsOp.cc:20
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
static void DelayedRetry(void *data)
legacy wrapper for Ipc::UdsSender::delayedRetry()
Definition: UdsOp.cc:161
void address(const struct sockaddr_un &addr)
sets [dest.] address
Definition: TypedMsgHdr.cc:85
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition: event.cc:107
Definition: IpcIoFile.h:23
static void Start(const Pointer &job)
Definition: AsyncJob.cc:37
Comm::ConnectionPointer & conn()
creates if needed and returns raw UDS socket descriptor
Definition: UdsOp.cc:42

 

Introduction

Documentation

Support

Miscellaneous