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 <sys/un.h>
12 #include <sys/socket.h>
13 #include <sys/select.h>
14
15 #include "main.h"
16 #include "handlers.h"
17
18 static int served_sockets = 0;
19
20 static int listen_socket = -1; /* not listening */
21 static int connected_sockets = 0;
22 static int *conn_sockets = 0;
23
24 static char *socket_path = 0;
25
26 static char default_path_prefix[] = "/tmp/tm-socket.";
27
get_unix_path()28 void get_unix_path()
29 {
30 char *new;
31
32 new = getenv("TM_SOCKET");
33 if (new == 0) /* Compose the path from the default values */
34 {
35 char num[20]; /* enough for an int */
36 int len;
37
38 sprintf(num, "%i", (int) getuid());
39
40 len = strlen(default_path_prefix) + strlen(num) + 1;
41
42 command_line.unix_path = malloc(len);
43
44 sprintf(command_line.unix_path, "%s%s",
45 default_path_prefix, num);
46 } else
47 {
48 command_line.unix_path = malloc(strlen(new) + 1);
49 strcpy(command_line.unix_path, new);
50 }
51 }
52
53
start_listening(int new)54 static void start_listening(int new)
55 {
56 int ls;
57 struct sockaddr_un addr;
58 int res;
59
60 assert(new > 0);
61 assert(command_line.unix_path != 0);
62
63 socket_path = command_line.unix_path;
64
65 ls = socket(AF_UNIX, SOCK_STREAM, 0);
66 if (ls == -1)
67 error("Cannot create the unix listen socket in the server");
68
69 addr.sun_family = AF_UNIX;
70 strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
71
72 res = bind(ls, (struct sockaddr *) & addr, sizeof(addr));
73 if (res == -1)
74 error("Error binding to %s", socket_path);
75
76 /* NUANCE: 0 backlog. Why should we assure future connections? */
77 res = listen(ls, 0);
78 if (res == -1)
79 error("Error listening on the binded unix socket");
80
81 listen_socket = ls;
82 }
83
s_unix_update_served(int new)84 void s_unix_update_served(int new)
85 {
86 if (new > served_sockets && new > 0 )
87 {
88 conn_sockets = realloc(conn_sockets, sizeof(*conn_sockets) * new);
89 if (listen_socket == -1) /* not listening */
90 {
91 start_listening(new);
92 }
93 served_sockets = new;
94 }
95 else if (new < served_sockets)
96 {
97 not_implemented("new < served_sockets at unix_update_served");
98 }
99 }
100
s_unix_shutdown()101 void s_unix_shutdown()
102 {
103 int i;
104
105 if (listen_socket != -1)
106 {
107 close(listen_socket);
108 unlink(socket_path);
109 }
110
111 for (i=0; i < connected_sockets; ++i)
112 {
113 close(conn_sockets[i]);
114 }
115 connected_sockets = 0;
116 served_sockets = 0;
117 }
118
s_unix_prepare_read_fdset(fd_set * read_set,int * maxfd)119 void s_unix_prepare_read_fdset(fd_set *read_set, int *maxfd)
120 {
121 int i;
122
123 FD_SET(listen_socket, read_set);
124 *maxfd = max(*maxfd, listen_socket);
125
126 for (i=0; i < connected_sockets; ++i)
127 {
128 /* We only accept if we don't have any
129 * connetion opened. */
130 FD_SET(conn_sockets[i], read_set);
131 *maxfd = max(*maxfd, conn_sockets[i]);
132 }
133 }
134
remove_conn_socket(int n)135 static void remove_conn_socket(int n)
136 {
137 int i;
138
139 assert(n >= 0);
140
141 for(i=n+1; i<connected_sockets; ++i)
142 {
143 conn_sockets[i-1] = conn_sockets[i];
144 }
145
146 connected_sockets -= 1;
147
148 /* We shrink the memory until we have an array for served_sockets */
149 if (served_sockets <= connected_sockets)
150 {
151 conn_sockets = realloc(conn_sockets, sizeof(*conn_sockets)
152 * connected_sockets);
153 }
154 }
155
accept_connection(int ls)156 static int accept_connection(int ls)
157 {
158 int cs;
159 cs = accept(ls, 0, 0);
160 if (cs == -1)
161 not_implemented("accept unix socket error check");
162
163 /* TODO: Prepare unblocking sockets if needed */
164
165 return cs;
166 }
167
s_unix_process_read_fdset(fd_set * read_set)168 void s_unix_process_read_fdset(fd_set *read_set)
169 {
170 int i;
171 /* Active streams */
172 for (i=0; i < connected_sockets; ++i)
173 {
174 if (FD_ISSET(conn_sockets[i], read_set))
175 {
176 int res;
177 res = read(conn_sockets[i], stream_buffer,
178 stream_buffer_size);
179 if (res == 0)
180 {
181 close(conn_sockets[i]);
182 remove_conn_socket(i);
183 } else
184 {
185 app_control_remote_send_to_stdin(stream_buffer, res);
186 }
187 }
188 }
189
190 /* Listen connection */
191 if (FD_ISSET(listen_socket, read_set))
192 {
193 if (served_sockets > connected_sockets)
194 {
195 int s;
196 s = accept_connection(listen_socket);
197 conn_sockets[connected_sockets++] = s;
198 welcome_new_client_socket(s);
199 } else
200 {
201 int s;
202 s = accept_connection(listen_socket);
203 close(s);
204 }
205 }
206 }
207
s_unix_send_to_connected(const char * buffer,size_t size)208 void s_unix_send_to_connected(const char *buffer, size_t size)
209 {
210 int i;
211
212 for (i=0; i < connected_sockets; ++i)
213 {
214 write(conn_sockets[i], buffer, size);
215 }
216 }
217