ObjFW  Check-in [dabcc373f7]

Overview
Comment:readLine: for OFTCPSocket.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: dabcc373f7b9bac73776c274fa1d5e19eba245e24500f766ce3e514405e972c3
User & Date: js on 2009-05-03 15:45:10
Other Links: manifest | tags
Context
2009-05-03
15:49
Remove multiply overflow check in OFArray - it's done by resizeMem. check-in: 4eb87f934f user: js tags: trunk
15:45
readLine: for OFTCPSocket. check-in: dabcc373f7 user: js tags: trunk
15:38
Fix very stupid bug in OFExceptions. check-in: ab290b71ad user: js tags: trunk
Changes

Modified TODO from [5112e114d4] to [061c6493ac].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Test if autorelease pool releases everything correctly when thread is ended

Proper UTF-8 support!
Tests for OFFile.
Tests for OFNumber.

OFThread

Serialization

OFQueue
OFSortedArray

OFBase64
OFDirectory

OFXMLParser

... and of course enhance the already existing classes!





|
|












1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Test if autorelease pool releases everything correctly when thread is ended

Proper UTF-8 support!
Tests for OFFile.
Tests for OFNumber.
readLine: for OFFile.
Tests for readLine:.

Serialization

OFQueue
OFSortedArray

OFBase64
OFDirectory

OFXMLParser

... and of course enhance the already existing classes!

Modified src/OFTCPSocket.h from [a8e391accf] to [68a22b9b8b].

36
37
38
39
40
41
42
43
44
45
46
47
48


49
50
51
52
53
54
55

/**
 * The OFTCPSocket class provides functions to create and use sockets.
 */
@interface OFTCPSocket: OFObject <OFStream>
{
#ifndef _WIN32
	int	  sock;
#else
	SOCKET	  sock;
#endif
	struct	  sockaddr *saddr;
	socklen_t saddr_len;


}

/**
 * \return A new autoreleased OFTCPSocket
 */
+ tcpSocket;








|

|

|
|
>
>







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

/**
 * The OFTCPSocket class provides functions to create and use sockets.
 */
@interface OFTCPSocket: OFObject <OFStream>
{
#ifndef _WIN32
	int		sock;
#else
	SOCKET		sock;
#endif
	struct sockaddr	*saddr;
	socklen_t	saddr_len;
	char		*cache;
	size_t		cache_len;
}

/**
 * \return A new autoreleased OFTCPSocket
 */
+ tcpSocket;

95
96
97
98
99
100
101
























102
103
104
105
106
107
108
/**
 * Accept an incoming connection.
 * \return An OFTCPSocket for the accepted connection, which is NOT
 *	   autoreleased!
 */
- (OFTCPSocket*)accept;

























/**
 * Enables/disables non-blocking I/O.
 */
- setBlocking: (BOOL)enable;

/**
 * Enable or disable keep alives for the connection.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/**
 * Accept an incoming connection.
 * \return An OFTCPSocket for the accepted connection, which is NOT
 *	   autoreleased!
 */
- (OFTCPSocket*)accept;

/**
 * Read until a newline or \0 occurs.
 *
 * If you want to use readNBytes afterwards again, you have to clear the cache
 * before and optionally get the cache before clearing it!
 *
 * \return The line that was read. Use freeMem: to free it!
 */
- (char*)readLine;

/**
 * Sets a specified pointer to the cache and returns the length of the cache.
 *
 * \param ptr A pointer to a pointer. It will be set to the cache.
 *	      If it is NULL, only the number of bytes in the cache is returned.
 * \return The number of bytes in the cache.
 */
- (size_t)getCache: (char**)ptr;

/**
 * Clears the cache.
 */
- clearCache;

/**
 * Enables/disables non-blocking I/O.
 */
- setBlocking: (BOOL)enable;

/**
 * Enable or disable keep alives for the connection.

Modified src/OFTCPSocket.m from [34c32e126e] to [0f96f0fac9].

15
16
17
18
19
20
21

22
23
24
25


26
27
28
29
30
31
32
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#import "OFTCPSocket.h"
#import "OFExceptions.h"


#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif



@implementation OFTCPSocket
+ tcpSocket
{
	return [[[OFTCPSocket alloc] init] autorelease];
}








>




>
>







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#import "OFTCPSocket.h"
#import "OFExceptions.h"
#import "OFMacros.h"

#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif

extern int getpagesize(void);

@implementation OFTCPSocket
+ tcpSocket
{
	return [[[OFTCPSocket alloc] init] autorelease];
}

45
46
47
48
49
50
51


52
53
54
55
56
57
58
- init
{
	self = [super init];

	sock = INVALID_SOCKET;
	saddr = NULL;
	saddr_len = 0;



	return self;
}

- free
{
	if (sock != INVALID_SOCKET)







>
>







48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
- init
{
	self = [super init];

	sock = INVALID_SOCKET;
	saddr = NULL;
	saddr_len = 0;
	cache = NULL;
	cache_len = 0;

	return self;
}

- free
{
	if (sock != INVALID_SOCKET)
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
	int s;

	newsock = [OFTCPSocket new];
	addrlen = sizeof(struct sockaddr);

	@try {
		addr = [newsock allocWithSize: sizeof(struct sockaddr)];
	} @catch (id e) {
		[newsock free];
		@throw e;
	}

	if ((s = accept(sock, addr, &addrlen)) == INVALID_SOCKET) {
		[newsock free];
		@throw [OFAcceptFailedException newWithClass: isa];







|







190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
	int s;

	newsock = [OFTCPSocket new];
	addrlen = sizeof(struct sockaddr);

	@try {
		addr = [newsock allocWithSize: sizeof(struct sockaddr)];
	} @catch (OFException *e) {
		[newsock free];
		@throw e;
	}

	if ((s = accept(sock, addr, &addrlen)) == INVALID_SOCKET) {
		[newsock free];
		@throw [OFAcceptFailedException newWithClass: isa];
221
222
223
224
225
226
227






















































































































228
229
230
231
232
233
234
		@throw [OFReadFailedException newWithClass: isa
						   andSize: size];
	}

	/* This is safe, as we already checked < 1 */
	return ret;
}























































































































- (size_t)writeNBytes: (size_t)size
	   fromBuffer: (const char*)buf
{
	ssize_t ret;

	if (sock == INVALID_SOCKET)







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
		@throw [OFReadFailedException newWithClass: isa
						   andSize: size];
	}

	/* This is safe, as we already checked < 1 */
	return ret;
}

- (char*)readLine
{
	size_t i, len;
	char *ret, *tmp, *tmp2;

	/* Look if there's a line or \0 in our cache */
	if (cache != NULL) {
		for (i = 0; i < cache_len; i++) {
			if (OF_UNLIKELY(cache[i] == '\n' ||
			    cache[i] == '\0')) {
				ret = [self allocWithSize: i + 1];
				memcpy(ret, cache, i);
				ret[i] = '\0';

				@try {
					tmp = [self allocWithSize: cache_len -
								   i - 1];
				} @catch (OFException *e) {
					[self freeMem: ret];
					@throw e;
				}
				memcpy(tmp, cache + i + 1, cache_len - i - 1);

				[self freeMem: cache];
				cache = tmp;
				cache_len = cache_len - i - 1;

				return ret;
			}
		}
	}

	/* Read until we get a newline or \0 */
	tmp = [self allocWithSize: getpagesize()];

	for (;;) {
		@try {
			len = [self readNBytes: getpagesize() - 1
				    intoBuffer: tmp];
		} @catch (OFException *e) {
			[self freeMem: tmp];
			@throw e;
		}

		/* Look if there's a newline or \0 */
		for (i = 0; i < len; i++) {
			if (OF_UNLIKELY(tmp[i] == '\n' || tmp[i] == '\0')) {
				@try {
					ret = [self
					    allocWithSize: cache_len + i + 1];
				} @catch (OFException *e) {
					[self freeMem: tmp];
					@throw e;
				}
				if (cache != NULL)
					memcpy(ret, cache, cache_len);
				memcpy(ret + cache_len, tmp, i);
				ret[i] = '\0';

				if (i < len) {
					@try {
						tmp2 = [self
						    allocWithSize: len - i - 1];
					} @catch (OFException *e) {
						[self freeMem: ret];
						[self freeMem: tmp];
						@throw e;
					}
					memcpy(tmp2, tmp + i + 1, len - i - 1);

					if (cache != NULL)
						[self freeMem: cache];
					cache = tmp2;
					cache_len = len - i - 1;
				} else {
					if (cache != NULL)
						[self freeMem: cache];
					cache = NULL;
					cache_len = 0;
				}

				[self freeMem: tmp];
				return ret;
			}
		}

		/* There was no newline or \0 */
		@try {
			cache = [self resizeMem: cache
					 toSize: cache_len + len];
		} @catch (OFException *e) {
			[self freeMem: tmp];
			@throw e;
		}
		memcpy(cache + cache_len, tmp, len);
		cache_len += len;
	}
}

- (size_t)getCache: (char**)ptr
{
	if (ptr != NULL)
		*ptr = cache;

	return cache_len;
}

- clearCache
{
	if (cache != NULL)
		[self freeMem: cache];

	cache = NULL;
	cache_len = 0;

	return self;
}

- (size_t)writeNBytes: (size_t)size
	   fromBuffer: (const char*)buf
{
	ssize_t ret;

	if (sock == INVALID_SOCKET)