~ubuntu-branches/ubuntu/karmic/gnustep-base/karmic

« back to all changes in this revision

Viewing changes to Source/NSMessagePort.m

  • Committer: Bazaar Package Importer
  • Author(s): Eric Heintzmann
  • Date: 2005-04-17 00:14:38 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050417001438-enf0y07c9tku85z1
Tags: 1.10.3-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** Implementation of network port object based on unix domain sockets
 
2
   Copyright (C) 2000 Free Software Foundation, Inc.
 
3
 
 
4
   Written by:  Richard Frith-Macdonald <richard@brainstorm.co.uk>
 
5
   Based on code by:  Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
 
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., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
 
22
   */
 
23
 
 
24
#include "config.h"
 
25
#include "GNUstepBase/preface.h"
 
26
#include "GNUstepBase/GSLock.h"
 
27
#include "Foundation/NSArray.h"
 
28
#include "Foundation/NSNotification.h"
 
29
#include "Foundation/NSException.h"
 
30
#include "Foundation/NSRunLoop.h"
 
31
#include "Foundation/NSByteOrder.h"
 
32
#include "Foundation/NSData.h"
 
33
#include "Foundation/NSDate.h"
 
34
#include "Foundation/NSMapTable.h"
 
35
#include "Foundation/NSPortMessage.h"
 
36
#include "Foundation/NSPortNameServer.h"
 
37
#include "Foundation/NSLock.h"
 
38
#include "Foundation/NSThread.h"
 
39
#include "Foundation/NSConnection.h"
 
40
#include "Foundation/NSDebug.h"
 
41
#include "Foundation/NSPathUtilities.h"
 
42
#include "Foundation/NSValue.h"
 
43
#include "Foundation/NSFileManager.h"
 
44
#include "Foundation/NSProcessInfo.h"
 
45
#include <stdio.h>
 
46
#include <stdlib.h>
 
47
#ifdef HAVE_UNISTD_H
 
48
#include <unistd.h>             /* for gethostname() */
 
49
#endif
 
50
 
 
51
#ifndef __MINGW__
 
52
#include <sys/param.h>          /* for MAXHOSTNAMELEN */
 
53
#include <sys/types.h>
 
54
#include <sys/un.h>
 
55
#include <arpa/inet.h>          /* for inet_ntoa() */
 
56
#endif /* !__MINGW__ */
 
57
#include <errno.h>
 
58
#include <limits.h>
 
59
#include <string.h>             /* for strchr() */
 
60
#include <ctype.h>              /* for strchr() */
 
61
#include <fcntl.h>
 
62
#ifdef __MINGW__
 
63
#include <winsock2.h>
 
64
#include <wininet.h>
 
65
#include <process.h>
 
66
#include <sys/time.h>
 
67
#else
 
68
#include <sys/time.h>
 
69
#include <sys/resource.h>
 
70
#include <netdb.h>
 
71
#include <sys/socket.h>
 
72
#include <sys/file.h>
 
73
#include <sys/stat.h>
 
74
/*
 
75
 *      Stuff for setting the sockets into non-blocking mode.
 
76
 */
 
77
#ifdef  __POSIX_SOURCE
 
78
#define NBLK_OPT     O_NONBLOCK
 
79
#else
 
80
#define NBLK_OPT     FNDELAY
 
81
#endif
 
82
 
 
83
#include <netinet/in.h>
 
84
#include <net/if.h>
 
85
#if     !defined(SIOCGIFCONF) || defined(__CYGWIN__)
 
86
#include <sys/ioctl.h>
 
87
#ifndef SIOCGIFCONF
 
88
#include <sys/sockio.h>
 
89
#endif
 
90
#endif
 
91
 
 
92
#if     defined(__svr4__)
 
93
#include <sys/stropts.h>
 
94
#endif
 
95
#endif /* !__MINGW__ */
 
96
 
 
97
#ifdef __MINGW__
 
98
#define close closesocket
 
99
#endif
 
100
 
 
101
/* Older systems (Solaris) compatibility */
 
102
#ifndef AF_LOCAL
 
103
#define AF_LOCAL AF_UNIX
 
104
#define PF_LOCAL PF_UNIX
 
105
#endif
 
106
#ifndef SUN_LEN
 
107
#define SUN_LEN(su) \
 
108
        (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
 
109
#endif
 
110
 
 
111
/*
 
112
 * Largest chunk of data possible in DO
 
113
 */
 
114
static gsu32    maxDataLength = 10 * 1024 * 1024;
 
115
 
 
116
#if 0
 
117
#define M_LOCK(X) {NSDebugMLLog(@"NSMessagePort",@"lock %@",X); [X lock];}
 
118
#define M_UNLOCK(X) {NSDebugMLLog(@"NSMessagePort",@"unlock %@",X); [X unlock];}
 
119
#else
 
120
#define M_LOCK(X) {[X lock];}
 
121
#define M_UNLOCK(X) {[X unlock];}
 
122
#endif
 
123
 
 
124
#define GS_CONNECTION_MSG       0
 
125
#define NETBLOCK        8192
 
126
 
 
127
#ifndef INADDR_NONE
 
128
#define INADDR_NONE     -1
 
129
#endif
 
130
 
 
131
/*
 
132
 * Theory of operation
 
133
 *
 
134
 *
 
135
 */
 
136
 
 
137
 
 
138
/* Private interfaces */
 
139
 
 
140
/*
 
141
 * The GSPortItemType constant is used to identify the type of data in
 
142
 * each packet read.  All data transmitted is in a packet, each packet
 
143
 * has an initial packet type and packet length.
 
144
 */
 
145
typedef enum {
 
146
  GSP_NONE,
 
147
  GSP_PORT,             /* Simple port item.                    */
 
148
  GSP_DATA,             /* Simple data item.                    */
 
149
  GSP_HEAD              /* Port message header + initial data.  */
 
150
} GSPortItemType;
 
151
 
 
152
/*
 
153
 * The GSPortItemHeader structure defines the header for each item transmitted.
 
154
 * Its contents are transmitted in network byte order.
 
155
 */
 
156
typedef struct {
 
157
  gsu32 type;           /* A GSPortItemType as a 4-byte number.         */
 
158
  gsu32 length;         /* The length of the item (excluding header).   */
 
159
} GSPortItemHeader;
 
160
 
 
161
/*
 
162
 * The GSPortMsgHeader structure is at the start of any item of type GSP_HEAD.
 
163
 * Its contents are transmitted in network byte order.
 
164
 * Any additional data in the item is an NSData object.
 
165
 * NB. additional data counts as part of the same item.
 
166
 */
 
167
typedef struct {
 
168
  gsu32 mId;            /* The ID for the message starting with this.   */
 
169
  gsu32 nItems;         /* Number of items (including this one).        */
 
170
} GSPortMsgHeader;
 
171
 
 
172
typedef struct {
 
173
  char  version;
 
174
  char  addr[0];        /* name of the socket in the port directory */
 
175
} GSPortInfo;
 
176
 
 
177
/*
 
178
 * Here is how data is transmitted over a socket -
 
179
 * Initially the process making the connection sends an item of type
 
180
 * GSP_PORT to tell the remote end what port is connecting to it.
 
181
 * Therafter, all communication is via port messages.  Each port message
 
182
 * consists of an item of type GSP_HEAD followed by zero or more items
 
183
 * of type GSP_PORT or GSP_DATA.  The number of items in a port message
 
184
 * is encoded in the 'nItems' field of the header.
 
185
 */
 
186
 
 
187
typedef enum {
 
188
  GS_H_UNCON = 0,       // Currently idle and unconnected.
 
189
  GS_H_TRYCON,          // Trying connection (outgoing).
 
190
  GS_H_ACCEPT,          // Making initial connection (incoming).
 
191
  GS_H_CONNECTED        // Currently connected.
 
192
} GSHandleState;
 
193
 
 
194
@interface GSMessageHandle : NSObject <GCFinalization, RunLoopEvents>
 
195
{
 
196
  int                   desc;           /* File descriptor for I/O.     */
 
197
  unsigned              wItem;          /* Index of item being written. */
 
198
  NSMutableData         *wData;         /* Data object being written.   */
 
199
  unsigned              wLength;        /* Ammount written so far.      */
 
200
  NSMutableArray        *wMsgs;         /* Message in progress.         */
 
201
  NSMutableData         *rData;         /* Buffer for incoming data     */
 
202
  gsu32                 rLength;        /* Amount read so far.          */
 
203
  gsu32                 rWant;          /* Amount desired.              */
 
204
  NSMutableArray        *rItems;        /* Message in progress.         */
 
205
  GSPortItemType        rType;          /* Type of data being read.     */
 
206
  gsu32                 rId;            /* Id of incoming message.      */
 
207
  unsigned              nItems;         /* Number of items to be read.  */
 
208
  GSHandleState         state;          /* State of the handle.         */
 
209
  unsigned int          addrNum;        /* Address number within host.  */
 
210
@public
 
211
  NSRecursiveLock       *myLock;        /* Lock for this handle.        */
 
212
  BOOL                  caller;         /* Did we connect to other end? */
 
213
  BOOL                  valid;
 
214
  NSMessagePort         *recvPort;
 
215
  NSMessagePort         *sendPort;
 
216
  struct sockaddr_un    sockAddr;       /* Far end of connection.       */
 
217
}
 
218
 
 
219
+ (GSMessageHandle*) handleWithDescriptor: (int)d;
 
220
- (BOOL) connectToPort: (NSMessagePort*)aPort beforeDate: (NSDate*)when;
 
221
- (int) descriptor;
 
222
- (void) invalidate;
 
223
- (BOOL) isValid;
 
224
- (void) receivedEvent: (void*)data
 
225
                  type: (RunLoopEventType)type
 
226
                 extra: (void*)extra
 
227
               forMode: (NSString*)mode;
 
228
- (NSMessagePort*) recvPort;
 
229
- (BOOL) sendMessage: (NSArray*)components beforeDate: (NSDate*)when;
 
230
- (NSMessagePort*) sendPort;
 
231
- (void) setState: (GSHandleState)s;
 
232
- (GSHandleState) state;
 
233
- (NSDate*) timedOutEvent: (void*)data
 
234
                     type: (RunLoopEventType)type
 
235
                  forMode: (NSString*)mode;
 
236
@end
 
237
 
 
238
 
 
239
/*
 
240
 * Utility functions for encoding and decoding ports.
 
241
 */
 
242
static NSMessagePort*
 
243
decodePort(NSData *data)
 
244
{
 
245
  GSPortItemHeader      *pih;
 
246
  GSPortInfo            *pi;
 
247
 
 
248
  pih = (GSPortItemHeader*)[data bytes];
 
249
  NSCAssert(GSSwapBigI32ToHost(pih->type) == GSP_PORT,
 
250
    NSInternalInconsistencyException);
 
251
  pi = (GSPortInfo*)&pih[1];
 
252
  if (pi->version != 0)
 
253
    {
 
254
      NSLog(@"Remote version of GNUstep is more recent than this one (%i)",
 
255
        pi->version);
 
256
      return nil;
 
257
    }
 
258
 
 
259
  NSDebugFLLog(@"NSMessagePort", @"Decoded port as '%s'", pi->addr);
 
260
 
 
261
  return [NSMessagePort _portWithName: pi->addr
 
262
                             listener: NO];
 
263
}
 
264
 
 
265
static NSData*
 
266
newDataWithEncodedPort(NSMessagePort *port)
 
267
{
 
268
  GSPortItemHeader      *pih;
 
269
  GSPortInfo            *pi;
 
270
  NSMutableData         *data;
 
271
  unsigned              plen;
 
272
  const unsigned char   *name = [port _name];
 
273
 
 
274
  plen = 2 + strlen(name);
 
275
 
 
276
  data = [[NSMutableData alloc] initWithLength: sizeof(GSPortItemHeader)+plen];
 
277
  pih = (GSPortItemHeader*)[data mutableBytes];
 
278
  pih->type = GSSwapHostI32ToBig(GSP_PORT);
 
279
  pih->length = GSSwapHostI32ToBig(plen);
 
280
  pi = (GSPortInfo*)&pih[1];
 
281
  strcpy(pi->addr, name);
 
282
 
 
283
  NSDebugFLLog(@"NSMessagePort", @"Encoded port as '%s'", pi->addr);
 
284
 
 
285
  return data;
 
286
}
 
287
 
 
288
 
 
289
 
 
290
@implementation GSMessageHandle
 
291
 
 
292
static Class    mutableArrayClass;
 
293
static Class    mutableDataClass;
 
294
static Class    portMessageClass;
 
295
static Class    runLoopClass;
 
296
 
 
297
 
 
298
+ (id) allocWithZone: (NSZone*)zone
 
299
{
 
300
  [NSException raise: NSGenericException
 
301
              format: @"attempt to alloc a GSMessageHandle!"];
 
302
  return nil;
 
303
}
 
304
 
 
305
+ (GSMessageHandle*) handleWithDescriptor: (int)d
 
306
{
 
307
  GSMessageHandle       *handle;
 
308
#ifdef __MINGW__
 
309
  unsigned long dummy;
 
310
#else
 
311
  int           e;
 
312
#endif /* __MINGW__ */
 
313
 
 
314
  if (d < 0)
 
315
    {
 
316
      NSLog(@"illegal descriptor (%d) for message handle", d);
 
317
      return nil;
 
318
    }
 
319
#ifdef __MINGW__
 
320
  dummy = 1;
 
321
  if (ioctlsocket(d, FIONBIO, &dummy) < 0)
 
322
    {
 
323
      NSLog(@"unable to set non-blocking mode on %d - %s",
 
324
        d, GSLastErrorStr(errno));
 
325
      return nil;
 
326
    }
 
327
#else /* !__MINGW__ */
 
328
  if ((e = fcntl(d, F_GETFL, 0)) >= 0)
 
329
    {
 
330
      e |= NBLK_OPT;
 
331
      if (fcntl(d, F_SETFL, e) < 0)
 
332
        {
 
333
          NSLog(@"unable to set non-blocking mode on %d - %s",
 
334
            d, GSLastErrorStr(errno));
 
335
          return nil;
 
336
        }
 
337
    }
 
338
  else
 
339
    {
 
340
      NSLog(@"unable to get non-blocking mode on %d - %s",
 
341
        d, GSLastErrorStr(errno));
 
342
      return nil;
 
343
    }
 
344
#endif
 
345
  handle = (GSMessageHandle*)NSAllocateObject(self, 0, NSDefaultMallocZone());
 
346
  handle->desc = d;
 
347
  handle->wMsgs = [NSMutableArray new];
 
348
  handle->myLock = [GSLazyRecursiveLock new];
 
349
  handle->valid = YES;
 
350
  return AUTORELEASE(handle);
 
351
}
 
352
 
 
353
+ (void) initialize
 
354
{
 
355
  if (self == [GSMessageHandle class])
 
356
    {
 
357
#ifdef __MINGW__
 
358
      WORD wVersionRequested;
 
359
      WSADATA wsaData;
 
360
 
 
361
      wVersionRequested = MAKEWORD(2, 0);
 
362
      WSAStartup(wVersionRequested, &wsaData);
 
363
#endif
 
364
      mutableArrayClass = [NSMutableArray class];
 
365
      mutableDataClass = [NSMutableData class];
 
366
      portMessageClass = [NSPortMessage class];
 
367
      runLoopClass = [NSRunLoop class];
 
368
    }
 
369
}
 
370
 
 
371
- (BOOL) connectToPort: (NSMessagePort*)aPort beforeDate: (NSDate*)when
 
372
{
 
373
  NSRunLoop             *l;
 
374
  const unsigned char *name;
 
375
 
 
376
  M_LOCK(myLock);
 
377
  NSDebugMLLog(@"NSMessagePort", @"Connecting on 0x%x before %@", self, when);
 
378
  if (state != GS_H_UNCON)
 
379
    {
 
380
      BOOL      result;
 
381
 
 
382
      if (state == GS_H_CONNECTED)      /* Already connected.   */
 
383
        {
 
384
          NSLog(@"attempting connect on connected handle");
 
385
          result = YES;
 
386
        }
 
387
      else if (state == GS_H_ACCEPT)    /* Impossible.  */
 
388
        {
 
389
          NSLog(@"attempting connect with accepting handle");
 
390
          result = NO;
 
391
        }
 
392
      else                              /* Already connecting.  */
 
393
        {
 
394
          NSLog(@"attempting connect while connecting");
 
395
          result = NO;
 
396
        }
 
397
      M_UNLOCK(myLock);
 
398
      return result;
 
399
    }
 
400
 
 
401
  if (recvPort == nil || aPort == nil)
 
402
    {
 
403
      NSLog(@"attempting connect with port(s) unset");
 
404
      M_UNLOCK(myLock);
 
405
      return NO;        /* impossible.          */
 
406
    }
 
407
 
 
408
 
 
409
  name = [aPort _name];
 
410
  memset(&sockAddr, '\0', sizeof(sockAddr));
 
411
  sockAddr.sun_family = AF_LOCAL;
 
412
  strncpy(sockAddr.sun_path, name, sizeof(sockAddr.sun_path));
 
413
 
 
414
  if (connect(desc, (struct sockaddr*)&sockAddr, SUN_LEN(&sockAddr)) < 0)
 
415
    {
 
416
#ifdef __MINGW__
 
417
      if (WSAGetLastError() != WSAEWOULDBLOCK)
 
418
#else
 
419
      if (errno != EINPROGRESS)
 
420
#endif
 
421
        {
 
422
          NSLog(@"unable to make connection to %s - %s",
 
423
            sockAddr.sun_path,
 
424
            GSLastErrorStr(errno));
 
425
          M_UNLOCK(myLock);
 
426
          return NO;
 
427
        }
 
428
    }
 
429
 
 
430
  state = GS_H_TRYCON;
 
431
  l = [NSRunLoop currentRunLoop];
 
432
  [l addEvent: (void*)(gsaddr)desc
 
433
         type: ET_WDESC
 
434
      watcher: self
 
435
      forMode: NSConnectionReplyMode];
 
436
  [l addEvent: (void*)(gsaddr)desc
 
437
         type: ET_EDESC
 
438
      watcher: self
 
439
      forMode: NSConnectionReplyMode];
 
440
 
 
441
  while (valid == YES && state == GS_H_TRYCON
 
442
    && [when timeIntervalSinceNow] > 0)
 
443
    {
 
444
      [l runMode: NSConnectionReplyMode beforeDate: when];
 
445
    }
 
446
 
 
447
  [l removeEvent: (void*)(gsaddr)desc
 
448
            type: ET_WDESC
 
449
         forMode: NSConnectionReplyMode
 
450
             all: NO];
 
451
  [l removeEvent: (void*)(gsaddr)desc
 
452
            type: ET_EDESC
 
453
         forMode: NSConnectionReplyMode
 
454
             all: NO];
 
455
 
 
456
  if (state == GS_H_TRYCON)
 
457
    {
 
458
      state = GS_H_UNCON;
 
459
      addrNum = 0;
 
460
      M_UNLOCK(myLock);
 
461
      return NO;        /* Timed out    */
 
462
    }
 
463
  else if (state == GS_H_UNCON)
 
464
    {
 
465
      addrNum = 0;
 
466
      state = GS_H_UNCON;
 
467
      M_UNLOCK(myLock);
 
468
      return NO;
 
469
    }
 
470
  else
 
471
    {
 
472
      addrNum = 0;
 
473
      caller = YES;
 
474
      [aPort addHandle: self forSend: YES];
 
475
      M_UNLOCK(myLock);
 
476
      return YES;
 
477
    }
 
478
}
 
479
 
 
480
- (void) dealloc
 
481
{
 
482
  [self gcFinalize];
 
483
  DESTROY(rData);
 
484
  DESTROY(rItems);
 
485
  DESTROY(wMsgs);
 
486
  DESTROY(myLock);
 
487
  [super dealloc];
 
488
}
 
489
 
 
490
- (NSString*) description
 
491
{
 
492
  return [NSString stringWithFormat: @"<GSMessageHandle %p (%d) to %s>",
 
493
    self, desc, sockAddr.sun_path];
 
494
}
 
495
 
 
496
- (int) descriptor
 
497
{
 
498
  return desc;
 
499
}
 
500
 
 
501
- (void) gcFinalize
 
502
{
 
503
  [self invalidate];
 
504
  (void)close(desc);
 
505
  desc = -1;
 
506
}
 
507
 
 
508
- (void) invalidate
 
509
{
 
510
  if (valid == YES)
 
511
    {
 
512
      M_LOCK(myLock);
 
513
      if (valid == YES)
 
514
        {
 
515
          NSRunLoop     *l;
 
516
 
 
517
          valid = NO;
 
518
          l = [runLoopClass currentRunLoop];
 
519
          [l removeEvent: (void*)(gsaddr)desc
 
520
                    type: ET_RDESC
 
521
                 forMode: nil
 
522
                     all: YES];
 
523
          [l removeEvent: (void*)(gsaddr)desc
 
524
                    type: ET_WDESC
 
525
                 forMode: nil
 
526
                     all: YES];
 
527
          [l removeEvent: (void*)(gsaddr)desc
 
528
                    type: ET_EDESC
 
529
                 forMode: nil
 
530
                     all: YES];
 
531
          NSDebugMLLog(@"NSMessagePort", @"invalidated 0x%x", self);
 
532
          [[self recvPort] removeHandle: self];
 
533
          [[self sendPort] removeHandle: self];
 
534
        }
 
535
      M_UNLOCK(myLock);
 
536
    }
 
537
}
 
538
 
 
539
- (BOOL) isValid
 
540
{
 
541
  return valid;
 
542
}
 
543
 
 
544
- (NSMessagePort*) recvPort
 
545
{
 
546
  if (recvPort == nil)
 
547
    return nil;
 
548
  else
 
549
    return GS_GC_UNHIDE(recvPort);
 
550
}
 
551
 
 
552
- (void) receivedEvent: (void*)data
 
553
                  type: (RunLoopEventType)type
 
554
                 extra: (void*)extra
 
555
               forMode: (NSString*)mode
 
556
{
 
557
  NSDebugMLLog(@"NSMessagePort_details",
 
558
    @"received %s event on 0x%x",
 
559
    type == ET_RPORT ? "read" : "write", self);
 
560
  /*
 
561
   * If we have been invalidated (desc < 0) then we should ignore this
 
562
   * event and remove ourself from the runloop.
 
563
   */
 
564
  if (desc < 0)
 
565
    {
 
566
      NSRunLoop *l = [runLoopClass currentRunLoop];
 
567
 
 
568
      [l removeEvent: data
 
569
                type: ET_WDESC
 
570
             forMode: mode
 
571
                 all: YES];
 
572
      [l removeEvent: data
 
573
                type: ET_EDESC
 
574
             forMode: mode
 
575
                 all: YES];
 
576
      return;
 
577
    }
 
578
 
 
579
  M_LOCK(myLock);
 
580
 
 
581
  if (type == ET_RPORT)
 
582
    {
 
583
      unsigned  want;
 
584
      void      *bytes;
 
585
      int       res;
 
586
 
 
587
      /*
 
588
       * Make sure we have a buffer big enough to hold all the data we are
 
589
       * expecting, or NETBLOCK bytes, whichever is greater.
 
590
       */
 
591
      if (rData == nil)
 
592
        {
 
593
          rData = [[mutableDataClass alloc] initWithLength: NETBLOCK];
 
594
          rWant = sizeof(GSPortItemHeader);
 
595
          rLength = 0;
 
596
          want = NETBLOCK;
 
597
        }
 
598
      else
 
599
        {
 
600
          want = [rData length];
 
601
          if (want < rWant)
 
602
            {
 
603
              want = rWant;
 
604
              [rData setLength: want];
 
605
            }
 
606
          if (want < NETBLOCK)
 
607
            {
 
608
              want = NETBLOCK;
 
609
              [rData setLength: want];
 
610
            }
 
611
        }
 
612
 
 
613
      /*
 
614
       * Now try to fill the buffer with data.
 
615
       */
 
616
      bytes = [rData mutableBytes];
 
617
#ifdef __MINGW__
 
618
      res = recv(desc, bytes + rLength, want - rLength, 0);
 
619
#else
 
620
      res = read(desc, bytes + rLength, want - rLength);
 
621
#endif
 
622
      if (res <= 0)
 
623
        {
 
624
          if (res == 0)
 
625
            {
 
626
              NSDebugMLLog(@"NSMessagePort", @"read eof on 0x%x", self);
 
627
              M_UNLOCK(myLock);
 
628
              [self invalidate];
 
629
              return;
 
630
            }
 
631
          else if (errno != EINTR && errno != EAGAIN)
 
632
            {
 
633
              NSDebugMLLog(@"NSMessagePort",
 
634
                @"read failed - %s on 0x%x", GSLastErrorStr(errno), self);
 
635
              M_UNLOCK(myLock);
 
636
              [self invalidate];
 
637
              return;
 
638
            }
 
639
          res = 0;      /* Interrupted - continue       */
 
640
        }
 
641
      NSDebugMLLog(@"NSMessagePort_details",
 
642
        @"read %d bytes on 0x%x", res, self);
 
643
      rLength += res;
 
644
 
 
645
      while (valid == YES && rLength >= rWant)
 
646
        {
 
647
          BOOL  shouldDispatch = NO;
 
648
 
 
649
          switch (rType)
 
650
            {
 
651
              case GSP_NONE:
 
652
                {
 
653
                  GSPortItemHeader      *h;
 
654
                  unsigned              l;
 
655
 
 
656
                  /*
 
657
                   * We have read an item header - set up to read the
 
658
                   * remainder of the item.
 
659
                   */
 
660
                  h = (GSPortItemHeader*)bytes;
 
661
                  rType = GSSwapBigI32ToHost(h->type);
 
662
                  l = GSSwapBigI32ToHost(h->length);
 
663
                  if (rType == GSP_PORT)
 
664
                    {
 
665
                      if (l > 512)
 
666
                        {
 
667
                          NSLog(@"%@ - unreasonable length (%u) for port",
 
668
                            self, l);
 
669
                          M_UNLOCK(myLock);
 
670
                          [self invalidate];
 
671
                          return;
 
672
                        }
 
673
                      /*
 
674
                       * For a port, we leave the item header in the data
 
675
                       * so that our decode function can check length info.
 
676
                       */
 
677
                      rWant += l;
 
678
                    }
 
679
                  else if (rType == GSP_DATA)
 
680
                    {
 
681
                      if (l == 0)
 
682
                        {
 
683
                          NSData        *d;
 
684
 
 
685
                          /*
 
686
                           * For a zero-length data chunk, we create an empty
 
687
                           * data object and add it to the current message.
 
688
                           */
 
689
                          rType = GSP_NONE;     /* ready for a new item */
 
690
                          rLength -= rWant;
 
691
                          if (rLength > 0)
 
692
                            {
 
693
                              memmove(bytes, bytes + rWant, rLength);
 
694
                            }
 
695
                          rWant = sizeof(GSPortItemHeader);
 
696
                          d = [mutableDataClass new];
 
697
                          [rItems addObject: d];
 
698
                          RELEASE(d);
 
699
                          if (nItems == [rItems count])
 
700
                            {
 
701
                              shouldDispatch = YES;
 
702
                            }
 
703
                        }
 
704
                      else
 
705
                        {
 
706
                          if (l > maxDataLength)
 
707
                            {
 
708
                              NSLog(@"%@ - unreasonable length (%u) for data",
 
709
                                self, l);
 
710
                              M_UNLOCK(myLock);
 
711
                              [self invalidate];
 
712
                              return;
 
713
                            }
 
714
                          /*
 
715
                           * If not a port or zero length data,
 
716
                           * we discard the data read so far and fill the
 
717
                           * data object with the data item from the msg.
 
718
                           */
 
719
                          rLength -= rWant;
 
720
                          if (rLength > 0)
 
721
                            {
 
722
                              memmove(bytes, bytes + rWant, rLength);
 
723
                            }
 
724
                          rWant = l;
 
725
                        }
 
726
                    }
 
727
                  else if (rType == GSP_HEAD)
 
728
                    {
 
729
                      if (l > maxDataLength)
 
730
                        {
 
731
                          NSLog(@"%@ - unreasonable length (%u) for data",
 
732
                            self, l);
 
733
                          M_UNLOCK(myLock);
 
734
                          [self invalidate];
 
735
                          return;
 
736
                        }
 
737
                      /*
 
738
                       * If not a port or zero length data,
 
739
                       * we discard the data read so far and fill the
 
740
                       * data object with the data item from the msg.
 
741
                       */
 
742
                      rLength -= rWant;
 
743
                      if (rLength > 0)
 
744
                        {
 
745
                          memmove(bytes, bytes + rWant, rLength);
 
746
                        }
 
747
                      rWant = l;
 
748
                    }
 
749
                  else
 
750
                    {
 
751
                      NSLog(@"%@ - bad data received on port handle, rType=%i",
 
752
                        self, rType);
 
753
                      M_UNLOCK(myLock);
 
754
                      [self invalidate];
 
755
                      return;
 
756
                    }
 
757
                }
 
758
                break;
 
759
 
 
760
              case GSP_HEAD:
 
761
                {
 
762
                  GSPortMsgHeader       *h;
 
763
 
 
764
                  rType = GSP_NONE;     /* ready for a new item */
 
765
                  /*
 
766
                   * We have read a message header - set up to read the
 
767
                   * remainder of the message.
 
768
                   */
 
769
                  h = (GSPortMsgHeader*)bytes;
 
770
                  rId = GSSwapBigI32ToHost(h->mId);
 
771
                  nItems = GSSwapBigI32ToHost(h->nItems);
 
772
                  NSAssert(nItems >0, NSInternalInconsistencyException);
 
773
                  rItems
 
774
                    = [mutableArrayClass allocWithZone: NSDefaultMallocZone()];
 
775
                  rItems = [rItems initWithCapacity: nItems];
 
776
                  if (rWant > sizeof(GSPortMsgHeader))
 
777
                    {
 
778
                      NSData    *d;
 
779
 
 
780
                      /*
 
781
                       * The first data item of the message was included in
 
782
                       * the header - so add it to the rItems array.
 
783
                       */
 
784
                      rWant -= sizeof(GSPortMsgHeader);
 
785
                      d = [mutableDataClass alloc];
 
786
                      d = [d initWithBytes: bytes + sizeof(GSPortMsgHeader)
 
787
                                    length: rWant];
 
788
                      [rItems addObject: d];
 
789
                      RELEASE(d);
 
790
                      rWant += sizeof(GSPortMsgHeader);
 
791
                      rLength -= rWant;
 
792
                      if (rLength > 0)
 
793
                        {
 
794
                          memmove(bytes, bytes + rWant, rLength);
 
795
                        }
 
796
                      rWant = sizeof(GSPortItemHeader);
 
797
                      if (nItems == 1)
 
798
                        {
 
799
                          shouldDispatch = YES;
 
800
                        }
 
801
                    }
 
802
                  else
 
803
                    {
 
804
                      /*
 
805
                       * want to read another item
 
806
                       */
 
807
                      rLength -= rWant;
 
808
                      if (rLength > 0)
 
809
                        {
 
810
                          memmove(bytes, bytes + rWant, rLength);
 
811
                        }
 
812
                      rWant = sizeof(GSPortItemHeader);
 
813
                    }
 
814
                }
 
815
                break;
 
816
 
 
817
              case GSP_DATA:
 
818
                {
 
819
                  NSData        *d;
 
820
 
 
821
                  rType = GSP_NONE;     /* ready for a new item */
 
822
                  d = [mutableDataClass allocWithZone: NSDefaultMallocZone()];
 
823
                  d = [d initWithBytes: bytes length: rWant];
 
824
                  [rItems addObject: d];
 
825
                  RELEASE(d);
 
826
                  rLength -= rWant;
 
827
                  if (rLength > 0)
 
828
                    {
 
829
                      memmove(bytes, bytes + rWant, rLength);
 
830
                    }
 
831
                  rWant = sizeof(GSPortItemHeader);
 
832
                  if (nItems == [rItems count])
 
833
                    {
 
834
                      shouldDispatch = YES;
 
835
                    }
 
836
                }
 
837
                break;
 
838
 
 
839
              case GSP_PORT:
 
840
                {
 
841
                  NSMessagePort *p;
 
842
 
 
843
                  rType = GSP_NONE;     /* ready for a new item */
 
844
                  p = decodePort(rData);
 
845
                  if (p == nil)
 
846
                    {
 
847
                      NSLog(@"%@ - unable to decode remote port", self);
 
848
                      M_UNLOCK(myLock);
 
849
                      [self invalidate];
 
850
                      return;
 
851
                    }
 
852
                  /*
 
853
                   * Set up to read another item header.
 
854
                   */
 
855
                  rLength -= rWant;
 
856
                  if (rLength > 0)
 
857
                    {
 
858
                      memmove(bytes, bytes + rWant, rLength);
 
859
                    }
 
860
                  rWant = sizeof(GSPortItemHeader);
 
861
 
 
862
                  if (state == GS_H_ACCEPT)
 
863
                    {
 
864
                      /*
 
865
                       * This is the initial port information on a new
 
866
                       * connection - set up port relationships.
 
867
                       */
 
868
                      state = GS_H_CONNECTED;
 
869
                      [p addHandle: self forSend: YES];
 
870
                    }
 
871
                  else
 
872
                    {
 
873
                      /*
 
874
                       * This is a port within a port message - add
 
875
                       * it to the message components.
 
876
                       */
 
877
                      [rItems addObject: p];
 
878
                      if (nItems == [rItems count])
 
879
                        {
 
880
                          shouldDispatch = YES;
 
881
                        }
 
882
                    }
 
883
                }
 
884
                break;
 
885
            }
 
886
 
 
887
          if (shouldDispatch == YES)
 
888
            {
 
889
              NSPortMessage     *pm;
 
890
              NSMessagePort             *rp = [self recvPort];
 
891
 
 
892
              pm = [portMessageClass allocWithZone: NSDefaultMallocZone()];
 
893
              pm = [pm initWithSendPort: [self sendPort]
 
894
                            receivePort: rp
 
895
                             components: rItems];
 
896
              [pm setMsgid: rId];
 
897
              rId = 0;
 
898
              DESTROY(rItems);
 
899
              NSDebugMLLog(@"NSMessagePort_details",
 
900
                @"got message %@ on 0x%x", pm, self);
 
901
              RETAIN(rp);
 
902
              M_UNLOCK(myLock);
 
903
              NS_DURING
 
904
                {
 
905
                  [rp handlePortMessage: pm];
 
906
                }
 
907
              NS_HANDLER
 
908
                {
 
909
                  M_LOCK(myLock);
 
910
                  RELEASE(pm);
 
911
                  RELEASE(rp);
 
912
                  [localException raise];
 
913
                }
 
914
              NS_ENDHANDLER
 
915
              M_LOCK(myLock);
 
916
              RELEASE(pm);
 
917
              RELEASE(rp);
 
918
              bytes = [rData mutableBytes];
 
919
            }
 
920
        }
 
921
    }
 
922
  else
 
923
    {
 
924
      if (state == GS_H_TRYCON) /* Connection attempt.  */
 
925
        {
 
926
          int   res = 0;
 
927
          int   len = sizeof(res);
 
928
 
 
929
          if (getsockopt(desc, SOL_SOCKET, SO_ERROR, (char*)&res, &len) == 0
 
930
            && res != 0)
 
931
            {
 
932
              state = GS_H_UNCON;
 
933
              NSLog(@"connect attempt failed - %s", GSLastErrorStr(res));
 
934
            }
 
935
          else
 
936
            {
 
937
              NSData    *d = newDataWithEncodedPort([self recvPort]);
 
938
 
 
939
#ifdef __MINGW__
 
940
              len = send(desc, [d bytes], [d length], 0);
 
941
#else
 
942
              len = write(desc, [d bytes], [d length]);
 
943
#endif
 
944
              if (len == (int)[d length])
 
945
                {
 
946
                  NSDebugMLLog(@"NSMessagePort_details",
 
947
                    @"wrote %d bytes on 0x%x", len, self);
 
948
                  state = GS_H_CONNECTED;
 
949
                }
 
950
              else
 
951
                {
 
952
                  state = GS_H_UNCON;
 
953
                  NSLog(@"connect write attempt failed - %s",
 
954
                    GSLastErrorStr(errno));
 
955
                }
 
956
              RELEASE(d);
 
957
            }
 
958
        }
 
959
      else
 
960
        {
 
961
          int           res;
 
962
          unsigned      l;
 
963
          const void    *b;
 
964
 
 
965
          if (wData == nil)
 
966
            {
 
967
              if ([wMsgs count] > 0)
 
968
                {
 
969
                  NSArray       *components = [wMsgs objectAtIndex: 0];
 
970
 
 
971
                  wData = [components objectAtIndex: wItem++];
 
972
                  wLength = 0;
 
973
                }
 
974
              else
 
975
                {
 
976
                  // NSLog(@"No messages to write on 0x%x.", self);
 
977
                  M_UNLOCK(myLock);
 
978
                  return;
 
979
                }
 
980
            }
 
981
          b = [wData bytes];
 
982
          l = [wData length];
 
983
#ifdef __MINGW__
 
984
          res = send(desc, b + wLength,  l - wLength, 0);
 
985
#else
 
986
          res = write(desc, b + wLength,  l - wLength);
 
987
#endif
 
988
          if (res < 0)
 
989
            {
 
990
              if (errno != EINTR && errno != EAGAIN)
 
991
                {
 
992
                  NSLog(@"write attempt failed - %s", GSLastErrorStr(errno));
 
993
                  M_UNLOCK(myLock);
 
994
                  [self invalidate];
 
995
                  return;
 
996
                }
 
997
            }
 
998
          else
 
999
            {
 
1000
              NSDebugMLLog(@"NSMessagePort_details",
 
1001
                @"wrote %d bytes on 0x%x", res, self);
 
1002
              wLength += res;
 
1003
              if (wLength == l)
 
1004
                {
 
1005
                  NSArray       *components;
 
1006
 
 
1007
                  /*
 
1008
                   * We have completed a data item so see what is
 
1009
                   * left of the message components.
 
1010
                   */
 
1011
                  components = [wMsgs objectAtIndex: 0];
 
1012
                  wLength = 0;
 
1013
                  if ([components count] > wItem)
 
1014
                    {
 
1015
                      /*
 
1016
                       * More to write - get next item.
 
1017
                       */
 
1018
                      wData = [components objectAtIndex: wItem++];
 
1019
                    }
 
1020
                  else
 
1021
                    {
 
1022
                      /*
 
1023
                       * message completed - remove from list.
 
1024
                       */
 
1025
                      NSDebugMLLog(@"NSMessagePort_details",
 
1026
                        @"completed 0x%x on 0x%x", components, self);
 
1027
                      wData = nil;
 
1028
                      wItem = 0;
 
1029
                      [wMsgs removeObjectAtIndex: 0];
 
1030
                    }
 
1031
                }
 
1032
            }
 
1033
        }
 
1034
    }
 
1035
 
 
1036
  M_UNLOCK(myLock);
 
1037
}
 
1038
 
 
1039
- (BOOL) sendMessage: (NSArray*)components beforeDate: (NSDate*)when
 
1040
{
 
1041
  NSRunLoop     *l;
 
1042
  BOOL          sent = NO;
 
1043
 
 
1044
  NSAssert([components count] > 0, NSInternalInconsistencyException);
 
1045
  NSDebugMLLog(@"NSMessagePort_details",
 
1046
    @"Sending message 0x%x %@ on 0x%x(%d) before %@",
 
1047
    components, components, self, desc, when);
 
1048
  M_LOCK(myLock);
 
1049
  [wMsgs addObject: components];
 
1050
 
 
1051
  l = [runLoopClass currentRunLoop];
 
1052
 
 
1053
  RETAIN(self);
 
1054
 
 
1055
  [l addEvent: (void*)(gsaddr)desc
 
1056
         type: ET_WDESC
 
1057
      watcher: self
 
1058
      forMode: NSConnectionReplyMode];
 
1059
  [l addEvent: (void*)(gsaddr)desc
 
1060
         type: ET_EDESC
 
1061
      watcher: self
 
1062
      forMode: NSConnectionReplyMode];
 
1063
 
 
1064
  while (valid == YES
 
1065
    && [wMsgs indexOfObjectIdenticalTo: components] != NSNotFound
 
1066
    && [when timeIntervalSinceNow] > 0)
 
1067
    {
 
1068
      M_UNLOCK(myLock);
 
1069
      [l runMode: NSConnectionReplyMode beforeDate: when];
 
1070
      M_LOCK(myLock);
 
1071
    }
 
1072
 
 
1073
  [l removeEvent: (void*)(gsaddr)desc
 
1074
            type: ET_WDESC
 
1075
         forMode: NSConnectionReplyMode
 
1076
             all: NO];
 
1077
  [l removeEvent: (void*)(gsaddr)desc
 
1078
            type: ET_EDESC
 
1079
         forMode: NSConnectionReplyMode
 
1080
             all: NO];
 
1081
 
 
1082
  if ([wMsgs indexOfObjectIdenticalTo: components] == NSNotFound)
 
1083
    {
 
1084
      sent = YES;
 
1085
    }
 
1086
  M_UNLOCK(myLock);
 
1087
  RELEASE(self);
 
1088
  NSDebugMLLog(@"NSMessagePort_details",
 
1089
    @"Message send 0x%x on 0x%x status %d", components, self, sent);
 
1090
  return sent;
 
1091
}
 
1092
 
 
1093
- (NSMessagePort*) sendPort
 
1094
{
 
1095
  if (sendPort == nil)
 
1096
    return nil;
 
1097
  else if (caller == YES)
 
1098
    return GS_GC_UNHIDE(sendPort);      // We called, so port is not retained.
 
1099
  else
 
1100
    return sendPort;                    // Retained port.
 
1101
}
 
1102
 
 
1103
- (void) setState: (GSHandleState)s
 
1104
{
 
1105
  state = s;
 
1106
}
 
1107
 
 
1108
- (GSHandleState) state
 
1109
{
 
1110
  return state;
 
1111
}
 
1112
 
 
1113
- (NSDate*) timedOutEvent: (void*)data
 
1114
                     type: (RunLoopEventType)type
 
1115
                  forMode: (NSString*)mode
 
1116
{
 
1117
  return nil;
 
1118
}
 
1119
 
 
1120
@end
 
1121
 
 
1122
 
 
1123
 
 
1124
@interface NSMessagePort (RunLoop) <RunLoopEvents>
 
1125
- (void) receivedEvent: (void*)data
 
1126
                  type: (RunLoopEventType)type
 
1127
                 extra: (void*)extra
 
1128
               forMode: (NSString*)mode;
 
1129
- (NSDate*) timedOutEvent: (void*)data
 
1130
                     type: (RunLoopEventType)type
 
1131
                  forMode: (NSString*)mode;
 
1132
@end
 
1133
 
 
1134
 
 
1135
@implementation NSMessagePort
 
1136
 
 
1137
static NSRecursiveLock  *messagePortLock = nil;
 
1138
 
 
1139
/*
 
1140
Maps NSData objects with the socket name to NSMessagePort objects.
 
1141
*/
 
1142
static NSMapTable       *messagePortMap = 0;
 
1143
static Class            messagePortClass;
 
1144
 
 
1145
 
 
1146
static void clean_up_sockets(void)
 
1147
{
 
1148
  NSMessagePort *port;
 
1149
  NSData *name;
 
1150
  NSMapEnumerator mEnum;
 
1151
  BOOL  unknownThread = GSRegisterCurrentThread();
 
1152
  CREATE_AUTORELEASE_POOL(arp);
 
1153
 
 
1154
  mEnum = NSEnumerateMapTable(messagePortMap);
 
1155
  while (NSNextMapEnumeratorPair(&mEnum, (void *)&name, (void *)&port))
 
1156
    {
 
1157
      if ([port _listener] != -1)
 
1158
        unlink([name bytes]);
 
1159
    }
 
1160
  NSEndMapTableEnumeration(&mEnum);
 
1161
  DESTROY(arp);
 
1162
  if (unknownThread == YES)
 
1163
    {
 
1164
      GSUnregisterCurrentThread();
 
1165
    }
 
1166
}
 
1167
 
 
1168
 
 
1169
#if NEED_WORD_ALIGNMENT
 
1170
static unsigned wordAlign;
 
1171
#endif
 
1172
 
 
1173
+ (void) initialize
 
1174
{
 
1175
  if (self == [NSMessagePort class])
 
1176
    {
 
1177
#if NEED_WORD_ALIGNMENT
 
1178
      wordAlign = objc_alignof_type(@encode(gsu32));
 
1179
#endif
 
1180
      messagePortClass = self;
 
1181
      messagePortMap = NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks,
 
1182
        NSNonOwnedPointerMapValueCallBacks, 0);
 
1183
 
 
1184
      messagePortLock = [GSLazyRecursiveLock new];
 
1185
      atexit(clean_up_sockets);
 
1186
    }
 
1187
}
 
1188
 
 
1189
+ (id) new
 
1190
{
 
1191
static int unique_index = 0;
 
1192
  NSString      *path;
 
1193
  NSNumber      *p = [NSNumber numberWithInt: 0700];
 
1194
  NSDictionary  *attr;
 
1195
 
 
1196
  attr = [NSDictionary dictionaryWithObject: p
 
1197
                                     forKey: NSFilePosixPermissions];
 
1198
 
 
1199
  path = NSTemporaryDirectory();
 
1200
 
 
1201
  path = [path stringByAppendingPathComponent: @"NSMessagePort"];
 
1202
  [[NSFileManager defaultManager] createDirectoryAtPath: path
 
1203
                                  attributes: attr];
 
1204
 
 
1205
  path = [path stringByAppendingPathComponent: @"ports"];
 
1206
  [[NSFileManager defaultManager] createDirectoryAtPath: path
 
1207
                                  attributes: attr];
 
1208
 
 
1209
  M_LOCK(messagePortLock);
 
1210
  path = [path stringByAppendingPathComponent:
 
1211
   [NSString stringWithFormat: @"%i.%i",
 
1212
        [[NSProcessInfo processInfo] processIdentifier], unique_index++]];
 
1213
  M_UNLOCK(messagePortLock);
 
1214
 
 
1215
  return RETAIN([self _portWithName: [path fileSystemRepresentation]
 
1216
                           listener: YES]);
 
1217
}
 
1218
 
 
1219
/*
 
1220
 * This is the preferred initialisation method for NSMessagePort
 
1221
 *
 
1222
 * 'socketName' is the name of the socket in the port directory
 
1223
 */
 
1224
+ (NSMessagePort*) _portWithName: (const unsigned char *)socketName
 
1225
                     listener: (BOOL)shouldListen
 
1226
{
 
1227
  unsigned              i;
 
1228
  NSMessagePort         *port = nil;
 
1229
  NSData                *theName;
 
1230
 
 
1231
  theName = [[NSData alloc] initWithBytes: socketName
 
1232
                                   length: strlen(socketName)+1];
 
1233
 
 
1234
  M_LOCK(messagePortLock);
 
1235
 
 
1236
  /*
 
1237
   * First try to find a pre-existing port.
 
1238
   */
 
1239
  port = (NSMessagePort*)NSMapGet(messagePortMap, theName);
 
1240
 
 
1241
  if (port == nil)
 
1242
    {
 
1243
      port = (NSMessagePort*)NSAllocateObject(self, 0, NSDefaultMallocZone());
 
1244
      port->name = theName;
 
1245
      port->listener = -1;
 
1246
      port->handles = NSCreateMapTable(NSIntMapKeyCallBacks,
 
1247
        NSObjectMapValueCallBacks, 0);
 
1248
      port->myLock = [GSLazyRecursiveLock new];
 
1249
      port->_is_valid = YES;
 
1250
 
 
1251
      if (shouldListen == YES)
 
1252
        {
 
1253
          int   desc;
 
1254
          struct sockaddr_un    sockaddr;
 
1255
 
 
1256
          /*
 
1257
           * Creating a new port on the local host - so we must create a
 
1258
           * listener socket to accept incoming connections.
 
1259
           */
 
1260
          memset(&sockaddr, '\0', sizeof(sockaddr));
 
1261
          sockaddr.sun_family = AF_LOCAL;
 
1262
          strncpy(sockaddr.sun_path, socketName, sizeof(sockaddr.sun_path));
 
1263
 
 
1264
          /*
 
1265
           * Need size of buffer for getsockbyname() later.
 
1266
           */
 
1267
          i = sizeof(sockaddr);
 
1268
 
 
1269
          if ((desc = socket(PF_LOCAL, SOCK_STREAM, PF_UNSPEC)) < 0)
 
1270
            {
 
1271
              NSLog(@"unable to create socket - %s", GSLastErrorStr(errno));
 
1272
              DESTROY(port);
 
1273
            }
 
1274
          else if (bind(desc, (struct sockaddr *)&sockaddr,
 
1275
            sizeof(sockaddr)) < 0)
 
1276
            {
 
1277
              NSLog(@"unable to bind to %s - %s",
 
1278
                sockaddr.sun_path, GSLastErrorStr(errno));
 
1279
              (void) close(desc);
 
1280
              DESTROY(port);
 
1281
            }
 
1282
          else if (listen(desc, 5) < 0)
 
1283
            {
 
1284
              NSLog(@"unable to listen on port - %s", GSLastErrorStr(errno));
 
1285
              (void) close(desc);
 
1286
              DESTROY(port);
 
1287
            }
 
1288
          else if (getsockname(desc, (struct sockaddr*)&sockaddr, &i) < 0)
 
1289
            {
 
1290
              NSLog(@"unable to get socket name - %s", GSLastErrorStr(errno));
 
1291
              (void) close(desc);
 
1292
              DESTROY(port);
 
1293
            }
 
1294
          else
 
1295
            {
 
1296
              /*
 
1297
               * Set up the listening descriptor and the actual message port
 
1298
               * number (which will have been set to a real port number when
 
1299
               * we did the 'bind' call.
 
1300
               */
 
1301
              port->listener = desc;
 
1302
              /*
 
1303
               * Make sure we have the map table for this port.
 
1304
               */
 
1305
              NSMapInsert(messagePortMap, (void*)theName, (void*)port);
 
1306
              NSDebugMLLog(@"NSMessagePort", @"Created listening port: %@",
 
1307
                port);
 
1308
            }
 
1309
        }
 
1310
      else
 
1311
        {
 
1312
          /*
 
1313
           * Make sure we have the map table for this port.
 
1314
           */
 
1315
          NSMapInsert(messagePortMap, (void*)theName, (void*)port);
 
1316
          NSDebugMLLog(@"NSMessagePort", @"Created speaking port: %@", port);
 
1317
        }
 
1318
    }
 
1319
  else
 
1320
    {
 
1321
      RELEASE(theName);
 
1322
      RETAIN(port);
 
1323
      NSDebugMLLog(@"NSMessagePort", @"Using pre-existing port: %@", port);
 
1324
    }
 
1325
  IF_NO_GC(AUTORELEASE(port));
 
1326
 
 
1327
  M_UNLOCK(messagePortLock);
 
1328
  return port;
 
1329
}
 
1330
 
 
1331
- (void) addHandle: (GSMessageHandle*)handle forSend: (BOOL)send
 
1332
{
 
1333
  M_LOCK(myLock);
 
1334
  if (send == YES)
 
1335
    {
 
1336
      if (handle->caller == YES)
 
1337
        handle->sendPort = GS_GC_HIDE(self);
 
1338
      else
 
1339
        ASSIGN(handle->sendPort, self);
 
1340
    }
 
1341
  else
 
1342
    {
 
1343
      handle->recvPort = GS_GC_HIDE(self);
 
1344
    }
 
1345
  NSMapInsert(handles, (void*)(gsaddr)[handle descriptor], (void*)handle);
 
1346
  M_UNLOCK(myLock);
 
1347
}
 
1348
 
 
1349
- (id) copyWithZone: (NSZone*)zone
 
1350
{
 
1351
  return RETAIN(self);
 
1352
}
 
1353
 
 
1354
- (void) dealloc
 
1355
{
 
1356
  [self gcFinalize];
 
1357
  DESTROY(name);
 
1358
  [super dealloc];
 
1359
}
 
1360
 
 
1361
- (NSString*) description
 
1362
{
 
1363
  NSString      *desc;
 
1364
 
 
1365
  desc = [NSString stringWithFormat: @"<NSMessagePort %p with name %s>",
 
1366
           self, [name bytes]];
 
1367
  return desc;
 
1368
}
 
1369
 
 
1370
- (void) gcFinalize
 
1371
{
 
1372
  NSDebugMLLog(@"NSMessagePort", @"NSMessagePort 0x%x finalized", self);
 
1373
  [self invalidate];
 
1374
}
 
1375
 
 
1376
/*
 
1377
 * This is a callback method used by the NSRunLoop class to determine which
 
1378
 * descriptors to watch for the port.
 
1379
 */
 
1380
- (void) getFds: (int*)fds count: (int*)count
 
1381
{
 
1382
  NSMapEnumerator       me;
 
1383
  int                   sock;
 
1384
  GSMessageHandle               *handle;
 
1385
  id                    recvSelf;
 
1386
 
 
1387
  M_LOCK(myLock);
 
1388
 
 
1389
  /*
 
1390
   * Make sure there is enough room in the provided array.
 
1391
   */
 
1392
  NSAssert(*count > (int)NSCountMapTable(handles),
 
1393
    NSInternalInconsistencyException);
 
1394
 
 
1395
  /*
 
1396
   * Put in our listening socket.
 
1397
   */
 
1398
  *count = 0;
 
1399
  if (listener >= 0)
 
1400
    {
 
1401
      fds[(*count)++] = listener;
 
1402
    }
 
1403
 
 
1404
  /*
 
1405
   * Enumerate all our socket handles, and put them in as long as they
 
1406
   * are to be used for receiving.
 
1407
   */
 
1408
  recvSelf = GS_GC_HIDE(self);
 
1409
  me = NSEnumerateMapTable(handles);
 
1410
  while (NSNextMapEnumeratorPair(&me, (void*)&sock, (void*)&handle))
 
1411
    {
 
1412
      if (handle->recvPort == recvSelf)
 
1413
        {
 
1414
          fds[(*count)++] = sock;
 
1415
        }
 
1416
    }
 
1417
  NSEndMapTableEnumeration(&me);
 
1418
  M_UNLOCK(myLock);
 
1419
}
 
1420
 
 
1421
- (id) conversation: (NSPort*)recvPort
 
1422
{
 
1423
  NSMapEnumerator       me;
 
1424
  int                   sock;
 
1425
  GSMessageHandle       *handle = nil;
 
1426
 
 
1427
  M_LOCK(myLock);
 
1428
  /*
 
1429
   * Enumerate all our socket handles, and look for one with port.
 
1430
   */
 
1431
  me = NSEnumerateMapTable(handles);
 
1432
  while (NSNextMapEnumeratorPair(&me, (void*)&sock, (void*)&handle))
 
1433
    {
 
1434
      if ([handle recvPort] == recvPort)
 
1435
        {
 
1436
          RETAIN(handle);
 
1437
          NSEndMapTableEnumeration(&me);
 
1438
          M_UNLOCK(myLock);
 
1439
          return AUTORELEASE(handle);
 
1440
        }
 
1441
    }
 
1442
  NSEndMapTableEnumeration(&me);
 
1443
  M_UNLOCK(myLock);
 
1444
  return nil;
 
1445
}
 
1446
 
 
1447
- (GSMessageHandle*) handleForPort: (NSMessagePort*)recvPort
 
1448
                        beforeDate: (NSDate*)when
 
1449
{
 
1450
  NSMapEnumerator       me;
 
1451
  int                   sock;
 
1452
#ifndef BROKEN_SO_REUSEADDR
 
1453
  int                   opt = 1;
 
1454
#endif
 
1455
  GSMessageHandle       *handle = nil;
 
1456
 
 
1457
  M_LOCK(myLock);
 
1458
  /*
 
1459
   * Enumerate all our socket handles, and look for one with port.
 
1460
   */
 
1461
  me = NSEnumerateMapTable(handles);
 
1462
  while (NSNextMapEnumeratorPair(&me, (void*)&sock, (void*)&handle))
 
1463
    {
 
1464
      if ([handle recvPort] == recvPort)
 
1465
        {
 
1466
          M_UNLOCK(myLock);
 
1467
          NSEndMapTableEnumeration(&me);
 
1468
          return handle;
 
1469
        }
 
1470
    }
 
1471
  NSEndMapTableEnumeration(&me);
 
1472
 
 
1473
  /*
 
1474
   * Not found ... create a new handle.
 
1475
   */
 
1476
  handle = nil;
 
1477
  if ((sock = socket(PF_LOCAL, SOCK_STREAM, PF_UNSPEC)) < 0)
 
1478
    {
 
1479
      NSLog(@"unable to create socket - %s", GSLastErrorStr(errno));
 
1480
    }
 
1481
#ifndef BROKEN_SO_REUSEADDR
 
1482
  /*
 
1483
   * Under decent systems, SO_REUSEADDR means that the port can be reused
 
1484
   * immediately that this process exits.  Under some it means
 
1485
   * that multiple processes can serve the same port simultaneously.
 
1486
   * We don't want that broken behavior!
 
1487
   */
 
1488
  else if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt,
 
1489
    sizeof(opt)) < 0)
 
1490
    {
 
1491
      (void)close(sock);
 
1492
      NSLog(@"unable to set reuse on socket - %s", GSLastErrorStr(errno));
 
1493
    }
 
1494
#endif
 
1495
  else if ((handle = [GSMessageHandle handleWithDescriptor: sock]) == nil)
 
1496
    {
 
1497
      (void)close(sock);
 
1498
      NSLog(@"unable to create GSMessageHandle - %s", GSLastErrorStr(errno));
 
1499
    }
 
1500
  else
 
1501
    {
 
1502
      [recvPort addHandle: handle forSend: NO];
 
1503
    }
 
1504
  M_UNLOCK(myLock);
 
1505
  /*
 
1506
   * If we succeeded in creating a new handle - connect to remote host.
 
1507
   */
 
1508
  if (handle != nil)
 
1509
    {
 
1510
      if ([handle connectToPort: self beforeDate: when] == NO)
 
1511
        {
 
1512
          [handle invalidate];
 
1513
          handle = nil;
 
1514
        }
 
1515
    }
 
1516
  return handle;
 
1517
}
 
1518
 
 
1519
- (void) handlePortMessage: (NSPortMessage*)m
 
1520
{
 
1521
  id    d = [self delegate];
 
1522
 
 
1523
  if (d == nil)
 
1524
    {
 
1525
      NSDebugMLLog(@"NSMessagePort",
 
1526
        @"No delegate to handle incoming message", 0);
 
1527
      return;
 
1528
    }
 
1529
  if ([d respondsToSelector: @selector(handlePortMessage:)] == NO)
 
1530
    {
 
1531
      NSDebugMLLog(@"NSMessagePort", @"delegate doesn't handle messages", 0);
 
1532
      return;
 
1533
    }
 
1534
  [d handlePortMessage: m];
 
1535
}
 
1536
 
 
1537
- (unsigned) hash
 
1538
{
 
1539
  return [name hash];
 
1540
}
 
1541
 
 
1542
- (id) init
 
1543
{
 
1544
  RELEASE(self);
 
1545
  self = [messagePortClass new];
 
1546
  return self;
 
1547
}
 
1548
 
 
1549
- (void) invalidate
 
1550
{
 
1551
  if ([self isValid] == YES)
 
1552
    {
 
1553
      M_LOCK(myLock);
 
1554
 
 
1555
      if ([self isValid] == YES)
 
1556
        {
 
1557
          NSArray       *handleArray;
 
1558
          unsigned      i;
 
1559
 
 
1560
          M_LOCK(messagePortLock);
 
1561
          if (listener >= 0)
 
1562
            {
 
1563
              (void) close(listener);
 
1564
              unlink([name bytes]);
 
1565
              listener = -1;
 
1566
            }
 
1567
          NSMapRemove(messagePortMap, (void*)name);
 
1568
          M_UNLOCK(messagePortLock);
 
1569
 
 
1570
          if (handles != 0)
 
1571
            {
 
1572
              handleArray = NSAllMapTableValues(handles);
 
1573
              i = [handleArray count];
 
1574
              while (i-- > 0)
 
1575
                {
 
1576
                  GSMessageHandle       *handle;
 
1577
 
 
1578
                  handle = [handleArray objectAtIndex: i];
 
1579
                  [handle invalidate];
 
1580
                }
 
1581
              /*
 
1582
               * We permit mutual recursive invalidation, so the handles map
 
1583
               * may already have been destroyed.
 
1584
               */
 
1585
              if (handles != 0)
 
1586
                {
 
1587
                  NSFreeMapTable(handles);
 
1588
                  handles = 0;
 
1589
                }
 
1590
            }
 
1591
          [[NSMessagePortNameServer sharedInstance] removePort: self];
 
1592
          [super invalidate];
 
1593
        }
 
1594
      M_UNLOCK(myLock);
 
1595
    }
 
1596
}
 
1597
 
 
1598
- (BOOL) isEqual: (id)anObject
 
1599
{
 
1600
  if (anObject == self)
 
1601
    {
 
1602
      return YES;
 
1603
    }
 
1604
  if ([anObject class] == [self class])
 
1605
    {
 
1606
      NSMessagePort     *o = (NSMessagePort*)anObject;
 
1607
 
 
1608
      return [o->name isEqual: name];
 
1609
    }
 
1610
  return NO;
 
1611
}
 
1612
 
 
1613
- (void) receivedEvent: (void*)data
 
1614
                  type: (RunLoopEventType)type
 
1615
                 extra: (void*)extra
 
1616
               forMode: (NSString*)mode
 
1617
{
 
1618
  int           desc = (int)(gsaddr)extra;
 
1619
  GSMessageHandle       *handle;
 
1620
 
 
1621
  if (desc == listener)
 
1622
    {
 
1623
      struct sockaddr_un        sockAddr;
 
1624
      int                       size = sizeof(sockAddr);
 
1625
 
 
1626
      desc = accept(listener, (struct sockaddr*)&sockAddr, &size);
 
1627
      if (desc < 0)
 
1628
        {
 
1629
          NSDebugMLLog(@"NSMessagePort",
 
1630
            @"accept failed - handled in other thread?");
 
1631
        }
 
1632
      else
 
1633
        {
 
1634
          /*
 
1635
           * Create a handle for the socket and set it up so we are its
 
1636
           * receiving port, and it's waiting to get the port name from
 
1637
           * the other end.
 
1638
           */
 
1639
          handle = [GSMessageHandle handleWithDescriptor: desc];
 
1640
          memcpy(&handle->sockAddr, &sockAddr, sizeof(sockAddr));
 
1641
 
 
1642
          [handle setState: GS_H_ACCEPT];
 
1643
          [self addHandle: handle forSend: NO];
 
1644
        }
 
1645
    }
 
1646
  else
 
1647
    {
 
1648
      M_LOCK(myLock);
 
1649
      handle = (GSMessageHandle*)NSMapGet(handles, (void*)(gsaddr)desc);
 
1650
      IF_NO_GC(AUTORELEASE(RETAIN(handle)));
 
1651
      M_UNLOCK(myLock);
 
1652
      if (handle == nil)
 
1653
        {
 
1654
          const char    *t;
 
1655
 
 
1656
          if (type == ET_RDESC) t = "rdesc";
 
1657
          else if (type == ET_WDESC) t = "wdesc";
 
1658
          else if (type == ET_EDESC) t = "edesc";
 
1659
          else if (type == ET_RPORT) t = "rport";
 
1660
          else t = "unknown";
 
1661
          NSLog(@"No handle for event %s on descriptor %d", t, desc);
 
1662
          [[runLoopClass currentRunLoop] removeEvent: extra
 
1663
                                                type: type
 
1664
                                             forMode: mode
 
1665
                                                 all: YES];
 
1666
        }
 
1667
      else
 
1668
        {
 
1669
          [handle receivedEvent: data type: type extra: extra forMode: mode];
 
1670
        }
 
1671
    }
 
1672
}
 
1673
 
 
1674
- (void) removeHandle: (GSMessageHandle*)handle
 
1675
{
 
1676
  M_LOCK(myLock);
 
1677
  if ([handle sendPort] == self)
 
1678
    {
 
1679
      if (handle->caller != YES)
 
1680
        {
 
1681
          /*
 
1682
           * This is a handle for a send port, and the handle was not formed
 
1683
           * by calling the remote process, so this port object must have
 
1684
           * been created to deal with an incoming connection and will have
 
1685
           * been retained - we must therefore release this port since the
 
1686
           * handle no longer uses it.
 
1687
           */
 
1688
          AUTORELEASE(self);
 
1689
        }
 
1690
      handle->sendPort = nil;
 
1691
    }
 
1692
  if ([handle recvPort] == self)
 
1693
    {
 
1694
      handle->recvPort = nil;
 
1695
    }
 
1696
  NSMapRemove(handles, (void*)(gsaddr)[handle descriptor]);
 
1697
  if (listener < 0 && NSCountMapTable(handles) == 0)
 
1698
    {
 
1699
      [self invalidate];
 
1700
    }
 
1701
  M_UNLOCK(myLock);
 
1702
}
 
1703
 
 
1704
/*
 
1705
 * This returns the amount of space that a port coder should reserve at the
 
1706
 * start of its encoded data so that the NSMessagePort can insert header info
 
1707
 * into the data.
 
1708
 * The idea is that a message consisting of a single data item with space at
 
1709
 * the start can be written directly without having to copy data to another
 
1710
 * buffer etc.
 
1711
 */
 
1712
- (unsigned int) reservedSpaceLength
 
1713
{
 
1714
  return sizeof(GSPortItemHeader) + sizeof(GSPortMsgHeader);
 
1715
}
 
1716
 
 
1717
- (BOOL) sendBeforeDate: (NSDate*)when
 
1718
                  msgid: (int)msgId
 
1719
             components: (NSMutableArray*)components
 
1720
                   from: (NSPort*)receivingPort
 
1721
               reserved: (unsigned)length
 
1722
{
 
1723
  BOOL          sent = NO;
 
1724
  GSMessageHandle       *h;
 
1725
  unsigned      rl;
 
1726
 
 
1727
  if ([self isValid] == NO)
 
1728
    {
 
1729
      return NO;
 
1730
    }
 
1731
  if ([components count] == 0)
 
1732
    {
 
1733
      NSLog(@"empty components sent");
 
1734
      return NO;
 
1735
    }
 
1736
  /*
 
1737
   * If the reserved length in the first data object is wrong - we have to
 
1738
   * fail, unless it's zero, in which case we can insert a data object for
 
1739
   * the header.
 
1740
   */
 
1741
  rl = [self reservedSpaceLength];
 
1742
  if (length != 0 && length != rl)
 
1743
    {
 
1744
      NSLog(@"bad reserved length - %u", length);
 
1745
      return NO;
 
1746
    }
 
1747
  if ([receivingPort isKindOfClass: messagePortClass] == NO)
 
1748
    {
 
1749
      NSLog(@"woah there - receiving port is not the correct type");
 
1750
      return NO;
 
1751
    }
 
1752
 
 
1753
  h = [self handleForPort: (NSMessagePort*)receivingPort beforeDate: when];
 
1754
  if (h != nil)
 
1755
    {
 
1756
      NSMutableData     *header;
 
1757
      unsigned          hLength;
 
1758
      unsigned          l;
 
1759
      GSPortItemHeader  *pih;
 
1760
      GSPortMsgHeader   *pmh;
 
1761
      unsigned          c = [components count];
 
1762
      unsigned          i;
 
1763
      BOOL              pack = YES;
 
1764
 
 
1765
      /*
 
1766
       * Ok - ensure we have space to insert header info.
 
1767
       */
 
1768
      if (length == 0 && rl != 0)
 
1769
        {
 
1770
          header = [[mutableDataClass alloc] initWithCapacity: NETBLOCK];
 
1771
 
 
1772
          [header setLength: rl];
 
1773
          [components insertObject: header atIndex: 0];
 
1774
          RELEASE(header);
 
1775
        }
 
1776
 
 
1777
      header = [components objectAtIndex: 0];
 
1778
      /*
 
1779
       * The Item header contains the item type and the length of the
 
1780
       * data in the item (excluding the item header itself).
 
1781
       */
 
1782
      hLength = [header length];
 
1783
      l = hLength - sizeof(GSPortItemHeader);
 
1784
      pih = (GSPortItemHeader*)[header mutableBytes];
 
1785
      pih->type = GSSwapHostI32ToBig(GSP_HEAD);
 
1786
      pih->length = GSSwapHostI32ToBig(l);
 
1787
 
 
1788
      /*
 
1789
       * The message header contains the message Id and the original count
 
1790
       * of components in the message (excluding any extra component added
 
1791
       * simply to hold the header).
 
1792
       */
 
1793
      pmh = (GSPortMsgHeader*)&pih[1];
 
1794
      pmh->mId = GSSwapHostI32ToBig(msgId);
 
1795
      pmh->nItems = GSSwapHostI32ToBig(c);
 
1796
 
 
1797
      /*
 
1798
       * Now insert item header information as required.
 
1799
       * Pack as many items into the initial data object as possible, up to
 
1800
       * a maximum of NETBLOCK bytes.  This is to try to get a single,
 
1801
       * efficient write operation if possible.
 
1802
       */
 
1803
      for (i = 1; i < c; i++)
 
1804
        {
 
1805
          id    o = [components objectAtIndex: i];
 
1806
 
 
1807
          if ([o isKindOfClass: [NSData class]])
 
1808
            {
 
1809
              GSPortItemHeader  *pih;
 
1810
              unsigned          h = sizeof(GSPortItemHeader);
 
1811
              unsigned          l = [o length];
 
1812
              void              *b;
 
1813
 
 
1814
              if (pack == YES && hLength + l + h <= NETBLOCK)
 
1815
                {
 
1816
                  [header setLength: hLength + l + h];
 
1817
                  b = [header mutableBytes];
 
1818
                  b += hLength;
 
1819
#if NEED_WORD_ALIGNMENT
 
1820
                  /*
 
1821
                   * When packing data, an item may not be aligned on a
 
1822
                   * word boundary, so we work with an aligned buffer
 
1823
                   * and use memcmpy()
 
1824
                   */
 
1825
                  if ((hLength % wordAlign) != 0)
 
1826
                    {
 
1827
                      GSPortItemHeader  itemHeader;
 
1828
 
 
1829
                      pih = (GSPortItemHeader*)&itemHeader;
 
1830
                      pih->type = GSSwapHostI32ToBig(GSP_DATA);
 
1831
                      pih->length = GSSwapHostI32ToBig(l);
 
1832
                      memcpy(b, (void*)pih, h);
 
1833
                    }
 
1834
                  else
 
1835
                    {
 
1836
                      pih = (GSPortItemHeader*)b;
 
1837
                      pih->type = GSSwapHostI32ToBig(GSP_DATA);
 
1838
                      pih->length = GSSwapHostI32ToBig(l);
 
1839
                    }
 
1840
#else
 
1841
                  pih = (GSPortItemHeader*)b;
 
1842
                  pih->type = GSSwapHostI32ToBig(GSP_DATA);
 
1843
                  pih->length = GSSwapHostI32ToBig(l);
 
1844
#endif
 
1845
                  memcpy(b+h, [o bytes], l);
 
1846
                  [components removeObjectAtIndex: i--];
 
1847
                  c--;
 
1848
                  hLength += l + h;
 
1849
                }
 
1850
              else
 
1851
                {
 
1852
                  NSMutableData *d;
 
1853
 
 
1854
                  pack = NO;
 
1855
                  d = [[NSMutableData alloc] initWithLength: l + h];
 
1856
                  b = [d mutableBytes];
 
1857
                  pih = (GSPortItemHeader*)b;
 
1858
                  memcpy(b+h, [o bytes], l);
 
1859
                  pih->type = GSSwapHostI32ToBig(GSP_DATA);
 
1860
                  pih->length = GSSwapHostI32ToBig(l);
 
1861
                  [components replaceObjectAtIndex: i
 
1862
                                        withObject: d];
 
1863
                  RELEASE(d);
 
1864
                }
 
1865
            }
 
1866
          else if ([o isKindOfClass: messagePortClass])
 
1867
            {
 
1868
              NSData    *d = newDataWithEncodedPort(o);
 
1869
              unsigned  dLength = [d length];
 
1870
 
 
1871
              if (pack == YES && hLength + dLength <= NETBLOCK)
 
1872
                {
 
1873
                  void  *b;
 
1874
 
 
1875
                  [header setLength: hLength + dLength];
 
1876
                  b = [header mutableBytes];
 
1877
                  b += hLength;
 
1878
                  hLength += dLength;
 
1879
                  memcpy(b, [d bytes], dLength);
 
1880
                  [components removeObjectAtIndex: i--];
 
1881
                  c--;
 
1882
                }
 
1883
              else
 
1884
                {
 
1885
                  pack = NO;
 
1886
                  [components replaceObjectAtIndex: i withObject: d];
 
1887
                }
 
1888
              RELEASE(d);
 
1889
            }
 
1890
        }
 
1891
 
 
1892
      /*
 
1893
       * Now send the message.
 
1894
       */
 
1895
      sent = [h sendMessage: components beforeDate: when];
 
1896
    }
 
1897
  return sent;
 
1898
}
 
1899
 
 
1900
- (NSDate*) timedOutEvent: (void*)data
 
1901
                     type: (RunLoopEventType)type
 
1902
                  forMode: (NSString*)mode
 
1903
{
 
1904
  return nil;
 
1905
}
 
1906
 
 
1907
 
 
1908
-(const unsigned char *) _name
 
1909
{
 
1910
  return [name bytes];
 
1911
}
 
1912
 
 
1913
-(int) _listener
 
1914
{
 
1915
  return listener;
 
1916
}
 
1917
 
 
1918
@end
 
1919