1
2 /******************************************************************************
3 * MODULE : socket_server.cpp
4 * DESCRIPTION: TeXmacs servers over sockets
5 * COPYRIGHT : (C) 2007 Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
11 #ifndef QTTEXMACS
12 #include "socket_server.hpp"
13 #include "sys_utils.hpp"
14 #include "hashset.hpp"
15 #include "iterator.hpp"
16 #include <stdlib.h>
17 #include <string.h>
18 #ifndef __MINGW32__
19 #include <unistd.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <sys/wait.h>
24 #include <sys/time.h>
25 #include <sys/select.h>
26 #else
27 namespace wsoc {
28 #include <sys/types.h>
29 #include <ws2tcpip.h>
30 }
31
32 #endif
33
34 hashset<pointer> socket_server_set;
35 void socket_server_callback (void *obj, void *info);
36
37 /******************************************************************************
38 * Constructors and destructors for socket_servers
39 ******************************************************************************/
40
socket_server_rep(int port2)41 socket_server_rep::socket_server_rep (int port2):
42 port (port2), sn ()
43 {
44 socket_server_set->insert ((pointer) this);
45 server= -1;
46 alive = false;
47 }
48
~socket_server_rep()49 socket_server_rep::~socket_server_rep () {
50 stop ();
51 socket_server_set->remove ((pointer) this);
52 }
53
54 tm_link
make_socket_server(int port)55 make_socket_server (int port) {
56 return tm_new<socket_server_rep> (port);
57 }
58
59 int
number_of_servers()60 number_of_servers () {
61 return N (socket_server_set);
62 }
63
64 void
close_all_servers()65 close_all_servers () {
66 iterator<pointer> it= iterate (socket_server_set);
67 while (it->busy()) {
68 socket_server_rep* ss= (socket_server_rep*) it->next();
69 if (ss->alive) {
70 // FIXME: cleanly close the connection to the socket here
71 ss->alive= false;
72 }
73 }
74 }
75
76 /******************************************************************************
77 * Routines for socket_servers
78 ******************************************************************************/
79
80 string
start()81 socket_server_rep::start () {
82 // get the server
83
84 #ifdef __MINGW32__
85 using namespace wsoc;
86 {
87 WSAData data;
88 int ret;
89 ret=WSAStartup(MAKEWORD(2,0), &data);
90 if(ret) {
91 char buf[32];
92 string str="Error: WSAStartup failed code:";
93 str << itoa(ret,buf,10);
94 return(str);
95 }
96 }
97 #endif
98 if ((server = socket (PF_INET, SOCK_STREAM, 0)) == -1) {
99 string ret="Error: call to 'socket' failed";
100 #ifdef __MINGW32__
101 char buf[32];
102 ret <<" code:"<<itoa(WSAGetLastError(),buf,10);
103 #endif
104 return ret;
105 }
106
107 // lose the pesky "address already in use" error message
108 int yes= 1;
109 #ifndef __MINGW32__
110 if (setsockopt (server, SOL_SOCKET, SO_REUSEADDR,
111 &yes, sizeof (int)) == -1)
112 #else
113 if (setsockopt (server, SOL_SOCKET, SO_REUSEADDR,
114 (const char*) &yes, sizeof (int)) == -1)
115 #endif
116 return "Error: call to 'setsockopt' failed";
117
118 // bind
119 struct sockaddr_in local_address;
120 local_address.sin_family = AF_INET;
121 local_address.sin_addr.s_addr = INADDR_ANY;
122 local_address.sin_port = htons (6561);
123 memset (local_address.sin_zero, '\0', sizeof local_address.sin_zero);
124 if (bind (server, (struct sockaddr *) &local_address,
125 sizeof (local_address)) == -1)
126 return "Error: call to 'bind' failed";
127
128 // listen
129 #ifdef __MINGW32__
130 if (wsoc::listen (server, 10) == -1)
131 #else
132 if (::listen (server, 10) == -1)
133 #endif
134 return "Error: call to 'listen' failed";
135
136 alive= true;
137
138 sn = socket_notifier (server, &socket_server_callback, this, NULL);
139 add_notifier (sn);
140
141 return "ok";
142
143 }
144
145 void
start_client()146 socket_server_rep::start_client () {
147 #ifdef __MINGW32__
148 using namespace wsoc;
149 #endif
150 struct sockaddr_in remote_address;
151 socklen_t addrlen= sizeof (remote_address);
152 int client= accept (server, (struct sockaddr *) &remote_address, &addrlen);
153 if (client == -1) io_warning << "Call to 'accept' failed\n";
154 else {
155 string addr= inet_ntoa (remote_address.sin_addr);
156 debug_io << "Opened connection from '" << addr << "'\n";
157 array<tm_link> update;
158 for (int i=0; i<N(incoming); i++)
159 if (incoming[i]->alive)
160 update << incoming[i];
161 incoming= update;
162 tm_link new_ln= make_socket_link (addr, -1, SOCKET_SERVER, client);
163 incoming << new_ln;
164 }
165 }
166
167 void
write(string s,int channel)168 socket_server_rep::write (string s, int channel) {
169 (void) s; (void) channel;
170 }
171
172 string&
watch(int channel)173 socket_server_rep::watch (int channel) {
174 static string empty_string= "";
175 (void) channel; return empty_string;
176 }
177
178 string
read(int channel)179 socket_server_rep::read (int channel) {
180 (void) channel; return "";
181 }
182
183 void
listen(int msecs)184 socket_server_rep::listen (int msecs) {
185 (void) msecs;
186 }
187
188 void
interrupt()189 socket_server_rep::interrupt () {
190 }
191
192 void
stop()193 socket_server_rep::stop () {
194 #ifdef __MINGW32__
195 using namespace wsoc;
196 #endif
197 // FIXME: close children
198 if (!alive) return;
199 incoming= array<tm_link> ();
200 alive= false;
201 remove_notifier (sn);
202 sn= socket_notifier ();
203 #ifdef __MINGW32__
204 closesocket (server);
205 WSACleanup();
206 #else
207 close (server);
208 wait (NULL);
209 #endif
210 }
211
212 /******************************************************************************
213 * Call back for new information on server
214 ******************************************************************************/
215
216 void
socket_server_callback(void * obj,void * info)217 socket_server_callback (void *obj, void *info) {
218 #ifdef __MINGW32__
219 using namespace wsoc;
220 #endif
221 (void) info;
222 socket_server_rep* ss = (socket_server_rep*) obj;
223 bool busy= true;
224 bool news= false;
225 while (busy) {
226 fd_set rfds;
227 FD_ZERO (&rfds);
228 int max_fd= ss->server + 1;
229 FD_SET (ss->server, &rfds);
230
231 struct timeval tv;
232 tv.tv_sec = 0;
233 tv.tv_usec = 0;
234 select (max_fd, &rfds, NULL, NULL, &tv);
235
236 busy= false;
237 if (ss->alive && FD_ISSET (ss->server, &rfds)) {
238 //cout << "server_callback" << LF;
239 ss->start_client ();
240 busy= news= true;
241 }
242 }
243
244 if (!is_nil (ss->feed_cmd) && news)
245 ss->feed_cmd->apply (); // call the data processor
246 }
247 #endif
248