]> git.ipfire.org Git - thirdparty/squid.git/blame - src/comm/Write.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / comm / Write.cc
CommitLineData
bbc27441 1/*
4ac4a490 2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
bbc27441
AJ
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
f7f3304a 9#include "squid.h"
b0388924 10#include "comm/Connection.h"
ec41b64c
AJ
11#include "comm/IoCallback.h"
12#include "comm/Write.h"
c4ad1349 13#include "fd.h"
ec41b64c 14#include "fde.h"
582c2af2 15#include "globals.h"
ec41b64c 16#include "MemBuf.h"
582c2af2 17#include "profiler/Profiler.h"
21d845b1
FC
18#include "SquidTime.h"
19#include "StatCounters.h"
21d845b1
FC
20#if USE_DELAY_POOLS
21#include "ClientInfo.h"
22#endif
074d6a40
AJ
23
24#include <cerrno>
ec41b64c
AJ
25
26void
b0388924 27Comm::Write(const Comm::ConnectionPointer &conn, MemBuf *mb, AsyncCall::Pointer &callback)
ec41b64c 28{
b0388924 29 Comm::Write(conn, mb->buf, mb->size, callback, mb->freeFunc());
ec41b64c
AJ
30}
31
32void
b0388924 33Comm::Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE * free_func)
ec41b64c 34{
b0388924 35 debugs(5, 5, HERE << conn << ": sz " << size << ": asynCall " << callback);
ec41b64c
AJ
36
37 /* Make sure we are open, not closing, and not writing */
b0388924
AJ
38 assert(fd_table[conn->fd].flags.open);
39 assert(!fd_table[conn->fd].closing());
40 Comm::IoCallback *ccb = COMMIO_FD_WRITECB(conn->fd);
ec41b64c
AJ
41 assert(!ccb->active());
42
b0388924
AJ
43 fd_table[conn->fd].writeStart = squid_curtime;
44 ccb->conn = conn;
ec41b64c
AJ
45 /* Queue the write */
46 ccb->setCallback(IOCB_WRITE, callback, (char *)buf, free_func, size);
47 ccb->selectOrQueueWrite();
48}
49
50/** Write to FD.
51 * This function is used by the lowest level of IO loop which only has access to FD numbers.
b0388924 52 * We have to use the comm iocb_table to map FD numbers to waiting data and Comm::Connections.
ec41b64c
AJ
53 * Once the write has been concluded we schedule the waiting call with success/fail results.
54 */
55void
56Comm::HandleWrite(int fd, void *data)
57{
58 Comm::IoCallback *state = static_cast<Comm::IoCallback *>(data);
59 int len = 0;
60 int nleft;
61
b0388924 62 assert(state->conn != NULL && state->conn->fd == fd);
ec41b64c
AJ
63
64 PROF_start(commHandleWrite);
b0388924 65 debugs(5, 5, HERE << state->conn << ": off " <<
ec41b64c
AJ
66 (long int) state->offset << ", sz " << (long int) state->size << ".");
67
68 nleft = state->size - state->offset;
69
9a0a18de 70#if USE_DELAY_POOLS
ec41b64c
AJ
71 ClientInfo * clientInfo=fd_table[fd].clientInfo;
72
73 if (clientInfo && !clientInfo->writeLimitingActive)
74 clientInfo = NULL; // we only care about quota limits here
75
76 if (clientInfo) {
77 assert(clientInfo->selectWaiting);
78 clientInfo->selectWaiting = false;
79
80 assert(clientInfo->hasQueue());
81 assert(clientInfo->quotaPeekFd() == fd);
82 clientInfo->quotaDequeue(); // we will write or requeue below
83
f31be4b0 84 if (nleft > 0) {
ec41b64c
AJ
85 const int quota = clientInfo->quotaForDequed();
86 if (!quota) { // if no write quota left, queue this fd
87 state->quotaQueueReserv = clientInfo->quotaEnqueue(fd);
88 clientInfo->kickQuotaQueue();
89 PROF_stop(commHandleWrite);
90 return;
91 }
92
93 const int nleft_corrected = min(nleft, quota);
94 if (nleft != nleft_corrected) {
b0388924 95 debugs(5, 5, HERE << state->conn << " writes only " <<
ec41b64c
AJ
96 nleft_corrected << " out of " << nleft);
97 nleft = nleft_corrected;
98 }
99
100 }
101 }
9a0a18de 102#endif /* USE_DELAY_POOLS */
ec41b64c
AJ
103
104 /* actually WRITE data */
5dc67d58 105 int xerrno = errno = 0;
ec41b64c 106 len = FD_WRITE_METHOD(fd, state->buf + state->offset, nleft);
5dc67d58 107 xerrno = errno;
ec41b64c
AJ
108 debugs(5, 5, HERE << "write() returns " << len);
109
9a0a18de 110#if USE_DELAY_POOLS
ec41b64c
AJ
111 if (clientInfo) {
112 if (len > 0) {
113 /* we wrote data - drain them from bucket */
114 clientInfo->bucketSize -= len;
115 if (clientInfo->bucketSize < 0.0) {
e0236918 116 debugs(5, DBG_IMPORTANT, HERE << "drained too much"); // should not happen
ec41b64c
AJ
117 clientInfo->bucketSize = 0;
118 }
119 }
120
121 // even if we wrote nothing, we were served; give others a chance
122 clientInfo->kickQuotaQueue();
123 }
9a0a18de 124#endif /* USE_DELAY_POOLS */
ec41b64c
AJ
125
126 fd_bytes(fd, len, FD_WRITE);
e4f1fdae 127 ++statCounter.syscalls.sock.writes;
ec41b64c
AJ
128 // After each successful partial write,
129 // reset fde::writeStart to the current time.
130 fd_table[fd].writeStart = squid_curtime;
131
132 if (len == 0) {
133 /* Note we even call write if nleft == 0 */
134 /* We're done */
135 if (nleft != 0)
136 debugs(5, DBG_IMPORTANT, "FD " << fd << " write failure: connection closed with " << nleft << " bytes remaining.");
137
5dc67d58 138 state->finish(nleft ? Comm::COMM_ERROR : Comm::OK, 0);
ec41b64c
AJ
139 } else if (len < 0) {
140 /* An error */
141 if (fd_table[fd].flags.socket_eof) {
5dc67d58
AD
142 debugs(50, 2, "FD " << fd << " write failure: " << xstrerr(xerrno) << ".");
143 state->finish(nleft ? Comm::COMM_ERROR : Comm::OK, xerrno);
144 } else if (ignoreErrno(xerrno)) {
145 debugs(50, 9, "FD " << fd << " write failure: " << xstrerr(xerrno) << ".");
ec41b64c
AJ
146 state->selectOrQueueWrite();
147 } else {
5dc67d58
AD
148 debugs(50, 2, "FD " << fd << " write failure: " << xstrerr(xerrno) << ".");
149 state->finish(nleft ? Comm::COMM_ERROR : Comm::OK, xerrno);
ec41b64c
AJ
150 }
151 } else {
152 /* A successful write, continue */
153 state->offset += len;
154
155 if (state->offset < state->size) {
156 /* Not done, reinstall the write handler and write some more */
157 state->selectOrQueueWrite();
158 } else {
5dc67d58 159 state->finish(nleft ? Comm::OK : Comm::COMM_ERROR, 0);
ec41b64c
AJ
160 }
161 }
162
163 PROF_stop(commHandleWrite);
164}
f53969cc 165