//
// PBSocket.m
//
// derived from SmallSockets Library (http://smallsockets.sourceforge.net/)
//
// Copyright (C) 2001 Steven Frank (stevenf@panic.com)
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must
// not claim that you wrote the original software. If you use this
// software in a product, an acknowledgment in the product
// documentation (and/or about box) would be appreciated but is not
// required.
//
// 2. Altered source versions must be plainly marked as such, and must
// not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
// modified by Pirmin Braun pirmin@pirmin.de
#import "PBSocket.h"
/* Windows-System */
#ifndef GNUSTEP
#include <winsock.h>
#include <io.h>
/* Unix-System */
#else
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#endif
@implementation PBSocket
ACCESSm(remoteHostName,setRemoteHostName)
- (id)init
//
// Designated initializer
//
{ if(!(self=[super init]))return nil;
connected = NO;
listening = NO;
[self setRemoteHostName:nil];
remotePort = SOCKET_INVALID_PORT;
// Create socket
if ( (socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )return nil;
return self;
}
+ (PBSocket *)socket
//
// Creates a Socket and returns it.
// The new Socket will be autoreleased, so be sure to retain it if you
// need to keep it around.
//
// Note: Sockets are blocking by default.
//
{ return [[[PBSocket alloc] init] autorelease];
}
- (void)dealloc
//
// Do not call this method directly! Use retain & release.
//
{ [self close];
[remoteHostName release];
[super dealloc];
}
- (void)close
//
// Closes the socket. You generally do not need to call this, as the socket
// will be automatically closed when it is released.
//
{ if ( socketfd != SOCKET_INVALID_DESCRIPTOR )
{ close(socketfd);
socketfd = SOCKET_INVALID_DESCRIPTOR;
}
[self setRemoteHostName:nil];
connected = NO;
listening = NO;
remotePort = SOCKET_INVALID_PORT;
}
- (void)connectToHostName:(NSString*)hostName port:(unsigned short)port
//
// Connect the socket to the host specified by hostName, on the requested port.
//
{ struct hostent* remoteHost;
struct sockaddr_in remoteAddr;
// Socket must be created, and not already connected
if ( socketfd == SOCKET_INVALID_DESCRIPTOR )
[NSException raise:SOCKET_EX_BAD_SOCKET_DESCRIPTOR
format:SOCKET_EX_BAD_SOCKET_DESCRIPTOR];
if ( connected )
[NSException raise:SOCKET_EX_ALREADY_CONNECTED
format:SOCKET_EX_ALREADY_CONNECTED];
// Look up host
if ( (remoteHost = gethostbyname([hostName cString])) == NULL )
[NSException raise:SOCKET_EX_HOST_NOT_FOUND
format:SOCKET_EX_HOST_NOT_FOUND_F, strerror(errno)];
// Copy host address and port into socket address structure
memset((char*)&remoteAddr, 0, sizeof(remoteAddr));
remoteAddr.sin_family = AF_INET;
memcpy((char*)&remoteAddr.sin_addr.s_addr, (char*)remoteHost->h_addr, remoteHost->h_length);
remoteAddr.sin_port = htons(port);
// Request connection, raise on failure
if ( (connect(socketfd, (struct sockaddr*)&remoteAddr, sizeof(remoteAddr)) < 0) )
[NSException raise:SOCKET_EX_CONNECT_FAILED
format:SOCKET_EX_CONNECT_FAILED_F, strerror(errno)];
// Note successful connection
[self setRemoteHostName:hostName];
remotePort = port;
connected = YES;
}
- (BOOL)connected;
{ return connected;
}
- (void)readData:(NSMutableData *)data;
//
// Append any available data from the socket to the supplied buffer.
// Returns number of bytes received. (May be 0)
//
{ int count = 0;
// data must not be null ptr
if (!data)return;
// Socket must be created and connected
if ( socketfd == SOCKET_INVALID_DESCRIPTOR )return;
if ( !connected )return;
// Request a read of as much as we can. Should return immediately if no data.
NS_DURING;
while((count = recv(socketfd, readBuffer, SOCKET_DEFAULT_READ_BUFFER_SIZE, 0))>0){ [data appendBytes:readBuffer length:count];
}
NS_HANDLER;
NS_ENDHANDLER;
[self close];
}
- (void)writeData:(NSData*)data
//
// Writes the given data to the socket
//
{ const char* bytes = [data bytes];
int len = [data length];
int sent;
// Socket must be created and connected
if ( socketfd == SOCKET_INVALID_DESCRIPTOR )
[NSException raise:SOCKET_EX_BAD_SOCKET_DESCRIPTOR
format:SOCKET_EX_BAD_SOCKET_DESCRIPTOR];
if ( !connected )
[NSException raise:SOCKET_EX_NOT_CONNECTED
format:SOCKET_EX_NOT_CONNECTED];
// Send the data
while ( len > 0 )
{ sent = send(socketfd, bytes, len, 0);
if ( sent < 0 )
[NSException raise:SOCKET_EX_SEND_FAILED
format:SOCKET_EX_SEND_FAILED_F, strerror(errno)];
bytes += sent;
len -= sent;
}
}
- (void)writeString:(NSString*)string
//
// Writes the given string to the socket
//
{ if ( [string length] > 0 )
[self writeData:[string dataUsingEncoding:NSUTF8StringEncoding]];
}
@end