nuclear@2: #include nuclear@2: #include nuclear@2: #include nuclear@5: #include nuclear@5: #include nuclear@2: #include nuclear@2: #include nuclear@2: #include nuclear@2: #include nuclear@2: #include nuclear@2: #include nuclear@2: #include "srv.h" nuclear@2: #include "dynarr.h" nuclear@2: nuclear@4: /* TODO convert this whole thing to multicast */ nuclear@4: nuclear@6: static int bsock = -1; nuclear@6: static struct sockaddr_in baddr; nuclear@2: static int lis_sock = -1, max_socket = -1; nuclear@2: static int *csock; nuclear@2: nuclear@2: int srv_init(int port) nuclear@2: { nuclear@6: int val; nuclear@2: struct sockaddr_in addr; nuclear@2: nuclear@2: if(lis_sock != -1) { nuclear@2: fprintf(stderr, "%s: already running\n", __func__); nuclear@2: return -1; nuclear@2: } nuclear@2: nuclear@2: if((lis_sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) { nuclear@2: fprintf(stderr, "%s: failed to create listening socket\n", __func__); nuclear@2: return -1; nuclear@2: } nuclear@2: if(!(csock = dynarr_alloc(1, sizeof *csock))) { nuclear@2: fprintf(stderr, "%s: failed to allocate client socket array\n", __func__); nuclear@2: return -1; nuclear@2: } nuclear@2: csock[0] = lis_sock; nuclear@2: max_socket = lis_sock; nuclear@2: nuclear@5: fcntl(lis_sock, F_SETFL, fcntl(lis_sock, F_GETFL) | O_NONBLOCK); nuclear@2: nuclear@2: memset(&addr, 0, sizeof addr); nuclear@2: addr.sin_family = AF_INET; nuclear@2: addr.sin_port = htons(port); nuclear@2: addr.sin_addr.s_addr = INADDR_ANY; nuclear@2: if(bind(lis_sock, (struct sockaddr*)&addr, sizeof addr) == -1) { nuclear@2: fprintf(stderr, "%s: failed to bind port %d\n", __func__, port); nuclear@2: close(lis_sock); nuclear@2: lis_sock = -1; nuclear@2: return -1; nuclear@2: } nuclear@4: listen(lis_sock, 8); nuclear@2: nuclear@6: /* then create the video broadcast socket */ nuclear@6: if((bsock = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { nuclear@6: fprintf(stderr, "%s: failed to create video broadcast socket\n", __func__); nuclear@6: return -1; nuclear@6: } nuclear@7: /*fcntl(bsock, F_SETFL, fcntl(bsock, F_GETFL) | O_NONBLOCK);*/ nuclear@6: val = 1; nuclear@6: setsockopt(bsock, SOL_SOCKET, SO_BROADCAST, &val, sizeof val); nuclear@6: nuclear@7: /* prepare the broadcast address struct */ nuclear@6: memset(&baddr, 0, sizeof baddr); nuclear@6: baddr.sin_family = AF_INET; nuclear@6: baddr.sin_port = htons(port + 1); nuclear@6: baddr.sin_addr.s_addr = 0xffffffff; nuclear@6: nuclear@2: return 0; nuclear@2: } nuclear@2: nuclear@2: void srv_shutdown(void) nuclear@2: { nuclear@2: int i, sz = dynarr_size(csock); nuclear@2: for(i=0; i max_socket) { nuclear@6: max_socket = s; nuclear@6: } nuclear@6: fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK); nuclear@6: return 0; nuclear@6: } nuclear@6: nuclear@6: static int handle_client(int s) nuclear@2: { nuclear@2: static char buf[1024]; nuclear@2: int sz; nuclear@2: nuclear@2: /* handle client */ nuclear@2: while((sz = read(s, buf, sizeof buf - 1)) > 0) { nuclear@2: printf("%s: got data: %s\n", __func__, buf); nuclear@2: } nuclear@7: if((sz < 0 && errno != EAGAIN) || sz == 0) { nuclear@2: /* client closed connection probably */ nuclear@2: int i, num_clients = dynarr_size(csock); nuclear@2: printf("%s: removing client\n", __func__); nuclear@2: close(s); nuclear@4: max_socket = lis_sock; nuclear@2: for(i=0; i max_socket) { nuclear@4: max_socket = csock[i]; nuclear@2: } nuclear@2: } nuclear@4: nuclear@4: csock = dynarr_pop(csock); nuclear@4: --num_clients; nuclear@2: } nuclear@2: return 0; nuclear@2: } nuclear@2: nuclear@6: int srv_handle(int s) nuclear@6: { nuclear@6: if(s == lis_sock) { nuclear@6: return handle_new_client(); nuclear@6: } nuclear@6: nuclear@6: return handle_client(s); nuclear@6: } nuclear@6: nuclear@4: struct video_block { nuclear@4: int frame; nuclear@7: uint16_t x, y; nuclear@7: uint16_t width, height; nuclear@7: uint16_t frame_width, frame_height; nuclear@7: uint16_t pixels[1]; nuclear@4: }; nuclear@4: #define VBLOCK_HEADER_SIZE (offsetof(struct video_block, pixels)) nuclear@4: nuclear@7: /* ideally we would want each block to stay under the MTU (1500) */ nuclear@7: #define BLKSZ 24 nuclear@7: nuclear@7: int srv_send_frame(unsigned char *frame, int xsz, int ysz) nuclear@2: { nuclear@5: static int frame_num; nuclear@7: int i, j; nuclear@4: struct video_block *vblock; nuclear@7: int blksz; nuclear@5: nuclear@7: printf("sending frame: %d\n", frame_num); nuclear@4: nuclear@7: blksz = BLKSZ * BLKSZ * 2 + VBLOCK_HEADER_SIZE; nuclear@7: if(!(vblock = malloc(blksz))) { nuclear@7: fprintf(stderr, "failed to allocate %dx%d block buffer\n", BLKSZ, BLKSZ); nuclear@7: return -1; nuclear@4: } nuclear@5: nuclear@5: vblock->frame = frame_num++; nuclear@5: vblock->x = vblock->y = 0; nuclear@7: vblock->frame_width = xsz; nuclear@7: vblock->frame_height = ysz; nuclear@5: nuclear@7: vblock->y = 0; nuclear@7: while(vblock->y < ysz) { nuclear@7: if(vblock->y + BLKSZ <= ysz) { nuclear@7: vblock->height = BLKSZ; nuclear@7: } else { nuclear@7: vblock->height = ysz - vblock->y; nuclear@7: } nuclear@5: nuclear@7: vblock->x = 0; nuclear@7: while(vblock->x < xsz) { nuclear@7: if(vblock->x + BLKSZ <= xsz) { nuclear@7: vblock->width = BLKSZ; nuclear@7: } else { nuclear@7: vblock->width = xsz - vblock->x; nuclear@7: } nuclear@5: nuclear@7: unsigned char *src = frame + (vblock->y * xsz + vblock->x) * 4; nuclear@7: uint16_t *dest = vblock->pixels; nuclear@7: nuclear@7: /* convert block to 565 */ nuclear@7: for(i=0; iheight; i++) { nuclear@7: for(j=0; jwidth; j++) { nuclear@7: unsigned int r = src[0]; nuclear@7: unsigned int g = src[1]; nuclear@7: unsigned int b = src[2]; nuclear@7: nuclear@7: *dest++ = ((r << 8) & 0xf800) | ((g << 3) & 0x7e0) | ((b >> 3) & 0x1f); nuclear@7: src += 4; nuclear@7: } nuclear@7: src += (xsz - vblock->width) * 4; nuclear@7: } nuclear@7: nuclear@7: /* and broadcast it */ nuclear@7: printf("f(%d) b(%d,%d)\n", frame_num - 1, vblock->x, vblock->y); nuclear@7: if(sendto(bsock, vblock, blksz, 0, (struct sockaddr*)&baddr, sizeof baddr) == -1) { nuclear@7: perror("failed to send block"); nuclear@7: if(errno == EMSGSIZE) { nuclear@7: abort(); nuclear@7: } nuclear@7: return -1; nuclear@7: } nuclear@7: nuclear@7: vblock->x += BLKSZ; nuclear@5: } nuclear@7: vblock->y += BLKSZ; nuclear@5: } nuclear@5: nuclear@7: free(vblock); nuclear@7: return 0; nuclear@2: }