This is MiscINETSocket.m in view mode; [Download] [Up]
/* Class for handling sockets in the Internet domain. * * Copyright (c) 1996 Aleksey Sudakov <zander@cnext.crec.mipt.ru>. * * This software is subject to the terms of the MiscKit license * agreement. Refer to the license document included with the * MiscKit distribution for these terms. * * Version 1.0 BETA (16 December 1995) */ /* #import <misckit/MiscINETSocket.h> */ #import "MiscINETSocket.h" #import <Foundation/NSData.h> #import <Foundation/NSCoder.h> #import <objc/HashTable.h> #ifdef WIN32 #import <stdlib.h> #import <stdio.h> #import <winsock.h> #import <io.h> #define EDESTADDRREQ WSAEDESTADDRREQ #define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT #define fork() (-1) int gettimeofday ( struct timeval *tv, struct timezone *tz); #else #import <libc.h> #import <netdb.h> #import <netinet/in_systm.h> #import <netinet/ip.h> #import <netinet/ip_icmp.h> #import <netinet/tcp.h> #endif WIN32 #import <errno.h> extern int errno; static MiscINETSocket *handySocket = nil; static unsigned short in_cksum(unsigned char *cp, int nbytes) { unsigned short wa[(nbytes>>1)+1], *wp, result; long sum; wp = &wa[0]; memset((char *)wp, 0, sizeof(wp)); memcpy((char *)wp, cp, nbytes); for (sum = 0; 0 < nbytes; nbytes -= 2) sum += *wp++; while (sum >> 16) sum = (sum >> 16) + (sum & 0xffff); result = (unsigned short)~sum; if (result == 0x0) result = 0xffff; return result; } static int wait_for_socket_read(int sock, unsigned int ms) { struct timeval timeout = {ms/1000, (ms%1000)*1000}; fd_set rfds; int ret; FD_ZERO(&rfds); FD_SET(sock, &rfds); while ((ret = select(sock+1, &rfds, NULL, NULL, (ms==0 ? NULL : &timeout))) < 0) { if (errno == EINTR) continue; return -1; } return ret; } static int get_service_port(const char *service, int type) { struct servent *sent; switch (type) { case MiscSOCK_DGRAM : sent = getservbyname((char *)service, "udp"); if (sent == NULL) sent = getservbyport(atoi(service), "udp"); break; case MiscSOCK_STREAM: sent = getservbyname((char *)service, "tcp"); if (sent == NULL) sent = getservbyport(atoi(service), "tcp"); break; default : /* RAW connections to services are not supported. */ errno = ESOCKTNOSUPPORT; return -1; } if (sent == NULL) { errno = ENOENT; return -1; } return sent->s_port; } @implementation MiscINETSocket #define ECHOPKTLEN 32 - free { [self release]; printf("Freeing....\n"); return nil; } #ifndef WIN32 + (int)ping:(MiscINETAddress *)addr timeout:(unsigned int)ms useECHO:(BOOL)aBool { if (addr == nil) { errno = EDESTADDRREQ; return -1; } if (aBool) { char out_pkt[ECHOPKTLEN], in_pkt[2*ECHOPKTLEN]; int i, ret, in_len = sizeof(in_pkt); for (i = 0; i < ECHOPKTLEN; i++) out_pkt[i] = (char)(random()%256); ret = [MiscINETSocket sendDgram:out_pkt length:sizeof(out_pkt) to:addr service:"echo" timeout:ms retries:0 withReply:in_pkt length:&in_len]; if (ret <= 0) return ret; if (in_len != ECHOPKTLEN) return -1; for (i = 0; i < ECHOPKTLEN; i++) if (out_pkt[i] != in_pkt[i]) return -1; return 1; } else { struct { unsigned char type, code; unsigned short cksum, id, seq; unsigned char data[2*ICMP_MINLEN]; } out_pkt = {ICMP_ECHO, 0, 0, getpid() & 0xffff, 1}; struct sockaddr_in sockaddr; char buffer[sizeof(out_pkt)+64]; int ret; struct icmp *icmpp; if (handySocket == nil) handySocket = [MiscINETSocket alloc]; handySocket = [handySocket init]; handySocket->sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); if (handySocket->sock < 0) return -1; handySocket->domain = PF_INET; handySocket->type = RAW; out_pkt.cksum = in_cksum((u_char *)&out_pkt, sizeof(out_pkt)); sockaddr.sin_family = AF_INET; sockaddr.sin_addr = [addr address]; sockaddr.sin_port = 0; if (sendto(handySocket->sock, &out_pkt, sizeof(out_pkt), 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) return -1; ret = wait_for_socket_read(handySocket->sock, ms); if (ret <= 0) return ret; memset(buffer, '\0', sizeof(buffer)); if (recv(handySocket->sock, buffer, sizeof(buffer), 0) < 0) return -1; icmpp = (struct icmp *)(buffer + 4*((struct ip *)buffer)->ip_hl); if (icmpp->icmp_type == ICMP_ECHOREPLY && icmpp->icmp_id == (getpid() & 0xffff)) return 1; return -1; } } #endif WIN32 + runServer:(id)sockets target:(id)target action:(SEL)action fork:(BOOL)fFlag loop:(BOOL)lFlag { /* id newSocket; if (![target respondsTo:action] || ![sockets isKindOfClass:[MiscSocket class]]) { errno = EINVAL; return nil; } do { if ([sockets type] == MiscSOCK_STREAM) if ([sockets acceptNewConnection:newSocket timeout:0] < 0) return nil; if (fFlag) { switch (fork()) { case -1: return nil; case 0 : [target perform:action with:newSocket]; exit(0); } } else [target perform:action with:newSocket]; // Why did Chris free here? // if ([newSocket type] == MiscSOCK_STREAM) // [socket free]; } while (lFlag); return self; } */ BOOL isCollection = NO; fd_set fds; int fd, nfd; if (![target respondsTo:action] || sockets == nil) { errno = EINVAL; return nil; } FD_ZERO(&fds); if ([sockets isKindOf:[HashTable class]]) { Class Socket = [MiscSocket class]; for (fd = sizeof(fds)*8; fd--;) { id obj; if (![sockets isKey:(void *)fd]) continue; obj = [sockets valueForKey:(void *)fd]; if ([obj isKindOfClass:Socket] && ![obj isClosed]) FD_SET([obj socket], &fds); } isCollection = YES; } else if ([sockets isKindOfClass:[MiscSocket class]] && ![sockets isClosed]) FD_SET([sockets socket], &fds); else return nil; for (fd = sizeof(fds)*8; fd--;) if (FD_ISSET(fd, &fds)) break; nfd = fd + 1; if (nfd <= 0) { errno = EINVAL; return nil; } do { fd_set rfds; id sock_obj; memcpy(&rfds, &fds, sizeof(rfds)); if (select(nfd, &rfds, NULL, NULL, NULL) < 0) { if (errno == EINTR) continue; return nil; } for (fd = 0; fd < nfd; fd++) { id newSocket = nil; if (!FD_ISSET(fd, &rfds)) continue; sock_obj = isCollection ? (id)[sockets valueForKey:(void *)fd] : sockets; if ([sock_obj type] == MiscSOCK_STREAM) if ([sock_obj acceptNewConnection:newSocket timeout:0] < 0) return nil; if (fFlag) { switch (fork()) { case -1: return nil; case 0 : [target perform:action with:newSocket]; exit(0); } } else [target perform:action with:newSocket]; // if ([newSocket type] == MiscSOCK_STREAM) //{printf("Gonna free\n"); // Freeing is ain't good at all // [newSocket autorelease]; //// [sock_obj free]; //} } } while (lFlag); return self; } + runServerPort:(int *)port type:(int)aType action:(SEL)action fork:(BOOL)fFlag loop:(BOOL)lFlag{ MiscINETSocket* soc = [[self alloc] openServerPort:port type:aType]; return [self runServer:soc target:soc action:action fork:fFlag loop:lFlag]; } + sendDgram:(void *)data length:(int)dlen to:(MiscINETAddress *)addr port:(int)portNum { struct sockaddr_in sockaddr; if (addr == nil) { errno = EDESTADDRREQ; return nil; } if (handySocket == nil) handySocket = [MiscINETSocket alloc]; handySocket = [handySocket initDomain:PF_INET type:MiscSOCK_DGRAM]; if (handySocket == nil || portNum < 0) return nil; sockaddr.sin_family = AF_INET; sockaddr.sin_addr = [addr address]; sockaddr.sin_port = htons((short)(portNum & 0xffff)); if (sendto(handySocket->sock, data, dlen, 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) return nil; return self; } + sendDgram:(void *)data length:(int)dlen to:(MiscINETAddress *)addr service:(const char *)service { return [self sendDgram:data length:dlen to:addr port:get_service_port(service, MiscSOCK_DGRAM)]; } + (int)sendDgram:(void *)data length:(int)dlen to:(MiscINETAddress *)addr port:(int)portNum timeout:(unsigned int)ms retries:(int)retries withReply:(void *)repl length:(int *)rlen { struct sockaddr_in to_addr; if (addr == nil) { errno = EDESTADDRREQ; return -1; } if (handySocket == nil) handySocket = [MiscINETSocket alloc]; handySocket = [handySocket initDomain:PF_INET type:MiscSOCK_DGRAM]; if (handySocket == nil || portNum < 0) return -1; to_addr.sin_family = AF_INET; to_addr.sin_addr = [addr address]; to_addr.sin_port = htons((short)(portNum & 0xffff)); do { int ret; if (sendto(handySocket->sock, data, dlen, 0, (struct sockaddr *)&to_addr, sizeof(to_addr)) < 0) return -1; ret = wait_for_socket_read(handySocket->sock, ms); if (ret < 0) return -1; if (0 < ret) { struct sockaddr_in from_addr; int len = sizeof(from_addr); ret = recvfrom(handySocket->sock, repl, *rlen, 0, (struct sockaddr *)&from_addr, &len); if (ret < 0) return -1; if (!memcmp(&to_addr, &from_addr, len-sizeof(to_addr.sin_zero))) { *rlen = ret; return 1; } } } while (retries-- > 0); return 0; } + (int)sendDgram:(void *)data length:(int)dlen to:(MiscINETAddress *)addr service:(const char *)service timeout:(unsigned int)ms retries:(int)retries withReply:(void *)repl length:(int *)rlen { return [self sendDgram:data length:dlen to:addr port:get_service_port(service, MiscSOCK_DGRAM) timeout:ms retries:retries withReply:repl length:rlen]; } - init { [super init]; if (localAddress != nil) [localAddress release]; if (remoteAddress != nil) [remoteAddress release]; localPortNum = remotePortNum = -1; localAddress = remoteAddress = nil; return self; } - (void)dealloc { if (localAddress != nil) [localAddress release]; if (remoteAddress != nil) [remoteAddress release]; [super dealloc]; } - initWithCoder:(NSCoder *)coder { self = [super initWithCoder:coder]; [coder decodeValuesOfObjCTypes:"ii", &localPortNum, &remotePortNum]; localAddress = [[coder decodeObject] retain]; remoteAddress = [[coder decodeObject] retain]; return self; } - (void)encodeWithCoder:(NSCoder *)coder { [super encodeWithCoder:coder]; [coder encodeValuesOfObjCTypes:"ii", &localPortNum, &remotePortNum]; [coder encodeObject:localAddress]; [coder encodeObject:remoteAddress]; } - copy { return [self copyWithZone:[self zone]]; } - copyWithZone:(NSZone*)zone { MiscINETSocket *copy = [[[self class] allocWithZone:zone] init]; copy->localAddress = [[localAddress copyWithZone:zone] retain]; copy->remoteAddress = [[remoteAddress copyWithZone:zone] retain]; return copy; } - (int)acceptNewConnection:(MiscINETSocket *)newSocket timeout:(unsigned int)ms { int ret; if (type != MiscSOCK_STREAM) { errno = EINVAL; return -1; } ret = wait_for_socket_read(sock, ms); if (0 < ret) { struct sockaddr_in sockaddr; int len = sizeof(sockaddr); ret = accept(sock, (struct sockaddr *)&sockaddr, &len); if (0 <= ret) { newSocket = [newSocket isKindOfClass:[MiscINETSocket class]] ? [newSocket init] : [MiscINETSocket new]; newSocket->sock = ret; newSocket->domain = PF_INET; newSocket->type = MiscSOCK_STREAM; ret = 1; } // else // newSocket = nil; } return ret; } - connectTo:(MiscINETAddress *)addr port:(int)portNum type:(int)aType { struct sockaddr_in sockaddr; if (addr == nil) { errno = EDESTADDRREQ; return [self free]; } self = [self initDomain:PF_INET type:aType]; if (self == nil || portNum < 0) return [self free]; sockaddr.sin_family = AF_INET; sockaddr.sin_addr = [addr address]; sockaddr.sin_port = htons((short)(portNum & 0xffff)); if (connect(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) return [self free]; return self; } - connectTo:(MiscINETAddress *)addr service:(const char *)service type:(int)aType { return [self connectTo:addr port:get_service_port(service, aType) type:aType]; } - openServerPort:(int *)portNum type:(int)aType { struct sockaddr_in sockaddr; int on = 1, old_errno = errno; self = [self initDomain:PF_INET type:aType]; if (self == nil || *portNum < 0) return [self free]; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); errno = old_errno; sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons((short)(*portNum & 0xffff)); sockaddr.sin_addr.s_addr = INADDR_ANY; if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) return [self free]; if (aType == MiscSOCK_STREAM) listen(sock, 2); return self; } - openServerService:(const char *)service type:(int)aType { int port = get_service_port(service, aType); if (port < 0) return [self free]; return [self openServerPort:&port type:aType]; } - (int)receiveData:(void *)data length:(int *)dlen { return [self receiveData:data length:dlen timeout:0 from:nil port:NULL]; } - (int)receiveData:(void *)data length:(int *)dlen timeout:(unsigned int)ms from:(MiscINETAddress *)addr port:(int *)port { int ret; ret = wait_for_socket_read(sock, ms); if (0 <= ret) { struct sockaddr_in sockaddr; int len = sizeof(sockaddr); ret = recvfrom(sock, data, *dlen, 0, (struct sockaddr *)&sockaddr, &len); if (0 == ret) { [self close]; errno = EPIPE; ret = -1; } else if (0 < ret) { [addr initTo:sockaddr.sin_addr]; *dlen = ret; if (port != NULL) *port = (int)ntohs(sockaddr.sin_port); ret = 1; } } return ret; } - (int)receiveData:(void *)data length:(int *)dlen timeout:(unsigned int)ms toNext:(unsigned char)sentinel { struct timeval t1, t2; int i, ret; if (type != MiscSOCK_STREAM) { errno = EINVAL; return -1; } gettimeofday(&t1, NULL); for (i = *dlen, *dlen = 0; i--;) { if (0 < ms) { int ms_left; gettimeofday(&t2, NULL); ms_left = ms - 1000*(t2.tv_sec-t1.tv_sec) + (t2.tv_usec-t1.tv_usec)/1000; if (ms_left < 1) return 0; ret = wait_for_socket_read(sock, ms_left); if (ret <= 0) return ret; } ret = read(sock, data, 1); if (ret < 0) return -1; else if (0 == ret) { [self close]; errno = EPIPE; return -1; } (*dlen)++; if (*(unsigned char *)data == sentinel) return 1; data++; } return 1; } - (int)receiveData:(NSMutableData *)data { int length = [data length]; int ret = [self receiveData:[data mutableBytes] length:&length]; if (ret>0) [data setLength:length]; return ret; } - sendData:(void *)data length:(int)dlen { while (0 < dlen) { int ret = write(sock, data, dlen); if (ret <= 0) { if (errno == EINTR) continue; else if (errno == EPIPE || errno == 0) { [self close]; return nil; } return nil; } dlen -= ret; data += ret; } return self; } - sendData:(NSData *)data { return [self sendData:(void *)[data bytes] length:[data length]]; } - shutdownLocalEnd { if (localAddress != nil) [localAddress release]; localPortNum = -1; localAddress = nil; return (shutdown(sock, 1) < 0 ? nil : self); } - shutdownRemoteEnd { if (remoteAddress != nil) [remoteAddress release]; remotePortNum = -1; remoteAddress = nil; return (shutdown(sock, 0) < 0 ? nil : self); } - enableDebug:(BOOL)aBool { int on = aBool; if (![self isClosed]) { int size = sizeof(on), old_errno = errno; setsockopt(sock, SOL_SOCKET, SO_DEBUG, (char *)&on, size); errno = old_errno; } return self; } - (BOOL)debugEnabled { int on = NO; if (![self isClosed]) { int size = sizeof(on), old_errno = errno; getsockopt(sock, SOL_SOCKET, SO_DEBUG, (char *)&on, &size); errno = old_errno; } return (BOOL)on; } - enableDelay:(BOOL)aBool { int on = aBool; if (![self isClosed]) { int size = sizeof(on), old_errno = errno; setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&on, size); errno = old_errno; } return self; } - (BOOL)delayEnabled { int on = YES; if (![self isClosed]) { int size = sizeof(on), old_errno = errno; getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&on, &size); errno = old_errno; } return (BOOL)on; } - enableKeepAlive:(BOOL)aBool { int on = aBool; if (![self isClosed]) { int size = sizeof(on), old_errno = errno; setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, size); errno = old_errno; } return self; } - (BOOL)keepAliveEnabled { int on = NO; if (![self isClosed]) { int size = sizeof(on), old_errno = errno; getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, &size); errno = old_errno; } return (BOOL)on; } - setLingerTime:(int)secs { if (![self isClosed]) { struct linger ling; int size = sizeof(ling), old_errno = errno; ling.l_onoff = 0 < secs ? 1 : 0; ling.l_linger = 0 < secs ? secs : 0; setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&ling, size); errno = old_errno; } return self; } - (int)lingerTime { int time = 0; if (![self isClosed]) { struct linger ling; int size = sizeof(ling), old_errno = errno; getsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&ling, &size); errno = old_errno; if (ling.l_onoff) time = ling.l_linger; } return time; } - (BOOL)dataAvailable { int old_errno = errno; BOOL avail = NO; if (![self isClosed]) { struct timeval timeout = {0, 0}; fd_set rfds; FD_ZERO(&rfds); FD_SET(sock, &rfds); if (0 < select(sock+1, &rfds, NULL, NULL, &timeout)) avail = YES; } errno = old_errno; return avail; } - (MiscINETAddress *)localAddress { if (localAddress == nil) { struct sockaddr_in sockaddr; int len = sizeof(sockaddr); if (getsockname(sock, (struct sockaddr *)&sockaddr, &len) < 0) return nil; localAddress = [[[MiscINETAddress allocWithZone:[self zone]] initTo:sockaddr.sin_addr] retain]; if (localAddress != nil) localPortNum = ntohs(sockaddr.sin_port & 0xffff); } return localAddress; } - (int)localPortNum { if (localPortNum == -1) [self localAddress]; return localPortNum; } - (MiscINETAddress *)remoteAddress { if (remoteAddress == nil) { struct sockaddr_in sockaddr; int len = sizeof(sockaddr); if (getpeername(sock, (struct sockaddr *)&sockaddr, &len) < 0) return nil; remoteAddress = [[[MiscINETAddress allocWithZone:[self zone]] initTo:sockaddr.sin_addr] retain]; if (remoteAddress != nil) remotePortNum = ntohs(sockaddr.sin_port & 0xffff); } return remoteAddress; } - (int)remotePortNum { if (remotePortNum == -1) [self remoteAddress]; return remotePortNum; } - (int)socketError { int err = 0; if (![self isClosed]) { int size = sizeof(err), old_errno = errno; getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&err, &size); errno = old_errno; } return err; } @end // Alternate info to get this working on NT // (I haven't messed with it yet --don) /* From: Aleksey Sudakov <zander@conextions.com> Well, all that you gotta do is to implement negotiation with WinSock.dll in +(void)initialize and change couple of methods, like ioctl sould become ioctlsocket; errno -> h_errno; read -> recv; write -> send, etc. Use #define macro. It should be something like this #if defined(__MACH__) #define MISC_ioctl(x,y,z) ioctl(x,y,z) #define MISC_EWOULDBLOCK EWOULDBLOCK #define MISC_EINPROGRESS EINPROGRESS #define MISC_errno errno #define MISC_read(x,y,z) read(x,y,z) #define MISC_write(x,y,z) write(x,y,z) #define INVALID_SOCKET (-1) #define SOCKET_ERROR (-1) #elif defined(__WIN__) #define MISC_ioctl(x,y,z) ioctlsocket((SOCKET)x,(long)y,(u_long FAR *)z) #define MISC_EWOULDBLOCK WSAEWOULDBLOCK #define MISC_EINPROGRESS WSAEINPROGRESS #define MISC_errno h_errno #define MISC_read(x,y,z) recv((SOCKET)x, (char FAR *)y, (int)z, 0) #define MISC_write(x,y,z) send((SOCKET)x, (const char FAR *)y, (int)z, 0) #define bcopy(src,dest,nb) memcpy(dest,src,nb) #define bzero(ptr,nb) memset(ptr,0,nb) #endif */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.