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