1 /*
2 Terminal Mixer - multi-point multi-user access to terminal applications
3 Copyright (C) 2007 Lluís Batlle i Rossell
4
5 Please find the license in the provided COPYING file.
6 */
7 #include <stdlib.h>
8 #include <assert.h>
9 #include <unistd.h>
10 #include <stdio.h>
11 #include <netinet/in.h>
12 #include <string.h>
13 #include <sys/socket.h>
14 #include <sys/select.h>
15
16 #include "main.h"
17 #include "handlers.h"
18
19 static int served_sockets = 0;
20
21 static int listen_socket = -1; /* not listening */
22 static int connected_sockets = 0;
23 static int *conn_sockets = 0;
24
start_listening(int new)25 static void start_listening(int new)
26 {
27 int ls;
28 struct sockaddr_in addr;
29 int res;
30
31 assert(new > 0);
32
33 ls = socket(AF_INET, SOCK_STREAM, 0);
34 if (ls == -1)
35 error("Cannot create the tcp listen socket in the server");
36
37 {
38 int on = 1;
39 res = setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
40 if (res == -1)
41 error("Cannot set SO_REUSEADDR");
42 }
43
44 addr.sin_family = AF_INET;
45 addr.sin_port = htons(command_line.tcp_port);
46 addr.sin_addr.s_addr = htonl(INADDR_ANY);
47
48 res = bind(ls, (struct sockaddr *) & addr, sizeof(addr));
49 if (res == -1)
50 error("Error binding tcp to port %i", command_line.tcp_port);
51
52 /* NUANCE: 0 backlog. Why should we assure future connections? */
53 res = listen(ls, 0);
54 if (res == -1)
55 error("Error listening on the binded tcp socket");
56
57 listen_socket = ls;
58 }
59
s_tcp_update_served(int new)60 void s_tcp_update_served(int new)
61 {
62 if (new > served_sockets && new > 0 )
63 {
64 conn_sockets = realloc(conn_sockets, sizeof(*conn_sockets) * new);
65 if (listen_socket == -1) /* not listening */
66 {
67 start_listening(new);
68 }
69 served_sockets = new;
70 }
71 else if (new < served_sockets)
72 {
73 not_implemented("new < served_sockets at s_tcp_update_served");
74 }
75 }
76
s_tcp_shutdown()77 void s_tcp_shutdown()
78 {
79 int i;
80
81 if (listen_socket != -1)
82 {
83 close(listen_socket);
84 }
85
86 for (i=0; i < connected_sockets; ++i)
87 {
88 close(conn_sockets[i]);
89 }
90 connected_sockets = 0;
91 served_sockets = 0;
92 }
93
s_tcp_prepare_read_fdset(fd_set * read_set,int * maxfd)94 void s_tcp_prepare_read_fdset(fd_set *read_set, int *maxfd)
95 {
96 int i;
97
98 FD_SET(listen_socket, read_set);
99 *maxfd = max(*maxfd, listen_socket);
100
101 for (i=0; i < connected_sockets; ++i)
102 {
103 /* We only accept if we don't have any
104 * connetion opened. */
105 FD_SET(conn_sockets[i], read_set);
106 *maxfd = max(*maxfd, conn_sockets[i]);
107 }
108 }
109
remove_conn_socket(int n)110 static void remove_conn_socket(int n)
111 {
112 int i;
113
114 assert(n >= 0);
115
116 for(i=n+1; i<connected_sockets; ++i)
117 {
118 conn_sockets[i-1] = conn_sockets[i];
119 }
120
121 connected_sockets -= 1;
122
123 /* We shrink the memory until we have an array for served_sockets */
124 if (served_sockets <= connected_sockets)
125 {
126 conn_sockets = realloc(conn_sockets, sizeof(*conn_sockets)
127 * connected_sockets);
128 }
129 }
130
accept_connection(int ls)131 static int accept_connection(int ls)
132 {
133 int cs;
134 cs = accept(ls, 0, 0);
135 if (cs == -1)
136 not_implemented("accept tcp socket error check");
137
138 /* TODO: Prepare unblocking sockets if needed */
139
140 return cs;
141 }
142
s_tcp_process_read_fdset(fd_set * read_set)143 void s_tcp_process_read_fdset(fd_set *read_set)
144 {
145 int i;
146 /* Active streams */
147 for (i=0; i < connected_sockets; ++i)
148 {
149 if (FD_ISSET(conn_sockets[i], read_set))
150 {
151 int res;
152 res = read(conn_sockets[i], stream_buffer,
153 stream_buffer_size);
154 if (res == 0)
155 {
156 close(conn_sockets[i]);
157 remove_conn_socket(i);
158 } else
159 {
160 app_control_remote_send_to_stdin(stream_buffer, res);
161 }
162 }
163 }
164
165 /* Listen connection */
166 if (FD_ISSET(listen_socket, read_set))
167 {
168 if (served_sockets > connected_sockets)
169 {
170 int s;
171 s = accept_connection(listen_socket);
172 conn_sockets[connected_sockets++] = s;
173 welcome_new_client_socket(s);
174 } else
175 {
176 int s;
177 s = accept_connection(listen_socket);
178 close(s);
179 }
180 }
181 }
182
s_tcp_send_to_connected(const char * buffer,size_t size)183 void s_tcp_send_to_connected(const char *buffer, size_t size)
184 {
185 int i;
186
187 for (i=0; i < connected_sockets; ++i)
188 {
189 write(conn_sockets[i], buffer, size);
190 }
191 }
192