rev |
line source |
nuclear@2
|
1 #include <stdio.h>
|
nuclear@2
|
2 #include <stdlib.h>
|
nuclear@2
|
3 #include <string.h>
|
nuclear@2
|
4 #include <errno.h>
|
nuclear@2
|
5 #include <assert.h>
|
nuclear@2
|
6 #include <unistd.h>
|
nuclear@2
|
7 #include <fcntl.h>
|
nuclear@2
|
8 #include <sys/socket.h>
|
nuclear@2
|
9 #include <arpa/inet.h>
|
nuclear@2
|
10 #include "srv.h"
|
nuclear@2
|
11 #include "dynarr.h"
|
nuclear@2
|
12
|
nuclear@4
|
13 /* TODO convert this whole thing to multicast */
|
nuclear@4
|
14
|
nuclear@2
|
15 static int lis_sock = -1, max_socket = -1;
|
nuclear@2
|
16 static int *csock;
|
nuclear@2
|
17
|
nuclear@2
|
18 int srv_init(int port)
|
nuclear@2
|
19 {
|
nuclear@2
|
20 struct sockaddr_in addr;
|
nuclear@2
|
21
|
nuclear@2
|
22 if(lis_sock != -1) {
|
nuclear@2
|
23 fprintf(stderr, "%s: already running\n", __func__);
|
nuclear@2
|
24 return -1;
|
nuclear@2
|
25 }
|
nuclear@2
|
26
|
nuclear@2
|
27 if((lis_sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
|
nuclear@2
|
28 fprintf(stderr, "%s: failed to create listening socket\n", __func__);
|
nuclear@2
|
29 return -1;
|
nuclear@2
|
30 }
|
nuclear@2
|
31 if(!(csock = dynarr_alloc(1, sizeof *csock))) {
|
nuclear@2
|
32 fprintf(stderr, "%s: failed to allocate client socket array\n", __func__);
|
nuclear@2
|
33 return -1;
|
nuclear@2
|
34 }
|
nuclear@2
|
35 csock[0] = lis_sock;
|
nuclear@2
|
36 max_socket = lis_sock;
|
nuclear@2
|
37
|
nuclear@2
|
38 fcntl(lis_sock, F_SETFD, fcntl(lis_sock, F_GETFD) | O_NONBLOCK);
|
nuclear@2
|
39
|
nuclear@2
|
40 memset(&addr, 0, sizeof addr);
|
nuclear@2
|
41 addr.sin_family = AF_INET;
|
nuclear@2
|
42 addr.sin_port = htons(port);
|
nuclear@2
|
43 addr.sin_addr.s_addr = INADDR_ANY;
|
nuclear@2
|
44 if(bind(lis_sock, (struct sockaddr*)&addr, sizeof addr) == -1) {
|
nuclear@2
|
45 fprintf(stderr, "%s: failed to bind port %d\n", __func__, port);
|
nuclear@2
|
46 close(lis_sock);
|
nuclear@2
|
47 lis_sock = -1;
|
nuclear@2
|
48 return -1;
|
nuclear@2
|
49 }
|
nuclear@4
|
50 listen(lis_sock, 8);
|
nuclear@2
|
51
|
nuclear@2
|
52 return 0;
|
nuclear@2
|
53 }
|
nuclear@2
|
54
|
nuclear@2
|
55 void srv_shutdown(void)
|
nuclear@2
|
56 {
|
nuclear@2
|
57 int i, sz = dynarr_size(csock);
|
nuclear@2
|
58 for(i=0; i<sz; i++) {
|
nuclear@2
|
59 close(csock[i]);
|
nuclear@2
|
60 }
|
nuclear@2
|
61 dynarr_free(csock);
|
nuclear@2
|
62 csock = 0;
|
nuclear@2
|
63 lis_sock = -1;
|
nuclear@2
|
64 max_socket = -1;
|
nuclear@2
|
65 }
|
nuclear@2
|
66
|
nuclear@2
|
67 int srv_num_sockets(void)
|
nuclear@2
|
68 {
|
nuclear@2
|
69 return dynarr_size(csock);
|
nuclear@2
|
70 }
|
nuclear@2
|
71
|
nuclear@2
|
72 int *srv_sockets(void)
|
nuclear@2
|
73 {
|
nuclear@2
|
74 return csock;
|
nuclear@2
|
75 }
|
nuclear@2
|
76
|
nuclear@2
|
77 int srv_max_socket(void)
|
nuclear@2
|
78 {
|
nuclear@2
|
79 return max_socket;
|
nuclear@2
|
80 }
|
nuclear@2
|
81
|
nuclear@2
|
82 int srv_handle(int s)
|
nuclear@2
|
83 {
|
nuclear@2
|
84 static char buf[1024];
|
nuclear@2
|
85 int sz;
|
nuclear@2
|
86
|
nuclear@2
|
87 if(s == lis_sock) {
|
nuclear@2
|
88 /* incoming connection */
|
nuclear@2
|
89 struct sockaddr_in addr;
|
nuclear@4
|
90 socklen_t addr_size = sizeof addr;
|
nuclear@4
|
91 if((s = accept(lis_sock, (struct sockaddr*)&addr, &addr_size)) == -1) {
|
nuclear@4
|
92 fprintf(stderr, "%s: failed to accept incoming connection: %s\n", __func__, strerror(errno));
|
nuclear@2
|
93 return -1;
|
nuclear@2
|
94 }
|
nuclear@2
|
95 printf("%s: incoming connection from %s:%d\n", __func__,
|
nuclear@2
|
96 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
|
nuclear@2
|
97 csock = dynarr_push(csock, &s);
|
nuclear@2
|
98 assert(csock);
|
nuclear@4
|
99 if(s > max_socket) {
|
nuclear@4
|
100 max_socket = s;
|
nuclear@4
|
101 }
|
nuclear@4
|
102 fcntl(s, F_SETFD, fcntl(s, F_GETFD) | O_NONBLOCK);
|
nuclear@2
|
103 return 0;
|
nuclear@2
|
104 }
|
nuclear@2
|
105
|
nuclear@2
|
106 /* handle client */
|
nuclear@2
|
107 while((sz = read(s, buf, sizeof buf - 1)) > 0) {
|
nuclear@2
|
108 printf("%s: got data: %s\n", __func__, buf);
|
nuclear@2
|
109 }
|
nuclear@4
|
110 if(sz <= 0 && errno != EAGAIN) {
|
nuclear@2
|
111 /* client closed connection probably */
|
nuclear@2
|
112 int i, num_clients = dynarr_size(csock);
|
nuclear@2
|
113 printf("%s: removing client\n", __func__);
|
nuclear@2
|
114 close(s);
|
nuclear@4
|
115 max_socket = lis_sock;
|
nuclear@2
|
116 for(i=0; i<num_clients; i++) {
|
nuclear@2
|
117 if(csock[i] == s) {
|
nuclear@2
|
118 csock[i] = csock[num_clients - 1];
|
nuclear@4
|
119 }
|
nuclear@4
|
120 if(csock[i] > max_socket) {
|
nuclear@4
|
121 max_socket = csock[i];
|
nuclear@2
|
122 }
|
nuclear@2
|
123 }
|
nuclear@4
|
124
|
nuclear@4
|
125 csock = dynarr_pop(csock);
|
nuclear@4
|
126 --num_clients;
|
nuclear@2
|
127 }
|
nuclear@2
|
128 return 0;
|
nuclear@2
|
129 }
|
nuclear@2
|
130
|
nuclear@4
|
131 struct video_block {
|
nuclear@4
|
132 int frame;
|
nuclear@4
|
133 int x, y;
|
nuclear@4
|
134 int width, height;
|
nuclear@4
|
135 char pixels[1];
|
nuclear@4
|
136 };
|
nuclear@4
|
137 #define VBLOCK_HEADER_SIZE (offsetof(struct video_block, pixels))
|
nuclear@4
|
138
|
nuclear@2
|
139 void srv_send_frame(unsigned char *frame, int xsz, int ysz)
|
nuclear@2
|
140 {
|
nuclear@4
|
141 static unsigned char *buffer;
|
nuclear@4
|
142 struct video_block *vblock;
|
nuclear@4
|
143
|
nuclear@4
|
144 /* for now just send a big block */
|
nuclear@4
|
145 if(!buffer && !(buffer = malloc(xsz * ysz * 2) + VBLOCK_HEADER_SIZE)) {
|
nuclear@4
|
146 fprintf(stderr, "failed to allocate frame send buffer\n");
|
nuclear@4
|
147 return;
|
nuclear@4
|
148 }
|
nuclear@4
|
149 vblock = buffer;
|
nuclear@2
|
150 }
|