3 * (c) 2002 Eric Biederman
11 #include <sys/types.h>
13 #include <sys/socket.h>
15 #include <netinet/ip.h>
16 #include <netinet/in.h>
19 #include <arpa/inet.h>
22 * To specify the default interface for multicast packets use:
23 * route add -net 224.0.0.0 netmask 240.0.0.0 dev eth1
24 * This server is stupid and does not override the default.
29 * Waiting for clients.
30 * Sending data to clients.
31 * Pinging clients for data.
34 #define SLAM_PORT 10000
35 #define SLAM_MULTICAST_IP ((239<<24)|(255<<16)|(1<<8)|(1<<0))
36 #define SLAM_MULTICAST_PORT 10000
37 #define SLAM_MULTICAST_TTL 1
38 #define SLAM_MULTICAST_LOOPBACK 1
39 #define SLAM_MAX_CLIENTS 10
41 #define SLAM_PING_TIMEOUT 100 /* ms */
43 /*** Packets Formats ***
51 * Status Request Packet
67 #define MAX_HDR (7 + 7 + 7) /* transaction, total size, block size */
68 #define MIN_HDR (1 + 1 + 1) /* transaction, total size, block size */
70 #define MAX_DATA_HDR (MAX_HDR + 7) /* header, packet # */
71 #define MIN_DATA_HDR (MAX_HDR + 1) /* header, packet # */
73 /* ETH_MAX_MTU 1500 - sizeof(iphdr) 20 - sizeof(udphdr) 8 = 1472 */
74 #define SLAM_MAX_NACK (1500 - (20 + 8))
75 /* ETH_MAX_MTU 1500 - sizeof(iphdr) 20 - sizeof(udphdr) 8 - MAX_HDR = 1451 */
76 #define SLAM_BLOCK_SIZE (1500 - (20 + 8 + MAX_HDR))
79 /* Define how many debug messages you want
80 * 1 - sparse but useful
87 static int slam_encode(
88 unsigned char **ptr
, unsigned char *end
, unsigned long value
)
90 unsigned char *data
= *ptr
;
92 bytes
= sizeof(value
);
93 while ((bytes
> 0) && ((0xff & (value
>> ((bytes
-1)<<3))) == 0)) {
99 if (data
+ bytes
>= end
) {
102 if ((0xe0 & (value
>> ((bytes
-1)<<3))) == 0) {
103 /* packed together */
104 *data
= (bytes
<< 5) | (value
>> ((bytes
-1)<<3));
107 *data
= (bytes
<< 5);
112 *(data
++) = 0xff & (value
>> ((bytes
-1)<<3));
119 static unsigned long slam_decode(unsigned char **ptr
, unsigned char *end
, int *err
)
126 bytes
= ((**ptr
) >> 5) & 7;
127 if ((bytes
== 0) || (bytes
> sizeof(unsigned long))) {
131 if ((*ptr
) + bytes
>= end
) {
134 value
= (**ptr
) & 0x1f;
147 static struct sockaddr_in client
[SLAM_MAX_CLIENTS
];
151 void del_client(struct sockaddr_in
*old
)
154 for(i
= 0; i
< clients
; i
++) {
155 if ((client
[i
].sin_family
== old
->sin_family
) &&
156 (client
[i
].sin_addr
.s_addr
== old
->sin_addr
.s_addr
) &&
157 (client
[i
].sin_port
== old
->sin_port
)) {
158 memmove(&client
[i
], &client
[i
+1],
159 (clients
- (i
+1))*sizeof(client
[0]));
165 void add_client(struct sockaddr_in
*new)
168 if (clients
>= SLAM_MAX_CLIENTS
)
170 memcpy(&client
[clients
], new, sizeof(*new));
174 void push_client(struct sockaddr_in
*new)
177 if (clients
>= SLAM_MAX_CLIENTS
) {
180 memmove(&client
[1], &client
[0], clients
*sizeof(*new));
181 memcpy(&client
[0], new, sizeof(*new));
186 void next_client(struct sockaddr_in
*next
)
188 /* Find the next client we want to ping next */
190 next
->sin_family
= AF_UNSPEC
;
193 /* Return the first client */
194 memcpy(next
, &client
[0], sizeof(*next
));
197 int main(int argc
, char **argv
)
200 uint8_t nack_packet
[SLAM_MAX_NACK
];
202 uint8_t request_packet
[MAX_HDR
];
204 uint8_t data_packet
[MAX_DATA_HDR
+ SLAM_BLOCK_SIZE
];
207 struct sockaddr_in master_client
;
208 struct sockaddr_in sa_src
;
209 struct sockaddr_in sa_mcast
;
214 struct pollfd fds
[1];
216 #define STATE_PINGING 1
217 #define STATE_WAITING 2
218 #define STATE_RECEIVING 3
219 #define STATE_TRANSMITTING 4
222 uint64_t transaction
;
223 unsigned long packet
;
224 unsigned long packet_count
;
225 unsigned slam_port
, slam_multicast_port
;
226 struct in_addr slam_multicast_ip
;
228 slam_port
= SLAM_PORT
;
229 slam_multicast_port
= SLAM_MULTICAST_PORT
;
230 slam_multicast_ip
.s_addr
= htonl(SLAM_MULTICAST_IP
);
233 fprintf(stderr
, "Bad argument count\n");
234 fprintf(stderr
, "Usage: mini-slamd filename\n");
242 /* Setup the udp socket */
243 sockfd
= socket(PF_INET
, SOCK_DGRAM
, 0);
245 fprintf(stderr
, "Cannot create socket\n");
248 memset(&sa_src
, 0, sizeof(sa_src
));
249 sa_src
.sin_family
= AF_INET
;
250 sa_src
.sin_port
= htons(slam_port
);
251 sa_src
.sin_addr
.s_addr
= INADDR_ANY
;
253 result
= bind(sockfd
, &sa_src
, sizeof(sa_src
));
255 fprintf(stderr
, "Cannot bind socket to port %d\n",
256 ntohs(sa_src
.sin_port
));
260 /* Setup the multicast transmission address */
261 memset(&sa_mcast
, 0, sizeof(sa_mcast
));
262 sa_mcast
.sin_family
= AF_INET
;
263 sa_mcast
.sin_port
= htons(slam_multicast_port
);
264 sa_mcast
.sin_addr
.s_addr
= slam_multicast_ip
.s_addr
;
265 if (!IN_MULTICAST(ntohl(sa_mcast
.sin_addr
.s_addr
))) {
266 fprintf(stderr
, "Not a multicast ip\n");
270 /* Set the multicast ttl */
271 mcast_ttl
= SLAM_MULTICAST_TTL
;
272 setsockopt(sockfd
, IPPROTO_IP
, IP_MULTICAST_TTL
,
273 &mcast_ttl
, sizeof(mcast_ttl
));
275 /* Set the multicast loopback status */
276 mcast_loop
= SLAM_MULTICAST_LOOPBACK
;
277 setsockopt(sockfd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, &mcast_loop
, sizeof(mcast_loop
));
280 state
= STATE_WAITING
;
284 fds
[0].events
= POLLIN
;
289 state
= STATE_WAITING
;
290 next_client(&master_client
);
291 if (master_client
.sin_family
== AF_UNSPEC
) {
295 printf("Pinging %s:%d\n",
296 inet_ntoa(master_client
.sin_addr
),
297 ntohs(master_client
.sin_port
));
301 /* Prepare the request packet, it is all header */
302 ptr
= request_packet
;
303 end
= &request_packet
[sizeof(request_packet
) -1];
304 slam_encode(&ptr
, end
, transaction
);
305 slam_encode(&ptr
, end
, size
);
306 slam_encode(&ptr
, end
, SLAM_BLOCK_SIZE
);
307 request_len
= ptr
- request_packet
;
309 result
= sendto(sockfd
, request_packet
, request_len
, 0,
310 &master_client
, sizeof(master_client
));
311 /* Forget the client I just asked, when the reply
312 * comes in we will remember it again.
314 del_client(&master_client
);
321 if (master_client
.sin_family
!= AF_UNSPEC
) {
322 timeout
= SLAM_PING_TIMEOUT
;
324 result
= poll(fds
, sizeof(fds
)/sizeof(fds
[0]), timeout
);
326 /* On a timeout try the next client */
327 state
= STATE_PINGING
;
331 from_len
= sizeof(master_client
);
332 result
= recvfrom(sockfd
,
333 nack_packet
, sizeof(nack_packet
), 0,
334 &master_client
, &from_len
);
339 printf("Received Nack from %s:%d\n",
340 inet_ntoa(master_client
.sin_addr
),
341 ntohs(master_client
.sin_port
));
351 packet
+= slam_decode(&ptr
, end
, &result
);
352 if (result
< 0) break;
353 packet_count
= slam_decode(&ptr
, end
, &result
);
354 if (result
< 0) break;
356 packet
, packet
+ packet_count
-1);
362 /* Forget this client temporarily.
363 * If the packet appears good they will be
366 del_client(&master_client
);
368 end
= ptr
+ nack_len
;
370 packet
= slam_decode(&ptr
, end
, &result
);
373 packet_count
= slam_decode(&ptr
, end
, &result
);
376 /* We appear to have a good packet, keep
379 push_client(&master_client
);
381 /* Reopen the file to transmit */
385 filefd
= open(filename
, O_RDONLY
);
387 fprintf(stderr
, "Cannot open %s: %s\n",
388 filename
, strerror(errno
));
391 size
= lseek(filefd
, 0, SEEK_END
);
393 fprintf(stderr
, "Seek failed on %s: %s\n",
394 filename
, strerror(errno
));
397 result
= fstat(filefd
, &st
);
399 fprintf(stderr
, "Stat failed on %s: %s\n",
400 filename
, strerror(errno
));
403 transaction
= st
.st_mtime
;
405 state
= STATE_TRANSMITTING
;
410 case STATE_RECEIVING
:
411 /* Now clear the queue of received packets */
413 struct sockaddr_in from
;
415 uint8_t dummy_packet
[SLAM_MAX_NACK
];
416 state
= STATE_TRANSMITTING
;
417 result
= poll(fds
, sizeof(fds
)/sizeof(fds
[0]), 0);
420 from_len
= sizeof(from
);
421 result
= recvfrom(sockfd
,
422 dummy_packet
, sizeof(dummy_packet
), 0,
427 printf("Received Nack from %s:%d\n",
428 inet_ntoa(from
.sin_addr
),
429 ntohs(from
.sin_port
));
432 /* Receive packets until I don't get any more */
433 state
= STATE_RECEIVING
;
434 /* Process a packet */
435 if (dummy_packet
[0] == '\0') {
436 /* If the first byte is null it is a disconnect
442 /* Otherwise attempt to add the client. */
447 case STATE_TRANSMITTING
:
452 uint8_t *ptr2
, *end2
;
454 /* After I transmit a packet check for packets to receive. */
455 state
= STATE_RECEIVING
;
457 /* Find the packet to transmit */
458 offset
= packet
* SLAM_BLOCK_SIZE
;
460 /* Seek to the desired packet */
461 off
= lseek(filefd
, offset
, SEEK_SET
);
462 if ((off
< 0) || (off
!= offset
)) {
463 fprintf(stderr
, "Seek failed on %s:%s\n",
464 filename
, strerror(errno
));
467 /* Encode the packet header */
469 end2
= data_packet
+ sizeof(data_packet
);
470 slam_encode(&ptr2
, end2
, transaction
);
471 slam_encode(&ptr2
, end2
, size
);
472 slam_encode(&ptr2
, end2
, SLAM_BLOCK_SIZE
);
473 slam_encode(&ptr2
, end2
, packet
);
474 data_len
= ptr2
- data_packet
;
476 /* Read in the data */
477 bytes
= read(filefd
, &data_packet
[data_len
],
480 fprintf(stderr
, "Read failed on %s:%s\n",
481 filename
, strerror(errno
));
485 /* Write out the data */
486 result
= sendto(sockfd
, data_packet
, data_len
, 0,
487 &sa_mcast
, sizeof(sa_mcast
));
488 if (result
!= data_len
) {
489 fprintf(stderr
, "Send failed %s\n",
494 printf("Transmitted: %d\n", packet
);
497 /* Compute the next packet */
500 if (packet_count
== 0) {
501 packet
+= slam_decode(&ptr
, end
, &result
);
503 packet_count
= slam_decode(&ptr
, end
, &result
);
505 /* When a transmission is done close the file,
506 * so it may be updated. And then ping then start
507 * pinging clients to get the transmission started
510 state
= STATE_PINGING
;