Back to index

texmacs  1.0.7.15
socket_server.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : socket_server.cpp
00004 * DESCRIPTION: TeXmacs servers over sockets
00005 * COPYRIGHT  : (C) 2007  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "socket_server.hpp"
00013 #include "sys_utils.hpp"
00014 #include "hashset.hpp"
00015 #include "iterator.hpp"
00016 #include <stdlib.h>
00017 #include <string.h>
00018 #ifndef __MINGW32__
00019 #include <unistd.h>
00020 #include <sys/socket.h>
00021 #include <netinet/in.h>
00022 #include <arpa/inet.h>
00023 #include <sys/wait.h>
00024 #endif
00025 
00026 hashset<pointer> socket_server_set;
00027 void socket_server_callback (void *obj, void *info);
00028 
00029 /******************************************************************************
00030 * Constructors and destructors for socket_servers
00031 ******************************************************************************/
00032 
00033 socket_server_rep::socket_server_rep (int port2):
00034  port (port2), sn ()
00035 {
00036   socket_server_set->insert ((pointer) this);
00037   server= -1;
00038   alive = false;
00039 }
00040 
00041 socket_server_rep::~socket_server_rep () {
00042   stop ();
00043   socket_server_set->remove ((pointer) this);
00044 }
00045 
00046 tm_link
00047 make_socket_server (int port) {
00048   return tm_new<socket_server_rep> (port);
00049 }
00050 
00051 int
00052 number_of_servers () {
00053   return N (socket_server_set);
00054 }
00055 
00056 void
00057 close_all_servers () {
00058 #ifndef __MINGW32__
00059   iterator<pointer> it= iterate (socket_server_set);
00060   while (it->busy()) {
00061     socket_server_rep* ss= (socket_server_rep*) it->next();
00062     if (ss->alive) {
00063       // FIXME: cleanly close the connection to the socket here
00064       ss->alive= false;
00065     }
00066   }
00067 #endif
00068 }
00069 
00070 /******************************************************************************
00071 * Routines for socket_servers
00072 ******************************************************************************/
00073 
00074 string
00075 socket_server_rep::start () {
00076 #ifndef __MINGW32__
00077   // get the server
00078   if ((server = socket (PF_INET, SOCK_STREAM, 0)) == -1)
00079     return "Error: call to 'socket' failed";
00080 
00081   // lose the pesky "address already in use" error message
00082   int yes= 1;
00083   if (setsockopt (server, SOL_SOCKET, SO_REUSEADDR,
00084                 &yes, sizeof (int)) == -1)
00085     return "Error: call to 'setsockopt' failed";
00086 
00087   // bind
00088   struct sockaddr_in local_address;
00089   local_address.sin_family = AF_INET;
00090   local_address.sin_addr.s_addr = INADDR_ANY;
00091   local_address.sin_port = htons (6561);
00092   memset (local_address.sin_zero, '\0', sizeof local_address.sin_zero);
00093   if (bind (server, (struct sockaddr *) &local_address,
00094            sizeof (local_address)) == -1)
00095     return "Error: call to 'bind' failed";
00096 
00097   // listen
00098   if (::listen (server, 10) == -1)
00099     return "Error: call to 'listen' failed";
00100 
00101   alive= true;
00102   
00103   sn = socket_notifier (server, &socket_server_callback, this, NULL);
00104   add_notifier (sn);
00105   
00106   return "ok";
00107 #else
00108   return "Error: sockets not implemented";
00109 #endif
00110 }
00111 
00112 void
00113 socket_server_rep::start_client () {
00114 #ifndef __MINGW32__
00115   struct sockaddr_in remote_address;
00116   socklen_t addrlen= sizeof (remote_address);
00117   int client= accept (server, (struct sockaddr *) &remote_address, &addrlen);
00118   if (client == -1) system_warning ("Call to 'accept' failed");
00119   else {
00120     string addr= inet_ntoa (remote_address.sin_addr);
00121     cout << "TeXmacs] opened connection from '" << addr << "'\n";
00122     array<tm_link> update;
00123     for (int i=0; i<N(incoming); i++)
00124       if (incoming[i]->alive)
00125        update << incoming[i];
00126     incoming= update;
00127     incoming << make_socket_link (addr, -1, SOCKET_SERVER, client);
00128   }
00129 #endif
00130 }
00131 
00132 void
00133 socket_server_rep::write (string s, int channel) {
00134   (void) s; (void) channel;
00135 }
00136 
00137 string&
00138 socket_server_rep::watch (int channel) {
00139   static string empty_string= "";
00140   (void) channel; return empty_string;
00141 }
00142 
00143 string
00144 socket_server_rep::read (int channel) {
00145   (void) channel; return "";
00146 }
00147 
00148 void
00149 socket_server_rep::listen (int msecs) {
00150   (void) msecs;
00151 }
00152 
00153 void
00154 socket_server_rep::interrupt () {
00155 }
00156 
00157 void
00158 socket_server_rep::stop () {
00159 #ifndef __MINGW32__
00160   // FIXME: close children
00161   if (!alive) return;
00162   incoming= array<tm_link> ();
00163   alive= false;
00164   
00165   remove_notifier (sn);
00166   close (server);
00167   wait (NULL);
00168 #endif
00169 }
00170 
00171 /******************************************************************************
00172 * Call back for new information on server
00173 ******************************************************************************/
00174 
00175 void 
00176 socket_server_callback (void *obj, void *info) {
00177 #ifndef __MINGW32__
00178   (void) info;
00179   socket_server_rep* ss = (socket_server_rep*) obj;
00180   bool busy= true;
00181   bool news= false;
00182   while (busy) {
00183     fd_set rfds;
00184     FD_ZERO (&rfds);
00185     int max_fd= ss->server + 1;
00186     FD_SET (ss->server, &rfds);
00187   
00188     struct timeval tv;
00189     tv.tv_sec  = 0;
00190     tv.tv_usec = 0;
00191     select (max_fd, &rfds, NULL, NULL, &tv);
00192 
00193     busy= false;
00194     if (ss->alive && FD_ISSET (ss->server, &rfds)) {
00195       //cout << "server_callback" << LF;
00196       ss->start_client ();
00197       busy= news= true;
00198     }
00199   }
00200   
00201   if (!is_nil (ss->feed_cmd) && news)
00202     ss->feed_cmd->apply (); // call the data processor
00203 #endif
00204 }