RSS

(root)/iphone/tappity : /tappity/source/TappityServer.m (revision 46)

To get this branch, use:
bzr branch /browse/iphone/tappity
Line Revision Contents
1 46
//
2
//  TappityServer.m
3
//  Jigs
4
//
5
//  Created by döme on 25.10.2009.
6
//  Copyright 2009 __MyCompanyName__. All rights reserved.
7
//
8
9
#import "TappityServer.h"
10
#import "Tappity.h"
11
12
13
static void _setStandardSocketOpts(int socket)
14
{
15
    int yes = 1;
16
    setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
17
	int timeout = 2000;
18
	setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
19
	setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
20
}
21
22
@interface UIApplication (TappityPrivate)
23
- (void)_playbackEvents:(id)arg1 atPlaybackRate:(float)arg2 messageWhenDone:(id)arg3 withSelector:(SEL)arg4;
24
@end
25
26
@implementation TappityServer
27
28
- (BOOL) threadActive: (id) key
29
{
30
	return [[activeThreads objectForKey: key] boolValue];
31
}
32
33
- (void) receivingThread: (id) info
34
{
35
	NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
36
37
	@synchronized(self)
38
	{
39
		[self retain];
40
	}
41
42
	while ([self threadActive: info])
43
	{
44
		struct timeval tv;
45
		fd_set readfds;
46
		fd_set writefds;
47
		fd_set errorfds;
48
		int maxSocket = -1;
49
50
		tv.tv_sec = 1;
51
		tv.tv_usec = 0;
52
53
		FD_ZERO(&readfds);
54
		FD_ZERO(&writefds);
55
		FD_ZERO(&errorfds);
56
57
		FD_SET(commsSocket, &readfds);
58
		FD_SET(commsSocket, &errorfds);
59
		maxSocket = MAX(maxSocket, commsSocket);
60
		
61
		if (maxSocket < 0)
62
		{
63
			//printf("No sockets, sleeping for a bit...\n");
64
			usleep(1000000);
65
			continue;
66
		}
67
68
		if (select(maxSocket+1, &readfds, &writefds, &errorfds, &tv) < 0)
69
		{
70
			perror("select");
71
			break;
72
		}
73
74
		if (FD_ISSET(commsSocket, &readfds))
75
		{
76
			NSLog(@"receiving...");
77
			if (!expectedMessageSize)
78
			{
79
				uint32_t buf = 0;
80
				int actuallyRead = 0;
81
			
82
				actuallyRead = recv(commsSocket, &buf, sizeof(uint32_t), MSG_PEEK);
83
				
84
				if (actuallyRead == sizeof(uint32_t))
85
				{
86
					actuallyRead = recv(commsSocket, &buf, sizeof(uint32_t), 0);
87
					expectedMessageSize = ntohl(buf);
88
					currentData = [[NSMutableData alloc] initWithLength: expectedMessageSize];
89
				}
90
				else if (!actuallyRead)
91
				{
92
					// close this socket as nothing read means connection closed
93
					close(commsSocket);
94
					self->commsSocket = 0;
95
					printf("Connection dropped.\n");
96
					break;
97
				}
98
				if (actuallyRead == -1)
99
				{
100
					close(commsSocket);
101
					self->commsSocket = 0;
102
					printf("Connection dropped with error.\n");
103
					break;
104
				}
105
			}
106
			else
107
			{
108
				size_t readAmount = expectedMessageSize - currentlyRead;
109
				int actuallyRead = 0;
110
			
111
				actuallyRead = recv(commsSocket, [currentData mutableBytes] + currentlyRead, readAmount, 0);
112
				if (actuallyRead == -1)
113
				{
114
					close(commsSocket);
115
					self->commsSocket = 0;
116
					printf("Connection dropped with error.\n");
117
					break;
118
				}
119
				currentlyRead += actuallyRead;
120
				
121
				if (currentlyRead == expectedMessageSize)
122
				{
123
					@synchronized(self)
124
					{
125
						expectedMessageSize = 0;
126
						/*
127
						if (!receivedPackets)
128
							receivedPackets = [[NSMutableArray alloc] init];
129
						[receivedPackets addObject: currentData];
130
						[currentData release];
131
						*/
132
						
133
					}
134
					[self performSelectorOnMainThread: @selector(tapReceived:) withObject: currentData waitUntilDone: NO];
135
					currentData = nil;
136
					currentlyRead = 0;
137
				}
138
			}
139
140
		}
141
	}
142
143
	@synchronized(self)
144
	{
145
		[self release];
146
	}
147
148
	[info release];
149
	[pool drain];
150
}
151
152
153
- (void) runThreadWithSelector: (SEL) selector
154
{
155
	@synchronized(self)
156
	{
157
		if (!activeThreads)
158
			activeThreads = [[NSMutableDictionary alloc] init];
159
		id number = [NSNumber numberWithInt: threadIds++];
160
161
		[activeThreads setObject: [NSNumber numberWithBool: YES] forKey: number];
162
		[NSThread detachNewThreadSelector: selector toTarget: self withObject: [number retain]];
163
	}
164
}
165
166
- (void) acceptThread: (id) info
167
{
168
	NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
169
170
	@synchronized(self)
171
	{
172
		[self retain];
173
	}
174
175
	while ([self threadActive: info])
176
	{
177
178
		struct timeval tv;
179
		fd_set readfds;
180
		fd_set writefds;
181
		fd_set errorfds;
182
		int maxSocket = -1;
183
184
		tv.tv_sec = 1;
185
		tv.tv_usec = 0;
186
187
		FD_ZERO(&readfds);
188
		FD_ZERO(&writefds);
189
		FD_ZERO(&errorfds);
190
191
		FD_SET(listenSocket, &readfds);
192
		FD_SET(listenSocket, &errorfds);
193
		maxSocket = MAX(maxSocket, listenSocket);
194
		
195
		if (maxSocket < 0)
196
		{
197
			printf("No sockets, sleeping for a bit...\n");
198
			usleep(1000000);
199
			continue;
200
		}
201
		
202
		//NSLog(@"listening for connection...");
203
204
		if (select(maxSocket+1, &readfds, &writefds, &errorfds, &tv) < 0)
205
		{
206
			perror("select");
207
			break;
208
		}
209
210
		if (FD_ISSET(listenSocket, &readfds))
211
		{
212
			NSLog(@"Accepting connection...");
213
			// accept
214
			socklen_t	sinSize = sizeof(struct sockaddr_in);
215
			struct sockaddr_in	peerAddress;
216
			int newSocket = accept(listenSocket, (struct sockaddr *)&peerAddress, &sinSize);
217
			
218
			_setStandardSocketOpts(newSocket);
219
220
			
221
			if (newSocket == -1)
222
			{
223
				if (errno == EWOULDBLOCK)
224
				{
225
				}
226
				else
227
				{
228
					printf("Error accepting connection.\n");
229
					break;
230
				}
231
			}
232
			
233
			if (commsSocket)
234
				close(commsSocket);
235
236
			// add socket to sockets list
237
			commsSocket = newSocket;
238
			
239
			
240
			[self runThreadWithSelector: @selector(receivingThread:)];
241
			
242
			NSLog(@"Accepted connection.");
243
		}
244
245
	}
246
247
	@synchronized(self)
248
	{
249
		[self release];
250
	}
251
252
	[info release];
253
	[pool drain];
254
}
255
256
- (BOOL) enableBonjourWithDomain:(NSString*)domain applicationProtocol:(NSString*)protocol name:(NSString*)name
257
{
258
	if(![domain length])
259
		domain = @""; //Will use default Bonjour registration doamins, typically just ".local"
260
	if(![name length])
261
		name = @""; //Will use default Bonjour name, e.g. the name assigned to the device in iTunes
262
	
263
	assert([protocol length] && listenSocket);
264
	
265
	NSLog(@"tappity port: %d", ntohs(myAddress.sin_port));
266
267
	netService = [[NSNetService alloc] initWithDomain: domain type: protocol name: name port: ntohs(myAddress.sin_port)];
268
	if(netService == nil)
269
		return NO;
270
	
271
	[netService setDelegate:self];
272
//	[netService scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
273
	[netService publish];
274
	
275
	return YES;
276
}
277
278
- (void) start
279
{
280
	NSLog(@"starting tappity server");
281
	myAddress.sin_family = AF_INET;					// host byte order
282
	myAddress.sin_port = htons(1234);				// short, network byte order, any port
283
	myAddress.sin_addr.s_addr = htonl(INADDR_ANY);	// auto-fill with my IP
284
285
	listenSocket = socket(PF_INET, SOCK_STREAM, 0);
286
	assert(listenSocket != -1);
287
288
	_setStandardSocketOpts(listenSocket);
289
290
	int err = bind(self->listenSocket, (struct sockaddr *)&myAddress, sizeof(myAddress));
291
	assert(-1 != err);
292
	
293
	err = listen(self->listenSocket, 1);
294
	assert(-1 != err);
295
296
	[self runThreadWithSelector: @selector(acceptThread:)];
297
	
298
	if([self enableBonjourWithDomain: @"" applicationProtocol: @"_tappity._tcp" name: @"tappity"])
299
		NSLog(@"tappity bounjour advertisments up and running");
300
301
}
302
303
static size_t _read_i8(const void* buf, uint8_t* p)
304
{
305
	uint8_t v = 0;
306
	memcpy(&v, buf, 1);
307
	*p = v;
308
	return 1;
309
}
310
static size_t _read_i16(const void* buf, uint16_t* p)
311
{
312
	uint16_t v = 0;
313
	memcpy(&v, buf, 2);
314
	*p = CFSwapInt16BigToHost(v);
315
	return 2;
316
}
317
static size_t _read_i32(const void* buf, uint32_t* p)
318
{
319
	uint32_t v = 0;
320
	memcpy(&v, buf, 4);
321
	*p = CFSwapInt32BigToHost(v);
322
	return 4;
323
}
324
static size_t _read_i64(const void* buf, uint64_t* p)
325
{
326
	uint64_t v = 0;
327
	memcpy(&v, buf, 8);
328
	*p = CFSwapInt64BigToHost(v);
329
	return 8;
330
}
331
static size_t _read_float(const void* buf, float* p)
332
{
333
	CFSwappedFloat32 v;
334
	memcpy(&v, buf, 4);
335
	*p = CFConvertFloat32SwappedToHost(v);
336
	return 4;
337
}
338
339
static size_t _read_gspoint(const void* buf, GSTouchPointRef p)
340
{
341
	size_t bc = 0;
342
343
	bc += _read_i32(buf+bc, &p->unk0);
344
	bc += _read_float(buf+bc, &p->unk1);
345
	bc += _read_float(buf+bc, &p->touchSize);
346
	bc += _read_float(buf+bc, &p->x);
347
	bc += _read_float(buf+bc, &p->y);
348
	bc += _read_i32(buf+bc, (uint32_t*)&p->window);
349
	
350
	return bc;
351
}
352
353
- (GSEvent*) gsEventWithData: (NSData*) data
354
{
355
	GSEvent* gse = [[[GSEvent alloc] init] autorelease];
356
	
357
	size_t bc = 0;
358
	const void* buf = [data bytes];
359
	
360
	bc += _read_i32(buf+bc, &gse->type0);
361
	bc += _read_i32(buf+bc, &gse->type1);
362
	bc += _read_i32(buf+bc, &gse->r3);
363
	bc += _read_float(buf+bc, &gse->avgX0);
364
	bc += _read_float(buf+bc, &gse->avgY0);
365
	bc += _read_float(buf+bc, &gse->avgX1);
366
	bc += _read_float(buf+bc, &gse->avgY1);
367
	bc += _read_i32(buf+bc, &gse->processId);
368
	bc += _read_i64(buf+bc, &gse->timestamp);
369
	bc += _read_i32(buf+bc, (uint32_t*)&gse->window);
370
	bc += _read_i32(buf+bc, &gse->r11);
371
	bc += _read_i32(buf+bc, &gse->type12);
372
	bc += _read_i32(buf+bc, &gse->gesture13);
373
	bc += _read_i32(buf+bc, &gse->gesture14);
374
	bc += _read_i16(buf+bc, &gse->numInitialTouches);
375
	bc += _read_i16(buf+bc, &gse->numCurrentTouches);
376
	bc += _read_i32(buf+bc, &gse->r16);
377
	bc += _read_i32(buf+bc, &gse->r17);
378
	bc += _read_i32(buf+bc, &gse->r18);
379
	bc += _read_i32(buf+bc, &gse->r19);
380
	bc += _read_i32(buf+bc, &gse->r20);
381
	bc += _read_i32(buf+bc, &gse->r21);
382
	bc += _read_i8(buf+bc, &gse->r22_0);
383
	bc += _read_i8(buf+bc, &gse->numPoints);
384
	bc += _read_i16(buf+bc, &gse->r22_2);
385
	for (size_t i = 0; i < gse->numPoints; ++i)
386
		bc += _read_gspoint(buf+bc, gse->points + i);
387
388
	return gse;
389
}
390
391
- (void) tapReceived: (NSData*) tapData
392
{
393
	assert([tapData length] > 4);
394
	
395
	
396
	NSDictionary* tapDict = [NSPropertyListSerialization propertyListFromData: tapData mutabilityOption:NSPropertyListImmutable format: NULL errorDescription: NULL];
397
	assert(tapDict);
398
	switch([[tapDict objectForKey: TapIdKey] intValue])
399
	{
400
		case kTapTouchEvent:
401
		{
402
			NSLog(@"TOUCH EVENT");
403
			
404
			GSEvent* gse = [self gsEventWithData: [tapDict objectForKey: TapGSEventKey]];
405
			UIWindow* window = [[UIApplication sharedApplication] keyWindow];
406
			gse->window = window;
407
			for (size_t i = 0; i < gse->numPoints; ++i)
408
				gse->points[i].window = window;
409
			
410
			int phase = [[tapDict objectForKey: TapTouchPhaseKey] intValue];
411
			NSSet* touches = [UITouch _createTouchesWithGSEvent: gse phase: phase view: [[UIApplication sharedApplication] keyWindow]];
412
			
413
			assert([[UIApplication sharedApplication] keyWindow]);
414
			
415
			NSLog(@"%@", touches);
416
417
			UIEvent* event = [UIEvent alloc];
418
			
419
			Class touchesEventClass = objc_getClass("UITouchesEvent");
420
			if (touchesEventClass && ![[event class] isEqual: touchesEventClass])
421
			{
422
				event = [touchesEventClass alloc];
423
			}
424
			
425
			[event _initWithEvent: gse touches: touches];
426
			
427
			assert(event);
428
			
429
			[[UIApplication sharedApplication] sendEvent: event];
430
						
431
			
432
			break;
433
		}
434
		case kTapRecordedEvent:
435
		{
436
			NSLog(@"RECORDED EVENT");
437
			
438
			NSDictionary* eventDict = [tapDict objectForKey: TapRecordedEventKey];
439
			
440
			[[UIApplication sharedApplication] _playbackEvents:[NSArray arrayWithObject: eventDict] atPlaybackRate: 1.0f messageWhenDone: nil withSelector: nil];
441
442
			break;
443
		}
444
	}
445
	
446
}
447
448
449
/*
450
- (void)performTouches: (NSSet*) touches inView: (UIView *)view
451
{
452
    UITouch *touch = [[UITouch alloc] initInView:view];
453
    UIEvent *eventDown = [[UIEvent alloc] initWithTouch:touch];
454
    
455
    [touch.view touchesBegan:[eventDown allTouches] withEvent:eventDown];
456
    
457
    [touch setPhase:UITouchPhaseEnded];
458
    UIEvent *eventUp = [[UIEvent alloc] initWithTouch:touch];
459
    
460
    [touch.view touchesEnded:[eventUp allTouches] withEvent:eventUp];
461
    
462
    [eventDown release];
463
    [eventUp release];
464
    [touch release];
465
}
466
*/
467
468
- (void) dealloc
469
{
470
	
471
	[netService stop];
472
	[netService release];
473
474
	[activeThreads release];
475
476
	[super dealloc];
477
}
478
479
@end

Loggerhead 1.17 is a web-based interface for Bazaar branches