doorbell

annotate 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
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 }