doorbell

annotate doorbelld/src/srv.c @ 6:026156ea8801

foo
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 16 Mar 2016 00:00:06 +0200
parents f21ae31ef0e7
children dc4018af3a40
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@6 62 val = 1;
nuclear@6 63 setsockopt(bsock, SOL_SOCKET, SO_BROADCAST, &val, sizeof val);
nuclear@6 64
nuclear@6 65 memset(&baddr, 0, sizeof baddr);
nuclear@6 66 baddr.sin_family = AF_INET;
nuclear@6 67 baddr.sin_port = htons(port + 1);
nuclear@6 68 baddr.sin_addr.s_addr = 0xffffffff;
nuclear@6 69
nuclear@2 70 return 0;
nuclear@2 71 }
nuclear@2 72
nuclear@2 73 void srv_shutdown(void)
nuclear@2 74 {
nuclear@2 75 int i, sz = dynarr_size(csock);
nuclear@2 76 for(i=0; i<sz; i++) {
nuclear@2 77 close(csock[i]);
nuclear@2 78 }
nuclear@2 79 dynarr_free(csock);
nuclear@2 80 csock = 0;
nuclear@2 81 lis_sock = -1;
nuclear@2 82 max_socket = -1;
nuclear@2 83 }
nuclear@2 84
nuclear@2 85 int srv_num_sockets(void)
nuclear@2 86 {
nuclear@2 87 return dynarr_size(csock);
nuclear@2 88 }
nuclear@2 89
nuclear@2 90 int *srv_sockets(void)
nuclear@2 91 {
nuclear@2 92 return csock;
nuclear@2 93 }
nuclear@2 94
nuclear@2 95 int srv_max_socket(void)
nuclear@2 96 {
nuclear@2 97 return max_socket;
nuclear@2 98 }
nuclear@2 99
nuclear@6 100 static int handle_new_client(void)
nuclear@6 101 {
nuclear@6 102 int s;
nuclear@6 103 /* incoming connection */
nuclear@6 104 struct sockaddr_in addr;
nuclear@6 105 socklen_t addr_size = sizeof addr;
nuclear@6 106 if((s = accept(lis_sock, (struct sockaddr*)&addr, &addr_size)) == -1) {
nuclear@6 107 fprintf(stderr, "%s: failed to accept incoming connection: %s\n", __func__, strerror(errno));
nuclear@6 108 return -1;
nuclear@6 109 }
nuclear@6 110 printf("%s: incoming connection from %s:%d\n", __func__,
nuclear@6 111 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
nuclear@6 112 csock = dynarr_push(csock, &s);
nuclear@6 113 assert(csock);
nuclear@6 114 if(s > max_socket) {
nuclear@6 115 max_socket = s;
nuclear@6 116 }
nuclear@6 117 fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
nuclear@6 118 return 0;
nuclear@6 119 }
nuclear@6 120
nuclear@6 121 static int handle_client(int s)
nuclear@2 122 {
nuclear@2 123 static char buf[1024];
nuclear@2 124 int sz;
nuclear@2 125
nuclear@2 126 /* handle client */
nuclear@2 127 while((sz = read(s, buf, sizeof buf - 1)) > 0) {
nuclear@2 128 printf("%s: got data: %s\n", __func__, buf);
nuclear@2 129 }
nuclear@4 130 if(sz <= 0 && errno != EAGAIN) {
nuclear@2 131 /* client closed connection probably */
nuclear@2 132 int i, num_clients = dynarr_size(csock);
nuclear@2 133 printf("%s: removing client\n", __func__);
nuclear@2 134 close(s);
nuclear@4 135 max_socket = lis_sock;
nuclear@2 136 for(i=0; i<num_clients; i++) {
nuclear@2 137 if(csock[i] == s) {
nuclear@2 138 csock[i] = csock[num_clients - 1];
nuclear@4 139 }
nuclear@4 140 if(csock[i] > max_socket) {
nuclear@4 141 max_socket = csock[i];
nuclear@2 142 }
nuclear@2 143 }
nuclear@4 144
nuclear@4 145 csock = dynarr_pop(csock);
nuclear@4 146 --num_clients;
nuclear@2 147 }
nuclear@2 148 return 0;
nuclear@2 149 }
nuclear@2 150
nuclear@6 151 int srv_handle(int s)
nuclear@6 152 {
nuclear@6 153 if(s == lis_sock) {
nuclear@6 154 return handle_new_client();
nuclear@6 155 }
nuclear@6 156
nuclear@6 157 return handle_client(s);
nuclear@6 158 }
nuclear@6 159
nuclear@4 160 struct video_block {
nuclear@5 161 unsigned int magic;
nuclear@4 162 int frame;
nuclear@4 163 int x, y;
nuclear@4 164 int width, height;
nuclear@5 165 int frame_width, frame_height;
nuclear@4 166 char pixels[1];
nuclear@4 167 };
nuclear@4 168 #define VBLOCK_HEADER_SIZE (offsetof(struct video_block, pixels))
nuclear@4 169
nuclear@2 170 void srv_send_frame(unsigned char *frame, int xsz, int ysz)
nuclear@2 171 {
nuclear@5 172 static int frame_num;
nuclear@4 173 static unsigned char *buffer;
nuclear@5 174 int i, j, size, num_clients;
nuclear@4 175 struct video_block *vblock;
nuclear@5 176 uint16_t *dest;
nuclear@5 177
nuclear@5 178 printf("sending frame\n");
nuclear@4 179
nuclear@4 180 /* for now just send a big block */
nuclear@5 181 size = xsz * ysz * 2 + VBLOCK_HEADER_SIZE;
nuclear@5 182 if(!buffer && !(buffer = malloc(size))) {
nuclear@4 183 fprintf(stderr, "failed to allocate frame send buffer\n");
nuclear@4 184 return;
nuclear@4 185 }
nuclear@5 186 vblock = (struct video_block*)buffer;
nuclear@5 187
nuclear@5 188 vblock->magic = 0x12341234;
nuclear@5 189 vblock->frame = frame_num++;
nuclear@5 190 vblock->x = vblock->y = 0;
nuclear@5 191 vblock->width = vblock->frame_width = xsz;
nuclear@5 192 vblock->height = vblock->frame_height = ysz;
nuclear@5 193
nuclear@5 194 dest = (uint16_t*)vblock->pixels;
nuclear@5 195
nuclear@5 196 for(i=0; i<ysz; i++) {
nuclear@5 197 for(j=0; j<xsz; j++) {
nuclear@5 198 unsigned int r = frame[0];
nuclear@5 199 unsigned int g = frame[1];
nuclear@5 200 unsigned int b = frame[2];
nuclear@5 201
nuclear@5 202 *dest++ = ((r << 8) & 0xf800) | ((g << 3) & 0x7e0) | ((b >> 3) & 0x1f);
nuclear@5 203 frame += 4;
nuclear@5 204 }
nuclear@5 205 }
nuclear@5 206
nuclear@5 207 num_clients = dynarr_size(csock);
nuclear@5 208 for(i=1; i<num_clients; i++) { /* first socket is the listening socket */
nuclear@5 209 write(csock[i], buffer, size);
nuclear@5 210 }
nuclear@2 211 }