]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ipc/UdsOp.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / ipc / UdsOp.cc
CommitLineData
10cefb7b 1/*
4ac4a490 2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
10cefb7b 3 *
bbc27441
AJ
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.
10cefb7b 7 */
8
bbc27441
AJ
9/* DEBUG: section 54 Interprocess Communication */
10
f7f3304a 11#include "squid.h"
602d9612 12#include "base/TextException.h"
10cefb7b 13#include "comm.h"
8942ceb3 14#include "comm/Connection.h"
ec41b64c 15#include "comm/Write.h"
602d9612 16#include "CommCalls.h"
10cefb7b 17#include "ipc/UdsOp.h"
18
ba568924 19Ipc::UdsOp::UdsOp(const String& pathAddr):
f53969cc
SM
20 AsyncJob("Ipc::UdsOp"),
21 address(PathToAddress(pathAddr)),
22 options(COMM_NONBLOCKING)
10cefb7b 23{
ba568924 24 debugs(54, 5, HERE << '[' << this << "] pathAddr=" << pathAddr);
10cefb7b 25}
26
27Ipc::UdsOp::~UdsOp()
28{
29 debugs(54, 5, HERE << '[' << this << ']');
e0d28505
AJ
30 if (Comm::IsConnOpen(conn_))
31 conn_->close();
32 conn_ = NULL;
10cefb7b 33}
34
ba568924 35void Ipc::UdsOp::setOptions(int newOptions)
10cefb7b 36{
ba568924 37 options = newOptions;
10cefb7b 38}
39
e0d28505
AJ
40Comm::ConnectionPointer &
41Ipc::UdsOp::conn()
10cefb7b 42{
e0d28505 43 if (!Comm::IsConnOpen(conn_)) {
ba568924 44 if (options & COMM_DOBIND)
1bac0258 45 unlink(address.sun_path);
e0d28505
AJ
46 if (conn_ == NULL)
47 conn_ = new Comm::Connection;
48 conn_->fd = comm_open_uds(SOCK_DGRAM, 0, &address, options);
49 Must(Comm::IsConnOpen(conn_));
10cefb7b 50 }
e0d28505 51 return conn_;
10cefb7b 52}
53
ba568924 54void Ipc::UdsOp::setTimeout(int seconds, const char *handlerName)
10cefb7b 55{
4299f876 56 typedef CommCbMemFunT<UdsOp, CommTimeoutCbParams> Dialer;
ba568924 57 AsyncCall::Pointer handler = asyncCall(54,5, handlerName,
4299f876 58 Dialer(CbcPointer<UdsOp>(this), &UdsOp::noteTimeout));
8d77a37c 59 commSetConnTimeout(conn(), seconds, handler);
ba568924
AR
60}
61
62void Ipc::UdsOp::clearTimeout()
63{
8d77a37c 64 commUnsetConnTimeout(conn());
ba568924
AR
65}
66
67void Ipc::UdsOp::noteTimeout(const CommTimeoutCbParams &)
68{
69 timedout(); // our kid handles communication timeout
10cefb7b 70}
71
1bac0258 72struct sockaddr_un
5667a628 73Ipc::PathToAddress(const String& pathAddr) {
1bac0258
AR
74 assert(pathAddr.size() != 0);
75 struct sockaddr_un unixAddr;
76 memset(&unixAddr, 0, sizeof(unixAddr));
77 unixAddr.sun_family = AF_LOCAL;
78 xstrncpy(unixAddr.sun_path, pathAddr.termedBuf(), sizeof(unixAddr.sun_path));
79 return unixAddr;
80}
81
10cefb7b 82CBDATA_NAMESPACED_CLASS_INIT(Ipc, UdsSender);
83
1bac0258 84Ipc::UdsSender::UdsSender(const String& pathAddr, const TypedMsgHdr& aMessage):
f53969cc
SM
85 UdsOp(pathAddr),
86 message(aMessage),
87 retries(10), // TODO: make configurable?
88 timeout(10), // TODO: make configurable?
89 sleeping(false),
90 writing(false)
10cefb7b 91{
1bac0258 92 message.address(address);
10cefb7b 93}
94
3e81ed3a
AR
95void Ipc::UdsSender::swanSong()
96{
97 // did we abort while waiting between retries?
98 if (sleeping)
99 cancelSleep();
100
101 UdsOp::swanSong();
102}
103
10cefb7b 104void Ipc::UdsSender::start()
105{
ba568924 106 UdsOp::start();
10cefb7b 107 write();
108 if (timeout > 0)
ba568924 109 setTimeout(timeout, "Ipc::UdsSender::noteTimeout");
10cefb7b 110}
111
ba568924 112bool Ipc::UdsSender::doneAll() const
10cefb7b 113{
3e81ed3a 114 return !writing && !sleeping && UdsOp::doneAll();
10cefb7b 115}
116
117void Ipc::UdsSender::write()
118{
119 debugs(54, 5, HERE);
4299f876
AR
120 typedef CommCbMemFunT<UdsSender, CommIoCbParams> Dialer;
121 AsyncCall::Pointer writeHandler = JobCallback(54, 5,
4cb2536f 122 Dialer, this, UdsSender::wrote);
b0388924 123 Comm::Write(conn(), message.raw(), message.size(), writeHandler, NULL);
ba568924 124 writing = true;
10cefb7b 125}
126
ba568924 127void Ipc::UdsSender::wrote(const CommIoCbParams& params)
10cefb7b 128{
8bbb16e3 129 debugs(54, 5, HERE << params.conn << " flag " << params.flag << " retries " << retries << " [" << this << ']');
ba568924 130 writing = false;
c8407295 131 if (params.flag != Comm::OK && retries-- > 0) {
3e81ed3a
AR
132 // perhaps a fresh connection and more time will help?
133 conn()->close();
6905e266 134 startSleep();
3e81ed3a
AR
135 }
136}
137
138/// pause for a while before resending the message
6905e266 139void Ipc::UdsSender::startSleep()
3e81ed3a
AR
140{
141 Must(!sleeping);
142 sleeping = true;
143 eventAdd("Ipc::UdsSender::DelayedRetry",
144 Ipc::UdsSender::DelayedRetry,
145 new Pointer(this), 1, 0, false); // TODO: Use Fibonacci increments
146}
147
148/// stop sleeping (or do nothing if we were not)
149void Ipc::UdsSender::cancelSleep()
150{
151 if (sleeping) {
152 // Why not delete the event? See Comm::ConnOpener::cancelSleep().
153 sleeping = false;
154 debugs(54, 9, "stops sleeping");
155 }
156}
157
158/// legacy wrapper for Ipc::UdsSender::delayedRetry()
159void Ipc::UdsSender::DelayedRetry(void *data)
160{
161 Pointer *ptr = static_cast<Pointer*>(data);
162 assert(ptr);
163 if (UdsSender *us = dynamic_cast<UdsSender*>(ptr->valid())) {
164 // get back inside AsyncJob protection by scheduling an async job call
165 typedef NullaryMemFunT<Ipc::UdsSender> Dialer;
166 AsyncCall::Pointer call = JobCallback(54, 4, Dialer, us, Ipc::UdsSender::delayedRetry);
167 ScheduleCallHere(call);
168 }
169 delete ptr;
170}
171
172/// make another sending attempt after a pause
173void Ipc::UdsSender::delayedRetry()
174{
175 debugs(54, 5, HERE << sleeping);
176 if (sleeping) {
177 sleeping = false;
178 write(); // reopens the connection if needed
1bac0258 179 }
10cefb7b 180}
181
ba568924 182void Ipc::UdsSender::timedout()
10cefb7b 183{
184 debugs(54, 5, HERE);
ba568924 185 mustStop("timedout");
10cefb7b 186}
187
1bac0258 188void Ipc::SendMessage(const String& toAddress, const TypedMsgHdr &message)
10cefb7b 189{
4299f876 190 AsyncJob::Start(new UdsSender(toAddress, message));
10cefb7b 191}
51ea0904 192
1b76e6c1
AJ
193const Comm::ConnectionPointer &
194Ipc::ImportFdIntoComm(const Comm::ConnectionPointer &conn, int socktype, int protocol, Ipc::FdNoteId noteId)
51ea0904
CT
195{
196 struct sockaddr_in addr;
197 socklen_t len = sizeof(addr);
1b76e6c1
AJ
198 if (getsockname(conn->fd, reinterpret_cast<sockaddr*>(&addr), &len) == 0) {
199 conn->remote = addr;
51ea0904 200 struct addrinfo* addr_info = NULL;
4dd643d5 201 conn->remote.getAddrInfo(addr_info);
51ea0904
CT
202 addr_info->ai_socktype = socktype;
203 addr_info->ai_protocol = protocol;
1b76e6c1 204 comm_import_opened(conn, Ipc::FdNote(noteId), addr_info);
851614a8 205 Ip::Address::FreeAddr(addr_info);
51ea0904 206 } else {
b69e9ffa
AJ
207 int xerrno = errno;
208 debugs(54, DBG_CRITICAL, "ERROR: Ipc::ImportFdIntoComm: " << conn << ' ' << xstrerr(xerrno));
1b76e6c1 209 conn->close();
51ea0904 210 }
1b76e6c1 211 return conn;
51ea0904 212}
f53969cc 213