modules/up/src/Core/sys/Pipe.cc
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- pipeRead
- pipeWrite
- pipeTimeout
- Pipe
- Pipe
- Pipe
- read
- write
- send
- timeout
- flush
- flushAndClose
1 //
2 // $Id: Pipe.cc,v 1.1.1.1 2000/03/10 16:32:20 engin Exp $
3 //
4 // Author(s): Ramesh Govindan
5
6 #ifdef HAVE_CONFIG_H
7 #include <config.h>
8 #endif
9
10 #include "util/Types.hh"
11 #include "util/Trail.hh"
12 #include "util/Handler.hh"
13 #include "util/Buffer.hh"
14 #include "sys/Time.hh"
15 #include "sys/File.hh"
16 #include "sched/Timer.hh"
17 #include "sched/Dispatcher.hh"
18 #include "sys/Pipe.hh"
19
20 // Constants
21 static const int ReadBufferSize = 512;
22
23 // File locals
24 static TraceCode tracePipe("pipe");
25
26 static void
27 pipeRead(void* ptr,
/* [<][>][^][v][top][bottom][index][help] */
28 void*)
29 {
30 ((Pipe*) ptr)->read();
31 }
32
33 static void
34 pipeWrite(void* ptr,
/* [<][>][^][v][top][bottom][index][help] */
35 void*)
36 {
37 ((Pipe*) ptr)->write();
38 }
39
40 static void
41 pipeTimeout(void* ptr,
/* [<][>][^][v][top][bottom][index][help] */
42 void*)
43 {
44 ((Pipe*) ptr)->timeout();
45 }
46
47 Pipe::Pipe(ListenSocket* s,
/* [<][>][^][v][top][bottom][index][help] */
48 const TimeShort& t)
49 : ListNode()
50 {
51 Handler readH(pipeRead, this);
52 Handler nullH((CallBackFunc)NULL, (void *)NULL);
53 Handler tH(pipeTimeout, this);
54 TimeLong at;
55
56 incoming = new Buffer(ReadBufferSize);
57 if (s->accept(&socket, address, &port, readH, nullH) < 0) {
58 return; // XXX: cleanup?
59 }
60
61 timer = (Timer *)NULL;
62 gotsome = false;
63 connected = true;
64 interval = t;
65 passive = true;
66 logicallyDeleted = false;
67
68 if (interval < InfiniteInterval) {
69 dispatcher.systemClock.sync();
70 at = dispatcher.systemClock;
71 at = at + interval;
72 timer = new Timer(tH, at);
73 }
74
75 TRACE(tracePipe,
76 "new passive end of pipe for %s:%u\n",
77 address.name(), port);
78 return;
79 }
80
81 Pipe::Pipe(const Address& addr,
/* [<][>][^][v][top][bottom][index][help] */
82 Port p)
83 : ListNode()
84 {
85 Handler rh((CallBackFunc)NULL, (void *)NULL);
86 Handler wh(pipeWrite, this);
87
88 incoming = new Buffer(ReadBufferSize);
89 address = addr;
90 port = p;
91 connected = false;
92
93 passive = false;
94 gotsome = false;
95 interval = InfiniteInterval;
96 timer = (Timer *)NULL;
97 logicallyDeleted = false;
98
99 socket = new StreamSocket(address, port, rh, wh);
100 TRACE(tracePipe,
101 "new active end for pipe to %s:%u\n",
102 address.name(),
103 port);
104 return;
105 }
106
107 Pipe::~Pipe()
/* [<][>][^][v][top][bottom][index][help] */
108 {
109 TRACE(tracePipe,
110 "deleting server %s:%u\n",
111 address.name(),
112 port);
113
114 if (timer) {
115 delete timer;
116 }
117 delete socket;
118 delete incoming;
119 outgoing.clear();
120 }
121
122 void
123 Pipe::read()
/* [<][>][^][v][top][bottom][index][help] */
124 {
125 int length;
126
127 ASSERT(!logicallyDeleted);
128
129 gotsome = true;
130 length = socket->read((char *) (incoming->contents + incoming->size),
131 incoming->capacity - incoming->size);
132
133 if (length == 0 || length == FileOpHardError) {
134 terminate();
135 return;
136 } else if (length == FileOpSoftError) {
137 return;
138 }
139
140 TRACE(tracePipe,
141 "read %u bytes from %s:%d, size %u\n",
142 length, address.name(), port, incoming->size);
143
144 // Check if we can flush what we've read so far
145 incoming->size += length;
146 receive();
147
148 // If we have exceeded buffer capacity...
149 if (incoming->size == incoming->capacity) {
150 Buffer* old = incoming;
151
152 incoming = new Buffer((old->capacity << 1));
153 incoming->append(old->contents, old->size);
154 delete old;
155 }
156
157 return;
158 }
159
160 void
161 Pipe::write()
/* [<][>][^][v][top][bottom][index][help] */
162 {
163 int length;
164 Handler rh(pipeRead, this);
165 Handler nh((CallBackFunc)NULL, (void *)NULL);
166 Buffer* send;
167
168 if (!connected) {
169 TRACE(tracePipe, "client connected to %s:%u\n",
170 address.name(), port);
171
172 connected = true;
173 if (outgoing.isEmpty()) {
174 socket->setHandlers((logicallyDeleted) ? nh : rh, nh);
175 }
176 return;
177 }
178
179 gotsome = true;
180 send = outgoing.head();
181 length = socket->write((char *) (send->contents + send->offset),
182 send->size - send->offset);
183
184 if (length < 0) {
185 switch (length) {
186 case FileOpHardError:
187 terminate();
188 return;
189 case FileOpSoftError:
190 return;
191 default:
192 ASSERT(false);
193 }
194 }
195
196 if (length == 0) {
197 TRACE(tracePipe,
198 "remote end %s:%u closed connection\n",
199 address.name(), port);
200 terminate();
201 return;
202 }
203
204 TRACE(tracePipe,
205 "wrote %u bytes to %s:%u\n",
206 length,
207 address.name(),
208 port);
209
210 send->offset += length;
211 if (send->offset == send->size) {
212 TRACE(tracePipe,
213 "completed send of length %u on %s:%u\n",
214 send->size, address.name(), port);
215
216 outgoing.remove(send);
217 delete send;
218 if (outgoing.isEmpty()) {
219 if (logicallyDeleted) {
220 TRACE(tracePipe, "closing logically deleted pipe %s:%u\n",
221 address.name(), port);
222 terminate();
223 return;
224 } else {
225 socket->setHandlers(rh, nh);
226 }
227 }
228 }
229 return;
230 }
231
232 void
233 Pipe::send(Buffer *buf)
/* [<][>][^][v][top][bottom][index][help] */
234 {
235 Handler rh(pipeRead, this);
236 Handler wh(pipeWrite, this);
237
238 // Can't call send after deleting pipe
239 if (logicallyDeleted) {
240 delete buf;
241 return;
242 }
243
244 buf->offset = 0;
245 gotsome = true;
246 if (outgoing.isEmpty()) {
247 socket->setHandlers(rh, wh);
248 }
249 outgoing.append(buf);
250
251 TRACE(tracePipe,
252 "queued response of length %u on %s:%u\n",
253 buf->size, address.name(), port);
254 return;
255 }
256
257 void
258 Pipe::timeout()
/* [<][>][^][v][top][bottom][index][help] */
259 {
260 Handler th(pipeTimeout, this);
261 TimeLong at;
262
263 timer = (Timer *)NULL;
264 if (!gotsome) {
265 TRACE(tracePipe,
266 "no activity on connection to %s:%u, closing\n",
267 address.name(), port);
268 terminate();
269 return;
270 }
271
272 gotsome = false;
273 dispatcher.systemClock.sync();
274 at = dispatcher.systemClock;
275 at = at + interval;
276 timer = new Timer(th, at);
277 return;
278 }
279
280 void
281 Pipe::flush(int length)
/* [<][>][^][v][top][bottom][index][help] */
282 {
283 Buffer* buf;
284 int rlen;
285
286 // Create a new buffer, and move up remaining data
287 rlen = incoming->size - length;
288 ASSERT(rlen >= 0);
289 TRACE(tracePipe,
290 "flushing %d bytes from incoming buffer for %s:%u\n",
291 length, address.name(), port);
292 if (rlen == 0) {
293 incoming->size = 0;
294 return;
295 }
296 buf = new Buffer(ReadBufferSize >? rlen);
297 buf->append(incoming->contents + length, rlen);
298 delete incoming;
299 incoming = buf;
300
301 return;
302 }
303
304 void
305 Pipe::flushAndClose()
/* [<][>][^][v][top][bottom][index][help] */
306 {
307 Handler nh((CallBackFunc) NULL, (void*) NULL);
308 Handler wh(pipeWrite, this);
309
310 logicallyDeleted = true;
311 if (outgoing.isEmpty()) {
312 terminate();
313 return;
314 }
315 socket->setHandlers(nh, wh); // Prevent reads
316 return;
317 }
318
319 // Copyright (c) 1994 by the University of Southern California.
320 // All rights reserved.
321 //
322 // Permission to use, copy, modify, and distribute this software and
323 // its documentation in source and binary forms for lawful
324 // non-commercial purposes and without fee is hereby granted, provided
325 // that the above copyright notice appear in all copies and that both
326 // the copyright notice and this permission notice appear in supporting
327 // documentation, and that any documentation, advertising materials,
328 // and other materials related to such distribution and use acknowledge
329 // that the software was developed by the University of Southern
330 // California and/or Information Sciences Institute.
331 // The name of the University of Southern California may not
332 // be used to endorse or promote products derived from this software
333 // without specific prior written permission.
334 //
335 // THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
336 // ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
337 // PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
338 // INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
339 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
340 // NON-INFRINGEMENT.
341 //
342 // IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
343 // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
344 // TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
345 // THE USE OR PERFORMANCE OF THIS SOFTWARE.
346 //
347 // Questions concerning this software should be directed to
348 // info-ra@isi.edu.
349 //
350