2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE 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 SOPE 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 SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #if !defined(WIN32) || defined(__CYGWIN32__)
24 // similiar functions for Windows can be found in NGSocket.[hm]
26 #include "NGDescriptorFunctions.h"
27 #include "NGStreamExceptions.h"
35 # ifdef HAVE_SYS_POLL_H
36 # include <sys/poll.h>
39 # define POLLRDNORM POLLIN /* needed on Linux */
47 #if defined(HAVE_SYS_SOCKET_H) || defined(__APPLE__)
48 # include <sys/socket.h>
51 #ifdef HAVE_SYS_FCNTL_H
52 # include <sys/fcntl.h>
54 #if defined(HAVE_FCNTL_H) || defined(__APPLE__)
58 #if HAVE_UNISTD_H || defined(__APPLE__)
64 #if HAVE_SYS_TIME_H || defined(__APPLE__)
65 # include <sys/time.h>
67 #if HAVE_SYS_TYPES_H || defined(__APPLE__)
68 # include <sys/types.h>
72 # if LIB_FOUNDATION_LIBRARY
73 extern NSRecursiveLock *libFoundationLock = nil;
74 # define systemLock libFoundationLock
77 # warning "No locking support for ttyname on this platform"
79 # define systemLock (id)nil
83 // ******************** Poll *********************
85 int NGPollDescriptor(int _fd, short _events, int _timeout) {
95 result = poll(&pfd, 1, _timeout);
97 if (result < 0) { // error
101 NSLog(@"%s: errno is 0, but return value of poll is <0 (%i) (retry) ?!",
102 __PRETTY_FUNCTION__, result);
106 if ((e != EAGAIN) && (e != EINTR))
107 // only retry of interrupted or repeatable
113 /* revents: POLLERR POLLHUP POLLNVAL */
115 return (result < 0) ? -1 : result;
117 struct timeval timeout;
126 if (_events & POLLIN) FD_SET(_fd, &rSet);
127 if (_events & POLLOUT) FD_SET(_fd, &wSet);
128 if (_events & POLLERR) FD_SET(_fd, &eSet);
130 timeout.tv_sec = _timeout / 1000;
131 timeout.tv_usec = _timeout * 1000 - timeout.tv_sec * 1000000;
134 result = select(FD_SETSIZE, &rSet, &wSet, &eSet, &timeout);
135 if (result == -1) { // error
137 if ((e != EAGAIN) && (e != EINTR))
138 // only retry of interrupted or repeatable
142 while (result == -1);
144 return (result < 0) ? -1 : result;
148 // ******************** Flags ********************
150 int NGGetDescriptorFlags(int _fd) {
153 val = fcntl(_fd, F_GETFL, 0);
155 [NGIOException raiseWithReason:@"could not get descriptor flags"];
158 void NGSetDescriptorFlags(int _fd, int _flags) {
159 if (fcntl(_fd, F_SETFL, _flags) == -1)
160 [NGIOException raiseWithReason:@"could not set descriptor flags"];
163 void NGAddDescriptorFlag(int _fd, int _flag) {
164 int val = NGGetDescriptorFlags(_fd);
165 NGSetDescriptorFlags(_fd, val | _flag);
168 // ******************** NonBlocking IO ************
170 static int enableDescLogging = -1;
172 int NGDescriptorRecv(int _fd, char *_buf, int _len, int _flags, int _timeout /* in ms */) {
176 if (enableDescLogging == -1) {
178 [[[NSUserDefaults standardUserDefaults]
179 objectForKey:@"NGLogDescriptorRecv"] boolValue] ? YES : NO;
182 if (enableDescLogging) {
183 NSLog(@"%s(fd=%i,buf=0x%08X,len=%i,flags=%i,timeout=%i)",
184 __PRETTY_FUNCTION__, _fd,_buf,_len,_flags,_timeout);
188 _timeout = 1000 * 60 * 60; /* default timeout: 1 hour */
190 result = recv(_fd, _buf, _len, _flags);
192 if (result == 0) return 0; // EOF
194 if (enableDescLogging) {
195 if ((result < 0) && (errorCode == EINVAL)) {
196 NSLog(@"%s: invalid argument in recv(%i, 0x%08X, %i, %i)",
197 __PRETTY_FUNCTION__, _fd, _buf, _len, _flags);
201 if (enableDescLogging) {
202 NSLog(@"result=%i, error=%i(%s)", result, errorCode, strerror(errorCode));
205 if ((result == -1) && (errorCode == EWOULDBLOCK)) { // retry
209 pfd.events = POLLRDNORM;
213 if (enableDescLogging) NSLog(@"starting poll, loop (to=%i)", _timeout);
215 if ((result = poll(&pfd, 1, _timeout)) < 0) {
218 if (enableDescLogging) {
220 NSLog(@"%s: invalid argument to poll(...)", __PRETTY_FUNCTION__);
223 if (errorCode == 0) {
224 NSLog(@"%s: errno is 0, but return value of poll is <0 (%i) (retry) ?!",
225 __PRETTY_FUNCTION__, result);
229 // retry if interrupted
230 if ((errorCode != EINTR) && (errorCode != EAGAIN))
236 struct timeval timeout;
246 timeout.tv_sec = _timeout / 1000;
247 timeout.tv_usec = _timeout * 1000 - timeout.tv_sec * 1000000;
250 result = select(FD_SETSIZE, &rSet, &wSet, &eSet, &timeout);
251 if (enableDescLogging) {
252 if ((result < 0) && (errno == EINVAL))
253 NSLog(@"%s: invalid argument in select(...)", __PRETTY_FUNCTION__);
256 if (result == -1) { // error
258 if ((e != EAGAIN) && (e != EINTR))
259 // only retry of interrupted or repeatable
263 while (result == -1);
266 if (result == 1) { // data waiting, try to read
267 if (enableDescLogging) NSLog(@"receiving data ...");
269 result = recv(_fd, _buf, _len, _flags);
272 else if (result == -1) {
275 if (errorCode == EWOULDBLOCK)
276 NSLog(@"WARNING: would block although descriptor was polled ..");
279 else if (result == 0) {
280 if (enableDescLogging) {
281 NSLog(@"nonblock: recv on %i timed out after %i milliseconds ..",
294 (int _fd, const char *_buf, int _len, int _flags, int _timeout)
299 result = send(_fd, _buf, _len, _flags);
300 if (result == 0) return 0; // EOF
304 if ((result == -1) && (errorCode == EWOULDBLOCK)) { // retry
308 pfd.events = POLLWRNORM;
312 if ((result = poll(&pfd, 1, _timeout)) < 0) {
315 if (errorCode == 0) {
316 NSLog(@"%s: errno is 0, but return value of poll is <0 (%i) (retry) ?!",
317 __PRETTY_FUNCTION__, result);
321 if (errorCode != EINTR) // retry only if interrupted
327 struct timeval timeout;
337 timeout.tv_sec = _timeout / 1000;
338 timeout.tv_usec = _timeout * 1000 - timeout.tv_sec * 1000000;
341 result = select(FD_SETSIZE, &rSet, &wSet, &eSet, &timeout);
342 if (result == -1) { // error
344 if ((e != EAGAIN) && (e != EINTR))
345 // only retry of interrupted or repeatable
349 while (result == -1);
352 if (result == 1) { // data waiting, try to read
353 result = send(_fd, _buf, _len, _flags);
354 if (result == 0) return 0; // EOF
356 else if (result == 0) {
357 NSLog(@"nonblock: send on %i timed out after %i milliseconds ..",
368 // ******************** TTY *********************
371 Check whether the descriptor is associated to a terminal device.
372 Get the name of the associated terminal device.
375 BOOL NGDescriptorIsAtty(int _fd) {
377 return isatty(_fd) == 1 ? YES : NO;
383 NSString *NGDescriptorGetTtyName(int _fd) {
385 if (isatty(_fd) != 1) // not connected to a terminal device ?
391 extern int ttyname_r(int, char*, size_t);
393 # ifdef _POSIX_PATH_MAX
394 char namebuffer[_POSIX_PATH_MAX + 128];
396 char namebuffer[4096];
399 if (ttyname_r(_fd, namebuffer, sizeof(namebuffer)))
400 return [NSString stringWithCString:namebuffer];
409 result = ttyname(_fd);
411 if (result) str = [NSString stringWithCString:result];