doorbell

annotate doorbelld/src/srv.c @ 5:f21ae31ef0e7

craptacular
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 15 Mar 2016 08:35:21 +0200
parents 08ea0abdbb8a
children 026156ea8801
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@2 17 static int lis_sock = -1, max_socket = -1;
nuclear@2 18 static int *csock;
nuclear@2 19
nuclear@2 20 int srv_init(int port)
nuclear@2 21 {
nuclear@2 22 struct sockaddr_in addr;
nuclear@2 23
nuclear@2 24 if(lis_sock != -1) {
nuclear@2 25 fprintf(stderr, "%s: already running\n", __func__);
nuclear@2 26 return -1;
nuclear@2 27 }
nuclear@2 28
nuclear@2 29 if((lis_sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
nuclear@2 30 fprintf(stderr, "%s: failed to create listening socket\n", __func__);
nuclear@2 31 return -1;
nuclear@2 32 }
nuclear@2 33 if(!(csock = dynarr_alloc(1, sizeof *csock))) {
nuclear@2 34 fprintf(stderr, "%s: failed to allocate client socket array\n", __func__);
nuclear@2 35 return -1;
nuclear@2 36 }
nuclear@2 37 csock[0] = lis_sock;
nuclear@2 38 max_socket = lis_sock;
nuclear@2 39
nuclear@5 40 fcntl(lis_sock, F_SETFL, fcntl(lis_sock, F_GETFL) | O_NONBLOCK);
nuclear@2 41
nuclear@2 42 memset(&addr, 0, sizeof addr);
nuclear@2 43 addr.sin_family = AF_INET;
nuclear@2 44 addr.sin_port = htons(port);
nuclear@2 45 addr.sin_addr.s_addr = INADDR_ANY;
nuclear@2 46 if(bind(lis_sock, (struct sockaddr*)&addr, sizeof addr) == -1) {
nuclear@2 47 fprintf(stderr, "%s: failed to bind port %d\n", __func__, port);
nuclear@2 48 close(lis_sock);
nuclear@2 49 lis_sock = -1;
nuclear@2 50 return -1;
nuclear@2 51 }
nuclear@4 52 listen(lis_sock, 8);
nuclear@2 53
nuclear@2 54 return 0;
nuclear@2 55 }
nuclear@2 56
nuclear@2 57 void srv_shutdown(void)
nuclear@2 58 {
nuclear@2 59 int i, sz = dynarr_size(csock);
nuclear@2 60 for(i=0; i<sz; i++) {
nuclear@2 61 close(csock[i]);
nuclear@2 62 }
nuclear@2 63 dynarr_free(csock);
nuclear@2 64 csock = 0;
nuclear@2 65 lis_sock = -1;
nuclear@2 66 max_socket = -1;
nuclear@2 67 }
nuclear@2 68
nuclear@2 69 int srv_num_sockets(void)
nuclear@2 70 {
nuclear@2 71 return dynarr_size(csock);
nuclear@2 72 }
nuclear@2 73
nuclear@2 74 int *srv_sockets(void)
nuclear@2 75 {
nuclear@2 76 return csock;
nuclear@2 77 }
nuclear@2 78
nuclear@2 79 int srv_max_socket(void)
nuclear@2 80 {
nuclear@2 81 return max_socket;
nuclear@2 82 }
nuclear@2 83
nuclear@2 84 int srv_handle(int s)
nuclear@2 85 {
nuclear@2 86 static char buf[1024];
nuclear@2 87 int sz;
nuclear@2 88
nuclear@2 89 if(s == lis_sock) {
nuclear@2 90 /* incoming connection */
nuclear@2 91 struct sockaddr_in addr;
nuclear@4 92 socklen_t addr_size = sizeof addr;
nuclear@4 93 if((s = accept(lis_sock, (struct sockaddr*)&addr, &addr_size)) == -1) {
nuclear@4 94 fprintf(stderr, "%s: failed to accept incoming connection: %s\n", __func__, strerror(errno));
nuclear@2 95 return -1;
nuclear@2 96 }
nuclear@2 97 printf("%s: incoming connection from %s:%d\n", __func__,
nuclear@2 98 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
nuclear@2 99 csock = dynarr_push(csock, &s);
nuclear@2 100 assert(csock);
nuclear@4 101 if(s > max_socket) {
nuclear@4 102 max_socket = s;
nuclear@4 103 }
nuclear@5 104 fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
nuclear@2 105 return 0;
nuclear@2 106 }
nuclear@2 107
nuclear@2 108 /* handle client */
nuclear@2 109 while((sz = read(s, buf, sizeof buf - 1)) > 0) {
nuclear@2 110 printf("%s: got data: %s\n", __func__, buf);
nuclear@2 111 }
nuclear@4 112 if(sz <= 0 && errno != EAGAIN) {
nuclear@2 113 /* client closed connection probably */
nuclear@2 114 int i, num_clients = dynarr_size(csock);
nuclear@2 115 printf("%s: removing client\n", __func__);
nuclear@2 116 close(s);
nuclear@4 117 max_socket = lis_sock;
nuclear@2 118 for(i=0; i<num_clients; i++) {
nuclear@2 119 if(csock[i] == s) {
nuclear@2 120 csock[i] = csock[num_clients - 1];
nuclear@4 121 }
nuclear@4 122 if(csock[i] > max_socket) {
nuclear@4 123 max_socket = csock[i];
nuclear@2 124 }
nuclear@2 125 }
nuclear@4 126
nuclear@4 127 csock = dynarr_pop(csock);
nuclear@4 128 --num_clients;
nuclear@2 129 }
nuclear@2 130 return 0;
nuclear@2 131 }
nuclear@2 132
nuclear@4 133 struct video_block {
nuclear@5 134 unsigned int magic;
nuclear@4 135 int frame;
nuclear@4 136 int x, y;
nuclear@4 137 int width, height;
nuclear@5 138 int frame_width, frame_height;
nuclear@4 139 char pixels[1];
nuclear@4 140 };
nuclear@4 141 #define VBLOCK_HEADER_SIZE (offsetof(struct video_block, pixels))
nuclear@4 142
nuclear@2 143 void srv_send_frame(unsigned char *frame, int xsz, int ysz)
nuclear@2 144 {
nuclear@5 145 static int frame_num;
nuclear@4 146 static unsigned char *buffer;
nuclear@5 147 int i, j, size, num_clients;
nuclear@4 148 struct video_block *vblock;
nuclear@5 149 uint16_t *dest;
nuclear@5 150
nuclear@5 151 printf("sending frame\n");
nuclear@4 152
nuclear@4 153 /* for now just send a big block */
nuclear@5 154 size = xsz * ysz * 2 + VBLOCK_HEADER_SIZE;
nuclear@5 155 if(!buffer && !(buffer = malloc(size))) {
nuclear@4 156 fprintf(stderr, "failed to allocate frame send buffer\n");
nuclear@4 157 return;
nuclear@4 158 }
nuclear@5 159 vblock = (struct video_block*)buffer;
nuclear@5 160
nuclear@5 161 vblock->magic = 0x12341234;
nuclear@5 162 vblock->frame = frame_num++;
nuclear@5 163 vblock->x = vblock->y = 0;
nuclear@5 164 vblock->width = vblock->frame_width = xsz;
nuclear@5 165 vblock->height = vblock->frame_height = ysz;
nuclear@5 166
nuclear@5 167 dest = (uint16_t*)vblock->pixels;
nuclear@5 168
nuclear@5 169 for(i=0; i<ysz; i++) {
nuclear@5 170 for(j=0; j<xsz; j++) {
nuclear@5 171 unsigned int r = frame[0];
nuclear@5 172 unsigned int g = frame[1];
nuclear@5 173 unsigned int b = frame[2];
nuclear@5 174
nuclear@5 175 *dest++ = ((r << 8) & 0xf800) | ((g << 3) & 0x7e0) | ((b >> 3) & 0x1f);
nuclear@5 176 frame += 4;
nuclear@5 177 }
nuclear@5 178 }
nuclear@5 179
nuclear@5 180 num_clients = dynarr_size(csock);
nuclear@5 181 for(i=1; i<num_clients; i++) { /* first socket is the listening socket */
nuclear@5 182 write(csock[i], buffer, size);
nuclear@5 183 }
nuclear@2 184 }