]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/comm/Write.cc
2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
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.
11 #include "comm/Connection.h"
12 #include "comm/IoCallback.h"
13 #include "comm/Loops.h"
14 #include "comm/Write.h"
19 #include "profiler/Profiler.h"
20 #include "SquidTime.h"
21 #include "StatCounters.h"
23 #include "ClientInfo.h"
29 Comm::Write(const Comm::ConnectionPointer
&conn
, MemBuf
*mb
, AsyncCall::Pointer
&callback
)
31 Comm::Write(conn
, mb
->buf
, mb
->size
, callback
, mb
->freeFunc());
35 Comm::Write(const Comm::ConnectionPointer
&conn
, const char *buf
, int size
, AsyncCall::Pointer
&callback
, FREE
* free_func
)
37 debugs(5, 5, HERE
<< conn
<< ": sz " << size
<< ": asynCall " << callback
);
39 /* Make sure we are open, not closing, and not writing */
40 assert(fd_table
[conn
->fd
].flags
.open
);
41 assert(!fd_table
[conn
->fd
].closing());
42 Comm::IoCallback
*ccb
= COMMIO_FD_WRITECB(conn
->fd
);
43 assert(!ccb
->active());
45 fd_table
[conn
->fd
].writeStart
= squid_curtime
;
48 ccb
->setCallback(IOCB_WRITE
, callback
, (char *)buf
, free_func
, size
);
49 ccb
->selectOrQueueWrite();
53 * This function is used by the lowest level of IO loop which only has access to FD numbers.
54 * We have to use the comm iocb_table to map FD numbers to waiting data and Comm::Connections.
55 * Once the write has been concluded we schedule the waiting call with success/fail results.
58 Comm::HandleWrite(int fd
, void *data
)
60 Comm::IoCallback
*state
= static_cast<Comm::IoCallback
*>(data
);
64 assert(state
->conn
!= NULL
);
65 assert(state
->conn
->fd
== fd
);
67 PROF_start(commHandleWrite
);
68 debugs(5, 5, HERE
<< state
->conn
<< ": off " <<
69 (long int) state
->offset
<< ", sz " << (long int) state
->size
<< ".");
71 nleft
= state
->size
- state
->offset
;
74 BandwidthBucket
*bucket
= BandwidthBucket::SelectBucket(&fd_table
[fd
]);
76 assert(bucket
->selectWaiting
);
77 bucket
->selectWaiting
= false;
78 if (nleft
> 0 && !bucket
->applyQuota(nleft
, state
)) {
79 PROF_stop(commHandleWrite
);
83 #endif /* USE_DELAY_POOLS */
85 /* actually WRITE data */
86 int xerrno
= errno
= 0;
87 len
= FD_WRITE_METHOD(fd
, state
->buf
+ state
->offset
, nleft
);
89 debugs(5, 5, HERE
<< "write() returns " << len
);
93 /* we wrote data - drain them from bucket */
94 bucket
->reduceBucket(len
);
96 #endif /* USE_DELAY_POOLS */
98 fd_bytes(fd
, len
, FD_WRITE
);
99 ++statCounter
.syscalls
.sock
.writes
;
100 // After each successful partial write,
101 // reset fde::writeStart to the current time.
102 fd_table
[fd
].writeStart
= squid_curtime
;
105 /* Note we even call write if nleft == 0 */
108 debugs(5, DBG_IMPORTANT
, "FD " << fd
<< " write failure: connection closed with " << nleft
<< " bytes remaining.");
110 state
->finish(nleft
? Comm::COMM_ERROR
: Comm::OK
, 0);
111 } else if (len
< 0) {
113 if (fd_table
[fd
].flags
.socket_eof
) {
114 debugs(50, 2, "FD " << fd
<< " write failure: " << xstrerr(xerrno
) << ".");
115 state
->finish(nleft
? Comm::COMM_ERROR
: Comm::OK
, xerrno
);
116 } else if (ignoreErrno(xerrno
)) {
117 debugs(50, 9, "FD " << fd
<< " write failure: " << xstrerr(xerrno
) << ".");
118 state
->selectOrQueueWrite();
120 debugs(50, 2, "FD " << fd
<< " write failure: " << xstrerr(xerrno
) << ".");
121 state
->finish(nleft
? Comm::COMM_ERROR
: Comm::OK
, xerrno
);
124 /* A successful write, continue */
125 state
->offset
+= len
;
127 if (state
->offset
< state
->size
) {
128 /* Not done, reinstall the write handler and write some more */
129 state
->selectOrQueueWrite();
131 state
->finish(nleft
? Comm::OK
: Comm::COMM_ERROR
, 0);
135 PROF_stop(commHandleWrite
);