Finished the server sockets, almost. Not touched clients yet. Cleanups for other...
[ITFoundation.git] / ITInetServerSocket.m
1 //
2 //  ITInetServerSocket.m
3 //  ITFoundation
4 //
5 //  Created by Alexander Strange on Thu Feb 13 2003.
6 //  Copyright (c) 2003 __MyCompanyName__. All rights reserved.
7 //
8
9 #import "ITInetServerSocket.h"
10 #import "ITInetSocket.h"
11 #import <sys/types.h>
12 #import <arpa/inet.h>
13 #import <netinet/in.h>
14 #import <sys/socket.h>
15 #import <netdb.h>
16 #import <fcntl.h>
17
18 @interface ITInetServerSocket(Private)
19 -(void)setupConnectionWithServiceName:(NSString*)name;
20 -(void)setupConnectionWithPortNumber:(NSNumber*)port;
21 -(void)setupRendezvousAdvertising:(NSString*)name;
22 -(void)setupTimer;
23 -(void)timerFunc:(NSTimer*)timer;
24 @end
25
26 @implementation ITInetServerSocket
27 - (id)init
28 {
29     if (self = [super init])
30            {
31            sockfd = 0;
32            delegate = clients = nil;
33            }
34     return self;
35 }
36
37 - (id)initWithServiceName:(NSString*)name delegate:(id)d
38 {
39     if (self = [super init])
40            {
41            delegate = [d retain];
42            clients = [[NSMutableSet alloc] init];
43            [self setupConnectionWithServiceName:name];
44            }
45     return self;
46 }
47
48 - (id)initWithPort:(NSNumber*)port rendezvousName:(NSString*)name delegate:(id)d
49 {
50     if (self = [super init])
51            {
52            delegate = [d retain];
53            clients = [[NSMutableSet alloc] init];
54            [self setupConnectionWithPortNumber:port];
55            }
56     return self;
57 }
58
59 - (void)dealloc
60 {
61     [service stop];
62     [service release];
63     [clients release];
64     [delegate release];
65     shutdown(sockfd,2);
66 }
67
68 - (int)sockfd
69 {
70     return sockfd;
71 }
72
73 - (NSSet*)clients
74 {
75     return clients;
76 }
77
78 - (id)delegate
79 {
80     return delegate;
81 }
82 @end
83
84 @implementation ITInetServerSocket(Private)
85 -(void)setupConnectionWithServiceName:(NSString*)name
86 {
87     const char *_name = [name cString];
88     struct addrinfo hints,*res;
89
90     hints.ai_flags = AI_PASSIVE;
91     hints.ai_family = PF_INET;
92     hints.ai_socktype = SOCK_STREAM;
93     hints.ai_protocol = IPPROTO_TCP;
94     hints.ai_addrlen = 0;
95     hints.ai_canonname = NULL;
96     hints.ai_addr = NULL;
97     hints.ai_next = NULL;
98
99     getaddrinfo(NULL,_name,&hints,&res);
100     sockfd = socket(res->ai_family, res->ai_socktype,res->ai_protocol);
101     bind(sockfd, res->ai_addr, res->ai_addrlen);
102     listen(sockfd, SOMAXCONN);
103     fcntl(sockfd,F_SETFL,O_NONBLOCK);
104     freeaddrinfo(res);
105 }
106
107 -(void)setupConnectionWithPortNumber:(NSNumber*)port
108 {
109     short _port = [port shortValue];
110     struct sockaddr_in sa;
111
112     sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
113     sa.sin_addr.s_addr = INADDR_ANY;
114     sa.sin_family = AF_INET;
115     sa.sin_port = htons(_port);
116     bind(sockfd,(struct sockaddr *)&sa,sizeof(sa));
117     listen(sockfd, SOMAXCONN);
118     fcntl(sockfd,F_SETFL,O_NONBLOCK);
119 }
120
121 - (void)setupRendezvousAdvertising:(NSString*)name port:(NSNumber*)port
122 {
123     service = [[NSNetService alloc] initWithDomain:@"" type:[NSString stringWithFormat:@"_%@._tcp.",name] port:htons([port shortValue])];
124     [service publish];
125 }
126
127 - (void)setupTimer
128 {
129     NSTimer *timer = [NSTimer timerWithTimeInterval:0 target:self selector:@selector(timerFunc:) userInfo:nil repeats:YES];
130     [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
131 }
132
133 - (void)timerFunc:(NSTimer*)timer
134 {
135     struct sockaddr_in csa;
136     int csalen;
137     signed int cfd;
138     (void) timer;
139     cfd = accept(sockfd,(struct sockaddr*)&csa,&csalen);
140     if (cfd == -1) {
141            if (errno == EWOULDBLOCK) return;
142            else {perror("Too bad I haven't implemented error checking yet");}
143            }
144            else {
145                    ITInetSocket *csocket = [[[ITInetSocket alloc] initWithFD:cfd delegate:self] autorelease];
146                    [clients addObject:csocket];
147                    [delegate newClientJoined:csocket];
148                    
149            }
150 }
151 @end