File: main.c

package info (click to toggle)
spiped 1.6.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,328 kB
  • sloc: ansic: 11,951; sh: 1,081; makefile: 629; perl: 121
file content (162 lines) | stat: -rw-r--r-- 3,118 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include <sys/time.h>

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "millisleep.h"
#include "monoclock.h"
#include "parsenum.h"
#include "warnp.h"

#include "simple_server.h"

#define MAX_CONNECTIONS 2
#define SHUTDOWN_AFTER 1

struct nc_cookie {
	FILE * out;
	size_t bps;		/* Average bytes per second to send. */
};

/* Send a message, limited to bytes per second.  Send in bursts of 10ms. */
static int
write_bps(int sock, uint8_t * buf, size_t buflen, size_t bps)
{
	size_t remaining = buflen;
	size_t goal_send;
	size_t actual_sent = 0;
	size_t to_send;
	struct timeval orig, now;

	/* Get initial time. */
	if (monoclock_get(&orig)) {
		warn0("monoclock_get");
		goto err0;
	}

	do {
		/* Wait 10ms. */
		millisleep(10);

		/* How much data should we have sent by now? */
		if (monoclock_get(&now)) {
			warn0("monoclock_get");
			goto err0;
		}
		goal_send = (size_t)((double)bps * timeval_diff(orig, now));

		/* If clocks did something really weird, loop again. */
		if (goal_send <= actual_sent)
			continue;

		/* How data should we send to reach the time-based goal? */
		to_send = goal_send - actual_sent;
		if (to_send > remaining)
			to_send = remaining;

		/* Send a burst. */
		if (write(sock, buf, to_send) == -1) {
			warnp("write");
			goto err0;
		}

		/* Record effect of sending. */
		remaining -= to_send;
		buf += to_send;
		actual_sent += to_send;
	} while (remaining > 0);

	/* Success! */
	return (0);

err0:
	/* Failure! */
	return (-1);
}

/* A client sent a message. */
static int
callback_snc_response(void * cookie, uint8_t * buf, size_t buflen, int sock)
{
	struct nc_cookie * C = cookie;

	/* Write buffer to the previously-opened file. */
	if (fwrite(buf, sizeof(uint8_t), buflen, C->out) != buflen) {
		warnp("fwrite");
		goto err0;
	}

	/* Echo to the client (if applicable). */
	if ((C->bps > 0) && (write_bps(sock, buf, buflen, C->bps)))
		goto err0;

	/* Success! */
	return (0);

err0:
	/* Failure! */
	return (-1);
}

int
main(int argc, char ** argv)
{
	struct nc_cookie cookie;
	struct nc_cookie * C = &cookie;
	const char * sockname;
	const char * filename;

	WARNP_INIT;

	/* Parse command-line arguments. */
	if (argc < 3) {
		fprintf(stderr, "usage: %s ADDRESS FILENAME [ECHO_BPS]\n",
		    argv[0]);
		goto err0;
	}
	sockname = argv[1];
	filename = argv[2];
	if (argc > 3) {
		/* Allow up to 1 MB per second of echoing. */
		if (PARSENUM(&C->bps, argv[3], 0, 1000000)) {
			warnp("parsenum");
			goto err0;
		}
		if ((C->bps % 100) != 0) {
			warn0("BPS must be a multiple of 100");
			goto err0;
		}
	} else
		C->bps = 0;

	/* Open the output file; can be /dev/null. */
	if ((C->out = fopen(filename, "wb")) == NULL) {
		warnp("fopen");
		goto err0;
	}

	/* Run the server. */
	if (simple_server(sockname, MAX_CONNECTIONS, SHUTDOWN_AFTER,
	    &callback_snc_response, C)) {
		warn0("simple_server failed");
		goto err1;
	}

	/* Write the output file. */
	if (fclose(C->out) != 0) {
		warnp("fclose");
		goto err0;
	}

	/* Success! */
	exit(0);

err1:
	if (fclose(C->out))
		warnp("fclose");
err0:
	/* Failure! */
	exit(1);
}