Преглед на файлове

[slam] Add Scalable Local Area Multicast (SLAM) protocol support

Tested against the mini-slamd server located in contrib/mini-slamd
with a single client, on a lossy network.
tags/v0.9.4
Michael Brown преди 16 години
родител
ревизия
72c1bb8224
променени са 4 файла, в които са добавени 751 реда и са изтрити 541 реда
  1. 1
    0
      src/include/gpxe/errfile.h
  2. 1
    0
      src/include/gpxe/features.h
  3. 749
    0
      src/net/udp/slam.c
  4. 0
    541
      src/proto/slam.c

+ 1
- 0
src/include/gpxe/errfile.h Целия файл

@@ -132,6 +132,7 @@
132 132
 #define ERRFILE_infiniband		( ERRFILE_NET | 0x00130000 )
133 133
 #define ERRFILE_netdev_settings		( ERRFILE_NET | 0x00140000 )
134 134
 #define ERRFILE_dhcppkt			( ERRFILE_NET | 0x00150000 )
135
+#define ERRFILE_slam			( ERRFILE_NET | 0x00160000 )
135 136
 
136 137
 #define ERRFILE_image		      ( ERRFILE_IMAGE | 0x00000000 )
137 138
 #define ERRFILE_elf		      ( ERRFILE_IMAGE | 0x00010000 )

+ 1
- 0
src/include/gpxe/features.h Целия файл

@@ -41,6 +41,7 @@
41 41
 #define DHCP_EB_FEATURE_DNS		0x17 /**< DNS protocol */
42 42
 #define DHCP_EB_FEATURE_BZIMAGE		0x18 /**< bzImage format */
43 43
 #define DHCP_EB_FEATURE_MULTIBOOT	0x19 /**< Multiboot format */
44
+#define DHCP_EB_FEATURE_SLAM		0x1a /**< SLAM protocol */
44 45
 #define DHCP_EB_FEATURE_NBI		0x20 /**< NBI format */
45 46
 #define DHCP_EB_FEATURE_PXE		0x21 /**< PXE format */
46 47
 #define DHCP_EB_FEATURE_ELF		0x22 /**< ELF format */

+ 749
- 0
src/net/udp/slam.c Целия файл

@@ -0,0 +1,749 @@
1
+/*
2
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+#include <stdint.h>
20
+#include <stdlib.h>
21
+#include <string.h>
22
+#include <strings.h>
23
+#include <errno.h>
24
+#include <assert.h>
25
+#include <byteswap.h>
26
+#include <gpxe/features.h>
27
+#include <gpxe/iobuf.h>
28
+#include <gpxe/bitmap.h>
29
+#include <gpxe/xfer.h>
30
+#include <gpxe/open.h>
31
+#include <gpxe/uri.h>
32
+#include <gpxe/tcpip.h>
33
+#include <gpxe/retry.h>
34
+
35
+/** @file
36
+ *
37
+ * Scalable Local Area Multicast protocol
38
+ *
39
+ * The SLAM protocol is supported only by Etherboot; it was designed
40
+ * and implemented by Eric Biederman.  A server implementation is
41
+ * available in contrib/mini-slamd.  There does not appear to be any
42
+ * documentation beyond a few sparse comments in Etherboot's
43
+ * proto_slam.c.
44
+ *
45
+ * SLAM packets use three types of data field:
46
+ *
47
+ *  Nul : A single NUL (0) byte, used as a list terminator
48
+ *
49
+ *  Raw : A block of raw data
50
+ *
51
+ *  Int : A variable-length integer, in big-endian order.  The length
52
+ *        of the integer is encoded in the most significant three bits.
53
+ *
54
+ * Packets received by the client have the following layout:
55
+ *
56
+ *  Int : Transaction identifier.  This is an opaque value.
57
+ *
58
+ *  Int : Total number of bytes in the transfer.
59
+ *
60
+ *  Int : Block size, in bytes.
61
+ *
62
+ *  Int : Packet sequence number within the transfer (if this packet
63
+ *        contains data).
64
+ *
65
+ *  Raw : Packet data (if this packet contains data).
66
+ *
67
+ * Packets transmitted by the client consist of a run-length-encoded
68
+ * representation of the received-blocks bitmap, looking something
69
+ * like:
70
+ *
71
+ *  Int : Number of consecutive successfully-received packets
72
+ *  Int : Number of consecutive missing packets
73
+ *  Int : Number of consecutive successfully-received packets
74
+ *  Int : Number of consecutive missing packets
75
+ *  ....
76
+ *  Nul
77
+ *
78
+ */
79
+
80
+FEATURE ( FEATURE_PROTOCOL, "SLAM", DHCP_EB_FEATURE_SLAM, 1 );
81
+
82
+/** Default SLAM server port */
83
+#define SLAM_DEFAULT_PORT 10000
84
+
85
+/** Default SLAM multicast IP address */
86
+#define SLAM_DEFAULT_MULTICAST_IP \
87
+	( ( 239 << 24 ) | ( 255 << 16 ) | ( 1 << 8 ) | ( 1 << 0 ) )
88
+
89
+/** Default SLAM multicast port */
90
+#define SLAM_DEFAULT_MULTICAST_PORT 10000
91
+
92
+/** Maximum SLAM header length */
93
+#define SLAM_MAX_HEADER_LEN ( 8 /* transaction id */ + 8 /* total_bytes */ + \
94
+			      8 /* block_size */ )
95
+
96
+/** A SLAM request */
97
+struct slam_request {
98
+	/** Reference counter */
99
+	struct refcnt refcnt;
100
+
101
+	/** Data transfer interface */
102
+	struct xfer_interface xfer;
103
+	/** Unicast socket */
104
+	struct xfer_interface socket;
105
+	/** Multicast socket */
106
+	struct xfer_interface mc_socket;
107
+
108
+	/** NACK timer */
109
+	struct retry_timer timer;
110
+
111
+	/** Cached header */
112
+	uint8_t header[SLAM_MAX_HEADER_LEN];
113
+	/** Size of cached header */
114
+	size_t header_len;
115
+	/** Total number of bytes in transfer */
116
+	unsigned long total_bytes;
117
+	/** Transfer block size */
118
+	unsigned long block_size;
119
+	/** Number of blocks in transfer */
120
+	unsigned long num_blocks;
121
+	/** Block bitmap */
122
+	struct bitmap bitmap;
123
+	/** NACK sent flag */
124
+	int nack_sent;
125
+};
126
+
127
+/**
128
+ * Free a SLAM request
129
+ *
130
+ * @v refcnt		Reference counter
131
+ */
132
+static void slam_free ( struct refcnt *refcnt ) {
133
+	struct slam_request *slam =
134
+		container_of ( refcnt, struct slam_request, refcnt );
135
+
136
+	bitmap_free ( &slam->bitmap );
137
+	free ( slam );
138
+}
139
+
140
+/**
141
+ * Mark SLAM request as complete
142
+ *
143
+ * @v slam		SLAM request
144
+ * @v rc		Return status code
145
+ */
146
+static void slam_finished ( struct slam_request *slam, int rc ) {
147
+	static const uint8_t slam_disconnect[] = { 0 };
148
+
149
+	DBGC ( slam, "SLAM %p finished with status code %d (%s)\n",
150
+	       slam, rc, strerror ( rc ) );
151
+
152
+	/* Send a disconnect message if we ever sent anything to the
153
+	 * server.
154
+	 */
155
+	if ( slam->nack_sent ) {
156
+		xfer_deliver_raw ( &slam->socket, slam_disconnect,
157
+				   sizeof ( slam_disconnect ) );
158
+	}
159
+
160
+	/* Stop the retry timer */
161
+	stop_timer ( &slam->timer );
162
+
163
+	/* Close all data transfer interfaces */
164
+	xfer_nullify ( &slam->socket );
165
+	xfer_close ( &slam->socket, rc );
166
+	xfer_nullify ( &slam->mc_socket );
167
+	xfer_close ( &slam->mc_socket, rc );
168
+	xfer_nullify ( &slam->xfer );
169
+	xfer_close ( &slam->xfer, rc );
170
+}
171
+
172
+/****************************************************************************
173
+ *
174
+ * TX datapath
175
+ *
176
+ */
177
+
178
+/**
179
+ * Add a variable-length value to a SLAM packet
180
+ *
181
+ * @v slam		SLAM request
182
+ * @v iobuf		I/O buffer
183
+ * @v value		Value to add
184
+ * @ret rc		Return status code
185
+ *
186
+ * Adds a variable-length value to the end of an I/O buffer.  Will
187
+ * refuse to use the last byte of the I/O buffer; this is to allow
188
+ * space for the terminating NUL.
189
+ */
190
+static int slam_put_value ( struct slam_request *slam,
191
+			    struct io_buffer *iobuf, unsigned long value ) {
192
+	uint8_t *data;
193
+	size_t len;
194
+	unsigned int i;
195
+
196
+	/* Calculate variable length required to store value.  Always
197
+	 * leave at least one byte in the I/O buffer.
198
+	 */
199
+	len = ( ( flsl ( value ) + 10 ) / 8 );
200
+	if ( len >= iob_tailroom ( iobuf ) ) {
201
+		DBGC ( slam, "SLAM %p cannot add %d-byte value\n",
202
+		       slam, len );
203
+		return -ENOBUFS;
204
+	}
205
+	/* There is no valid way within the protocol that we can end
206
+	 * up trying to push a full-sized long (i.e. without space for
207
+	 * the length encoding).
208
+	 */
209
+	assert ( len <= sizeof ( value ) );
210
+
211
+	/* Add value */
212
+	data = iob_put ( iobuf, len );
213
+	for ( i = len ; i-- ; ) {
214
+		data[i] = value;
215
+		value >>= 8;
216
+	}
217
+	*data |= ( len << 5 );
218
+	assert ( value == 0 );
219
+
220
+	return 0;
221
+}
222
+
223
+/**
224
+ * Send SLAM NACK packet
225
+ *
226
+ * @v slam		SLAM request
227
+ * @ret rc		Return status code
228
+ */
229
+static int slam_tx_nack ( struct slam_request *slam ) {
230
+	struct io_buffer *iobuf;
231
+	unsigned int block;
232
+	unsigned int block_count;
233
+	int block_present;
234
+	int last_block_present;
235
+	uint8_t *nul;
236
+
237
+	DBGC ( slam, "SLAM %p transmitting NACK\n", slam );
238
+
239
+	/* Mark NACK as sent, so that we know we have to disconnect later */
240
+	slam->nack_sent = 1;
241
+
242
+	/* Use the current block size as a good estimate of how much
243
+	 * data we can fit in a packet.  If we overrun, it seems to be
244
+	 * acceptable to drop information anyway.
245
+	 */
246
+	iobuf = xfer_alloc_iob ( &slam->socket,	slam->block_size );
247
+	if ( ! iobuf ) {
248
+		DBGC ( slam, "SLAM %p could not allocate I/O buffer\n",
249
+		       slam );
250
+		return -ENOMEM;
251
+	}
252
+
253
+	/* Walk bitmap to construct list */
254
+	block_count = 0;
255
+	last_block_present = ( ! 0 );
256
+	for ( block = 0 ; block < slam->num_blocks ; block++ ) {
257
+		block_present = ( !! bitmap_test ( &slam->bitmap, block ) );
258
+		if ( block_present != last_block_present ) {
259
+			slam_put_value ( slam, iobuf, block_count );
260
+			block_count = 0;
261
+			last_block_present = block_present;
262
+		}
263
+		block_count++;
264
+	}
265
+	slam_put_value ( slam, iobuf, block_count );
266
+
267
+	/* Add NUL terminator */
268
+	nul = iob_put ( iobuf, 1 );
269
+	*nul = 0;
270
+
271
+	/* Transmit packet */
272
+	return xfer_deliver_iob ( &slam->socket, iobuf );
273
+}
274
+
275
+/**
276
+ * Handle SLAM retransmission timer expiry
277
+ *
278
+ * @v timer		Retry timer
279
+ * @v fail		Failure indicator
280
+ */
281
+static void slam_timer_expired ( struct retry_timer *timer, int fail ) {
282
+	struct slam_request *slam =
283
+		container_of ( timer, struct slam_request, timer );
284
+
285
+	if ( fail ) {
286
+		slam_finished ( slam, -ETIMEDOUT );
287
+	} else {
288
+		start_timer ( timer );
289
+		slam_tx_nack ( slam );
290
+	}
291
+}
292
+
293
+/****************************************************************************
294
+ *
295
+ * RX datapath
296
+ *
297
+ */
298
+
299
+/**
300
+ * Read and strip a variable-length value from a SLAM packet
301
+ *
302
+ * @v slam		SLAM request
303
+ * @v iobuf		I/O buffer
304
+ * @v value		Value to fill in, or NULL to ignore value
305
+ * @ret rc		Return status code
306
+ *
307
+ * Reads a variable-length value from the start of the I/O buffer.  
308
+ */
309
+static int slam_pull_value ( struct slam_request *slam,
310
+			     struct io_buffer *iobuf,
311
+			     unsigned long *value ) {
312
+	uint8_t *data;
313
+	size_t len;
314
+
315
+	/* Sanity check */
316
+	if ( iob_len ( iobuf ) == 0 ) {
317
+		DBGC ( slam, "SLAM %p empty value\n", slam );
318
+		return -EINVAL;
319
+	}
320
+
321
+	/* Read and verify length of value */
322
+	data = iobuf->data;
323
+	len = ( *data >> 5 );
324
+	if ( ( len == 0 ) ||
325
+	     ( value && ( len > sizeof ( *value ) ) ) ) {
326
+		DBGC ( slam, "SLAM %p invalid value length %d bytes\n",
327
+		       slam, len );
328
+		return -EINVAL;
329
+	}
330
+	if ( len > iob_len ( iobuf ) ) {
331
+		DBGC ( slam, "SLAM %p value extends beyond I/O buffer\n",
332
+		       slam );
333
+		return -EINVAL;
334
+	}
335
+
336
+	/* Read value */
337
+	iob_pull ( iobuf, len );
338
+	*value = ( *data & 0x1f );
339
+	while ( --len ) {
340
+		*value <<= 8;
341
+		*value |= *(++data);
342
+	}
343
+
344
+	return 0;
345
+}
346
+
347
+/**
348
+ * Read and strip SLAM header
349
+ *
350
+ * @v slam		SLAM request
351
+ * @v iobuf		I/O buffer
352
+ * @ret rc		Return status code
353
+ */
354
+static int slam_pull_header ( struct slam_request *slam,
355
+			      struct io_buffer *iobuf ) {
356
+	void *header = iobuf->data;
357
+	int rc;
358
+
359
+	/* If header matches cached header, just pull it and return */
360
+	if ( ( slam->header_len <= iob_len ( iobuf ) ) &&
361
+	     ( memcmp ( slam->header, iobuf->data, slam->header_len ) == 0 )){
362
+		iob_pull ( iobuf, slam->header_len );
363
+		return 0;
364
+	}
365
+
366
+	DBGC ( slam, "SLAM %p detected changed header; resetting\n", slam );
367
+
368
+	/* Read and strip transaction ID, total number of bytes, and
369
+	 * block size.
370
+	 */
371
+	if ( ( rc = slam_pull_value ( slam, iobuf, NULL ) ) != 0 )
372
+		return rc;
373
+	if ( ( rc = slam_pull_value ( slam, iobuf,
374
+				      &slam->total_bytes ) ) != 0 )
375
+		return rc;
376
+	if ( ( rc = slam_pull_value ( slam, iobuf,
377
+				      &slam->block_size ) ) != 0 )
378
+		return rc;
379
+
380
+	/* Update the cached header */
381
+	slam->header_len = ( iobuf->data - header );
382
+	assert ( slam->header_len <= sizeof ( slam->header ) );
383
+	memcpy ( slam->header, header, slam->header_len );
384
+
385
+	/* Calculate number of blocks */
386
+	slam->num_blocks = ( ( slam->total_bytes + slam->block_size - 1 ) /
387
+			     slam->block_size );
388
+
389
+	DBGC ( slam, "SLAM %p has total bytes %ld, block size %ld, num "
390
+	       "blocks %ld\n", slam, slam->total_bytes, slam->block_size,
391
+	       slam->num_blocks );
392
+
393
+	/* Discard and reset the bitmap */
394
+	bitmap_free ( &slam->bitmap );
395
+	memset ( &slam->bitmap, 0, sizeof ( slam->bitmap ) );
396
+
397
+	/* Allocate a new bitmap */
398
+	if ( ( rc = bitmap_resize ( &slam->bitmap,
399
+				    slam->num_blocks ) ) != 0 ) {
400
+		/* Failure to allocate a bitmap is fatal */
401
+		DBGC ( slam, "SLAM %p could not allocate bitmap for %ld "
402
+		       "blocks: %s\n", slam, slam->num_blocks,
403
+		       strerror ( rc ) );
404
+		slam_finished ( slam, rc );
405
+		return rc;
406
+	}
407
+
408
+	/* Notify recipient of file size */
409
+	xfer_seek ( &slam->xfer, slam->total_bytes, SEEK_SET );
410
+
411
+	return 0;
412
+}
413
+
414
+/**
415
+ * Receive SLAM data packet
416
+ *
417
+ * @v mc_socket		SLAM multicast socket
418
+ * @v iobuf		I/O buffer
419
+ * @ret rc		Return status code
420
+ */
421
+static int slam_mc_socket_deliver ( struct xfer_interface *mc_socket,
422
+				    struct io_buffer *iobuf,
423
+				    struct xfer_metadata *rx_meta __unused ) {
424
+	struct slam_request *slam =
425
+		container_of ( mc_socket, struct slam_request, mc_socket );
426
+	struct xfer_metadata meta;
427
+	unsigned long packet;
428
+	size_t len;
429
+	int rc;
430
+
431
+	/* Hit the timer */
432
+	stop_timer ( &slam->timer );
433
+	start_timer ( &slam->timer );
434
+
435
+	/* Read and strip packet header */
436
+	if ( ( rc = slam_pull_header ( slam, iobuf ) ) != 0 )
437
+		goto err_discard;
438
+
439
+	/* Read and strip packet number */
440
+	if ( ( rc = slam_pull_value ( slam, iobuf, &packet ) ) != 0 )
441
+		goto err_discard;
442
+
443
+	/* Sanity check packet number */
444
+	if ( packet >= slam->num_blocks ) {
445
+		DBGC ( slam, "SLAM %p received out-of-range packet %ld "
446
+		       "(num_blocks=%ld)\n", slam, packet, slam->num_blocks );
447
+		rc = -EINVAL;
448
+		goto err_discard;
449
+	}
450
+
451
+	/* Sanity check length */
452
+	len = iob_len ( iobuf );
453
+	if ( len > slam->block_size ) {
454
+		DBGC ( slam, "SLAM %p received oversize packet of %zd bytes "
455
+		       "(block_size=%ld)\n", slam, len, slam->block_size );
456
+		rc = -EINVAL;
457
+		goto err_discard;
458
+	}
459
+	if ( ( packet != ( slam->num_blocks - 1 ) ) &&
460
+	     ( len < slam->block_size ) ) {
461
+		DBGC ( slam, "SLAM %p received short packet of %zd bytes "
462
+		       "(block_size=%ld)\n", slam, len, slam->block_size );
463
+		rc = -EINVAL;
464
+		goto err_discard;
465
+	}
466
+
467
+	/* If we have already seen this packet, discard it */
468
+	if ( bitmap_test ( &slam->bitmap, packet ) ) {
469
+		goto discard;
470
+	}
471
+
472
+	/* Pass to recipient */
473
+	memset ( &meta, 0, sizeof ( meta ) );
474
+	meta.whence = SEEK_SET;
475
+	meta.offset = ( packet * slam->block_size );
476
+	if ( ( rc = xfer_deliver_iob_meta ( &slam->xfer, iobuf,
477
+					    &meta ) ) != 0 )
478
+		goto err;
479
+
480
+	/* Mark block as received */
481
+	bitmap_set ( &slam->bitmap, packet );
482
+
483
+	/* If we have received all blocks, terminate */
484
+	if ( bitmap_full ( &slam->bitmap ) )
485
+		slam_finished ( slam, 0 );
486
+
487
+	return 0;
488
+
489
+ err_discard:
490
+ discard:
491
+	free_iob ( iobuf );
492
+ err:
493
+	return rc;
494
+}
495
+
496
+/**
497
+ * Receive SLAM non-data packet
498
+ *
499
+ * @v socket		SLAM unicast socket
500
+ * @v iobuf		I/O buffer
501
+ * @ret rc		Return status code
502
+ */
503
+static int slam_socket_deliver ( struct xfer_interface *socket,
504
+				 struct io_buffer *iobuf,
505
+				 struct xfer_metadata *rx_meta __unused ) {
506
+	struct slam_request *slam =
507
+		container_of ( socket, struct slam_request, socket );
508
+	int rc;
509
+
510
+	/* Hit the timer */
511
+	stop_timer ( &slam->timer );
512
+	start_timer ( &slam->timer );
513
+
514
+	/* Read and strip packet header */
515
+	if ( ( rc = slam_pull_header ( slam, iobuf ) ) != 0 )
516
+		goto discard;
517
+
518
+	/* Sanity check */
519
+	if ( iob_len ( iobuf ) != 0 ) {
520
+		DBGC ( slam, "SLAM %p received trailing garbage:\n", slam );
521
+		DBGC_HD ( slam, iobuf->data, iob_len ( iobuf ) );
522
+		rc = -EINVAL;
523
+		goto discard;
524
+	}
525
+
526
+	/* Discard packet */
527
+	free_iob ( iobuf );
528
+
529
+	/* Send NACK in reply */
530
+	slam_tx_nack ( slam );
531
+
532
+	return 0;
533
+
534
+ discard:
535
+	free_iob ( iobuf );
536
+	return rc;
537
+
538
+}
539
+
540
+/**
541
+ * Close SLAM unicast socket
542
+ *
543
+ * @v socket		SLAM unicast socket
544
+ * @v rc		Reason for close
545
+ */
546
+static void slam_socket_close ( struct xfer_interface *socket, int rc ) {
547
+	struct slam_request *slam =
548
+		container_of ( socket, struct slam_request, socket );
549
+
550
+	DBGC ( slam, "SLAM %p unicast socket closed: %s\n",
551
+	       slam, strerror ( rc ) );
552
+
553
+	slam_finished ( slam, rc );
554
+}
555
+
556
+/** SLAM unicast socket data transfer operations */
557
+static struct xfer_interface_operations slam_socket_operations = {
558
+	.close		= slam_socket_close,
559
+	.vredirect	= xfer_vopen,
560
+	.window		= unlimited_xfer_window,
561
+	.alloc_iob	= default_xfer_alloc_iob,
562
+	.deliver_iob	= slam_socket_deliver,
563
+	.deliver_raw	= xfer_deliver_as_iob,
564
+};
565
+
566
+/**
567
+ * Close SLAM multicast socket
568
+ *
569
+ * @v mc_socket		SLAM multicast socket
570
+ * @v rc		Reason for close
571
+ */
572
+static void slam_mc_socket_close ( struct xfer_interface *mc_socket, int rc ){
573
+	struct slam_request *slam =
574
+		container_of ( mc_socket, struct slam_request, mc_socket );
575
+
576
+	DBGC ( slam, "SLAM %p multicast socket closed: %s\n",
577
+	       slam, strerror ( rc ) );
578
+
579
+	slam_finished ( slam, rc );
580
+}
581
+
582
+/** SLAM multicast socket data transfer operations */
583
+static struct xfer_interface_operations slam_mc_socket_operations = {
584
+	.close		= slam_mc_socket_close,
585
+	.vredirect	= xfer_vopen,
586
+	.window		= unlimited_xfer_window,
587
+	.alloc_iob	= default_xfer_alloc_iob,
588
+	.deliver_iob	= slam_mc_socket_deliver,
589
+	.deliver_raw	= xfer_deliver_as_iob,
590
+};
591
+
592
+/****************************************************************************
593
+ *
594
+ * Data transfer interface
595
+ *
596
+ */
597
+
598
+/**
599
+ * Close SLAM data transfer interface
600
+ *
601
+ * @v xfer		SLAM data transfer interface
602
+ * @v rc		Reason for close
603
+ */
604
+static void slam_xfer_close ( struct xfer_interface *xfer, int rc ) {
605
+	struct slam_request *slam =
606
+		container_of ( xfer, struct slam_request, xfer );
607
+
608
+	DBGC ( slam, "SLAM %p data transfer interface closed: %s\n",
609
+	       slam, strerror ( rc ) );
610
+
611
+	slam_finished ( slam, rc );
612
+}
613
+
614
+/** SLAM data transfer operations */
615
+static struct xfer_interface_operations slam_xfer_operations = {
616
+	.close		= slam_xfer_close,
617
+	.vredirect	= ignore_xfer_vredirect,
618
+	.window		= unlimited_xfer_window,
619
+	.alloc_iob	= default_xfer_alloc_iob,
620
+	.deliver_iob	= xfer_deliver_as_raw,
621
+	.deliver_raw	= ignore_xfer_deliver_raw,
622
+};
623
+
624
+/**
625
+ * Parse SLAM URI multicast address
626
+ *
627
+ * @v slam		SLAM request
628
+ * @v path		Path portion of x-slam:// URI
629
+ * @v address		Socket address to fill in
630
+ * @ret rc		Return status code
631
+ */
632
+static int slam_parse_multicast_address ( struct slam_request *slam,
633
+					  const char *path,
634
+					  struct sockaddr_in *address ) {
635
+	char path_dup[ strlen ( path ) + 1 ];
636
+	char *sep;
637
+
638
+	/* Create temporary copy of path */
639
+	memcpy ( path_dup, path, sizeof ( path_dup ) );
640
+
641
+	/* Parse port, if present */
642
+	sep = strchr ( path_dup, ':' );
643
+	if ( sep ) {
644
+		*(sep++) = '\0';
645
+		address->sin_port = htons ( strtoul ( sep, &sep, 0 ) );
646
+		if ( *sep != '\0' ) {
647
+			DBGC ( slam, "SLAM %p invalid multicast port\n",
648
+			       slam );
649
+			return -EINVAL;
650
+		}
651
+	}
652
+
653
+	/* Parse address */
654
+	if ( inet_aton ( path_dup, &address->sin_addr ) == 0 ) {
655
+		DBGC ( slam, "SLAM %p invalid multicast address\n", slam );
656
+		return -EINVAL;
657
+	}
658
+
659
+	return 0;
660
+}
661
+
662
+/**
663
+ * Initiate a SLAM request
664
+ *
665
+ * @v xfer		Data transfer interface
666
+ * @v uri		Uniform Resource Identifier
667
+ * @ret rc		Return status code
668
+ */
669
+static int slam_open ( struct xfer_interface *xfer, struct uri *uri ) {
670
+	static const struct sockaddr_in default_multicast = {
671
+		.sin_family = AF_INET,
672
+		.sin_port = htons ( SLAM_DEFAULT_MULTICAST_PORT ),
673
+		.sin_addr = { htonl ( SLAM_DEFAULT_MULTICAST_IP ) },
674
+	};
675
+	struct slam_request *slam;
676
+	struct sockaddr_tcpip server;
677
+	struct sockaddr_in multicast;
678
+	int rc;
679
+
680
+	/* Sanity checks */
681
+	if ( ! uri->host )
682
+		return -EINVAL;
683
+
684
+	/* Allocate and populate structure */
685
+	slam = zalloc ( sizeof ( *slam ) );
686
+	if ( ! slam )
687
+		return -ENOMEM;
688
+	slam->refcnt.free = slam_free;
689
+	xfer_init ( &slam->xfer, &slam_xfer_operations, &slam->refcnt );
690
+	xfer_init ( &slam->socket, &slam_socket_operations, &slam->refcnt );
691
+	xfer_init ( &slam->mc_socket, &slam_mc_socket_operations,
692
+		    &slam->refcnt );
693
+	slam->timer.expired = slam_timer_expired;
694
+	/* Fake an invalid cached header of { 0x00, ... } */
695
+	slam->header_len = 1;
696
+	/* Fake parameters for initial NACK */
697
+	slam->block_size = 512;
698
+	slam->num_blocks = 1;
699
+	if ( ( rc = bitmap_resize ( &slam->bitmap, 1 ) ) != 0 ) {
700
+		DBGC ( slam, "SLAM %p could not allocate initial bitmap: "
701
+		       "%s\n", slam, strerror ( rc ) );
702
+		goto err;
703
+	}
704
+
705
+	/* Open unicast socket */
706
+	memset ( &server, 0, sizeof ( server ) );
707
+	server.st_port = htons ( uri_port ( uri, SLAM_DEFAULT_PORT ) );
708
+	if ( ( rc = xfer_open_named_socket ( &slam->socket, SOCK_DGRAM,
709
+					     ( struct sockaddr * ) &server,
710
+					     uri->host, NULL ) ) != 0 ) {
711
+		DBGC ( slam, "SLAM %p could not open unicast socket: %s\n",
712
+		       slam, strerror ( rc ) );
713
+		goto err;
714
+	}
715
+
716
+	/* Open multicast socket */
717
+	memcpy ( &multicast, &default_multicast, sizeof ( multicast ) );
718
+	if ( uri->path && 
719
+	     ( ( rc = slam_parse_multicast_address ( slam, uri->path,
720
+						     &multicast ) ) != 0 ) ) {
721
+		goto err;
722
+	}
723
+	if ( ( rc = xfer_open_socket ( &slam->mc_socket, SOCK_DGRAM,
724
+				 ( struct sockaddr * ) &multicast,
725
+				 ( struct sockaddr * ) &multicast ) ) != 0 ) {
726
+		DBGC ( slam, "SLAM %p could not open multicast socket: %s\n",
727
+		       slam, strerror ( rc ) );
728
+		goto err;
729
+	}
730
+
731
+	/* Start retry timer */
732
+	start_timer ( &slam->timer );
733
+
734
+	/* Attach to parent interface, mortalise self, and return */
735
+	xfer_plug_plug ( &slam->xfer, xfer );
736
+	ref_put ( &slam->refcnt );
737
+	return 0;
738
+
739
+ err:
740
+	slam_finished ( slam, rc );
741
+	ref_put ( &slam->refcnt );
742
+	return rc;
743
+}
744
+
745
+/** SLAM URI opener */
746
+struct uri_opener slam_uri_opener __uri_opener = {
747
+	.scheme	= "x-slam",
748
+	.open	= slam_open,
749
+};

+ 0
- 541
src/proto/slam.c Целия файл

@@ -1,541 +0,0 @@
1
-#if 0
2
-
3
-/*
4
- * IMPORTANT
5
- *
6
- * This file should be rewritten to avoid the use of a bitmap.  Our
7
- * buffer routines can cope with being handed blocks in an arbitrary
8
- * order, duplicate blocks, etc.  This code could be substantially
9
- * simplified by taking advantage of these features.
10
- *
11
- */
12
-
13
-#define SLAM_PORT 10000
14
-#define SLAM_MULTICAST_IP ((239<<24)|(255<<16)|(1<<8)|(1<<0))
15
-#define SLAM_MULTICAST_PORT 10000
16
-#define SLAM_LOCAL_PORT 10000
17
-
18
-/* Set the timeout intervals to at least 1 second so
19
- * on a 100Mbit ethernet can receive 10000 packets
20
- * in one second.  
21
- *
22
- * The only case that is likely to trigger all of the nodes
23
- * firing a nack packet is a slow server.  The odds of this
24
- * happening could be reduced being slightly smarter and utilizing 
25
- * the multicast channels for nacks.   But that only improves the odds
26
- * it doesn't improve the worst case.  So unless this proves to be
27
- * a common case having the control data going unicast should increase
28
- * the odds of the data not being dropped.  
29
- *
30
- * When doing exponential backoff we increase just the timeout
31
- * interval and not the base to optimize for throughput.  This is only
32
- * expected to happen when the server is down.  So having some nodes
33
- * pinging immediately should get the transmission restarted quickly after a
34
- * server restart.  The host nic won't be to baddly swamped because of
35
- * the random distribution of the nodes.
36
- *
37
- */
38
-#define SLAM_INITIAL_MIN_TIMEOUT      (TICKS_PER_SEC/3)
39
-#define SLAM_INITIAL_TIMEOUT_INTERVAL (TICKS_PER_SEC)
40
-#define SLAM_BASE_MIN_TIMEOUT         (2*TICKS_PER_SEC)
41
-#define SLAM_BASE_TIMEOUT_INTERVAL    (4*TICKS_PER_SEC)
42
-#define SLAM_BACKOFF_LIMIT 5
43
-#define SLAM_MAX_RETRIES 20
44
-
45
-/*** Packets Formats ***
46
- * Data Packet:
47
- *   transaction
48
- *   total bytes
49
- *   block size
50
- *   packet #
51
- *   data
52
- *
53
- * Status Request Packet
54
- *   transaction
55
- *   total bytes
56
- *   block size
57
- *
58
- * Status Packet
59
- *   received packets
60
- *   requested packets
61
- *   received packets
62
- *   requested packets
63
- *   ...
64
- *   received packets
65
- *   requested packtes
66
- *   0
67
- */
68
-
69
-#define MAX_HDR (7 + 7 + 7) /* transaction, total size, block size */
70
-#define MIN_HDR (1 + 1 + 1) /* transactino, total size, block size */
71
-
72
-#define MAX_SLAM_REQUEST MAX_HDR
73
-#define MIN_SLAM_REQUEST MIN_HDR
74
-
75
-#define MIN_SLAM_DATA (MIN_HDR + 1)
76
-
77
-static struct slam_nack {
78
-	struct iphdr ip;
79
-	struct udphdr udp;
80
-	unsigned char data[ETH_MAX_MTU - 
81
-		(sizeof(struct iphdr) + sizeof(struct udphdr))];
82
-} nack;
83
-
84
-struct slam_state {
85
-	unsigned char hdr[MAX_HDR];
86
-	unsigned long hdr_len;
87
-	unsigned long block_size;
88
-	unsigned long total_bytes;
89
-	unsigned long total_packets;
90
-
91
-	unsigned long received_packets;
92
-
93
-	struct buffer *buffer;
94
-	unsigned char *image;
95
-	unsigned char *bitmap;
96
-} state;
97
-
98
-
99
-static void init_slam_state(void)
100
-{
101
-	state.hdr_len = sizeof(state.hdr);
102
-	memset(state.hdr, 0, state.hdr_len);
103
-	state.block_size = 0;
104
-	state.total_packets = 0;
105
-
106
-	state.received_packets = 0;
107
-
108
-	state.image = 0;
109
-	state.bitmap = 0;
110
-}
111
-
112
-struct slam_info {
113
-	struct sockaddr_in server;
114
-	struct sockaddr_in local;
115
-	struct sockaddr_in multicast;
116
-	int sent_nack;
117
-	struct buffer *buffer;
118
-};
119
-
120
-#define SLAM_TIMEOUT 0
121
-#define SLAM_REQUEST 1
122
-#define SLAM_DATA    2
123
-static int await_slam(int ival __unused, void *ptr,
124
-		      unsigned short ptype __unused, struct iphdr *ip,
125
-		      struct udphdr *udp, struct tcphdr *tcp __unused)
126
-{
127
-	struct slam_info *info = ptr;
128
-	if (!udp) {
129
-		return 0;
130
-	}
131
-	/* I can receive two kinds of packets here, a multicast data packet,
132
-	 * or a unicast request for information 
133
-	 */
134
-	/* Check for a data request packet */
135
-	if ((ip->dest.s_addr == arptable[ARP_CLIENT].ipaddr.s_addr) &&
136
-		(ntohs(udp->dest) == info->local.sin_port) && 
137
-		(nic.packetlen >= 
138
-			ETH_HLEN + 
139
-			sizeof(struct iphdr) + 
140
-			sizeof(struct udphdr) +
141
-			MIN_SLAM_REQUEST)) {
142
-		return SLAM_REQUEST;
143
-	}
144
-	/* Check for a multicast data packet */
145
-	if ((ip->dest.s_addr == info->multicast.sin_addr.s_addr) &&
146
-		(ntohs(udp->dest) == info->multicast.sin_port) &&
147
-		(nic.packetlen >= 
148
-			ETH_HLEN + 
149
-			sizeof(struct iphdr) + 
150
-			sizeof(struct udphdr) +
151
-			MIN_SLAM_DATA)) {
152
-		return SLAM_DATA;
153
-	}
154
-#if 0
155
-	printf("#");
156
-	printf("dest: %@ port: %d len: %d\n", 
157
-		ip->dest.s_addr, ntohs(udp->dest), nic.packetlen);
158
-#endif
159
-	return 0;
160
-		
161
-}
162
-
163
-static int slam_encode(
164
-	unsigned char **ptr, unsigned char *end, unsigned long value)
165
-{
166
-	unsigned char *data = *ptr;
167
-	int bytes;
168
-	bytes = sizeof(value);
169
-	while ((bytes > 0) && ((0xff & (value >> ((bytes -1)<<3))) == 0)) {
170
-		bytes--;
171
-	}
172
-	if (bytes <= 0) {
173
-		bytes = 1;
174
-	}
175
-	if (data + bytes >= end) {
176
-		return -1;
177
-	}
178
-	if ((0xe0 & (value >> ((bytes -1)<<3))) == 0) {
179
-		/* packed together */
180
-		*data = (bytes << 5) | (value >> ((bytes -1)<<3));
181
-	} else {
182
-		bytes++;
183
-		*data = (bytes << 5);
184
-	}
185
-	bytes--;
186
-	data++;
187
-	while(bytes) {
188
-		*(data++) = 0xff & (value >> ((bytes -1)<<3));
189
-		bytes--;
190
-	}
191
-	*ptr = data;
192
-	return 0;
193
-}
194
-
195
-static int slam_skip(unsigned char **ptr, unsigned char *end) 
196
-{
197
-	int bytes;
198
-	if (*ptr >= end) {
199
-		return -1;
200
-	}
201
-	bytes = ((**ptr) >> 5) & 7;
202
-	if (bytes == 0) {
203
-		return -1;
204
-	}
205
-	if (*ptr + bytes >= end) {
206
-		return -1;
207
-	}
208
-	(*ptr) += bytes;
209
-	return 0;
210
-	
211
-}
212
-
213
-static unsigned long slam_decode(unsigned char **ptr, unsigned char *end,
214
-				 int *err)
215
-{
216
-	unsigned long value;
217
-	unsigned bytes;
218
-	if (*ptr >= end) {
219
-		*err = -1;
220
-	}
221
-	bytes = ((**ptr) >> 5) & 7;
222
-	if ((bytes == 0) || (bytes > sizeof(unsigned long))) {
223
-		*err = -1;
224
-		return 0;
225
-	}
226
-	if ((*ptr) + bytes >= end) {
227
-		*err =  -1;
228
-	}
229
-	value = (**ptr) & 0x1f;
230
-	bytes--;
231
-	(*ptr)++;
232
-	while(bytes) {
233
-		value <<= 8;
234
-		value |= **ptr;
235
-		(*ptr)++;
236
-		bytes--;
237
-	}
238
-	return value;
239
-}
240
-
241
-
242
-static long slam_sleep_interval(int exp)
243
-{
244
-	long range;
245
-	long divisor;
246
-	long interval;
247
-	range = SLAM_BASE_TIMEOUT_INTERVAL;
248
-	if (exp < 0) { 
249
-		divisor = RAND_MAX/SLAM_INITIAL_TIMEOUT_INTERVAL;
250
-	} else {
251
-		if (exp > SLAM_BACKOFF_LIMIT) 
252
-			exp = SLAM_BACKOFF_LIMIT;
253
-		divisor = RAND_MAX/(range << exp);
254
-	}
255
-	interval = random()/divisor;
256
-	if (exp < 0) {
257
-		interval += SLAM_INITIAL_MIN_TIMEOUT;
258
-	} else {
259
-		interval += SLAM_BASE_MIN_TIMEOUT;
260
-	}
261
-	return interval;
262
-}
263
-
264
-
265
-static unsigned char *reinit_slam_state(
266
-	unsigned char *header, unsigned char *end)
267
-{
268
-	unsigned long total_bytes;
269
-	unsigned long block_size;
270
-
271
-	unsigned long bitmap_len;
272
-	unsigned long max_packet_len;
273
-	unsigned char *data;
274
-	int err;
275
-
276
-#if 0
277
-	printf("reinit\n");
278
-#endif
279
-	data = header;
280
-
281
-	state.hdr_len = 0;
282
-	err = slam_skip(&data, end); /* transaction id */
283
-	total_bytes = slam_decode(&data, end, &err);
284
-	block_size  = slam_decode(&data, end, &err);
285
-	if (err) {
286
-		printf("ALERT: slam size out of range\n");
287
-		return 0;
288
-	}
289
-	state.block_size = block_size;
290
-	state.total_bytes = total_bytes;
291
-	state.total_packets = (total_bytes + block_size - 1)/block_size;
292
-	state.hdr_len = data - header;
293
-	state.received_packets = 0;
294
-
295
-	data = state.hdr;
296
-	slam_encode(&data, &state.hdr[sizeof(state.hdr)], state.total_packets);
297
-	max_packet_len = data - state.hdr;
298
-	memcpy(state.hdr, header, state.hdr_len);
299
-	
300
-#if 0
301
-	printf("block_size:     %ld\n", block_size);
302
-	printf("total_bytes:    %ld\n", total_bytes);
303
-	printf("total_packets:  %ld\n", state.total_packets);
304
-	printf("hdr_len:        %ld\n", state.hdr_len);
305
-	printf("max_packet_len: %ld\n", max_packet_len);
306
-#endif
307
-
308
-	if (state.block_size > ETH_MAX_MTU - (
309
-		sizeof(struct iphdr) + sizeof(struct udphdr) +
310
-		state.hdr_len + max_packet_len)) {
311
-		printf("ALERT: slam blocksize to large\n");
312
-		return 0;
313
-	}
314
-	bitmap_len   = (state.total_packets + 1 + 7)/8;
315
-	state.image  = phys_to_virt ( state.buffer->addr );
316
-	/* We don't use the buffer routines properly yet; fake it */
317
-	state.buffer->fill = total_bytes;
318
-	state.bitmap = state.image + total_bytes;
319
-	if ((unsigned long)state.image < 1024*1024) {
320
-		printf("ALERT: slam filesize to large for available memory\n");
321
-		return 0;
322
-	}
323
-	memset(state.bitmap, 0, bitmap_len);
324
-
325
-	return header + state.hdr_len;
326
-}
327
-
328
-static int slam_recv_data(unsigned char *data)
329
-{
330
-	unsigned long packet;
331
-	unsigned long data_len;
332
-	int err;
333
-	struct udphdr *udp;
334
-	udp = (struct udphdr *)&nic.packet[ETH_HLEN + sizeof(struct iphdr)];
335
-	err = 0;
336
-	packet = slam_decode(&data, &nic.packet[nic.packetlen], &err);
337
-	if (err || (packet > state.total_packets)) {
338
-		printf("ALERT: Invalid packet number\n");
339
-		return 0;
340
-	}
341
-	/* Compute the expected data length */
342
-	if (packet != state.total_packets -1) {
343
-		data_len = state.block_size;
344
-	} else {
345
-		data_len = state.total_bytes % state.block_size;
346
-	}
347
-	/* If the packet size is wrong drop the packet and then continue */
348
-	if (ntohs(udp->len) != (data_len + (data - (unsigned char*)udp))) {
349
-		printf("ALERT: udp packet is not the correct size\n");
350
-		return 1;
351
-	}
352
-	if (nic.packetlen < data_len + (data - nic.packet)) {
353
-		printf("ALERT: Ethernet packet shorter than data_len\n");
354
-		return 1;
355
-	}
356
-	if (data_len > state.block_size) {
357
-		data_len = state.block_size;
358
-	}
359
-	if (((state.bitmap[packet >> 3] >> (packet & 7)) & 1) == 0) {
360
-		/* Non duplicate packet */
361
-		state.bitmap[packet >> 3] |= (1 << (packet & 7));
362
-		memcpy(state.image + (packet*state.block_size), data, data_len);
363
-		state.received_packets++;
364
-	} else {
365
-#ifdef MDEBUG
366
-		printf("<DUP>\n");
367
-#endif
368
-	}
369
-	return 1;
370
-}
371
-
372
-static void transmit_nack(unsigned char *ptr, struct slam_info *info)
373
-{
374
-	int nack_len;
375
-	/* Ensure the packet is null terminated */
376
-	*ptr++ = 0;
377
-	nack_len = ptr - (unsigned char *)&nack;
378
-	build_udp_hdr(info->server.sin_addr.s_addr, info->local.sin_port,
379
-		      info->server.sin_port, 1, nack_len, &nack);
380
-	ip_transmit(nack_len, &nack);
381
-#if defined(MDEBUG) && 0
382
-	printf("Sent NACK to %@ bytes: %d have:%ld/%ld\n", 
383
-		info->server_ip, nack_len,
384
-		state.received_packets, state.total_packets);
385
-#endif
386
-}
387
-
388
-static void slam_send_nack(struct slam_info *info)
389
-{
390
-	unsigned char *ptr, *end;
391
-	/* Either I timed out or I was explicitly 
392
-	 * asked for a request packet 
393
-	 */
394
-	ptr = &nack.data[0];
395
-	/* Reserve space for the trailling null */
396
-	end = &nack.data[sizeof(nack.data) -1]; 
397
-	if (!state.bitmap) {
398
-		slam_encode(&ptr, end, 0);
399
-		slam_encode(&ptr, end, 1);
400
-	}
401
-	else {
402
-		/* Walk the bitmap */
403
-		unsigned long i;
404
-		unsigned long len;
405
-		unsigned long max;
406
-		int value;
407
-		int last;
408
-		/* Compute the last bit and store an inverted trailer */
409
-		max = state.total_packets;
410
-		value = ((state.bitmap[(max -1) >> 3] >> ((max -1) & 7) ) & 1);
411
-		value = !value;
412
-		state.bitmap[max >> 3] &= ~(1 << (max & 7));
413
-		state.bitmap[max >> 3] |= value << (max & 7);
414
-
415
-		len = 0;
416
-		last = 1; /* Start with the received packets */
417
-		for(i = 0; i <= max; i++) {
418
-			value = (state.bitmap[i>>3] >> (i & 7)) & 1;
419
-			if (value == last) {
420
-				len++;
421
-			} else {
422
-				if (slam_encode(&ptr, end, len))
423
-					break;
424
-				last = value;
425
-				len = 1;
426
-			}
427
-		}
428
-	}
429
-	info->sent_nack = 1;
430
-	transmit_nack(ptr, info);
431
-}
432
-
433
-static void slam_send_disconnect(struct slam_info *info)
434
-{
435
-	if (info->sent_nack) {
436
-		/* A disconnect is a packet with just the null terminator */
437
-		transmit_nack(&nack.data[0], info);
438
-	}
439
-	info->sent_nack = 0;
440
-}
441
-
442
-
443
-static int proto_slam(struct slam_info *info)
444
-{
445
-	int retry;
446
-	long timeout;
447
-
448
-	init_slam_state();
449
-	state.buffer = info->buffer;
450
-
451
-	retry = -1;
452
-	rx_qdrain();
453
-	/* Arp for my server */
454
-	if (arptable[ARP_SERVER].ipaddr.s_addr != info->server.sin_addr.s_addr) {
455
-		arptable[ARP_SERVER].ipaddr.s_addr = info->server.sin_addr.s_addr;
456
-		memset(arptable[ARP_SERVER].node, 0, ETH_ALEN);
457
-	}
458
-	/* If I'm running over multicast join the multicast group */
459
-	join_group(IGMP_SERVER, info->multicast.sin_addr.s_addr);
460
-	for(;;) {
461
-		unsigned char *header;
462
-		unsigned char *data;
463
-		int type;
464
-		header = data = 0;
465
-
466
-		timeout = slam_sleep_interval(retry);
467
-		type = await_reply(await_slam, 0, info, timeout);
468
-		/* Compute the timeout for next time */
469
-		if (type == SLAM_TIMEOUT) {
470
-			/* If I timeouted recompute the next timeout */
471
-			if (retry++ > SLAM_MAX_RETRIES) {
472
-				return 0;
473
-			}
474
-		} else {
475
-			retry = 0;
476
-		}
477
-		if ((type == SLAM_DATA) || (type == SLAM_REQUEST)) {
478
-			/* Check the incomming packet and reinit the data 
479
-			 * structures if necessary.
480
-			 */
481
-			header = &nic.packet[ETH_HLEN + 
482
-				sizeof(struct iphdr) + sizeof(struct udphdr)];
483
-			data = header + state.hdr_len;
484
-			if (memcmp(state.hdr, header, state.hdr_len) != 0) {
485
-				/* Something is fishy reset the transaction */
486
-				data = reinit_slam_state(header, &nic.packet[nic.packetlen]);
487
-				if (!data) {
488
-					return 0;
489
-				}
490
-			}
491
-		}
492
-		if (type == SLAM_DATA) {
493
-			if (!slam_recv_data(data)) {
494
-				return 0;
495
-			}
496
-			if (state.received_packets == state.total_packets) {
497
-				/* We are done get out */
498
-				break;
499
-			}
500
-		}
501
-		if ((type == SLAM_TIMEOUT) || (type == SLAM_REQUEST)) {
502
-			/* Either I timed out or I was explicitly 
503
-			 * asked by a request packet 
504
-			 */
505
-			slam_send_nack(info);
506
-		}
507
-	}
508
-	slam_send_disconnect(info);
509
-
510
-	/* Leave the multicast group */
511
-	leave_group(IGMP_SERVER);
512
-	/* FIXME don't overwrite myself */
513
-	/* load file to correct location */
514
-	return 1;
515
-}
516
-
517
-static int url_slam ( char *url __unused, struct sockaddr_in *server,
518
-		      char *file, struct buffer *buffer ) {
519
-	struct slam_info info;
520
-	/* Set the defaults */
521
-	info.server = *server;
522
-	info.multicast.sin_addr.s_addr = htonl(SLAM_MULTICAST_IP);
523
-	info.multicast.sin_port      = SLAM_MULTICAST_PORT;
524
-	info.local.sin_addr.s_addr   = arptable[ARP_CLIENT].ipaddr.s_addr;
525
-	info.local.sin_port          = SLAM_LOCAL_PORT;
526
-	info.buffer                  = buffer;
527
-	info.sent_nack = 0;
528
-	if (file[0]) {
529
-		printf("\nBad url\n");
530
-		return 0;
531
-	}
532
-	return proto_slam(&info);
533
-}
534
-
535
-struct protocol slam_protocol __protocol = {
536
-	.name = "x-slam",
537
-	.default_port = SLAM_PORT,
538
-	.load = url_slam,
539
-};
540
-
541
-#endif

Loading…
Отказ
Запис