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