1
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
// % Project : GUSI - Grand Unified Socket Interface
3
// % File : GUSISocketMixins.nw - Useful building blocks
4
// % Author : Matthias Neeracher
7
// % $Log: GUSISocketMixins.h,v $
8
// % Revision 1.1 2001/03/11 22:38:21 sgehani%netscape.com
11
// % Revision 1.11 2000/10/16 04:10:12 neeri
12
// % Add GUSISMProcess
14
// % Revision 1.10 2000/05/23 07:24:58 neeri
15
// % Improve formatting
17
// % Revision 1.9 1999/08/26 05:45:09 neeri
18
// % Fixes for literate edition of source code
20
// % Revision 1.8 1999/08/02 07:02:46 neeri
21
// % Support for asynchronous errors and other socket options
23
// % Revision 1.7 1999/05/29 06:26:45 neeri
24
// % Fixed header guards
26
// % Revision 1.6 1999/04/29 05:33:18 neeri
27
// % Fix fcntl prototype
29
// % Revision 1.5 1999/03/17 09:05:13 neeri
30
// % Added GUSITimer, expanded docs
32
// % Revision 1.4 1998/10/11 16:45:24 neeri
33
// % Ready to release 2.0a2
35
// % Revision 1.3 1998/01/25 20:53:59 neeri
36
// % Engine implemented, except for signals & scheduling
38
// % Revision 1.2 1997/11/13 21:12:13 neeri
41
// % Revision 1.1 1996/12/16 02:12:42 neeri
42
// % TCP Sockets sort of work
44
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
46
// \chapter{Mixin Classes for Sockets}
48
// This section contains some building block classes for sockets:
51
// \item [[GUSISMBlocking]] implements the blocking/nonblocking flag.
52
// \item [[GUSISMState]] implements a state variable.
53
// \item [[GUSISMInputBuffer]] provides a [[GUSIBuffer]] for input.
54
// \item [[GUSISMOutputBuffer]] provides a [[GUSIBuffer]] for output.
55
// \item [[GUSISMAsyncError]] provides storage for asynchronous errors.
56
// \item [[GUSISMProcess]] maintains a link to the process instance.
60
// <GUSISocketMixins.h>=
61
#ifndef _GUSISocketMixins_
62
#define _GUSISocketMixins_
66
#include "GUSISocket.h"
67
#include "GUSIBuffer.h"
70
#include <sys/ioctl.h>
72
// \section{Definition of [[GUSISocketMixins]]}
74
// [[GUSISMBlocking]] implements the [[fBlocking]] flags and the [[DoIoctl]] and
75
// [[DoFcntl]] variants to manipulate it. These two functions work like their
76
// [[GUSISocket]] member function counterparts, but handle the return value
77
// differently: The POSIX function result is stored in [[*result]], while the
78
// return value indicates whether the request was handled.
80
// <Definition of class [[GUSISMBlocking]]>=
81
class GUSISMBlocking {
85
bool DoFcntl(int * result, int cmd, va_list arg);
86
bool DoIoctl(int * result, unsigned int request, va_list arg);
88
// [[GUSISMState]] captures the state of a socket over its lifetime. It starts out
89
// as [[Unbound]]. [[bind]] will put it into [[Unconnected]] state, though few
90
// socket classes care about this distinction. [[listen]] will put it into
91
// [[Listening]] state. [[accept]] starts a [[Connected]] new socket.
92
// [[connect]] puts an [[Unconnected]] socket into [[Connecting]] state from
93
// where it emerges [[Connected]]. [[fReadShutdown]] and [[fWriteShutdown]] record
96
// <Definition of class [[GUSISMState]]>=
111
void Shutdown(int how);
113
// [[GUSISMInputBuffer]] defines the input buffer and some socket options that go
114
// with it. [[DoGetSockOpt]] and [[DoSetSockOpt]] work the same way as
115
// [[DoFcntl]] and [[DoIoctl]] above.
117
// <Definition of class [[GUSISMInputBuffer]]>=
118
class GUSISMInputBuffer {
120
GUSIRingBuffer fInputBuffer;
123
int * result, int level, int optname,
124
void *optval, socklen_t * optlen);
126
int * result, int level, int optname,
127
void *optval, socklen_t optlen);
128
bool DoIoctl(int * result, unsigned int request, va_list arg);
130
// [[GUSISMOutputBuffer]] defines the output buffer and some socket options that go
133
// <Definition of class [[GUSISMOutputBuffer]]>=
134
class GUSISMOutputBuffer {
136
GUSIRingBuffer fOutputBuffer;
137
GUSISMOutputBuffer();
139
int * result, int level, int optname,
140
void *optval, socklen_t * optlen);
142
int * result, int level, int optname,
143
void *optval, socklen_t optlen);
145
// [[GUSISMAsyncError]] stores asynchronous errors and makes them available via
146
// [[getsockopt]]. [[GetAsyncError]] returns the error and resets the stored value.
148
// <Definition of class [[GUSISMAsyncError]]>=
149
class GUSISMAsyncError {
153
int SetAsyncPosixError(int error);
154
int SetAsyncMacError(OSErr error);
157
int * result, int level, int optname,
158
void *optval, socklen_t * optlen);
160
// [[GUSISMProcess]] stores a link to the global [[GUSIProcess]] instance, which is useful for completion routines.
162
// <Definition of class [[GUSISMProcess]]>=
163
class GUSISMProcess {
167
GUSIProcess * Process();
169
GUSIProcess * fProcess;
172
// \section{Implementation of [[GUSISocketMixins]]}
174
// Because all the member functions are simple and called in few places, it
175
// makes sense to inline them.
177
// All sockets start out blocking.
179
// <Inline member functions for class [[GUSISMBlocking]]>=
180
inline GUSISMBlocking::GUSISMBlocking() : fBlocking(true) {}
181
// For historical reasons, there is both an [[ioctl]] and a [[fcntl]] interface
182
// to the blocking flag.
184
// <Inline member functions for class [[GUSISMBlocking]]>=
185
inline bool GUSISMBlocking::DoFcntl(int * result, int cmd, va_list arg)
189
return (*result = fBlocking ? 0: FNDELAY), true;
191
fBlocking = !(va_arg(arg, int) & FNDELAY);
193
return (*result = 0), true;
197
inline bool GUSISMBlocking::DoIoctl(int * result, unsigned int request, va_list arg)
199
if (request == FIONBIO) {
200
fBlocking = !*va_arg(arg, int *);
201
return (*result = 0), true;
205
// Sockets start out as unconnected.
207
// <Inline member functions for class [[GUSISMState]]>=
208
inline GUSISMState::GUSISMState() :
209
fState(Unbound), fReadShutdown(false), fWriteShutdown(false) {}
210
// <Inline member functions for class [[GUSISMState]]>=
211
inline void GUSISMState::Shutdown(int how)
214
fReadShutdown = true;
216
fWriteShutdown = true;
218
// Buffers initially are 8K.
220
// <Inline member functions for class [[GUSISMInputBuffer]]>=
221
inline GUSISMInputBuffer::GUSISMInputBuffer() : fInputBuffer(8192) {}
222
// [[getsockopt]] is used to obtain the buffer size.
224
// <Inline member functions for class [[GUSISMInputBuffer]]>=
225
inline bool GUSISMInputBuffer::DoGetSockOpt(
226
int * result, int level, int optname,
227
void *optval, socklen_t *)
229
if (level == SOL_SOCKET && optname == SO_RCVBUF) {
230
*(int *)optval = (int)fInputBuffer.Size();
232
return (*result = 0), true;
236
// [[setsockopt]] modifies the buffer size.
238
// <Inline member functions for class [[GUSISMInputBuffer]]>=
239
inline bool GUSISMInputBuffer::DoSetSockOpt(
240
int * result, int level, int optname,
241
void *optval, socklen_t)
243
if (level == SOL_SOCKET && optname == SO_RCVBUF) {
244
fInputBuffer.SwitchBuffer(*(int *)optval);
246
return (*result = 0), true;
250
// [[ioctl]] returns the number of available bytes.
252
// <Inline member functions for class [[GUSISMInputBuffer]]>=
253
inline bool GUSISMInputBuffer::DoIoctl(int * result, unsigned int request, va_list arg)
255
if (request == FIONREAD) {
256
*va_arg(arg, long *) = fInputBuffer.Valid();
257
return (*result = 0), true;
261
// [[GUSISMOutputBuffer]] works identically to the input buffer.
263
// <Inline member functions for class [[GUSISMOutputBuffer]]>=
264
inline GUSISMOutputBuffer::GUSISMOutputBuffer() : fOutputBuffer(8192) {}
265
// [[getsockopt]] is used to obtain the buffer size.
267
// <Inline member functions for class [[GUSISMOutputBuffer]]>=
268
inline bool GUSISMOutputBuffer::DoGetSockOpt(
269
int * result, int level, int optname,
270
void *optval, socklen_t *)
272
if (level == SOL_SOCKET && optname == SO_SNDBUF) {
273
*(int *)optval = (int)fOutputBuffer.Size();
275
return (*result = 0), true;
279
// [[setsockopt]] is modifies the buffer size.
281
// <Inline member functions for class [[GUSISMOutputBuffer]]>=
282
inline bool GUSISMOutputBuffer::DoSetSockOpt(
283
int * result, int level, int optname,
284
void *optval, socklen_t)
286
if (level == SOL_SOCKET && optname == SO_SNDBUF) {
287
fOutputBuffer.SwitchBuffer(*(int *)optval);
289
return (*result = 0), true;
293
// <Inline member functions for class [[GUSISMAsyncError]]>=
294
inline GUSISMAsyncError::GUSISMAsyncError()
298
// The central member functions of [[GUSISMAsyncError]] are [[SetAsyncXXXError]] and
299
// [[GetAsyncError]].
301
// <Inline member functions for class [[GUSISMAsyncError]]>=
302
inline int GUSISMAsyncError::SetAsyncPosixError(int error)
306
GUSI_MESSAGE(("GUSISMAsyncError::SetAsyncPosixError %d\n", fAsyncError));
312
inline int GUSISMAsyncError::GetAsyncError()
314
int err = fAsyncError;
318
// For some reason, the CW Pro 4 compilers generated bad code for this in some combination, so
319
// we make it out of line.
321
// <Inline member functions for class [[GUSISMAsyncError]]>=
322
inline int GUSISMAsyncError::SetAsyncMacError(OSErr error)
325
fAsyncError = GUSIMapMacError(error);
326
GUSI_MESSAGE(("GUSISMAsyncError::SetAsyncMacError %d -> %d\n", error, fAsyncError));
332
// [[DoGetSockOpt]] only handles [[SO_ERROR]] (hi Philippe!).
334
// <Inline member functions for class [[GUSISMAsyncError]]>=
335
inline bool GUSISMAsyncError::DoGetSockOpt(
336
int * result, int level, int optname,
337
void *optval, socklen_t * optlen)
339
if (level == SOL_SOCKET && optname == SO_ERROR) {
340
*(int *)optval = GetAsyncError();
341
*optlen = sizeof(int);
343
return (*result = 0), true;
347
// <Inline member functions for class [[GUSISMProcess]]>=
348
inline GUSISMProcess::GUSISMProcess()
349
: fProcess(GUSIProcess::Instance())
353
inline GUSIProcess * GUSISMProcess::Process()
358
#endif /* GUSI_INTERNAL */
360
#endif /* _GUSISocketMixins_ */