1996-03-01 16:06:57 +00:00
|
|
|
|
/* Implementation of UDP port object for use with Connection
|
|
|
|
|
Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
|
|
|
|
|
|
1996-04-17 20:17:45 +00:00
|
|
|
|
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
1996-03-01 16:06:57 +00:00
|
|
|
|
Created: July 1994
|
|
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
|
This file is part of the GNUstep Base Library.
|
1996-03-01 16:06:57 +00:00
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
|
License along with this library; if not, write to the Free
|
|
|
|
|
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
*/
|
|
|
|
|
|
1996-03-06 14:36:36 +00:00
|
|
|
|
/* xxx I should also look into SOCK_RDM and SOCK_SEQPACKET. */
|
|
|
|
|
|
1996-04-17 15:23:00 +00:00
|
|
|
|
#include <gnustep/base/UdpPort.h>
|
|
|
|
|
#include <gnustep/base/Lock.h>
|
|
|
|
|
#include <gnustep/base/Connection.h>
|
|
|
|
|
#include <gnustep/base/Coder.h>
|
|
|
|
|
#include <gnustep/base/Array.h>
|
|
|
|
|
#include <gnustep/base/ConnectedCoder.h>
|
|
|
|
|
#include <gnustep/base/String.h>
|
1996-03-01 16:06:57 +00:00
|
|
|
|
#include <assert.h>
|
1996-05-27 14:26:41 +00:00
|
|
|
|
#ifndef WIN32
|
1996-03-26 00:27:03 +00:00
|
|
|
|
#include <sys/param.h> /* for MAXHOSTNAMELEN */
|
1996-05-27 14:26:41 +00:00
|
|
|
|
#endif /* !WIN32 */
|
1996-03-01 16:06:57 +00:00
|
|
|
|
#if _AIX
|
|
|
|
|
#include <sys/select.h>
|
|
|
|
|
#endif /* _AIX */
|
|
|
|
|
#ifndef WIN32
|
|
|
|
|
#include <netdb.h>
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#endif /* !WIN32 */
|
|
|
|
|
|
|
|
|
|
@interface UdpInPort (Private)
|
|
|
|
|
@end
|
|
|
|
|
@interface UdpOutPort (Private)
|
|
|
|
|
+ newForSendingToSockaddr: (struct sockaddr_in*)addr;
|
|
|
|
|
@end
|
1996-03-18 14:02:44 +00:00
|
|
|
|
@interface UdpInPacket (Private)
|
1996-03-01 16:06:57 +00:00
|
|
|
|
- (void) _setReplyPort: p;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
/* The maximum size of packet UdpPort's will send or recieve. */
|
|
|
|
|
/* xxx What is the UDP maximum? */
|
|
|
|
|
#define MAX_PACKET_SIZE 2048
|
|
|
|
|
|
|
|
|
|
/* Make this a hashtable? */
|
|
|
|
|
static Lock* udp_port_gate = nil;
|
|
|
|
|
|
|
|
|
|
static BOOL udp_port_debug = NO;
|
|
|
|
|
|
1996-03-24 22:04:23 +00:00
|
|
|
|
|
|
|
|
|
/* Our current, sad excuse for a name server. */
|
|
|
|
|
|
|
|
|
|
static unsigned short
|
|
|
|
|
name_2_port_number (const char *name)
|
1996-03-01 16:06:57 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned int ret = 0;
|
|
|
|
|
unsigned int ctr = 0;
|
1996-03-24 22:04:23 +00:00
|
|
|
|
|
1996-03-01 16:06:57 +00:00
|
|
|
|
while (*name)
|
|
|
|
|
{
|
|
|
|
|
ret ^= *name++ << ctr;
|
|
|
|
|
ctr = (ctr + 1) % sizeof (void *);
|
|
|
|
|
}
|
1996-03-24 22:04:23 +00:00
|
|
|
|
return (ret % (65535 - IPPORT_USERRESERVED - 1)) + IPPORT_USERRESERVED;
|
|
|
|
|
/* return strlen (name) + IPPORT_USERRESERVED; */
|
1996-03-01 16:06:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@implementation UdpInPort
|
|
|
|
|
|
|
|
|
|
static NSMapTable *port_number_2_in_port = NULL;
|
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [UdpInPort class])
|
|
|
|
|
{
|
|
|
|
|
port_number_2_in_port =
|
|
|
|
|
NSCreateMapTable (NSIntMapKeyCallBacks,
|
|
|
|
|
NSNonOwnedPointerMapValueCallBacks, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-24 22:04:23 +00:00
|
|
|
|
/* This is the designated initializer.
|
|
|
|
|
If N is zero, it will choose a port number for you. */
|
1996-03-01 16:06:57 +00:00
|
|
|
|
|
|
|
|
|
+ newForReceivingFromPortNumber: (unsigned short)n
|
|
|
|
|
{
|
|
|
|
|
UdpInPort* p;
|
|
|
|
|
|
|
|
|
|
assert (n > IPPORT_USERRESERVED);
|
|
|
|
|
|
|
|
|
|
[udp_port_gate lock];
|
|
|
|
|
|
|
|
|
|
/* See if there is already one created */
|
|
|
|
|
if ((p = NSMapGet (port_number_2_in_port, (void*)(int)n)))
|
|
|
|
|
return p;
|
|
|
|
|
|
1996-03-24 22:04:23 +00:00
|
|
|
|
/* No, create a new port object */
|
1996-03-01 16:06:57 +00:00
|
|
|
|
p = [[self alloc] init];
|
1996-03-24 22:04:23 +00:00
|
|
|
|
|
|
|
|
|
/* Make a new socket for the port object */
|
1996-03-01 16:06:57 +00:00
|
|
|
|
if ((p->_socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
|
|
|
|
|
{
|
1996-03-24 22:04:23 +00:00
|
|
|
|
perror("[UdpInPort +newForReceivingFromPortNumber:] socket()");
|
1996-03-01 16:06:57 +00:00
|
|
|
|
abort ();
|
|
|
|
|
}
|
1996-03-24 22:04:23 +00:00
|
|
|
|
|
|
|
|
|
/* Give the socket a name using bind */
|
|
|
|
|
{
|
|
|
|
|
struct hostent *hp;
|
|
|
|
|
char hostname[MAXHOSTNAMELEN];
|
|
|
|
|
int len = MAXHOSTNAMELEN;
|
|
|
|
|
if (gethostname (hostname, len) < 0)
|
|
|
|
|
{
|
|
|
|
|
perror ("[UdpInPort +newForReceivingFromPortNumber:] gethostname()");
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
hp = gethostbyname (hostname);
|
|
|
|
|
if (!hp)
|
|
|
|
|
/* xxx This won't work with port connections on a network, though.
|
|
|
|
|
Fix this. Perhaps there is a better way of getting the address
|
|
|
|
|
of the local host. */
|
|
|
|
|
hp = gethostbyname ("localhost");
|
|
|
|
|
assert (hp);
|
|
|
|
|
/* Use host's address, and not INADDR_ANY, so that went we
|
|
|
|
|
encode our _address for a D.O. operation, they get
|
|
|
|
|
our unique host address that can identify us across the network. */
|
|
|
|
|
memcpy (&(p->_address.sin_addr), hp->h_addr, hp->h_length);
|
|
|
|
|
p->_address.sin_family = AF_INET;
|
|
|
|
|
p->_address.sin_port = htons (n);
|
|
|
|
|
/* N may be zero, in which case bind() will choose a port number
|
|
|
|
|
for us. */
|
|
|
|
|
if (bind (p->_socket,
|
|
|
|
|
(struct sockaddr*) &(p->_address),
|
|
|
|
|
sizeof (p->_address))
|
|
|
|
|
< 0)
|
|
|
|
|
{
|
|
|
|
|
perror ("[UdpInPort +newForReceivingFromPortNumber] bind()");
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the caller didn't specify a port number, it was chosen for us.
|
|
|
|
|
Here, find out what number was chosen. */
|
|
|
|
|
if (!n)
|
|
|
|
|
/* xxx Perhaps I should do this unconditionally? */
|
1996-03-01 16:06:57 +00:00
|
|
|
|
{
|
1996-03-24 22:04:23 +00:00
|
|
|
|
int size = sizeof (p->_address);
|
|
|
|
|
if (getsockname (p->_socket,
|
|
|
|
|
(struct sockaddr*)&(p->_address),
|
|
|
|
|
&size)
|
|
|
|
|
< 0)
|
|
|
|
|
{
|
|
|
|
|
perror ("[UdpInPort +newForReceivingFromPortNumber] getsockname()");
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
assert (p->_address.sin_port);
|
1996-03-01 16:06:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-24 22:04:23 +00:00
|
|
|
|
/* Record it in UdpInPort's map table. */
|
1996-03-01 16:06:57 +00:00
|
|
|
|
NSMapInsert (port_number_2_in_port, (void*)(int)n, p);
|
|
|
|
|
[udp_port_gate unlock];
|
|
|
|
|
|
1996-03-24 22:04:23 +00:00
|
|
|
|
if (udp_port_debug)
|
|
|
|
|
fprintf(stderr, "created new UdpInPort 0x%x, fd=%d port_number=%d\n",
|
|
|
|
|
(unsigned)p, p->_socket, htons(p->_address.sin_port));
|
|
|
|
|
|
1996-03-01 16:06:57 +00:00
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ newForReceivingFromRegisteredName: (id <String>)name
|
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
|
1996-03-24 22:04:23 +00:00
|
|
|
|
n = name_2_port_number ([name cStringNoCopy]);
|
1996-03-01 16:06:57 +00:00
|
|
|
|
return [self newForReceivingFromPortNumber: n];
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-24 22:04:23 +00:00
|
|
|
|
/* Usually, you would run the run loop to get packets, but if you
|
|
|
|
|
want to wait for one directly from a port, you can use this method. */
|
|
|
|
|
- newPacketReceivedBeforeDate: date
|
|
|
|
|
{
|
1996-03-26 00:27:03 +00:00
|
|
|
|
return nil;
|
1996-03-24 22:04:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1996-03-01 16:06:57 +00:00
|
|
|
|
/* Returns nil on timeout.
|
|
|
|
|
Pass -1 for milliseconds to ignore timeout parameter and block indefinitely.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
- receivePacketWithTimeout: (int)milliseconds
|
|
|
|
|
{
|
|
|
|
|
int r;
|
|
|
|
|
struct sockaddr_in remote_addr;
|
|
|
|
|
int remote_len;
|
1996-03-18 14:02:44 +00:00
|
|
|
|
UdpInPacket *packet;
|
1996-03-01 16:06:57 +00:00
|
|
|
|
|
|
|
|
|
if (udp_port_debug)
|
|
|
|
|
fprintf(stderr, "receiving from %d\n", [self portNumber]);
|
|
|
|
|
|
|
|
|
|
if (milliseconds >= 0)
|
|
|
|
|
{
|
|
|
|
|
/* A timeout was requested; use select to ask if something is ready. */
|
|
|
|
|
struct timeval timeout;
|
|
|
|
|
fd_set ready;
|
|
|
|
|
|
|
|
|
|
timeout.tv_sec = milliseconds / 1000;
|
|
|
|
|
timeout.tv_usec = (milliseconds % 1000) * 1000;
|
|
|
|
|
FD_ZERO(&ready);
|
|
|
|
|
FD_SET(_socket, &ready);
|
|
|
|
|
if ((r = select(_socket + 1, &ready, 0, 0, &timeout)) < 0)
|
|
|
|
|
{
|
|
|
|
|
perror("select");
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r == 0) /* timeout */
|
|
|
|
|
return nil;
|
|
|
|
|
if (!FD_ISSET(_socket, &ready))
|
|
|
|
|
[self error:"select lied"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* There is a packet on the socket ready for us to receive. */
|
|
|
|
|
|
|
|
|
|
/* Create a packet. */
|
1996-03-18 14:02:44 +00:00
|
|
|
|
packet = [[UdpInPacket alloc] initWithCapacity: MAX_PACKET_SIZE];
|
1996-03-01 16:06:57 +00:00
|
|
|
|
|
|
|
|
|
/* Fill it with the UDP packet data. */
|
|
|
|
|
remote_len = sizeof(remote_addr);
|
|
|
|
|
if (recvfrom (_socket, [packet streamBuffer], MAX_PACKET_SIZE, 0,
|
|
|
|
|
(struct sockaddr*)&remote_addr, &remote_len)
|
|
|
|
|
< 0)
|
|
|
|
|
{
|
|
|
|
|
perror("recvfrom");
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set the packet's reply_port. */
|
|
|
|
|
if (remote_len != sizeof(struct sockaddr_in))
|
|
|
|
|
[self error:"remote address size mismatch"];
|
|
|
|
|
[packet _setReplyPort: [[self class] newForSendingToSockaddr: &remote_addr]];
|
|
|
|
|
|
|
|
|
|
return packet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) invalidate
|
|
|
|
|
{
|
|
|
|
|
if (is_valid)
|
|
|
|
|
{
|
|
|
|
|
close (_socket);
|
|
|
|
|
[super invalidate];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
[self invalidate];
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (int) socket
|
|
|
|
|
{
|
|
|
|
|
return _socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (int) portNumber
|
|
|
|
|
{
|
|
|
|
|
return (int) ntohs (_address.sin_port);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (Class) packetClass
|
|
|
|
|
{
|
1996-03-18 14:02:44 +00:00
|
|
|
|
return [UdpInPacket class];
|
1996-03-01 16:06:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (Class) classForConnectedCoder: aRmc
|
|
|
|
|
{
|
|
|
|
|
/* Make sure that Connection's always send us bycopy, not a Proxy class.
|
|
|
|
|
Also, don't encode a "receive right" (ala Mach), encode a "send right". */
|
|
|
|
|
return [UdpOutPort class];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeWithCoder: aCoder
|
|
|
|
|
{
|
|
|
|
|
/* We are actually encoding a "send right" (ala Mach),
|
1996-03-06 14:36:36 +00:00
|
|
|
|
not a receive right.
|
|
|
|
|
These values must match those expected by [TcpOutPort +newWithCoder] */
|
1996-03-01 16:06:57 +00:00
|
|
|
|
[super encodeWithCoder: aCoder];
|
|
|
|
|
[aCoder encodeValueOfCType: @encode(typeof(_address.sin_port))
|
|
|
|
|
at: &_address.sin_port
|
|
|
|
|
withName: @"socket number"];
|
|
|
|
|
[aCoder encodeValueOfCType: @encode(typeof(_address.sin_addr.s_addr))
|
|
|
|
|
at: &_address.sin_addr.s_addr
|
|
|
|
|
withName: @"inet address"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ newWithCoder: aCoder
|
|
|
|
|
{
|
|
|
|
|
/* An InPort cannot be created by decoding, only OutPort's. */
|
|
|
|
|
[self shouldNotImplement: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-24 22:04:23 +00:00
|
|
|
|
+ (void) setDebug: (BOOL)f
|
|
|
|
|
{
|
|
|
|
|
udp_port_debug = f;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 16:06:57 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation UdpOutPort
|
|
|
|
|
|
|
|
|
|
static Array *udp_out_port_array;
|
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [UdpOutPort class])
|
|
|
|
|
{
|
|
|
|
|
udp_out_port_array = [Array new];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-06 14:36:36 +00:00
|
|
|
|
#define SOCKADDR_EQUAL(s1,s2) ((s1)->sin_port == (s2)->sin_port && (s1)->sin_addr.s_addr == (s2)->sin_addr.s_addr)
|
1996-03-01 16:06:57 +00:00
|
|
|
|
/* xxx Change to make INADDR_ANY and the localhost address be equal. */
|
|
|
|
|
/* Assume that sin_family is equal */
|
|
|
|
|
/* (!memcmp(s1, s2, sizeof(struct sockaddr_in)))
|
|
|
|
|
didn't work because sin_zero's differ. Does this matter? */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This is the designated initializer. */
|
|
|
|
|
|
|
|
|
|
+ newForSendingToSockaddr: (struct sockaddr_in*)sockaddr
|
|
|
|
|
{
|
|
|
|
|
UdpOutPort *p;
|
|
|
|
|
|
|
|
|
|
/* See if there already exists a port for this sockaddr;
|
|
|
|
|
if so, just return it. */
|
|
|
|
|
FOR_ARRAY (udp_out_port_array, p)
|
|
|
|
|
{
|
|
|
|
|
/* xxx Come up with a way to do this with a hashtable, not a list. */
|
|
|
|
|
if (SOCKADDR_EQUAL (sockaddr, &(p->_address)))
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
END_FOR_ARRAY (udp_out_port_array);
|
|
|
|
|
|
|
|
|
|
/* Create a new port. */
|
|
|
|
|
p = [[self alloc] init];
|
|
|
|
|
|
|
|
|
|
/* Set the address. */
|
|
|
|
|
memcpy (&(p->_address), sockaddr, sizeof(p->_address));
|
|
|
|
|
|
|
|
|
|
/* Remember it in the array. */
|
|
|
|
|
/* xxx This will retain it; how will it ever get dealloc'ed? */
|
|
|
|
|
[udp_out_port_array addObject: p];
|
|
|
|
|
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+ newForSendingToPortNumber: (unsigned short)n
|
|
|
|
|
onHost: (id <String>)hostname
|
|
|
|
|
{
|
|
|
|
|
struct hostent *hp;
|
|
|
|
|
const char *host_cstring;
|
|
|
|
|
struct sockaddr_in addr;
|
|
|
|
|
|
|
|
|
|
/* Look up the hostname. */
|
|
|
|
|
if (!hostname || ![hostname length])
|
|
|
|
|
host_cstring = "localhost";
|
|
|
|
|
else
|
|
|
|
|
host_cstring = [hostname cStringNoCopy];
|
|
|
|
|
hp = gethostbyname ((char*)host_cstring);
|
|
|
|
|
if (hp == 0)
|
|
|
|
|
[self error: "unknown host: \"%s\"", host_cstring];
|
|
|
|
|
|
|
|
|
|
/* Get the sockaddr_in address. */
|
|
|
|
|
memcpy (&addr.sin_addr, hp->h_addr, hp->h_length);
|
|
|
|
|
addr.sin_family = AF_INET;
|
|
|
|
|
addr.sin_port = htons (n);
|
|
|
|
|
|
|
|
|
|
return [self newForSendingToSockaddr: &addr];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This currently ignores the timeout parameter */
|
|
|
|
|
|
|
|
|
|
- (BOOL) sendPacket: packet withTimeout: (int)milliseconds
|
|
|
|
|
{
|
|
|
|
|
id reply_port = [packet replyPort];
|
|
|
|
|
int len = [packet streamEofPosition];
|
|
|
|
|
|
|
|
|
|
assert (len < MAX_PACKET_SIZE);
|
|
|
|
|
|
|
|
|
|
if ( ! [reply_port isKindOfClass: [UdpInPort class]])
|
|
|
|
|
[self error:"Trying to send to a port that is not a UdpInPort"];
|
|
|
|
|
if (udp_port_debug)
|
|
|
|
|
fprintf (stderr, "sending to %d\n", (int) ntohs (_address.sin_port));
|
|
|
|
|
if (sendto ([reply_port socket],
|
|
|
|
|
[packet streamBuffer], len, 0,
|
|
|
|
|
(struct sockaddr*)&_address, sizeof (_address))
|
|
|
|
|
< 0)
|
|
|
|
|
{
|
|
|
|
|
perror ("sendto");
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (int) portNumber
|
|
|
|
|
{
|
|
|
|
|
return (int) ntohs (_address.sin_port);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id <String>) hostname
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (Class) packetClass
|
|
|
|
|
{
|
1996-03-18 14:02:44 +00:00
|
|
|
|
return [UdpInPacket class];
|
1996-03-01 16:06:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeWithCoder: aCoder
|
|
|
|
|
{
|
|
|
|
|
[super encodeWithCoder: aCoder];
|
|
|
|
|
[aCoder encodeValueOfCType: @encode(typeof(_address.sin_port))
|
|
|
|
|
at: &_address.sin_port
|
|
|
|
|
withName: @"socket number"];
|
|
|
|
|
[aCoder encodeValueOfCType: @encode(typeof(_address.sin_addr.s_addr))
|
|
|
|
|
at: &_address.sin_addr.s_addr
|
|
|
|
|
withName: @"inet address"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ newWithCoder: aCoder
|
|
|
|
|
{
|
|
|
|
|
struct sockaddr_in addr;
|
|
|
|
|
|
|
|
|
|
addr.sin_family = AF_INET;
|
|
|
|
|
[aCoder decodeValueOfCType: @encode(typeof(addr.sin_port))
|
|
|
|
|
at: &addr.sin_port
|
|
|
|
|
withName: NULL];
|
|
|
|
|
[aCoder decodeValueOfCType: @encode(typeof(addr.sin_addr.s_addr))
|
|
|
|
|
at: &addr.sin_addr.s_addr
|
|
|
|
|
withName: NULL];
|
1996-03-06 14:36:36 +00:00
|
|
|
|
return [UdpOutPort newForSendingToSockaddr: &addr];
|
1996-03-01 16:06:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1996-03-18 14:02:44 +00:00
|
|
|
|
@implementation UdpInPacket
|
1996-03-01 16:06:57 +00:00
|
|
|
|
|
|
|
|
|
- (void) _setReplyPort: p
|
|
|
|
|
{
|
1996-03-18 14:02:44 +00:00
|
|
|
|
[self notImplemented: _cmd];
|
1996-03-01 16:06:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|