2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #if !defined(WIN32) || defined(__CYGWIN32__)
25 // similiar functions for Windows can be found in NGSocket.[hm]
27 #include "NGDescriptorFunctions.h"
28 #include "NGStreamExceptions.h"
36 # ifdef HAVE_SYS_POLL_H
37 # include <sys/poll.h>
40 # define POLLRDNORM POLLIN /* needed on Linux */
48 #if defined(HAVE_SYS_SOCKET_H) || defined(__APPLE__)
49 # include <sys/socket.h>
52 #ifdef HAVE_SYS_FCNTL_H
53 # include <sys/fcntl.h>
55 #if defined(HAVE_FCNTL_H) || defined(__APPLE__)
59 #if HAVE_UNISTD_H || defined(__APPLE__)
65 #if HAVE_SYS_TIME_H || defined(__APPLE__)
66 # include <sys/time.h>
68 #if HAVE_SYS_TYPES_H || defined(__APPLE__)
69 # include <sys/types.h>
73 # if LIB_FOUNDATION_LIBRARY
74 extern NSRecursiveLock *libFoundationLock = nil;
75 # define systemLock libFoundationLock
78 # warning "No locking support for ttyname on this platform"
80 # define systemLock (id)nil
84 // ******************** Poll *********************
86 int NGPollDescriptor(int _fd, short _events, int _timeout) {
96 result = poll(&pfd, 1, _timeout);
98 if (result < 0) { // error
102 NSLog(@"%s: errno is 0, but return value of poll is <0 (%i) (retry) ?!",
103 __PRETTY_FUNCTION__, result);
107 if ((e != EAGAIN) && (e != EINTR))
108 // only retry of interrupted or repeatable
114 /* revents: POLLERR POLLHUP POLLNVAL */
116 return (result < 0) ? -1 : result;
118 struct timeval timeout;
127 if (_events & POLLIN) FD_SET(_fd, &rSet);
128 if (_events & POLLOUT) FD_SET(_fd, &wSet);
129 if (_events & POLLERR) FD_SET(_fd, &eSet);
131 timeout.tv_sec = _timeout / 1000;
132 timeout.tv_usec = _timeout * 1000 - timeout.tv_sec * 1000000;
135 result = select(FD_SETSIZE, &rSet, &wSet, &eSet, &timeout);
136 if (result == -1) { // error
138 if ((e != EAGAIN) && (e != EINTR))
139 // only retry of interrupted or repeatable
143 while (result == -1);
145 return (result < 0) ? -1 : result;
149 // ******************** Flags ********************
151 int NGGetDescriptorFlags(int _fd) {
154 val = fcntl(_fd, F_GETFL, 0);
156 [NGIOException raiseWithReason:@"could not get descriptor flags"];
159 void NGSetDescriptorFlags(int _fd, int _flags) {
160 if (fcntl(_fd, F_SETFL, _flags) == -1)
161 [NGIOException raiseWithReason:@"could not set descriptor flags"];
164 void NGAddDescriptorFlag(int _fd, int _flag) {
165 int val = NGGetDescriptorFlags(_fd);
166 NGSetDescriptorFlags(_fd, val | _flag);
169 // ******************** NonBlocking IO ************
171 static int enableDescLogging = -1;
173 int NGDescriptorRecv(int _fd, char *_buf, int _len, int _flags, int _timeout /* in ms */) {
177 if (enableDescLogging == -1) {
179 [[[NSUserDefaults standardUserDefaults]
180 objectForKey:@"NGLogDescriptorRecv"] boolValue] ? YES : NO;
183 if (enableDescLogging) {
184 NSLog(@"%s(fd=%i,buf=0x%08X,len=%i,flags=%i,timeout=%i)",
185 __PRETTY_FUNCTION__, _fd,_buf,_len,_flags,_timeout);
189 _timeout = 1000 * 60 * 60; /* default timeout: 1 hour */
191 result = recv(_fd, _buf, _len, _flags);
193 if (result == 0) return 0; // EOF
195 if (enableDescLogging) {
196 if ((result < 0) && (errorCode == EINVAL)) {
197 NSLog(@"%s: invalid argument in recv(%i, 0x%08X, %i, %i)",
198 __PRETTY_FUNCTION__, _fd, _buf, _len, _flags);
202 if (enableDescLogging) {
203 NSLog(@"result=%i, error=%i(%s)", result, errorCode, strerror(errorCode));
206 if ((result == -1) && (errorCode == EWOULDBLOCK)) { // retry
210 pfd.events = POLLRDNORM;
214 if (enableDescLogging) NSLog(@"starting poll, loop (to=%i)", _timeout);
216 if ((result = poll(&pfd, 1, _timeout)) < 0) {
219 if (enableDescLogging) {
221 NSLog(@"%s: invalid argument to poll(...)", __PRETTY_FUNCTION__);
224 if (errorCode == 0) {
225 NSLog(@"%s: errno is 0, but return value of poll is <0 (%i) (retry) ?!",
226 __PRETTY_FUNCTION__, result);
230 // retry if interrupted
231 if ((errorCode != EINTR) && (errorCode != EAGAIN))
237 struct timeval timeout;
247 timeout.tv_sec = _timeout / 1000;
248 timeout.tv_usec = _timeout * 1000 - timeout.tv_sec * 1000000;
251 result = select(FD_SETSIZE, &rSet, &wSet, &eSet, &timeout);
252 if (enableDescLogging) {
253 if ((result < 0) && (errno == EINVAL))
254 NSLog(@"%s: invalid argument in select(...)", __PRETTY_FUNCTION__);
257 if (result == -1) { // error
259 if ((e != EAGAIN) && (e != EINTR))
260 // only retry of interrupted or repeatable
264 while (result == -1);
267 if (result == 1) { // data waiting, try to read
268 if (enableDescLogging) NSLog(@"receiving data ...");
270 result = recv(_fd, _buf, _len, _flags);
273 else if (result == -1) {
276 if (errorCode == EWOULDBLOCK)
277 NSLog(@"WARNING: would block although descriptor was polled ..");
280 else if (result == 0) {
281 if (enableDescLogging) {
282 NSLog(@"nonblock: recv on %i timed out after %i milliseconds ..",
295 (int _fd, const char *_buf, int _len, int _flags, int _timeout)
300 result = send(_fd, _buf, _len, _flags);
301 if (result == 0) return 0; // EOF
305 if ((result == -1) && (errorCode == EWOULDBLOCK)) { // retry
309 pfd.events = POLLWRNORM;
313 if ((result = poll(&pfd, 1, _timeout)) < 0) {
316 if (errorCode == 0) {
317 NSLog(@"%s: errno is 0, but return value of poll is <0 (%i) (retry) ?!",
318 __PRETTY_FUNCTION__, result);
322 if (errorCode != EINTR) // retry only if interrupted
328 struct timeval timeout;
338 timeout.tv_sec = _timeout / 1000;
339 timeout.tv_usec = _timeout * 1000 - timeout.tv_sec * 1000000;
342 result = select(FD_SETSIZE, &rSet, &wSet, &eSet, &timeout);
343 if (result == -1) { // error
345 if ((e != EAGAIN) && (e != EINTR))
346 // only retry of interrupted or repeatable
350 while (result == -1);
353 if (result == 1) { // data waiting, try to read
354 result = send(_fd, _buf, _len, _flags);
355 if (result == 0) return 0; // EOF
357 else if (result == 0) {
358 NSLog(@"nonblock: send on %i timed out after %i milliseconds ..",
369 // ******************** TTY *********************
372 Check whether the descriptor is associated to a terminal device.
373 Get the name of the associated terminal device.
376 BOOL NGDescriptorIsAtty(int _fd) {
378 return isatty(_fd) == 1 ? YES : NO;
384 NSString *NGDescriptorGetTtyName(int _fd) {
386 if (isatty(_fd) != 1) // not connected to a terminal device ?
392 extern int ttyname_r(int, char*, size_t);
394 # ifdef _POSIX_PATH_MAX
395 char namebuffer[_POSIX_PATH_MAX + 128];
397 char namebuffer[4096];
400 if (ttyname_r(_fd, namebuffer, sizeof(namebuffer)))
401 return [NSString stringWithCString:namebuffer];
410 result = ttyname(_fd);
412 if (result) str = [NSString stringWithCString:result];