~ubuntu-branches/ubuntu/edgy/gnustep-base/edgy

« back to all changes in this revision

Viewing changes to Source/win32/GSFileHandleWin32.m

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Berg, Hubert Chan, Christoph Berg
  • Date: 2005-12-29 18:14:22 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051229181422-abmd8d53tpyxrum2
Tags: 1.11.2-1
[ Hubert Chan ]
* New upstream release.

[ Christoph Berg ]
* Point gdomap symlink to /usr/sbin.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** Implementation for GSFileHandle for GNUStep
 
2
   Copyright (C) 1997-2002 Free Software Foundation, Inc.
 
3
 
 
4
   Written by:  Richard Frith-Macdonald <richard@brainstorm.co.uk>
 
5
   Date: 1997, 2002
 
6
 
 
7
   This file is part of the GNUstep Base Library.
 
8
 
 
9
   This library is free software; you can redistribute it and/or
 
10
   modify it under the terms of the GNU Library General Public
 
11
   License as published by the Free Software Foundation; either
 
12
   version 2 of the License, or (at your option) any later version.
 
13
 
 
14
   This library is distributed in the hope that it will be useful,
 
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
   Library General Public License for more details.
 
18
 
 
19
   You should have received a copy of the GNU Library General Public
 
20
   License along with this library; if not, write to the Free
 
21
   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
 
22
   */
 
23
 
 
24
#define _FILE_OFFSET_BITS 64
 
25
 
 
26
#include "config.h"
 
27
 
 
28
#include "GNUstepBase/preface.h"
 
29
#include "Foundation/NSObject.h"
 
30
#include "Foundation/NSData.h"
 
31
#include "Foundation/NSArray.h"
 
32
#include "Foundation/NSString.h"
 
33
#include "Foundation/NSFileHandle.h"
 
34
#include "GNUstepBase/GSFileHandle.h"
 
35
#include "Foundation/NSException.h"
 
36
#include "Foundation/NSRunLoop.h"
 
37
#include "Foundation/NSNotification.h"
 
38
#include "Foundation/NSNotificationQueue.h"
 
39
#include "Foundation/NSHost.h"
 
40
#include "Foundation/NSByteOrder.h"
 
41
#include "Foundation/NSProcessInfo.h"
 
42
#include "Foundation/NSUserDefaults.h"
 
43
#include "Foundation/NSDebug.h"
 
44
 
 
45
#include "../Tools/gdomap.h"
 
46
 
 
47
#include <winsock2.h>
 
48
#include <fcntl.h>
 
49
#include <sys/file.h>
 
50
#include <sys/types.h>
 
51
#include <sys/stat.h>
 
52
#include <io.h>
 
53
#include <stdio.h>
 
54
 
 
55
#include <string.h>
 
56
#ifdef HAVE_UNISTD_H
 
57
#include <unistd.h>
 
58
#endif
 
59
#include <errno.h>
 
60
 
 
61
#ifndef O_BINARY
 
62
#ifdef  _O_BINARY
 
63
#define O_BINARY        _O_BINARY
 
64
#else
 
65
#define O_BINARY        0
 
66
#endif
 
67
#endif
 
68
 
 
69
#ifndef INADDR_NONE
 
70
#define INADDR_NONE     -1
 
71
#endif
 
72
 
 
73
// Maximum data in single I/O operation
 
74
#define NETBUF_SIZE     4096
 
75
#define READ_SIZE       NETBUF_SIZE*10
 
76
 
 
77
static GSFileHandle*    fh_stdin = nil;
 
78
static GSFileHandle*    fh_stdout = nil;
 
79
static GSFileHandle*    fh_stderr = nil;
 
80
 
 
81
// Key to info dictionary for operation mode.
 
82
static NSString*        NotificationKey = @"NSFileHandleNotificationKey";
 
83
 
 
84
@interface GSFileHandle(private)
 
85
- (void) receivedEventRead;
 
86
- (void) receivedEventWrite;
 
87
@end
 
88
 
 
89
@implementation GSFileHandle
 
90
 
 
91
/**
 
92
 * Encapsulates low level read operation to get data from the operating
 
93
 * system.
 
94
 */
 
95
- (int) read: (void*)buf length: (int)len
 
96
{
 
97
#if     USE_ZLIB
 
98
  if (gzDescriptor != 0)
 
99
    {
 
100
      len = gzread(gzDescriptor, buf, len);
 
101
    }
 
102
  else
 
103
#endif
 
104
  if (isSocket)
 
105
    {
 
106
      len = recv((SOCKET)_get_osfhandle(descriptor), buf, len, 0);
 
107
    }
 
108
  else
 
109
    {
 
110
      len = read(descriptor, buf, len);
 
111
    }
 
112
  return len;
 
113
}
 
114
 
 
115
/**
 
116
 * Encapsulates low level write operation to send data to the operating
 
117
 * system.
 
118
 */
 
119
- (int) write: (const void*)buf length: (int)len
 
120
{
 
121
#if     USE_ZLIB
 
122
  if (gzDescriptor != 0)
 
123
    {
 
124
      len = gzwrite(gzDescriptor, (char*)buf, len);
 
125
    }
 
126
  else
 
127
#endif
 
128
  if (isSocket)
 
129
    {
 
130
      len = send((SOCKET)_get_osfhandle(descriptor), buf, len, 0);
 
131
    }
 
132
  else
 
133
    {
 
134
      len = write(descriptor, buf, len);
 
135
    }
 
136
  return len;
 
137
}
 
138
 
 
139
static BOOL
 
140
getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
 
141
{
 
142
  const char            *proto = "tcp";
 
143
  struct servent        *sp;
 
144
 
 
145
  if (pcl)
 
146
    {
 
147
      proto = [pcl lossyCString];
 
148
    }
 
149
  memset(sin, '\0', sizeof(*sin));
 
150
  sin->sin_family = AF_INET;
 
151
 
 
152
  /*
 
153
   *    If we were given a hostname, we use any address for that host.
 
154
   *    Otherwise we expect the given name to be an address unless it is
 
155
   *    a null (any address).
 
156
   */
 
157
  if (name)
 
158
    {
 
159
      NSHost*           host = [NSHost hostWithName: name];
 
160
 
 
161
      if (host != nil)
 
162
        {
 
163
          name = [host address];
 
164
        }
 
165
#ifndef HAVE_INET_ATON
 
166
      sin->sin_addr.s_addr = inet_addr([name lossyCString]);
 
167
      if (sin->sin_addr.s_addr == INADDR_NONE)
 
168
#else
 
169
      if (inet_aton([name lossyCString], &sin->sin_addr) == 0)
 
170
#endif
 
171
        {
 
172
          return NO;
 
173
        }
 
174
    }
 
175
  else
 
176
    {
 
177
      sin->sin_addr.s_addr = GSSwapHostI32ToBig(INADDR_ANY);
 
178
    }
 
179
  if (svc == nil)
 
180
    {
 
181
      sin->sin_port = 0;
 
182
      return YES;
 
183
    }
 
184
  else if ((sp = getservbyname([svc lossyCString], proto)) == 0)
 
185
    {
 
186
      const char*     ptr = [svc lossyCString];
 
187
      int             val = atoi(ptr);
 
188
 
 
189
      while (isdigit(*ptr))
 
190
        {
 
191
          ptr++;
 
192
        }
 
193
      if (*ptr == '\0' && val <= 0xffff)
 
194
        {
 
195
          gsu16       v = val;
 
196
 
 
197
          sin->sin_port = GSSwapHostI16ToBig(v);
 
198
          return YES;
 
199
        }
 
200
      else if (strcmp(ptr, "gdomap") == 0)
 
201
        {
 
202
          gsu16       v;
 
203
#ifdef  GDOMAP_PORT_OVERRIDE
 
204
          v = GDOMAP_PORT_OVERRIDE;
 
205
#else
 
206
          v = 538;      // IANA allocated port
 
207
#endif
 
208
          sin->sin_port = GSSwapHostI16ToBig(v);
 
209
          return YES;
 
210
        }
 
211
      else
 
212
        {
 
213
          return NO;
 
214
        }
 
215
    }
 
216
  else
 
217
    {
 
218
      sin->sin_port = sp->s_port;
 
219
      return YES;
 
220
    }
 
221
}
 
222
 
 
223
+ (id) allocWithZone: (NSZone*)z
 
224
{
 
225
  return NSAllocateObject ([self class], 0, z);
 
226
}
 
227
 
 
228
- (void) dealloc
 
229
{
 
230
  RELEASE(address);
 
231
  RELEASE(service);
 
232
  RELEASE(protocol);
 
233
 
 
234
  [self gcFinalize];
 
235
 
 
236
  RELEASE(readInfo);
 
237
  RELEASE(writeInfo);
 
238
  [super dealloc];
 
239
}
 
240
 
 
241
- (void) gcFinalize
 
242
{
 
243
  if (self == fh_stdin)
 
244
    fh_stdin = nil;
 
245
  if (self == fh_stdout)
 
246
    fh_stdout = nil;
 
247
  if (self == fh_stderr)
 
248
    fh_stderr = nil;
 
249
 
 
250
  [self ignoreReadDescriptor];
 
251
  [self ignoreWriteDescriptor];
 
252
 
 
253
#if     USE_ZLIB
 
254
  /*
 
255
   * The gzDescriptor should always be closed when we have done with it.
 
256
   */
 
257
  if (gzDescriptor != 0)
 
258
    {
 
259
      gzclose(gzDescriptor);
 
260
    }
 
261
#endif
 
262
  if (descriptor != -1)
 
263
    {
 
264
      [self setNonBlocking: wasNonBlocking];
 
265
      if (closeOnDealloc == YES)
 
266
        {
 
267
          if (isSocket)
 
268
            {
 
269
              closesocket((SOCKET)_get_osfhandle(descriptor));
 
270
              WSACloseEvent(event);
 
271
              event = WSA_INVALID_EVENT;
 
272
            }
 
273
          close(descriptor);
 
274
          descriptor = -1;
 
275
        }
 
276
    }
 
277
}
 
278
 
 
279
// Initializing a GSFileHandle Object
 
280
 
 
281
- (id) init
 
282
{
 
283
  return [self initWithNullDevice];
 
284
}
 
285
 
 
286
/**
 
287
 * Initialise as a client socket connection ... do this by using
 
288
 * [-initAsClientInBackgroundAtAddress:service:protocol:forModes:]
 
289
 * and running the current run loop in NSDefaultRunLoopMode until
 
290
 * the connection attempt succeeds, fails, or times out.
 
291
 */
 
292
- (id) initAsClientAtAddress: (NSString*)a
 
293
                     service: (NSString*)s
 
294
                    protocol: (NSString*)p
 
295
{
 
296
  self = [self initAsClientInBackgroundAtAddress: a
 
297
                                         service: s
 
298
                                        protocol: p
 
299
                                        forModes: nil];
 
300
  if (self != nil)
 
301
    {
 
302
      NSRunLoop *loop;
 
303
      NSDate    *limit;
 
304
 
 
305
      loop = [NSRunLoop currentRunLoop];
 
306
      limit = [NSDate dateWithTimeIntervalSinceNow: 300];
 
307
      while ([limit timeIntervalSinceNow] > 0
 
308
        && (readInfo != nil || [writeInfo count] > 0))
 
309
        {
 
310
          [loop runMode: NSDefaultRunLoopMode
 
311
             beforeDate: limit];
 
312
        }
 
313
      if (readInfo != nil || [writeInfo count] > 0 || readOK == NO)
 
314
        {
 
315
          /* Must have timed out or failed */
 
316
          DESTROY(self);
 
317
        }
 
318
      else
 
319
        {
 
320
          [self setNonBlocking: NO];
 
321
        }
 
322
    }
 
323
  return self;
 
324
}
 
325
 
 
326
/*
 
327
 * States for socks connection negotiation
 
328
 */
 
329
NSString * const GSSOCKSConnect = @"GSSOCKSConnect";
 
330
NSString * const GSSOCKSSendAuth = @"GSSOCKSSendAuth";
 
331
NSString * const GSSOCKSRecvAuth = @"GSSOCKSRecvAuth";
 
332
NSString * const GSSOCKSSendConn = @"GSSOCKSSendConn";
 
333
NSString * const GSSOCKSRecvConn = @"GSSOCKSRecvConn";
 
334
NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
 
335
 
 
336
- (void) _socksHandler: (NSNotification*)aNotification
 
337
{
 
338
  NSNotificationCenter  *nc = [NSNotificationCenter defaultCenter];
 
339
  NSString              *name = [aNotification name];
 
340
  NSDictionary          *info = (NSMutableDictionary*)[aNotification userInfo];
 
341
  NSArray               *modes;
 
342
  NSString              *error;
 
343
  NSMutableDictionary   *i = nil;
 
344
  NSNotification        *n = nil;
 
345
 
 
346
  NSDebugMLLog(@"NSFileHandle", @"%@ SOCKS connection: %@",
 
347
    self, aNotification);
 
348
 
 
349
  [nc removeObserver: self name: name object: self];
 
350
 
 
351
  modes = (NSArray*)[info objectForKey: NSFileHandleNotificationMonitorModes];
 
352
  error = [info objectForKey: GSFileHandleNotificationError];
 
353
 
 
354
  if (error == nil)
 
355
    {
 
356
      if (name == GSSOCKSConnect)
 
357
        {
 
358
          NSData        *item;
 
359
 
 
360
          /*
 
361
           * Send an authorisation record to the SOCKS server.
 
362
           */
 
363
          i = [info mutableCopy];
 
364
          /*
 
365
           * Authorisation record is at least three bytes -
 
366
           *   socks version (5)
 
367
           *   authorisation method bytes to follow (1)
 
368
           *   say we do no authorisation (0)
 
369
           */
 
370
          item = [[NSData alloc] initWithBytes: "\5\1\0"
 
371
                                        length: 3];
 
372
          [i setObject: item forKey: NSFileHandleNotificationDataItem];
 
373
          RELEASE(item);
 
374
          [i setObject: GSSOCKSSendAuth forKey: NotificationKey];
 
375
          [writeInfo addObject: i];
 
376
          RELEASE(i);
 
377
          [nc addObserver: self
 
378
                 selector: @selector(_socksHandler:)
 
379
                     name: GSSOCKSSendAuth
 
380
                   object: self];
 
381
          [self watchWriteDescriptor];
 
382
        }
 
383
      else if (name == GSSOCKSSendAuth)
 
384
        {
 
385
          NSMutableData *item;
 
386
 
 
387
          /*
 
388
           * We have written the authorisation record, so we
 
389
           * request a response from the SOCKS server.
 
390
           */
 
391
          readMax = 2;
 
392
          readInfo = [info mutableCopy];
 
393
          [readInfo setObject: GSSOCKSRecvAuth forKey: NotificationKey];
 
394
          item = [[NSMutableData alloc] initWithCapacity: 0];
 
395
          [readInfo setObject: item forKey: NSFileHandleNotificationDataItem];
 
396
          RELEASE(item);
 
397
          [nc addObserver: self
 
398
                 selector: @selector(_socksHandler:)
 
399
                     name: GSSOCKSRecvAuth
 
400
                   object: self];
 
401
          [self watchReadDescriptorForModes: modes];
 
402
        }
 
403
      else if (name == GSSOCKSRecvAuth)
 
404
        {
 
405
          NSData                *response;
 
406
          const unsigned char   *bytes;
 
407
 
 
408
          response = [info objectForKey: NSFileHandleNotificationDataItem];
 
409
          bytes = (const unsigned char*)[response bytes];
 
410
          if ([response length] != 2)
 
411
            {
 
412
              error = @"authorisation response from SOCKS was not two bytes";
 
413
            }
 
414
          else if (bytes[0] != 5)
 
415
            {
 
416
              error = @"authorisation response from SOCKS had wrong version";
 
417
            }
 
418
          else if (bytes[1] != 0)
 
419
            {
 
420
              error = @"authorisation response from SOCKS had wrong method";
 
421
            }
 
422
          else
 
423
            {
 
424
              NSData            *item;
 
425
              char              buf[10];
 
426
              const char        *ptr;
 
427
              int               p;
 
428
 
 
429
              /*
 
430
               * Send the address information to the SOCKS server.
 
431
               */
 
432
              i = [info mutableCopy];
 
433
              /*
 
434
               * Connect command is ten bytes -
 
435
               *   socks version
 
436
               *   connect command
 
437
               *   reserved byte
 
438
               *   address type
 
439
               *   address 4 bytes (big endian)
 
440
               *   port 2 bytes (big endian)
 
441
               */
 
442
              buf[0] = 5;       // Socks version number
 
443
              buf[1] = 1;       // Connect command
 
444
              buf[2] = 0;       // Reserved
 
445
              buf[3] = 1;       // Address type (IPV4)
 
446
              ptr = [address lossyCString];
 
447
              buf[4] = atoi(ptr);
 
448
              while (isdigit(*ptr))
 
449
                ptr++;
 
450
              ptr++;
 
451
              buf[5] = atoi(ptr);
 
452
              while (isdigit(*ptr))
 
453
                ptr++;
 
454
              ptr++;
 
455
              buf[6] = atoi(ptr);
 
456
              while (isdigit(*ptr))
 
457
                ptr++;
 
458
              ptr++;
 
459
              buf[7] = atoi(ptr);
 
460
              p = [service intValue];
 
461
              buf[8] = ((p & 0xff00) >> 8);
 
462
              buf[9] = (p & 0xff);
 
463
 
 
464
              item = [[NSData alloc] initWithBytes: buf length: 10];
 
465
              [i setObject: item forKey: NSFileHandleNotificationDataItem];
 
466
              RELEASE(item);
 
467
              [i setObject: GSSOCKSSendConn
 
468
                    forKey: NotificationKey];
 
469
              [writeInfo addObject: i];
 
470
              RELEASE(i);
 
471
              [nc addObserver: self
 
472
                     selector: @selector(_socksHandler:)
 
473
                         name: GSSOCKSSendConn
 
474
                       object: self];
 
475
              [self watchWriteDescriptor];
 
476
            }
 
477
        }
 
478
      else if (name == GSSOCKSSendConn)
 
479
        {
 
480
          NSMutableData *item;
 
481
 
 
482
          /*
 
483
           * We have written the connect command, so we
 
484
           * request a response from the SOCKS server.
 
485
           */
 
486
          readMax = 4;
 
487
          readInfo = [info mutableCopy];
 
488
          [readInfo setObject: GSSOCKSRecvConn forKey: NotificationKey];
 
489
          item = [[NSMutableData alloc] initWithCapacity: 0];
 
490
          [readInfo setObject: item forKey: NSFileHandleNotificationDataItem];
 
491
          RELEASE(item);
 
492
          [nc addObserver: self
 
493
                 selector: @selector(_socksHandler:)
 
494
                     name: GSSOCKSRecvConn
 
495
                   object: self];
 
496
          [self watchReadDescriptorForModes: modes];
 
497
        }
 
498
      else if (name == GSSOCKSRecvConn)
 
499
        {
 
500
          NSData                *response;
 
501
          const unsigned char   *bytes;
 
502
          unsigned              len = 0;
 
503
 
 
504
          response = [info objectForKey: NSFileHandleNotificationDataItem];
 
505
          bytes = (const unsigned char*)[response bytes];
 
506
          if ([response length] != 4)
 
507
            {
 
508
              error = @"connect response from SOCKS had bad length";
 
509
            }
 
510
          else if (bytes[0] != 5)
 
511
            {
 
512
              error = @"connect response from SOCKS had wrong version";
 
513
            }
 
514
          else if (bytes[1] != 0)
 
515
            {
 
516
              switch (bytes[1])
 
517
                {
 
518
                  case 1:
 
519
                    error = @"SOCKS server general failure";
 
520
                    break;
 
521
                  case 2:
 
522
                    error = @"SOCKS server says permission denied";
 
523
                    break;
 
524
                  case 3:
 
525
                    error = @"SOCKS server says network unreachable";
 
526
                    break;
 
527
                  case 4:
 
528
                    error = @"SOCKS server says host unreachable";
 
529
                    break;
 
530
                  case 5:
 
531
                    error = @"SOCKS server says connection refused";
 
532
                    break;
 
533
                  case 6:
 
534
                    error = @"SOCKS server says connection timed out";
 
535
                    break;
 
536
                  case 7:
 
537
                    error = @"SOCKS server says command not supported";
 
538
                    break;
 
539
                  case 8:
 
540
                    error = @"SOCKS server says address type not supported";
 
541
                    break;
 
542
                  default:
 
543
                    error = @"connect response from SOCKS was failure";
 
544
                    break;
 
545
                }
 
546
            }
 
547
          else if (bytes[3] == 1)
 
548
            {
 
549
              len = 4;                  // Fixed size (IPV4) address
 
550
            }
 
551
          else if (bytes[3] == 3)
 
552
            {
 
553
              len = 1 + bytes[4];       // Domain name with leading length
 
554
            }
 
555
          else if (bytes[3] == 4)
 
556
            {
 
557
              len = 16;                 // Fixed size (IPV6) address
 
558
            }
 
559
          else
 
560
            {
 
561
              error = @"SOCKS server returned unknown address type";
 
562
            }
 
563
 
 
564
          if (error == nil)
 
565
            {
 
566
              NSMutableData     *item;
 
567
 
 
568
              /*
 
569
               * We have received a success, so we must now consume the
 
570
               * address and port information the SOCKS server sends.
 
571
               */
 
572
              readMax = len + 2;
 
573
              readInfo = [info mutableCopy];
 
574
              [readInfo setObject: GSSOCKSRecvAddr forKey: NotificationKey];
 
575
              item = [[NSMutableData alloc] initWithCapacity: 0];
 
576
              [readInfo setObject: item
 
577
                           forKey: NSFileHandleNotificationDataItem];
 
578
              RELEASE(item);
 
579
              [nc addObserver: self
 
580
                     selector: @selector(_socksHandler:)
 
581
                         name: GSSOCKSRecvAddr
 
582
                       object: self];
 
583
              [self watchReadDescriptorForModes: modes];
 
584
            }
 
585
        }
 
586
      else if (name == GSSOCKSRecvAddr)
 
587
        {
 
588
          /*
 
589
           * Success ... We read the address from the socks server so
 
590
           * the connection is now ready to go.
 
591
           */
 
592
          name = GSFileHandleConnectCompletionNotification;
 
593
          i = [info mutableCopy];
 
594
          [i setObject: name forKey: NotificationKey];
 
595
          n = [NSNotification notificationWithName: name
 
596
                                            object: self
 
597
                                          userInfo: i];
 
598
          RELEASE(i);
 
599
        }
 
600
      else
 
601
        {
 
602
          /*
 
603
           * Argh ... unexpected notification.
 
604
           */
 
605
          error = @"unexpected notification during SOCKS connection";
 
606
        }
 
607
    }
 
608
 
 
609
  /*
 
610
   * If 'error' is non-null, we set up a notification to tell people
 
611
   * the connection failed.
 
612
   */
 
613
  if (error != nil)
 
614
    {
 
615
      NSDebugMLLog(@"NSFileHandle", @"%@ SOCKS error: %@", self, error);
 
616
 
 
617
      /*
 
618
       * An error in the initial connection ... notify observers
 
619
       * by re-posting the notification with a new name.
 
620
       */
 
621
      name = GSFileHandleConnectCompletionNotification;
 
622
      i = [info mutableCopy];
 
623
      [i setObject: name forKey: NotificationKey];
 
624
      [i setObject: error forKey: GSFileHandleNotificationError];
 
625
      n = [NSNotification notificationWithName: name
 
626
                                        object: self
 
627
                                      userInfo: i];
 
628
      RELEASE(i);
 
629
    }
 
630
 
 
631
  /*
 
632
   * If a notification has been set up, we post it as the last thing we do.
 
633
   */
 
634
  if (n != nil)
 
635
    {
 
636
      NSNotificationQueue       *q;
 
637
 
 
638
      q = [NSNotificationQueue defaultQueue];
 
639
      [q enqueueNotification: n
 
640
                postingStyle: NSPostASAP
 
641
                coalesceMask: NSNotificationNoCoalescing
 
642
                    forModes: modes];
 
643
    }
 
644
}
 
645
 
 
646
- (id) initAsClientInBackgroundAtAddress: (NSString*)a
 
647
                                 service: (NSString*)s
 
648
                                protocol: (NSString*)p
 
649
                                forModes: (NSArray*)modes
 
650
{
 
651
  static NSString       *esocks = nil;
 
652
  static NSString       *dsocks = nil;
 
653
  static BOOL           beenHere = NO;
 
654
  SOCKET                net;
 
655
  struct sockaddr_in    sin;
 
656
  struct sockaddr_in    lsin;
 
657
  NSString              *lhost = nil;
 
658
  NSString              *shost = nil;
 
659
  NSString              *sport = nil;
 
660
  int                   status;
 
661
 
 
662
  if (beenHere == NO)
 
663
    {
 
664
      NSUserDefaults    *defs;
 
665
 
 
666
      beenHere = YES;
 
667
      defs = [NSUserDefaults standardUserDefaults];
 
668
      dsocks = [[defs stringForKey: @"GSSOCKS"] copy];
 
669
      if (dsocks == nil)
 
670
        {
 
671
          NSDictionary  *env;
 
672
 
 
673
          env = [[NSProcessInfo processInfo] environment];
 
674
          esocks = [env objectForKey: @"SOCKS5_SERVER"];
 
675
          if (esocks == nil)
 
676
            {
 
677
              esocks = [env objectForKey: @"SOCKS_SERVER"];
 
678
            }
 
679
          esocks = [esocks copy];
 
680
        }
 
681
    }
 
682
 
 
683
  if (a == nil || [a isEqualToString: @""])
 
684
    {
 
685
      a = @"localhost";
 
686
    }
 
687
  if (s == nil)
 
688
    {
 
689
      NSLog(@"bad argument - service is nil");
 
690
      RELEASE(self);
 
691
      return nil;
 
692
    }
 
693
 
 
694
  if ([p hasPrefix: @"bind-"] == YES)
 
695
    {
 
696
      NSRange   r;
 
697
 
 
698
      lhost = [p substringFromIndex: 5];
 
699
      r = [lhost rangeOfString: @":"];
 
700
      if (r.length > 0)
 
701
        {
 
702
          p = [lhost substringFromIndex: NSMaxRange(r)];
 
703
          lhost = [lhost substringToIndex: r.location];
 
704
        }
 
705
      else
 
706
        {
 
707
          p = nil;
 
708
        }
 
709
      if (getAddr(lhost, p, @"tcp", &lsin) == NO)
 
710
        {
 
711
          NSLog(@"bad bind address specification");
 
712
          RELEASE(self);
 
713
          return nil;
 
714
        }
 
715
      p = @"tcp";
 
716
    }
 
717
 
 
718
  /**
 
719
   * A protocol fo the form 'socks-...' controls socks operation,
 
720
   * overriding defaults and environment variables.<br />
 
721
   * If it is just 'socks-' it turns off socks for this fiel handle.<br />
 
722
   * Otherwise, the following text must be the name of the socks server
 
723
   * (optionally followed by :port).
 
724
   */
 
725
  if ([p hasPrefix: @"socks-"] == YES)
 
726
    {
 
727
      shost = [p substringFromIndex: 6];
 
728
      p = @"tcp";
 
729
    }
 
730
  else if (dsocks != nil)
 
731
    {
 
732
      shost = dsocks;   // GSSOCKS user default
 
733
    }
 
734
  else
 
735
    {
 
736
      shost = esocks;   // SOCKS_SERVER environment variable.
 
737
    }
 
738
 
 
739
  if (shost != nil && [shost length] > 0)
 
740
    {
 
741
      NSRange   r;
 
742
 
 
743
      r = [shost rangeOfString: @":"];
 
744
      if (r.length > 0)
 
745
        {
 
746
          sport = [shost substringFromIndex: NSMaxRange(r)];
 
747
          shost = [shost substringToIndex: r.location];
 
748
        }
 
749
      else
 
750
        {
 
751
          sport = @"1080";
 
752
        }
 
753
      p = @"tcp";
 
754
    }
 
755
 
 
756
  if (getAddr(a, s, p, &sin) == NO)
 
757
    {
 
758
      RELEASE(self);
 
759
      NSLog(@"bad address-service-protocol combination");
 
760
      return nil;
 
761
    }
 
762
  [self setAddr: &sin];         // Store the address of the remote end.
 
763
 
 
764
  /*
 
765
   * Don't use SOCKS if we are contacting the local host.
 
766
   */
 
767
  if (shost != nil)
 
768
    {
 
769
      NSHost    *remote = [NSHost hostWithAddress: [self socketAddress]];
 
770
      NSHost    *local = [NSHost currentHost];
 
771
 
 
772
      if ([remote isEqual: local] || [remote isEqual: [NSHost localHost]])
 
773
        {
 
774
          shost = nil;
 
775
        }
 
776
    }
 
777
  if (shost != nil)
 
778
    {
 
779
      if (getAddr(shost, sport, p, &sin) == NO)
 
780
        {
 
781
          NSLog(@"bad SOCKS host-port combination");
 
782
          RELEASE(self);
 
783
          return nil;
 
784
        }
 
785
    }
 
786
 
 
787
  if ((net = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) == INVALID_SOCKET)
 
788
    {
 
789
      NSLog(@"unable to create socket - %s", GSLastErrorStr(errno));
 
790
      RELEASE(self);
 
791
      return nil;
 
792
    }
 
793
  /*
 
794
   * Enable tcp-level tracking of whether connection is alive.
 
795
   */
 
796
  status = 1;
 
797
  setsockopt(net, SOL_SOCKET, SO_KEEPALIVE, (char *)&status, sizeof(status));
 
798
 
 
799
  if (lhost != nil)
 
800
    {
 
801
      if (bind(net, (struct sockaddr *)&lsin, sizeof(lsin)) == SOCKET_ERROR)
 
802
        {
 
803
          NSLog(@"unable to bind to port %s:%d - %s", inet_ntoa(lsin.sin_addr),
 
804
            GSSwapBigI16ToHost(sin.sin_port), GSLastErrorStr(errno));
 
805
          (void) closesocket(net);
 
806
          RELEASE(self);
 
807
          return nil;
 
808
        }
 
809
    }
 
810
 
 
811
  self = [self initWithNativeHandle: (void*)net closeOnDealloc: YES];
 
812
  if (self)
 
813
    {
 
814
      NSMutableDictionary*      info;
 
815
 
 
816
      isSocket = YES;
 
817
      [self setNonBlocking: YES];
 
818
      if (connect(net, (struct sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
 
819
        {
 
820
          if (WSAGetLastError() != WSAEWOULDBLOCK)
 
821
            {
 
822
              NSLog(@"unable to make connection to %s:%d - %s",
 
823
                inet_ntoa(sin.sin_addr),
 
824
                GSSwapBigI16ToHost(sin.sin_port), GSLastErrorStr(errno));
 
825
              RELEASE(self);
 
826
              return nil;
 
827
            }
 
828
        }
 
829
        
 
830
      info = [[NSMutableDictionary alloc] initWithCapacity: 4];
 
831
      [info setObject: address forKey: NSFileHandleNotificationDataItem];
 
832
      if (shost == nil)
 
833
        {
 
834
          [info setObject: GSFileHandleConnectCompletionNotification
 
835
                   forKey: NotificationKey];
 
836
        }
 
837
      else
 
838
        {
 
839
          NSNotificationCenter  *nc;
 
840
 
 
841
          /*
 
842
           * If we are making a socks connection, register self as an
 
843
           * observer of notifications and ensure we will manage this.
 
844
           */
 
845
          nc = [NSNotificationCenter defaultCenter];
 
846
          [nc addObserver: self
 
847
                 selector: @selector(_socksHandler:)
 
848
                     name: GSSOCKSConnect
 
849
                   object: self];
 
850
          [info setObject: GSSOCKSConnect
 
851
                   forKey: NotificationKey];
 
852
        }
 
853
      if (modes)
 
854
        {
 
855
          [info setObject: modes forKey: NSFileHandleNotificationMonitorModes];
 
856
        }
 
857
      [writeInfo addObject: info];
 
858
      RELEASE(info);
 
859
      [self watchWriteDescriptor];
 
860
      connectOK = YES;
 
861
      acceptOK = NO;
 
862
      readOK = NO;
 
863
      writeOK = NO;
 
864
    }
 
865
  return self;
 
866
}
 
867
 
 
868
- (id) initAsServerAtAddress: (NSString*)a
 
869
                     service: (NSString*)s
 
870
                    protocol: (NSString*)p
 
871
{
 
872
#ifndef BROKEN_SO_REUSEADDR
 
873
  int           status = 1;
 
874
#endif
 
875
  SOCKET        net;
 
876
  struct sockaddr_in    sin;
 
877
  unsigned int          size = sizeof(sin);
 
878
 
 
879
  if (getAddr(a, s, p, &sin) == NO)
 
880
    {
 
881
      RELEASE(self);
 
882
      NSLog(@"bad address-service-protocol combination");
 
883
      return  nil;
 
884
    }
 
885
 
 
886
  if ((net = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) == INVALID_SOCKET)
 
887
    {
 
888
      NSLog(@"unable to create socket - %s", GSLastErrorStr(errno));
 
889
      RELEASE(self);
 
890
      return nil;
 
891
    }
 
892
 
 
893
#ifndef BROKEN_SO_REUSEADDR
 
894
  /*
 
895
   * Under decent systems, SO_REUSEADDR means that the port can be reused
 
896
   * immediately that this process exits.  Under some it means
 
897
   * that multiple processes can serve the same port simultaneously.
 
898
   * We don't want that broken behavior!
 
899
   */
 
900
  setsockopt(net, SOL_SOCKET, SO_REUSEADDR, (char *)&status, sizeof(status));
 
901
#endif
 
902
 
 
903
  if (bind(net, (struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR)
 
904
    {
 
905
      NSLog(@"unable to bind to port %s:%d - %s", inet_ntoa(sin.sin_addr),
 
906
        GSSwapBigI16ToHost(sin.sin_port), GSLastErrorStr(errno));
 
907
      (void) closesocket(net);
 
908
      RELEASE(self);
 
909
      return nil;
 
910
    }
 
911
 
 
912
  if (listen(net, 256) == SOCKET_ERROR)
 
913
    {
 
914
      NSLog(@"unable to listen on port - %s", GSLastErrorStr(errno));
 
915
      (void) closesocket(net);
 
916
      RELEASE(self);
 
917
      return nil;
 
918
    }
 
919
 
 
920
  if (getsockname(net, (struct sockaddr*)&sin, &size) == SOCKET_ERROR)
 
921
    {
 
922
      NSLog(@"unable to get socket name - %s", GSLastErrorStr(errno));
 
923
      (void) closesocket(net);
 
924
      RELEASE(self);
 
925
      return nil;
 
926
    }
 
927
 
 
928
  self = [self initWithNativeHandle: (void*)net closeOnDealloc: YES];
 
929
  if (self)
 
930
    {
 
931
      isSocket = YES;
 
932
      connectOK = NO;
 
933
      acceptOK = YES;
 
934
      readOK = NO;
 
935
      writeOK = NO;
 
936
      [self setAddr: &sin];
 
937
    }
 
938
  return self;
 
939
}
 
940
 
 
941
- (id) initForReadingAtPath: (NSString*)path
 
942
{
 
943
  int   d = _wopen(
 
944
    (unichar*)[path cStringUsingEncoding: NSUnicodeStringEncoding],
 
945
    O_RDONLY|O_BINARY);
 
946
 
 
947
  if (d < 0)
 
948
    {
 
949
      RELEASE(self);
 
950
      return nil;
 
951
    }
 
952
  else
 
953
    {
 
954
      self = [self initWithFileDescriptor: d closeOnDealloc: YES];
 
955
      if (self)
 
956
        {
 
957
          connectOK = NO;
 
958
          acceptOK = NO;
 
959
          writeOK = NO;
 
960
        }
 
961
      return self;
 
962
    }
 
963
}
 
964
 
 
965
- (id) initForWritingAtPath: (NSString*)path
 
966
{
 
967
  int   d = _wopen(
 
968
    (unichar*)[path cStringUsingEncoding: NSUnicodeStringEncoding],
 
969
    O_WRONLY|O_BINARY);
 
970
 
 
971
  if (d < 0)
 
972
    {
 
973
      RELEASE(self);
 
974
      return nil;
 
975
    }
 
976
  else
 
977
    {
 
978
      self = [self initWithFileDescriptor: d closeOnDealloc: YES];
 
979
      if (self)
 
980
        {
 
981
          connectOK = NO;
 
982
          acceptOK = NO;
 
983
          readOK = NO;
 
984
        }
 
985
      return self;
 
986
    }
 
987
}
 
988
 
 
989
- (id) initForUpdatingAtPath: (NSString*)path
 
990
{
 
991
  int   d = _wopen(
 
992
    (unichar*)[path cStringUsingEncoding: NSUnicodeStringEncoding],
 
993
    O_RDWR|O_BINARY);
 
994
 
 
995
  if (d < 0)
 
996
    {
 
997
      RELEASE(self);
 
998
      return nil;
 
999
    }
 
1000
  else
 
1001
    {
 
1002
      self = [self initWithFileDescriptor: d closeOnDealloc: YES];
 
1003
      if (self != nil)
 
1004
        {
 
1005
          connectOK = NO;
 
1006
          acceptOK = NO;
 
1007
        }
 
1008
      return self;
 
1009
    }
 
1010
}
 
1011
 
 
1012
- (id) initWithStandardError
 
1013
{
 
1014
  if (fh_stderr != nil)
 
1015
    {
 
1016
      RETAIN(fh_stderr);
 
1017
      RELEASE(self);
 
1018
    }
 
1019
  else
 
1020
    {
 
1021
      self = [self initWithFileDescriptor: 2 closeOnDealloc: NO];
 
1022
      fh_stderr = self;
 
1023
    }
 
1024
  self = fh_stderr;
 
1025
  if (self)
 
1026
    {
 
1027
      readOK = NO;
 
1028
    }
 
1029
  return self;
 
1030
}
 
1031
 
 
1032
- (id) initWithStandardInput
 
1033
{
 
1034
  if (fh_stdin != nil)
 
1035
    {
 
1036
      RETAIN(fh_stdin);
 
1037
      RELEASE(self);
 
1038
    }
 
1039
  else
 
1040
    {
 
1041
      self = [self initWithFileDescriptor: 0 closeOnDealloc: NO];
 
1042
      fh_stdin = self;
 
1043
    }
 
1044
  self = fh_stdin;
 
1045
  if (self)
 
1046
    {
 
1047
      writeOK = NO;
 
1048
    }
 
1049
  return self;
 
1050
}
 
1051
 
 
1052
- (id) initWithStandardOutput
 
1053
{
 
1054
  if (fh_stdout != nil)
 
1055
    {
 
1056
      RETAIN(fh_stdout);
 
1057
      RELEASE(self);
 
1058
    }
 
1059
  else
 
1060
    {
 
1061
      self = [self initWithFileDescriptor: 1 closeOnDealloc: NO];
 
1062
      fh_stdout = self;
 
1063
    }
 
1064
  self = fh_stdout;
 
1065
  if (self)
 
1066
    {
 
1067
      readOK = NO;
 
1068
    }
 
1069
  return self;
 
1070
}
 
1071
 
 
1072
- (id) initWithNullDevice
 
1073
{
 
1074
  isNullDevice = YES;
 
1075
  isStandardFile = YES;
 
1076
  descriptor = -1;
 
1077
  return self;
 
1078
}
 
1079
 
 
1080
- (id) initWithFileDescriptor: (int)desc closeOnDealloc: (BOOL)flag
 
1081
{
 
1082
  self = [super init];
 
1083
  if (self != nil)
 
1084
    {
 
1085
      struct _stat sbuf;
 
1086
 
 
1087
      if (_fstat(desc, &sbuf) != 0)
 
1088
        {
 
1089
          NSLog(@"unable to get status of descriptor %d - %s",
 
1090
            desc, GSLastErrorStr(errno));
 
1091
        }
 
1092
      else
 
1093
        {
 
1094
          if (S_ISREG(sbuf.st_mode))
 
1095
            {
 
1096
              isStandardFile = YES;
 
1097
            }
 
1098
          else
 
1099
            {
 
1100
              isStandardFile = NO;
 
1101
            }
 
1102
        }
 
1103
 
 
1104
      if (isStandardFile == NO)
 
1105
        {
 
1106
          unsigned long nbio = 0;
 
1107
 
 
1108
          isSocket = YES;
 
1109
          /*
 
1110
           * This is probably a socket ... try
 
1111
           * using a socket specific call and see if that fails.
 
1112
           */
 
1113
          if (ioctlsocket((SOCKET)_get_osfhandle(desc), FIONBIO, &nbio) == 0)
 
1114
            {
 
1115
              wasNonBlocking = (nbio == 0) ? NO : YES;
 
1116
            }
 
1117
          else
 
1118
            {
 
1119
              isSocket = NO; // maybe special file desc. like std in/out/err?
 
1120
            }
 
1121
        }
 
1122
 
 
1123
      isNonBlocking = wasNonBlocking;
 
1124
      descriptor = desc;
 
1125
      closeOnDealloc = flag;
 
1126
      readInfo = nil;
 
1127
      writeInfo = [NSMutableArray new];
 
1128
      readMax = 0;
 
1129
      writePos = 0;
 
1130
      readOK = YES;
 
1131
      writeOK = YES;
 
1132
      acceptOK = YES;
 
1133
      connectOK = YES;
 
1134
      if (isSocket)
 
1135
        {
 
1136
          event = CreateEvent(NULL, NO, NO, NULL);
 
1137
          if (event == WSA_INVALID_EVENT)
 
1138
            {
 
1139
              NSLog(@"Invalid Event - '%d'", WSAGetLastError());
 
1140
              return nil;
 
1141
            }
 
1142
          WSAEventSelect(_get_osfhandle(descriptor), event, FD_ALL_EVENTS);
 
1143
        }
 
1144
      else
 
1145
        {
 
1146
          event = WSA_INVALID_EVENT;
 
1147
        }
 
1148
    }
 
1149
  return self;
 
1150
}
 
1151
 
 
1152
- (id) initWithNativeHandle: (void*)hdl
 
1153
{
 
1154
  return [self initWithFileDescriptor: _open_osfhandle((SOCKET)hdl, 0)
 
1155
                       closeOnDealloc: NO];
 
1156
}
 
1157
 
 
1158
- (id) initWithNativeHandle: (void*)hdl closeOnDealloc: (BOOL)flag
 
1159
{
 
1160
  return [self initWithFileDescriptor: _open_osfhandle((SOCKET)hdl, 0)
 
1161
                       closeOnDealloc: flag];
 
1162
}
 
1163
 
 
1164
- (void) checkAccept
 
1165
{
 
1166
  if (acceptOK == NO)
 
1167
    {
 
1168
      [NSException raise: NSFileHandleOperationException
 
1169
                  format: @"accept not permitted in this file handle"];
 
1170
    }
 
1171
  if (readInfo)
 
1172
    {
 
1173
      id        operation = [readInfo objectForKey: NotificationKey];
 
1174
 
 
1175
      if (operation == NSFileHandleConnectionAcceptedNotification)
 
1176
        {
 
1177
          [NSException raise: NSFileHandleOperationException
 
1178
                      format: @"accept already in progress"];
 
1179
        }
 
1180
      else
 
1181
        {
 
1182
          [NSException raise: NSFileHandleOperationException
 
1183
                      format: @"read already in progress"];
 
1184
        }
 
1185
    }
 
1186
}
 
1187
 
 
1188
- (void) checkConnect
 
1189
{
 
1190
  if (connectOK == NO)
 
1191
    {
 
1192
      [NSException raise: NSFileHandleOperationException
 
1193
                  format: @"connect not permitted in this file handle"];
 
1194
    }
 
1195
  if ([writeInfo count] > 0)
 
1196
    {
 
1197
      NSDictionary      *info = [writeInfo objectAtIndex: 0];
 
1198
      id                operation = [info objectForKey: NotificationKey];
 
1199
 
 
1200
      if (operation == GSFileHandleConnectCompletionNotification)
 
1201
        {
 
1202
          [NSException raise: NSFileHandleOperationException
 
1203
                      format: @"connect already in progress"];
 
1204
        }
 
1205
      else
 
1206
        {
 
1207
          [NSException raise: NSFileHandleOperationException
 
1208
                      format: @"write already in progress"];
 
1209
        }
 
1210
    }
 
1211
}
 
1212
 
 
1213
- (void) checkRead
 
1214
{
 
1215
  if (readOK == NO)
 
1216
    {
 
1217
      [NSException raise: NSFileHandleOperationException
 
1218
                  format: @"read not permitted on this file handle"];
 
1219
    }
 
1220
  if (readInfo)
 
1221
    {
 
1222
      id        operation = [readInfo objectForKey: NotificationKey];
 
1223
 
 
1224
      if (operation == NSFileHandleConnectionAcceptedNotification)
 
1225
        {
 
1226
          [NSException raise: NSFileHandleOperationException
 
1227
                      format: @"accept already in progress"];
 
1228
        }
 
1229
      else
 
1230
        {
 
1231
          [NSException raise: NSFileHandleOperationException
 
1232
                      format: @"read already in progress"];
 
1233
        }
 
1234
    }
 
1235
}
 
1236
 
 
1237
- (void) checkWrite
 
1238
{
 
1239
  if (writeOK == NO)
 
1240
    {
 
1241
      [NSException raise: NSFileHandleOperationException
 
1242
                  format: @"write not permitted in this file handle"];
 
1243
    }
 
1244
  if ([writeInfo count] > 0)
 
1245
    {
 
1246
      NSDictionary      *info = [writeInfo objectAtIndex: 0];
 
1247
      id                operation = [info objectForKey: NotificationKey];
 
1248
 
 
1249
      if (operation != GSFileHandleWriteCompletionNotification)
 
1250
        {
 
1251
          [NSException raise: NSFileHandleOperationException
 
1252
                      format: @"connect in progress"];
 
1253
        }
 
1254
    }
 
1255
}
 
1256
 
 
1257
// Returning file handles
 
1258
 
 
1259
- (int) fileDescriptor
 
1260
{
 
1261
  return descriptor;
 
1262
}
 
1263
 
 
1264
- (void*) nativeHandle
 
1265
{
 
1266
  return (void*)(SOCKET)_get_osfhandle(descriptor);
 
1267
}
 
1268
 
 
1269
// Synchronous I/O operations
 
1270
 
 
1271
- (NSData*) availableData
 
1272
{
 
1273
  char                  buf[READ_SIZE];
 
1274
  NSMutableData*        d;
 
1275
  int                   len;
 
1276
 
 
1277
  [self checkRead];
 
1278
  if (isNonBlocking == YES)
 
1279
    {
 
1280
      [self setNonBlocking: NO];
 
1281
    }
 
1282
  d = [NSMutableData dataWithCapacity: 0];
 
1283
  if (isStandardFile)
 
1284
    {
 
1285
      while ((len = [self read: buf length: sizeof(buf)]) > 0)
 
1286
        {
 
1287
          [d appendBytes: buf length: len];
 
1288
        }
 
1289
    }
 
1290
  else
 
1291
    {
 
1292
      len = [self read: buf length: sizeof(buf)];
 
1293
      if (len > 0)
 
1294
        {
 
1295
          [d appendBytes: buf length: len];
 
1296
        }
 
1297
    }
 
1298
  if (len < 0)
 
1299
    {
 
1300
      [NSException raise: NSFileHandleOperationException
 
1301
                  format: @"unable to read from descriptor - %s",
 
1302
                  GSLastErrorStr(errno)];
 
1303
    }
 
1304
  return d;
 
1305
}
 
1306
 
 
1307
- (NSData*) readDataToEndOfFile
 
1308
{
 
1309
  char                  buf[READ_SIZE];
 
1310
  NSMutableData*        d;
 
1311
  int                   len;
 
1312
 
 
1313
  [self checkRead];
 
1314
  if (isNonBlocking == YES)
 
1315
    {
 
1316
      [self setNonBlocking: NO];
 
1317
    }
 
1318
  d = [NSMutableData dataWithCapacity: 0];
 
1319
  while ((len = [self read: buf length: sizeof(buf)]) > 0)
 
1320
    {
 
1321
      [d appendBytes: buf length: len];
 
1322
    }
 
1323
  if (len < 0)
 
1324
    {
 
1325
      [NSException raise: NSFileHandleOperationException
 
1326
                  format: @"unable to read from descriptor - %s",
 
1327
                  GSLastErrorStr(errno)];
 
1328
    }
 
1329
  return d;
 
1330
}
 
1331
 
 
1332
- (NSData*) readDataOfLength: (unsigned)len
 
1333
{
 
1334
  NSMutableData *d;
 
1335
  int           got;
 
1336
 
 
1337
  [self checkRead];
 
1338
  if (isNonBlocking == YES)
 
1339
    {
 
1340
      [self setNonBlocking: NO];
 
1341
    }
 
1342
  if (len <= 65536)
 
1343
    {
 
1344
      char      *buf;
 
1345
 
 
1346
      buf = NSZoneMalloc(NSDefaultMallocZone(), len);
 
1347
      d = [NSMutableData dataWithBytesNoCopy: buf length: len];
 
1348
      got = [self read: [d mutableBytes] length: len];
 
1349
      if (got < 0)
 
1350
        {
 
1351
          [NSException raise: NSFileHandleOperationException
 
1352
                      format: @"unable to read from descriptor - %s",
 
1353
                      GSLastErrorStr(errno)];
 
1354
        }
 
1355
      [d setLength: got];
 
1356
    }
 
1357
  else
 
1358
    {
 
1359
      char      buf[READ_SIZE];
 
1360
 
 
1361
      d = [NSMutableData dataWithCapacity: 0];
 
1362
      do
 
1363
        {
 
1364
          int   chunk = len > sizeof(buf) ? sizeof(buf) : len;
 
1365
 
 
1366
          got = [self read: buf length: chunk];
 
1367
          if (got > 0)
 
1368
            {
 
1369
              [d appendBytes: buf length: got];
 
1370
              len -= got;
 
1371
            }
 
1372
          else if (got < 0)
 
1373
            {
 
1374
              [NSException raise: NSFileHandleOperationException
 
1375
                          format: @"unable to read from descriptor - %s",
 
1376
                          GSLastErrorStr(errno)];
 
1377
            }
 
1378
        }
 
1379
      while (len > 0 && got > 0);
 
1380
    }
 
1381
  return d;
 
1382
}
 
1383
 
 
1384
- (void) writeData: (NSData*)item
 
1385
{
 
1386
  int           rval = 0;
 
1387
  const void*   ptr = [item bytes];
 
1388
  unsigned int  len = [item length];
 
1389
  unsigned int  pos = 0;
 
1390
 
 
1391
  [self checkWrite];
 
1392
  if (isNonBlocking == YES)
 
1393
    {
 
1394
      [self setNonBlocking: NO];
 
1395
    }
 
1396
  while (pos < len)
 
1397
    {
 
1398
      int       toWrite = len - pos;
 
1399
 
 
1400
      if (toWrite > NETBUF_SIZE)
 
1401
        {
 
1402
          toWrite = NETBUF_SIZE;
 
1403
        }
 
1404
      rval = [self write: (char*)ptr+pos length: toWrite];
 
1405
      if (rval < 0)
 
1406
        {
 
1407
          if (WSAGetLastError()== WSAEINTR
 
1408
            || WSAGetLastError()== WSAEWOULDBLOCK)
 
1409
            {
 
1410
              rval = 0;
 
1411
            }
 
1412
          else
 
1413
            {
 
1414
              break;
 
1415
            }
 
1416
        }
 
1417
      pos += rval;
 
1418
    }
 
1419
  if (rval < 0)
 
1420
    {
 
1421
      [NSException raise: NSFileHandleOperationException
 
1422
                  format: @"unable to write to descriptor - %s",
 
1423
                  GSLastErrorStr(errno)];
 
1424
    }
 
1425
}
 
1426
 
 
1427
 
 
1428
// Asynchronous I/O operations
 
1429
 
 
1430
- (void) acceptConnectionInBackgroundAndNotifyForModes: (NSArray*)modes
 
1431
{
 
1432
  [self checkAccept];
 
1433
  readMax = 0;
 
1434
  RELEASE(readInfo);
 
1435
  readInfo = [[NSMutableDictionary alloc] initWithCapacity: 4];
 
1436
  [readInfo setObject: NSFileHandleConnectionAcceptedNotification
 
1437
               forKey: NotificationKey];
 
1438
  [self watchReadDescriptorForModes: modes];
 
1439
}
 
1440
 
 
1441
- (void) readDataInBackgroundAndNotifyLength: (unsigned)len
 
1442
                                    forModes: (NSArray*)modes
 
1443
{
 
1444
  NSMutableData *d;
 
1445
 
 
1446
  [self checkRead];
 
1447
  if (len > 0x7fffffff)
 
1448
    {
 
1449
      [NSException raise: NSInvalidArgumentException
 
1450
                  format: @"length (%u) too large", len];
 
1451
    }
 
1452
  readMax = len;
 
1453
  RELEASE(readInfo);
 
1454
  readInfo = [[NSMutableDictionary alloc] initWithCapacity: 4];
 
1455
  [readInfo setObject: NSFileHandleReadCompletionNotification
 
1456
               forKey: NotificationKey];
 
1457
  d = [[NSMutableData alloc] initWithCapacity: readMax];
 
1458
  [readInfo setObject: d forKey: NSFileHandleNotificationDataItem];
 
1459
  RELEASE(d);
 
1460
  [self watchReadDescriptorForModes: modes];
 
1461
}
 
1462
 
 
1463
- (void) readInBackgroundAndNotifyForModes: (NSArray*)modes
 
1464
{
 
1465
  NSMutableData *d;
 
1466
 
 
1467
  [self checkRead];
 
1468
  readMax = -1;         // Accept any quantity of data.
 
1469
  RELEASE(readInfo);
 
1470
  readInfo = [[NSMutableDictionary alloc] initWithCapacity: 4];
 
1471
  [readInfo setObject: NSFileHandleReadCompletionNotification
 
1472
               forKey: NotificationKey];
 
1473
  d = [[NSMutableData alloc] initWithCapacity: 0];
 
1474
  [readInfo setObject: d forKey: NSFileHandleNotificationDataItem];
 
1475
  RELEASE(d);
 
1476
  [self watchReadDescriptorForModes: modes];
 
1477
}
 
1478
 
 
1479
- (void) readToEndOfFileInBackgroundAndNotifyForModes: (NSArray*)modes
 
1480
{
 
1481
  NSMutableData *d;
 
1482
 
 
1483
  [self checkRead];
 
1484
  readMax = 0;
 
1485
  RELEASE(readInfo);
 
1486
  readInfo = [[NSMutableDictionary alloc] initWithCapacity: 4];
 
1487
  [readInfo setObject: NSFileHandleReadToEndOfFileCompletionNotification
 
1488
               forKey: NotificationKey];
 
1489
  d = [[NSMutableData alloc] initWithCapacity: 0];
 
1490
  [readInfo setObject: d forKey: NSFileHandleNotificationDataItem];
 
1491
  RELEASE(d);
 
1492
  [self watchReadDescriptorForModes: modes];
 
1493
}
 
1494
 
 
1495
- (void) waitForDataInBackgroundAndNotifyForModes: (NSArray*)modes
 
1496
{
 
1497
  [self checkRead];
 
1498
  readMax = 0;
 
1499
  RELEASE(readInfo);
 
1500
  readInfo = [[NSMutableDictionary alloc] initWithCapacity: 4];
 
1501
  [readInfo setObject: NSFileHandleDataAvailableNotification
 
1502
               forKey: NotificationKey];
 
1503
  [readInfo setObject: [NSMutableData dataWithCapacity: 0]
 
1504
               forKey: NSFileHandleNotificationDataItem];
 
1505
  [self watchReadDescriptorForModes: modes];
 
1506
}
 
1507
 
 
1508
// Seeking within a file
 
1509
 
 
1510
- (unsigned long long) offsetInFile
 
1511
{
 
1512
  off_t result = -1;
 
1513
 
 
1514
  if (isStandardFile && descriptor >= 0)
 
1515
    {
 
1516
#if     USE_ZLIB
 
1517
      if (gzDescriptor != 0)
 
1518
        {
 
1519
          result = gzseek(gzDescriptor, 0, SEEK_CUR);
 
1520
        }
 
1521
      else
 
1522
#endif
 
1523
      result = _lseek(descriptor, 0, SEEK_CUR);
 
1524
    }
 
1525
  if (result < 0)
 
1526
    {
 
1527
      [NSException raise: NSFileHandleOperationException
 
1528
                  format: @"failed to move to offset in file - %s",
 
1529
                  GSLastErrorStr(errno)];
 
1530
    }
 
1531
  return (unsigned long long)result;
 
1532
}
 
1533
 
 
1534
- (unsigned long long) seekToEndOfFile
 
1535
{
 
1536
  off_t result = -1;
 
1537
 
 
1538
  if (isStandardFile && descriptor >= 0)
 
1539
    {
 
1540
#if     USE_ZLIB
 
1541
      if (gzDescriptor != 0)
 
1542
        {
 
1543
          result = gzseek(gzDescriptor, 0, SEEK_END);
 
1544
        }
 
1545
      else
 
1546
#endif
 
1547
      result = _lseek(descriptor, 0, SEEK_END);
 
1548
    }
 
1549
  if (result < 0)
 
1550
    {
 
1551
      [NSException raise: NSFileHandleOperationException
 
1552
                  format: @"failed to move to offset in file - %s",
 
1553
                  GSLastErrorStr(errno)];
 
1554
    }
 
1555
  return (unsigned long long)result;
 
1556
}
 
1557
 
 
1558
- (void) seekToFileOffset: (unsigned long long)pos
 
1559
{
 
1560
  off_t result = -1;
 
1561
 
 
1562
  if (isStandardFile && descriptor >= 0)
 
1563
    {
 
1564
#if     USE_ZLIB
 
1565
      if (gzDescriptor != 0)
 
1566
        {
 
1567
          result = gzseek(gzDescriptor, (off_t)pos, SEEK_SET);
 
1568
        }
 
1569
      else
 
1570
#endif
 
1571
      result = _lseek(descriptor, (off_t)pos, SEEK_SET);
 
1572
    }
 
1573
  if (result < 0)
 
1574
    {
 
1575
      [NSException raise: NSFileHandleOperationException
 
1576
                  format: @"failed to move to offset in file - %s",
 
1577
                  GSLastErrorStr(errno)];
 
1578
    }
 
1579
}
 
1580
 
 
1581
 
 
1582
// Operations on file
 
1583
 
 
1584
- (void) closeFile
 
1585
{
 
1586
  if (descriptor < 0)
 
1587
    {
 
1588
      [NSException raise: NSFileHandleOperationException
 
1589
                  format: @"attempt to close closed file"];
 
1590
    }
 
1591
  [self ignoreReadDescriptor];
 
1592
  [self ignoreWriteDescriptor];
 
1593
 
 
1594
  [self setNonBlocking: wasNonBlocking];
 
1595
#if     USE_ZLIB
 
1596
  if (gzDescriptor != 0)
 
1597
    {
 
1598
      gzclose(gzDescriptor);
 
1599
      gzDescriptor = 0;
 
1600
    }
 
1601
#endif
 
1602
  if (isSocket)
 
1603
    {
 
1604
      (void)closesocket((SOCKET)_get_osfhandle(descriptor));
 
1605
      WSACloseEvent(event);
 
1606
      event = WSA_INVALID_EVENT;
 
1607
    }
 
1608
  (void)close(descriptor);
 
1609
  descriptor = -1;
 
1610
  acceptOK = NO;
 
1611
  connectOK = NO;
 
1612
  readOK = NO;
 
1613
  writeOK = NO;
 
1614
 
 
1615
  /*
 
1616
   *    Clear any pending operations on the file handle, sending
 
1617
   *    notifications if necessary.
 
1618
   */
 
1619
  if (readInfo)
 
1620
    {
 
1621
      [readInfo setObject: @"File handle closed locally"
 
1622
                   forKey: GSFileHandleNotificationError];
 
1623
      [self postReadNotification];
 
1624
    }
 
1625
 
 
1626
  if ([writeInfo count])
 
1627
    {
 
1628
      NSMutableDictionary       *info = [writeInfo objectAtIndex: 0];
 
1629
 
 
1630
      [info setObject: @"File handle closed locally"
 
1631
               forKey: GSFileHandleNotificationError];
 
1632
      [self postWriteNotification];
 
1633
      [writeInfo removeAllObjects];
 
1634
    }
 
1635
}
 
1636
 
 
1637
- (void) synchronizeFile
 
1638
{
 
1639
  if (isStandardFile)
 
1640
    {
 
1641
      (void)_commit(descriptor);
 
1642
    }
 
1643
}
 
1644
 
 
1645
- (void) truncateFileAtOffset: (unsigned long long)pos
 
1646
{
 
1647
  _chsize(descriptor, pos);
 
1648
  [self seekToFileOffset: pos];
 
1649
}
 
1650
 
 
1651
- (void) writeInBackgroundAndNotify: (NSData*)item forModes: (NSArray*)modes
 
1652
{
 
1653
  NSMutableDictionary*  info;
 
1654
 
 
1655
  [self checkWrite];
 
1656
 
 
1657
  info = [[NSMutableDictionary alloc] initWithCapacity: 4];
 
1658
  [info setObject: item forKey: NSFileHandleNotificationDataItem];
 
1659
  [info setObject: GSFileHandleWriteCompletionNotification
 
1660
                forKey: NotificationKey];
 
1661
  if (modes != nil)
 
1662
    {
 
1663
      [info setObject: modes forKey: NSFileHandleNotificationMonitorModes];
 
1664
    }
 
1665
  [writeInfo addObject: info];
 
1666
  RELEASE(info);
 
1667
  [self watchWriteDescriptor];
 
1668
}
 
1669
 
 
1670
- (void) writeInBackgroundAndNotify: (NSData*)item;
 
1671
{
 
1672
  [self writeInBackgroundAndNotify: item forModes: nil];
 
1673
}
 
1674
 
 
1675
- (void) postReadNotification
 
1676
{
 
1677
  NSMutableDictionary   *info = readInfo;
 
1678
  NSNotification        *n;
 
1679
  NSNotificationQueue   *q;
 
1680
  NSArray               *modes;
 
1681
  NSString              *name;
 
1682
 
 
1683
  [self ignoreReadDescriptor];
 
1684
  readInfo = nil;
 
1685
  readMax = 0;
 
1686
  modes = (NSArray*)[info objectForKey: NSFileHandleNotificationMonitorModes];
 
1687
  name = (NSString*)[info objectForKey: NotificationKey];
 
1688
 
 
1689
  if (name == nil)
 
1690
    {
 
1691
      return;
 
1692
    }
 
1693
  n = [NSNotification notificationWithName: name object: self userInfo: info];
 
1694
 
 
1695
  RELEASE(info);        /* Retained by the notification.        */
 
1696
 
 
1697
  q = [NSNotificationQueue defaultQueue];
 
1698
  [q enqueueNotification: n
 
1699
            postingStyle: NSPostASAP
 
1700
            coalesceMask: NSNotificationNoCoalescing
 
1701
                forModes: modes];
 
1702
}
 
1703
 
 
1704
- (void) postWriteNotification
 
1705
{
 
1706
  NSMutableDictionary   *info = [writeInfo objectAtIndex: 0];
 
1707
  NSNotificationQueue   *q;
 
1708
  NSNotification        *n;
 
1709
  NSArray               *modes;
 
1710
  NSString              *name;
 
1711
 
 
1712
  [self ignoreWriteDescriptor];
 
1713
  modes = (NSArray*)[info objectForKey: NSFileHandleNotificationMonitorModes];
 
1714
  name = (NSString*)[info objectForKey: NotificationKey];
 
1715
 
 
1716
  n = [NSNotification notificationWithName: name object: self userInfo: info];
 
1717
 
 
1718
  writePos = 0;
 
1719
  [writeInfo removeObjectAtIndex: 0];   /* Retained by notification.    */
 
1720
 
 
1721
  q = [NSNotificationQueue defaultQueue];
 
1722
  [q enqueueNotification: n
 
1723
            postingStyle: NSPostASAP
 
1724
            coalesceMask: NSNotificationNoCoalescing
 
1725
                forModes: modes];
 
1726
  if ((writeOK || connectOK) && [writeInfo count] > 0)
 
1727
    {
 
1728
      [self watchWriteDescriptor];      /* In case of queued writes.    */
 
1729
    }
 
1730
}
 
1731
 
 
1732
- (BOOL) readInProgress
 
1733
{
 
1734
  if (readInfo)
 
1735
    {
 
1736
      return YES;
 
1737
    }
 
1738
  return NO;
 
1739
}
 
1740
 
 
1741
- (BOOL) writeInProgress
 
1742
{
 
1743
  if ([writeInfo count] > 0)
 
1744
    {
 
1745
      return YES;
 
1746
    }
 
1747
  return NO;
 
1748
}
 
1749
 
 
1750
- (void) ignoreReadDescriptor
 
1751
{
 
1752
  NSRunLoop     *l;
 
1753
  NSArray       *modes;
 
1754
 
 
1755
  if (descriptor < 0)
 
1756
    {
 
1757
      return;
 
1758
    }
 
1759
  l = [NSRunLoop currentRunLoop];
 
1760
  modes = nil;
 
1761
 
 
1762
  if (readInfo)
 
1763
    {
 
1764
      modes = (NSArray*)[readInfo objectForKey:
 
1765
        NSFileHandleNotificationMonitorModes];
 
1766
    }
 
1767
 
 
1768
  if (modes && [modes count])
 
1769
    {
 
1770
      unsigned int      i;
 
1771
 
 
1772
      for (i = 0; i < [modes count]; i++)
 
1773
        {
 
1774
          [l removeEvent: (void*)(gsaddr)event
 
1775
                    type: ET_HANDLE
 
1776
                 forMode: [modes objectAtIndex: i]
 
1777
                     all: YES];
 
1778
        }
 
1779
    }
 
1780
  else
 
1781
    {
 
1782
      [l removeEvent: (void*)(gsaddr)event
 
1783
                type: ET_HANDLE
 
1784
             forMode: NSDefaultRunLoopMode
 
1785
                 all: YES];
 
1786
    }
 
1787
}
 
1788
 
 
1789
- (void) ignoreWriteDescriptor
 
1790
{
 
1791
  NSRunLoop     *l;
 
1792
  NSArray       *modes;
 
1793
 
 
1794
  if (descriptor < 0)
 
1795
    {
 
1796
      return;
 
1797
    }
 
1798
  l = [NSRunLoop currentRunLoop];
 
1799
  modes = nil;
 
1800
 
 
1801
  if ([writeInfo count] > 0)
 
1802
    {
 
1803
      NSMutableDictionary*      info = [writeInfo objectAtIndex: 0];
 
1804
 
 
1805
      modes=(NSArray*)[info objectForKey: NSFileHandleNotificationMonitorModes];
 
1806
    }
 
1807
 
 
1808
  if (modes && [modes count])
 
1809
    {
 
1810
      unsigned int      i;
 
1811
 
 
1812
      for (i = 0; i < [modes count]; i++)
 
1813
        {
 
1814
          [l removeEvent: (void*)(gsaddr)event
 
1815
                    type: ET_HANDLE
 
1816
                 forMode: [modes objectAtIndex: i]
 
1817
                     all: YES];
 
1818
        }
 
1819
    }
 
1820
  else
 
1821
    {
 
1822
      [l removeEvent: (void*)(gsaddr)event
 
1823
                type: ET_HANDLE
 
1824
             forMode: NSDefaultRunLoopMode
 
1825
                 all: YES];
 
1826
    }
 
1827
}
 
1828
 
 
1829
- (void) watchReadDescriptorForModes: (NSArray*)modes;
 
1830
{
 
1831
  NSRunLoop     *l;
 
1832
 
 
1833
  if (descriptor < 0)
 
1834
    {
 
1835
      return;
 
1836
    }
 
1837
 
 
1838
  l = [NSRunLoop currentRunLoop];
 
1839
  [self setNonBlocking: YES];
 
1840
  if (modes && [modes count])
 
1841
    {
 
1842
      unsigned int      i;
 
1843
 
 
1844
      for (i = 0; i < [modes count]; i++)
 
1845
        {
 
1846
          [l addEvent: (void*)(gsaddr)event
 
1847
                 type: ET_HANDLE
 
1848
              watcher: self
 
1849
              forMode: [modes objectAtIndex: i]];
 
1850
        }
 
1851
      [readInfo setObject: modes forKey: NSFileHandleNotificationMonitorModes];
 
1852
    }
 
1853
  else
 
1854
    {
 
1855
      [l addEvent: (void*)(gsaddr)event
 
1856
             type: ET_HANDLE
 
1857
          watcher: self
 
1858
          forMode: NSDefaultRunLoopMode];
 
1859
    }
 
1860
}
 
1861
 
 
1862
- (void) watchWriteDescriptor
 
1863
{
 
1864
  if (descriptor < 0)
 
1865
    {
 
1866
      return;
 
1867
    }
 
1868
  if ([writeInfo count] > 0)
 
1869
    {
 
1870
      NSMutableDictionary       *info = [writeInfo objectAtIndex: 0];
 
1871
      NSRunLoop                 *l = [NSRunLoop currentRunLoop];
 
1872
      NSArray                   *modes = nil;
 
1873
 
 
1874
      modes = [info objectForKey: NSFileHandleNotificationMonitorModes];
 
1875
 
 
1876
      [self setNonBlocking: YES];
 
1877
      if (modes && [modes count])
 
1878
        {
 
1879
          unsigned int  i;
 
1880
 
 
1881
          for (i = 0; i < [modes count]; i++)
 
1882
            {
 
1883
              [l addEvent: (void*)(gsaddr)event
 
1884
                     type: ET_HANDLE
 
1885
                  watcher: self
 
1886
                  forMode: [modes objectAtIndex: i]];
 
1887
            }
 
1888
        }
 
1889
      else
 
1890
        {
 
1891
          [l addEvent: (void*)(gsaddr)event
 
1892
                 type: ET_HANDLE
 
1893
              watcher: self
 
1894
              forMode: NSDefaultRunLoopMode];
 
1895
        }
 
1896
    }
 
1897
}
 
1898
 
 
1899
- (void) receivedEventRead
 
1900
{
 
1901
  NSString      *operation;
 
1902
 
 
1903
  operation = [readInfo objectForKey: NotificationKey];
 
1904
  if (operation == NSFileHandleConnectionAcceptedNotification)
 
1905
    {
 
1906
      struct sockaddr_in        buf;
 
1907
      SOCKET                    desc;
 
1908
      unsigned int              blen = sizeof(buf);
 
1909
 
 
1910
      desc = accept((SOCKET)_get_osfhandle(descriptor),
 
1911
        (struct sockaddr*)&buf, &blen);
 
1912
 
 
1913
      if (desc == INVALID_SOCKET)
 
1914
        {
 
1915
          NSString      *s;
 
1916
 
 
1917
          s = [NSString stringWithFormat: @"Accept attempt failed - %s",
 
1918
                GSLastErrorStr(errno)];
 
1919
          [readInfo setObject: s forKey: GSFileHandleNotificationError];
 
1920
        }
 
1921
      else
 
1922
        { // Accept attempt completed.
 
1923
          GSFileHandle          *h;
 
1924
          struct sockaddr_in    sin;
 
1925
          unsigned int          size = sizeof(sin);
 
1926
          int                   status;
 
1927
 
 
1928
          /*
 
1929
           * Enable tcp-level tracking of whether connection is alive.
 
1930
           */
 
1931
          status = 1;
 
1932
          setsockopt(desc, SOL_SOCKET, SO_KEEPALIVE, (char *)&status,
 
1933
            sizeof(status));
 
1934
 
 
1935
          h = [[[self class] alloc] initWithNativeHandle: (void*)desc
 
1936
                                                closeOnDealloc: YES];
 
1937
          h->isSocket = YES;
 
1938
          getpeername(desc, (struct sockaddr*)&sin, &size);
 
1939
          [h setAddr: &sin];
 
1940
          [readInfo setObject: h
 
1941
                   forKey: NSFileHandleNotificationFileHandleItem];
 
1942
          RELEASE(h);
 
1943
        }
 
1944
      [self postReadNotification];
 
1945
    }
 
1946
  else if (operation == NSFileHandleDataAvailableNotification)
 
1947
    {
 
1948
      [self postReadNotification];
 
1949
    }
 
1950
  else
 
1951
    {
 
1952
      NSMutableData     *item;
 
1953
      int               length;
 
1954
      int               received = 0;
 
1955
      char              buf[READ_SIZE];
 
1956
 
 
1957
      item = [readInfo objectForKey: NSFileHandleNotificationDataItem];
 
1958
      /*
 
1959
       * We may have a maximum data size set...
 
1960
       */
 
1961
      if (readMax > 0)
 
1962
        {
 
1963
          length = (unsigned int)readMax - [item length];
 
1964
          if (length > (int)sizeof(buf))
 
1965
            {
 
1966
              length = sizeof(buf);
 
1967
            }
 
1968
        }
 
1969
      else
 
1970
        {
 
1971
          length = sizeof(buf);
 
1972
        }
 
1973
 
 
1974
      received = [self read: buf length: length];
 
1975
      if (received == 0)
 
1976
        { // Read up to end of file.
 
1977
          [self postReadNotification];
 
1978
        }
 
1979
      else if (received < 0)
 
1980
        {
 
1981
          if (WSAGetLastError() != WSAEINTR
 
1982
            && WSAGetLastError() != WSAEWOULDBLOCK)
 
1983
            {
 
1984
              NSString  *s;
 
1985
 
 
1986
              s = [NSString stringWithFormat: @"Read attempt failed - %s",
 
1987
                    GSLastErrorStr(errno)];
 
1988
              [readInfo setObject: s forKey: GSFileHandleNotificationError];
 
1989
              [self postReadNotification];
 
1990
            }
 
1991
        }
 
1992
      else
 
1993
        {
 
1994
          [item appendBytes: buf length: received];
 
1995
          if (readMax < 0 || (readMax > 0 && (int)[item length] == readMax))
 
1996
            {
 
1997
              // Read a single chunk of data
 
1998
              [self postReadNotification];
 
1999
            }
 
2000
        }
 
2001
    }
 
2002
}
 
2003
 
 
2004
- (void) receivedEventWrite
 
2005
{
 
2006
  NSString      *operation;
 
2007
  NSMutableDictionary   *info;
 
2008
 
 
2009
  info = [writeInfo objectAtIndex: 0];
 
2010
  operation = [info objectForKey: NotificationKey];
 
2011
  if (operation == GSFileHandleConnectCompletionNotification
 
2012
    || operation == GSSOCKSConnect)
 
2013
    { // Connection attempt completed.
 
2014
      int       result;
 
2015
      unsigned  len = sizeof(result);
 
2016
 
 
2017
      if (getsockopt((SOCKET)_get_osfhandle(descriptor), SOL_SOCKET, SO_ERROR,
 
2018
        (char*)&result, &len) == 0 && result != 0)
 
2019
        {
 
2020
          NSString      *s;
 
2021
 
 
2022
          s = [NSString stringWithFormat: @"Connect attempt failed - %s",
 
2023
                GSLastErrorStr(result)];
 
2024
          [info setObject: s forKey: GSFileHandleNotificationError];
 
2025
        }
 
2026
      else
 
2027
        {
 
2028
          readOK = YES;
 
2029
          writeOK = YES;
 
2030
        }
 
2031
      connectOK = NO;
 
2032
      [self postWriteNotification];
 
2033
    }
 
2034
  else
 
2035
    {
 
2036
      NSData    *item;
 
2037
      int               length;
 
2038
      const void        *ptr;
 
2039
 
 
2040
      item = [info objectForKey: NSFileHandleNotificationDataItem];
 
2041
      length = [item length];
 
2042
      ptr = [item bytes];
 
2043
      if (writePos < length)
 
2044
        {
 
2045
          int   written;
 
2046
 
 
2047
          written = [self write: (char*)ptr+writePos
 
2048
                     length: length-writePos];
 
2049
          if (written <= 0)
 
2050
            {
 
2051
              if (written < 0 && WSAGetLastError()!= WSAEINTR
 
2052
                && WSAGetLastError()!= WSAEWOULDBLOCK)
 
2053
                {
 
2054
                  NSString      *s;
 
2055
 
 
2056
                  s = [NSString stringWithFormat:
 
2057
                        @"Write attempt failed - %s", GSLastErrorStr(errno)];
 
2058
                  [info setObject: s forKey: GSFileHandleNotificationError];
 
2059
                  [self postWriteNotification];
 
2060
                }
 
2061
            }
 
2062
          else
 
2063
            {
 
2064
              writePos += written;
 
2065
            }
 
2066
        }
 
2067
      if (writePos >= length)
 
2068
        { // Write operation completed.
 
2069
          [self postWriteNotification];
 
2070
        }
 
2071
    }
 
2072
}
 
2073
 
 
2074
- (void) receivedEvent: (void*)data
 
2075
                  type: (RunLoopEventType)type
 
2076
                 extra: (void*)extra
 
2077
               forMode: (NSString*)mode
 
2078
{
 
2079
  WSANETWORKEVENTS ocurredEvents;
 
2080
 
 
2081
  NSDebugMLLog(@"NSFileHandle", @"%@ event: %d", self, type);
 
2082
 
 
2083
  if (isNonBlocking == NO)
 
2084
    {
 
2085
      [self setNonBlocking: YES];
 
2086
    }
 
2087
  if (WSAEnumNetworkEvents((SOCKET)_get_osfhandle(descriptor), 
 
2088
    event, &ocurredEvents) == SOCKET_ERROR)
 
2089
    {
 
2090
      NSLog(@"Error getting event type %d", WSAGetLastError());
 
2091
      abort();
 
2092
    }
 
2093
  if (ocurredEvents.lNetworkEvents & FD_CONNECT)
 
2094
    {
 
2095
      NSDebugMLLog(@"NSFileHandle", @"Connect on %x", extra);
 
2096
      ocurredEvents.lNetworkEvents ^= FD_CONNECT;
 
2097
      [self receivedEventWrite];
 
2098
      GSNotifyASAP();
 
2099
    }
 
2100
  if (ocurredEvents.lNetworkEvents & FD_ACCEPT)
 
2101
    {
 
2102
      NSDebugMLLog(@"NSFileHandle", @"Accept on %x", extra);
 
2103
      ocurredEvents.lNetworkEvents ^= FD_ACCEPT;
 
2104
      [self receivedEventRead];
 
2105
      GSNotifyASAP();
 
2106
    }
 
2107
  if (ocurredEvents.lNetworkEvents & FD_WRITE)
 
2108
    {
 
2109
      NSDebugMLLog(@"NSFileHandle", @"Write on %x", extra);
 
2110
      ocurredEvents.lNetworkEvents ^= FD_WRITE;
 
2111
      [self receivedEventWrite];
 
2112
      GSNotifyASAP();
 
2113
    }
 
2114
  if (ocurredEvents.lNetworkEvents & FD_READ)
 
2115
    {
 
2116
      NSDebugMLLog(@"NSFileHandle", @"Read on %x", extra);
 
2117
      ocurredEvents.lNetworkEvents ^= FD_READ;
 
2118
      [self receivedEventRead];
 
2119
      GSNotifyASAP();
 
2120
    }
 
2121
  if (ocurredEvents.lNetworkEvents & FD_OOB)
 
2122
    {
 
2123
      NSDebugMLLog(@"NSFileHandle", @"OOB on %x", extra);
 
2124
      ocurredEvents.lNetworkEvents ^= FD_OOB;
 
2125
      [self receivedEventRead];
 
2126
      GSNotifyASAP();
 
2127
    }
 
2128
  if (ocurredEvents.lNetworkEvents & FD_CLOSE)
 
2129
    {
 
2130
      NSDebugMLLog(@"NSFileHandle", @"Close on %x", extra);
 
2131
      ocurredEvents.lNetworkEvents ^= FD_CLOSE;
 
2132
      if ([writeInfo count] > 0)
 
2133
        {
 
2134
          [self receivedEventWrite];
 
2135
        }
 
2136
      else
 
2137
        {
 
2138
          [self receivedEventRead];
 
2139
        }
 
2140
      GSNotifyASAP();
 
2141
    }
 
2142
  if (ocurredEvents.lNetworkEvents)
 
2143
    {
 
2144
      NSLog(@"Event not get %d", ocurredEvents.lNetworkEvents);
 
2145
      abort();      
 
2146
    }
 
2147
}
 
2148
 
 
2149
- (NSDate*) timedOutEvent: (void*)data
 
2150
                     type: (RunLoopEventType)type
 
2151
                  forMode: (NSString*)mode
 
2152
{
 
2153
  return nil;           /* Don't restart timed out events       */
 
2154
}
 
2155
 
 
2156
- (void) setAddr: (struct sockaddr_in *)sin
 
2157
{
 
2158
  address = [[NSString alloc] initWithCString: (char*)inet_ntoa(sin->sin_addr)];
 
2159
  service = [[NSString alloc] initWithFormat: @"%d",
 
2160
    (int)GSSwapBigI16ToHost(sin->sin_port)];
 
2161
  protocol = @"tcp";
 
2162
}
 
2163
 
 
2164
- (void) setNonBlocking: (BOOL)flag
 
2165
{
 
2166
  if (descriptor < 0)
 
2167
    {
 
2168
      return;
 
2169
    }
 
2170
  else if (isStandardFile == YES)
 
2171
    {
 
2172
      return;
 
2173
    }
 
2174
  else if (isNonBlocking == flag)
 
2175
    {
 
2176
      return;
 
2177
    }
 
2178
  else
 
2179
    {
 
2180
      unsigned long     dummy;
 
2181
 
 
2182
      if (isSocket != YES)
 
2183
        return;
 
2184
 
 
2185
      if (flag)
 
2186
        {
 
2187
          dummy = 1;
 
2188
          if (ioctlsocket((SOCKET)_get_osfhandle(descriptor), FIONBIO, &dummy)
 
2189
            == SOCKET_ERROR)
 
2190
            {
 
2191
              NSLog(@"unable to set non-blocking mode - %s",
 
2192
                GSLastErrorStr(errno));
 
2193
            }
 
2194
          else
 
2195
            isNonBlocking = flag;
 
2196
        }
 
2197
      else
 
2198
        {
 
2199
          dummy = 0;
 
2200
          if (ioctlsocket((SOCKET)_get_osfhandle(descriptor), FIONBIO, &dummy)
 
2201
            == SOCKET_ERROR)
 
2202
            {
 
2203
              NSLog(@"unable to set blocking mode - %s",
 
2204
                GSLastErrorStr(errno));
 
2205
            }
 
2206
          else
 
2207
            isNonBlocking = flag;
 
2208
        }
 
2209
    }
 
2210
}
 
2211
 
 
2212
- (NSString*) socketAddress
 
2213
{
 
2214
  return address;
 
2215
}
 
2216
 
 
2217
- (NSString*) socketLocalAddress
 
2218
{
 
2219
  NSString      *str = nil;
 
2220
  struct sockaddr_in sin;
 
2221
  unsigned      size = sizeof(sin);
 
2222
 
 
2223
  if (getsockname(descriptor, (struct sockaddr*)&sin, &size) == SOCKET_ERROR)
 
2224
    {
 
2225
      NSLog(@"unable to get socket name - %s", GSLastErrorStr(errno));
 
2226
    }
 
2227
  else
 
2228
    {
 
2229
      str = [NSString stringWithCString: (char*)inet_ntoa(sin.sin_addr)];
 
2230
    }
 
2231
  return str;
 
2232
}
 
2233
 
 
2234
- (NSString*) socketLocalService
 
2235
{
 
2236
  NSString      *str = nil;
 
2237
  struct sockaddr_in sin;
 
2238
  unsigned      size = sizeof(sin);
 
2239
 
 
2240
  if (getsockname(descriptor, (struct sockaddr*)&sin, &size) == SOCKET_ERROR)
 
2241
    {
 
2242
      NSLog(@"unable to get socket name - %s", GSLastErrorStr(errno));
 
2243
    }
 
2244
  else
 
2245
    {
 
2246
      str = [NSString stringWithFormat: @"%d",
 
2247
        (int)GSSwapBigI16ToHost(sin.sin_port)];
 
2248
    }
 
2249
  return str;
 
2250
}
 
2251
 
 
2252
- (NSString*) socketProtocol
 
2253
{
 
2254
  return protocol;
 
2255
}
 
2256
 
 
2257
- (NSString*) socketService
 
2258
{
 
2259
  return service;
 
2260
}
 
2261
 
 
2262
- (BOOL) useCompression
 
2263
{
 
2264
#if     USE_ZLIB
 
2265
  int   d;
 
2266
 
 
2267
  if (gzDescriptor != 0)
 
2268
    {
 
2269
      return YES;       // Already open
 
2270
    }
 
2271
  if (descriptor < 0)
 
2272
    {
 
2273
      return NO;        // No descriptor available.
 
2274
    }
 
2275
  if (readOK == YES && writeOK == YES)
 
2276
    {
 
2277
      return NO;        // Can't both read and write.
 
2278
    }
 
2279
  d = dup(descriptor);
 
2280
  if (d < 0)
 
2281
    {
 
2282
      return NO;        // No descriptor available.
 
2283
    }
 
2284
  if (readOK == YES)
 
2285
    {
 
2286
      gzDescriptor = gzdopen(d, "rb");
 
2287
    }
 
2288
  else
 
2289
    {
 
2290
      gzDescriptor = gzdopen(d, "wb");
 
2291
    }
 
2292
  if (gzDescriptor == 0)
 
2293
    {
 
2294
      close(d);
 
2295
      return NO;        // Open attempt failed.
 
2296
    }
 
2297
  return YES;
 
2298
#endif
 
2299
  return NO;
 
2300
}
 
2301
@end
 
2302