]> git.ipfire.org Git - thirdparty/squid.git/blob - src/comm/Write.cc
Docs: Copyright updates for 2018 (#114)
[thirdparty/squid.git] / src / comm / Write.cc
1 /*
2 * Copyright (C) 1996-2018 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 #include "squid.h"
10 #include "cbdata.h"
11 #include "comm/Connection.h"
12 #include "comm/IoCallback.h"
13 #include "comm/Loops.h"
14 #include "comm/Write.h"
15 #include "fd.h"
16 #include "fde.h"
17 #include "globals.h"
18 #include "MemBuf.h"
19 #include "profiler/Profiler.h"
20 #include "SquidTime.h"
21 #include "StatCounters.h"
22 #if USE_DELAY_POOLS
23 #include "ClientInfo.h"
24 #endif
25
26 #include <cerrno>
27
28 void
29 Comm::Write(const Comm::ConnectionPointer &conn, MemBuf *mb, AsyncCall::Pointer &callback)
30 {
31 Comm::Write(conn, mb->buf, mb->size, callback, mb->freeFunc());
32 }
33
34 void
35 Comm::Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE * free_func)
36 {
37 debugs(5, 5, HERE << conn << ": sz " << size << ": asynCall " << callback);
38
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());
44
45 fd_table[conn->fd].writeStart = squid_curtime;
46 ccb->conn = conn;
47 /* Queue the write */
48 ccb->setCallback(IOCB_WRITE, callback, (char *)buf, free_func, size);
49 ccb->selectOrQueueWrite();
50 }
51
52 /** Write to FD.
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.
56 */
57 void
58 Comm::HandleWrite(int fd, void *data)
59 {
60 Comm::IoCallback *state = static_cast<Comm::IoCallback *>(data);
61 int len = 0;
62 int nleft;
63
64 assert(state->conn != NULL);
65 assert(state->conn->fd == fd);
66
67 PROF_start(commHandleWrite);
68 debugs(5, 5, HERE << state->conn << ": off " <<
69 (long int) state->offset << ", sz " << (long int) state->size << ".");
70
71 nleft = state->size - state->offset;
72
73 #if USE_DELAY_POOLS
74 BandwidthBucket *bucket = BandwidthBucket::SelectBucket(&fd_table[fd]);
75 if (bucket) {
76 assert(bucket->selectWaiting);
77 bucket->selectWaiting = false;
78 if (nleft > 0 && !bucket->applyQuota(nleft, state)) {
79 PROF_stop(commHandleWrite);
80 return;
81 }
82 }
83 #endif /* USE_DELAY_POOLS */
84
85 /* actually WRITE data */
86 int xerrno = errno = 0;
87 len = FD_WRITE_METHOD(fd, state->buf + state->offset, nleft);
88 xerrno = errno;
89 debugs(5, 5, HERE << "write() returns " << len);
90
91 #if USE_DELAY_POOLS
92 if (bucket) {
93 /* we wrote data - drain them from bucket */
94 bucket->reduceBucket(len);
95 }
96 #endif /* USE_DELAY_POOLS */
97
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;
103
104 if (len == 0) {
105 /* Note we even call write if nleft == 0 */
106 /* We're done */
107 if (nleft != 0)
108 debugs(5, DBG_IMPORTANT, "FD " << fd << " write failure: connection closed with " << nleft << " bytes remaining.");
109
110 state->finish(nleft ? Comm::COMM_ERROR : Comm::OK, 0);
111 } else if (len < 0) {
112 /* An error */
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();
119 } else {
120 debugs(50, 2, "FD " << fd << " write failure: " << xstrerr(xerrno) << ".");
121 state->finish(nleft ? Comm::COMM_ERROR : Comm::OK, xerrno);
122 }
123 } else {
124 /* A successful write, continue */
125 state->offset += len;
126
127 if (state->offset < state->size) {
128 /* Not done, reinstall the write handler and write some more */
129 state->selectOrQueueWrite();
130 } else {
131 state->finish(nleft ? Comm::OK : Comm::COMM_ERROR, 0);
132 }
133 }
134
135 PROF_stop(commHandleWrite);
136 }
137