]>
Commit | Line | Data |
---|---|---|
bbc27441 | 1 | /* |
77b1029d | 2 | * Copyright (C) 1996-2020 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" |
b27668ec | 10 | #include "cbdata.h" |
b0388924 | 11 | #include "comm/Connection.h" |
ec41b64c | 12 | #include "comm/IoCallback.h" |
b27668ec | 13 | #include "comm/Loops.h" |
ec41b64c | 14 | #include "comm/Write.h" |
c4ad1349 | 15 | #include "fd.h" |
ec41b64c | 16 | #include "fde.h" |
582c2af2 | 17 | #include "globals.h" |
ec41b64c | 18 | #include "MemBuf.h" |
582c2af2 | 19 | #include "profiler/Profiler.h" |
21d845b1 FC |
20 | #include "SquidTime.h" |
21 | #include "StatCounters.h" | |
21d845b1 FC |
22 | #if USE_DELAY_POOLS |
23 | #include "ClientInfo.h" | |
24 | #endif | |
074d6a40 AJ |
25 | |
26 | #include <cerrno> | |
ec41b64c AJ |
27 | |
28 | void | |
b0388924 | 29 | Comm::Write(const Comm::ConnectionPointer &conn, MemBuf *mb, AsyncCall::Pointer &callback) |
ec41b64c | 30 | { |
b0388924 | 31 | Comm::Write(conn, mb->buf, mb->size, callback, mb->freeFunc()); |
ec41b64c AJ |
32 | } |
33 | ||
34 | void | |
b0388924 | 35 | Comm::Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE * free_func) |
ec41b64c | 36 | { |
b0388924 | 37 | debugs(5, 5, HERE << conn << ": sz " << size << ": asynCall " << callback); |
ec41b64c AJ |
38 | |
39 | /* Make sure we are open, not closing, and not writing */ | |
b0388924 AJ |
40 | assert(fd_table[conn->fd].flags.open); |
41 | assert(!fd_table[conn->fd].closing()); | |
42 | Comm::IoCallback *ccb = COMMIO_FD_WRITECB(conn->fd); | |
ec41b64c AJ |
43 | assert(!ccb->active()); |
44 | ||
b0388924 AJ |
45 | fd_table[conn->fd].writeStart = squid_curtime; |
46 | ccb->conn = conn; | |
ec41b64c AJ |
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. | |
b0388924 | 54 | * We have to use the comm iocb_table to map FD numbers to waiting data and Comm::Connections. |
ec41b64c AJ |
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 | ||
b27668ec EB |
64 | assert(state->conn != NULL); |
65 | assert(state->conn->fd == fd); | |
ec41b64c AJ |
66 | |
67 | PROF_start(commHandleWrite); | |
b0388924 | 68 | debugs(5, 5, HERE << state->conn << ": off " << |
ec41b64c AJ |
69 | (long int) state->offset << ", sz " << (long int) state->size << "."); |
70 | ||
71 | nleft = state->size - state->offset; | |
72 | ||
9a0a18de | 73 | #if USE_DELAY_POOLS |
b27668ec EB |
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; | |
ec41b64c AJ |
81 | } |
82 | } | |
9a0a18de | 83 | #endif /* USE_DELAY_POOLS */ |
ec41b64c AJ |
84 | |
85 | /* actually WRITE data */ | |
5dc67d58 | 86 | int xerrno = errno = 0; |
ec41b64c | 87 | len = FD_WRITE_METHOD(fd, state->buf + state->offset, nleft); |
5dc67d58 | 88 | xerrno = errno; |
ec41b64c AJ |
89 | debugs(5, 5, HERE << "write() returns " << len); |
90 | ||
9a0a18de | 91 | #if USE_DELAY_POOLS |
b27668ec EB |
92 | if (bucket) { |
93 | /* we wrote data - drain them from bucket */ | |
94 | bucket->reduceBucket(len); | |
ec41b64c | 95 | } |
9a0a18de | 96 | #endif /* USE_DELAY_POOLS */ |
ec41b64c AJ |
97 | |
98 | fd_bytes(fd, len, FD_WRITE); | |
e4f1fdae | 99 | ++statCounter.syscalls.sock.writes; |
ec41b64c AJ |
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 | ||
5dc67d58 | 110 | state->finish(nleft ? Comm::COMM_ERROR : Comm::OK, 0); |
ec41b64c AJ |
111 | } else if (len < 0) { |
112 | /* An error */ | |
113 | if (fd_table[fd].flags.socket_eof) { | |
5dc67d58 AD |
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) << "."); | |
ec41b64c AJ |
118 | state->selectOrQueueWrite(); |
119 | } else { | |
5dc67d58 AD |
120 | debugs(50, 2, "FD " << fd << " write failure: " << xstrerr(xerrno) << "."); |
121 | state->finish(nleft ? Comm::COMM_ERROR : Comm::OK, xerrno); | |
ec41b64c AJ |
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 { | |
5dc67d58 | 131 | state->finish(nleft ? Comm::OK : Comm::COMM_ERROR, 0); |
ec41b64c AJ |
132 | } |
133 | } | |
134 | ||
135 | PROF_stop(commHandleWrite); | |
136 | } | |
f53969cc | 137 |