doorbell

view doorbelld/src/srv.c @ 7:dc4018af3a40

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