rev |
line source |
nuclear@2
|
1 #include <stdio.h>
|
nuclear@2
|
2 #include <stdlib.h>
|
nuclear@2
|
3 #include <string.h>
|
nuclear@5
|
4 #include <stddef.h>
|
nuclear@5
|
5 #include <stdint.h>
|
nuclear@2
|
6 #include <errno.h>
|
nuclear@2
|
7 #include <assert.h>
|
nuclear@2
|
8 #include <unistd.h>
|
nuclear@2
|
9 #include <fcntl.h>
|
nuclear@2
|
10 #include <sys/socket.h>
|
nuclear@2
|
11 #include <arpa/inet.h>
|
nuclear@2
|
12 #include "srv.h"
|
nuclear@2
|
13 #include "dynarr.h"
|
nuclear@2
|
14
|
nuclear@4
|
15 /* TODO convert this whole thing to multicast */
|
nuclear@4
|
16
|
nuclear@6
|
17 static int bsock = -1;
|
nuclear@6
|
18 static struct sockaddr_in baddr;
|
nuclear@2
|
19 static int lis_sock = -1, max_socket = -1;
|
nuclear@2
|
20 static int *csock;
|
nuclear@2
|
21
|
nuclear@2
|
22 int srv_init(int port)
|
nuclear@2
|
23 {
|
nuclear@6
|
24 int val;
|
nuclear@2
|
25 struct sockaddr_in addr;
|
nuclear@2
|
26
|
nuclear@2
|
27 if(lis_sock != -1) {
|
nuclear@2
|
28 fprintf(stderr, "%s: already running\n", __func__);
|
nuclear@2
|
29 return -1;
|
nuclear@2
|
30 }
|
nuclear@2
|
31
|
nuclear@2
|
32 if((lis_sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
|
nuclear@2
|
33 fprintf(stderr, "%s: failed to create listening socket\n", __func__);
|
nuclear@2
|
34 return -1;
|
nuclear@2
|
35 }
|
nuclear@2
|
36 if(!(csock = dynarr_alloc(1, sizeof *csock))) {
|
nuclear@2
|
37 fprintf(stderr, "%s: failed to allocate client socket array\n", __func__);
|
nuclear@2
|
38 return -1;
|
nuclear@2
|
39 }
|
nuclear@2
|
40 csock[0] = lis_sock;
|
nuclear@2
|
41 max_socket = lis_sock;
|
nuclear@2
|
42
|
nuclear@5
|
43 fcntl(lis_sock, F_SETFL, fcntl(lis_sock, F_GETFL) | O_NONBLOCK);
|
nuclear@2
|
44
|
nuclear@2
|
45 memset(&addr, 0, sizeof addr);
|
nuclear@2
|
46 addr.sin_family = AF_INET;
|
nuclear@2
|
47 addr.sin_port = htons(port);
|
nuclear@2
|
48 addr.sin_addr.s_addr = INADDR_ANY;
|
nuclear@2
|
49 if(bind(lis_sock, (struct sockaddr*)&addr, sizeof addr) == -1) {
|
nuclear@2
|
50 fprintf(stderr, "%s: failed to bind port %d\n", __func__, port);
|
nuclear@2
|
51 close(lis_sock);
|
nuclear@2
|
52 lis_sock = -1;
|
nuclear@2
|
53 return -1;
|
nuclear@2
|
54 }
|
nuclear@4
|
55 listen(lis_sock, 8);
|
nuclear@2
|
56
|
nuclear@6
|
57 /* then create the video broadcast socket */
|
nuclear@6
|
58 if((bsock = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
|
nuclear@6
|
59 fprintf(stderr, "%s: failed to create video broadcast socket\n", __func__);
|
nuclear@6
|
60 return -1;
|
nuclear@6
|
61 }
|
nuclear@7
|
62 /*fcntl(bsock, F_SETFL, fcntl(bsock, F_GETFL) | O_NONBLOCK);*/
|
nuclear@6
|
63 val = 1;
|
nuclear@6
|
64 setsockopt(bsock, SOL_SOCKET, SO_BROADCAST, &val, sizeof val);
|
nuclear@6
|
65
|
nuclear@7
|
66 /* prepare the broadcast address struct */
|
nuclear@6
|
67 memset(&baddr, 0, sizeof baddr);
|
nuclear@6
|
68 baddr.sin_family = AF_INET;
|
nuclear@6
|
69 baddr.sin_port = htons(port + 1);
|
nuclear@6
|
70 baddr.sin_addr.s_addr = 0xffffffff;
|
nuclear@6
|
71
|
nuclear@2
|
72 return 0;
|
nuclear@2
|
73 }
|
nuclear@2
|
74
|
nuclear@2
|
75 void srv_shutdown(void)
|
nuclear@2
|
76 {
|
nuclear@2
|
77 int i, sz = dynarr_size(csock);
|
nuclear@2
|
78 for(i=0; i<sz; i++) {
|
nuclear@2
|
79 close(csock[i]);
|
nuclear@2
|
80 }
|
nuclear@2
|
81 dynarr_free(csock);
|
nuclear@2
|
82 csock = 0;
|
nuclear@2
|
83 lis_sock = -1;
|
nuclear@2
|
84 max_socket = -1;
|
nuclear@2
|
85 }
|
nuclear@2
|
86
|
nuclear@2
|
87 int srv_num_sockets(void)
|
nuclear@2
|
88 {
|
nuclear@2
|
89 return dynarr_size(csock);
|
nuclear@2
|
90 }
|
nuclear@2
|
91
|
nuclear@2
|
92 int *srv_sockets(void)
|
nuclear@2
|
93 {
|
nuclear@2
|
94 return csock;
|
nuclear@2
|
95 }
|
nuclear@2
|
96
|
nuclear@2
|
97 int srv_max_socket(void)
|
nuclear@2
|
98 {
|
nuclear@2
|
99 return max_socket;
|
nuclear@2
|
100 }
|
nuclear@2
|
101
|
nuclear@6
|
102 static int handle_new_client(void)
|
nuclear@6
|
103 {
|
nuclear@6
|
104 int s;
|
nuclear@6
|
105 /* incoming connection */
|
nuclear@6
|
106 struct sockaddr_in addr;
|
nuclear@6
|
107 socklen_t addr_size = sizeof addr;
|
nuclear@6
|
108 if((s = accept(lis_sock, (struct sockaddr*)&addr, &addr_size)) == -1) {
|
nuclear@6
|
109 fprintf(stderr, "%s: failed to accept incoming connection: %s\n", __func__, strerror(errno));
|
nuclear@6
|
110 return -1;
|
nuclear@6
|
111 }
|
nuclear@6
|
112 printf("%s: incoming connection from %s:%d\n", __func__,
|
nuclear@6
|
113 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
|
nuclear@6
|
114 csock = dynarr_push(csock, &s);
|
nuclear@6
|
115 assert(csock);
|
nuclear@6
|
116 if(s > max_socket) {
|
nuclear@6
|
117 max_socket = s;
|
nuclear@6
|
118 }
|
nuclear@6
|
119 fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
|
nuclear@6
|
120 return 0;
|
nuclear@6
|
121 }
|
nuclear@6
|
122
|
nuclear@6
|
123 static int handle_client(int s)
|
nuclear@2
|
124 {
|
nuclear@2
|
125 static char buf[1024];
|
nuclear@2
|
126 int sz;
|
nuclear@2
|
127
|
nuclear@2
|
128 /* handle client */
|
nuclear@2
|
129 while((sz = read(s, buf, sizeof buf - 1)) > 0) {
|
nuclear@2
|
130 printf("%s: got data: %s\n", __func__, buf);
|
nuclear@2
|
131 }
|
nuclear@7
|
132 if((sz < 0 && errno != EAGAIN) || sz == 0) {
|
nuclear@2
|
133 /* client closed connection probably */
|
nuclear@2
|
134 int i, num_clients = dynarr_size(csock);
|
nuclear@2
|
135 printf("%s: removing client\n", __func__);
|
nuclear@2
|
136 close(s);
|
nuclear@4
|
137 max_socket = lis_sock;
|
nuclear@2
|
138 for(i=0; i<num_clients; i++) {
|
nuclear@2
|
139 if(csock[i] == s) {
|
nuclear@2
|
140 csock[i] = csock[num_clients - 1];
|
nuclear@4
|
141 }
|
nuclear@4
|
142 if(csock[i] > max_socket) {
|
nuclear@4
|
143 max_socket = csock[i];
|
nuclear@2
|
144 }
|
nuclear@2
|
145 }
|
nuclear@4
|
146
|
nuclear@4
|
147 csock = dynarr_pop(csock);
|
nuclear@4
|
148 --num_clients;
|
nuclear@2
|
149 }
|
nuclear@2
|
150 return 0;
|
nuclear@2
|
151 }
|
nuclear@2
|
152
|
nuclear@6
|
153 int srv_handle(int s)
|
nuclear@6
|
154 {
|
nuclear@6
|
155 if(s == lis_sock) {
|
nuclear@6
|
156 return handle_new_client();
|
nuclear@6
|
157 }
|
nuclear@6
|
158
|
nuclear@6
|
159 return handle_client(s);
|
nuclear@6
|
160 }
|
nuclear@6
|
161
|
nuclear@4
|
162 struct video_block {
|
nuclear@4
|
163 int frame;
|
nuclear@7
|
164 uint16_t x, y;
|
nuclear@7
|
165 uint16_t width, height;
|
nuclear@7
|
166 uint16_t frame_width, frame_height;
|
nuclear@7
|
167 uint16_t pixels[1];
|
nuclear@4
|
168 };
|
nuclear@4
|
169 #define VBLOCK_HEADER_SIZE (offsetof(struct video_block, pixels))
|
nuclear@4
|
170
|
nuclear@7
|
171 /* ideally we would want each block to stay under the MTU (1500) */
|
nuclear@7
|
172 #define BLKSZ 24
|
nuclear@7
|
173
|
nuclear@7
|
174 int srv_send_frame(unsigned char *frame, int xsz, int ysz)
|
nuclear@2
|
175 {
|
nuclear@5
|
176 static int frame_num;
|
nuclear@7
|
177 int i, j;
|
nuclear@4
|
178 struct video_block *vblock;
|
nuclear@7
|
179 int blksz;
|
nuclear@5
|
180
|
nuclear@7
|
181 printf("sending frame: %d\n", frame_num);
|
nuclear@4
|
182
|
nuclear@7
|
183 blksz = BLKSZ * BLKSZ * 2 + VBLOCK_HEADER_SIZE;
|
nuclear@7
|
184 if(!(vblock = malloc(blksz))) {
|
nuclear@7
|
185 fprintf(stderr, "failed to allocate %dx%d block buffer\n", BLKSZ, BLKSZ);
|
nuclear@7
|
186 return -1;
|
nuclear@4
|
187 }
|
nuclear@5
|
188
|
nuclear@5
|
189 vblock->frame = frame_num++;
|
nuclear@5
|
190 vblock->x = vblock->y = 0;
|
nuclear@7
|
191 vblock->frame_width = xsz;
|
nuclear@7
|
192 vblock->frame_height = ysz;
|
nuclear@5
|
193
|
nuclear@7
|
194 vblock->y = 0;
|
nuclear@7
|
195 while(vblock->y < ysz) {
|
nuclear@7
|
196 if(vblock->y + BLKSZ <= ysz) {
|
nuclear@7
|
197 vblock->height = BLKSZ;
|
nuclear@7
|
198 } else {
|
nuclear@7
|
199 vblock->height = ysz - vblock->y;
|
nuclear@7
|
200 }
|
nuclear@5
|
201
|
nuclear@7
|
202 vblock->x = 0;
|
nuclear@7
|
203 while(vblock->x < xsz) {
|
nuclear@7
|
204 if(vblock->x + BLKSZ <= xsz) {
|
nuclear@7
|
205 vblock->width = BLKSZ;
|
nuclear@7
|
206 } else {
|
nuclear@7
|
207 vblock->width = xsz - vblock->x;
|
nuclear@7
|
208 }
|
nuclear@5
|
209
|
nuclear@7
|
210 unsigned char *src = frame + (vblock->y * xsz + vblock->x) * 4;
|
nuclear@7
|
211 uint16_t *dest = vblock->pixels;
|
nuclear@7
|
212
|
nuclear@7
|
213 /* convert block to 565 */
|
nuclear@7
|
214 for(i=0; i<vblock->height; i++) {
|
nuclear@7
|
215 for(j=0; j<vblock->width; j++) {
|
nuclear@7
|
216 unsigned int r = src[0];
|
nuclear@7
|
217 unsigned int g = src[1];
|
nuclear@7
|
218 unsigned int b = src[2];
|
nuclear@7
|
219
|
nuclear@7
|
220 *dest++ = ((r << 8) & 0xf800) | ((g << 3) & 0x7e0) | ((b >> 3) & 0x1f);
|
nuclear@7
|
221 src += 4;
|
nuclear@7
|
222 }
|
nuclear@7
|
223 src += (xsz - vblock->width) * 4;
|
nuclear@7
|
224 }
|
nuclear@7
|
225
|
nuclear@7
|
226 /* and broadcast it */
|
nuclear@7
|
227 printf("f(%d) b(%d,%d)\n", frame_num - 1, vblock->x, vblock->y);
|
nuclear@7
|
228 if(sendto(bsock, vblock, blksz, 0, (struct sockaddr*)&baddr, sizeof baddr) == -1) {
|
nuclear@7
|
229 perror("failed to send block");
|
nuclear@7
|
230 if(errno == EMSGSIZE) {
|
nuclear@7
|
231 abort();
|
nuclear@7
|
232 }
|
nuclear@7
|
233 return -1;
|
nuclear@7
|
234 }
|
nuclear@7
|
235
|
nuclear@7
|
236 vblock->x += BLKSZ;
|
nuclear@5
|
237 }
|
nuclear@7
|
238 vblock->y += BLKSZ;
|
nuclear@5
|
239 }
|
nuclear@5
|
240
|
nuclear@7
|
241 free(vblock);
|
nuclear@7
|
242 return 0;
|
nuclear@2
|
243 }
|