From: Lars Gullik Bjønnes Date: Wed, 21 Jul 2004 19:03:21 +0000 (+0000) Subject: the lyxsocket changes X-Git-Tag: 1.6.10~15151 X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=cfd21e6a2a816d0d596b80ff3cd03ff8abedb796;p=lyx.git the lyxsocket changes git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8841 a592a061-630c-0410-9148-cb99ea01b6c8 --- diff --git a/src/ChangeLog b/src/ChangeLog index 8f181310ad..926fa454ec 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,20 @@ +2004-07-21 Lars Gullik Bjonnes + + * lyxsocket.C (LyXServerSocket): reduce max outstanding clients to 3 + (LyXServerSocket): register the callback + (LyXServerSocket): unregister the callback + (fd): delete function + (serverCallback): improve error checking and setup the callbacks. + (dataCallback): change arg to fd. + (writeln): new func (copied fro the client socket) used for server + write to client. + (LyXDataSocket): simplify + (~LyXDataSocket): close ann unregiser callback + (server): delete function + (fd): delete function + (readln): small changes, improve some std::string usage + (writeln): constify a bit + 2004-06-24 Jean-Marc Lasgouttes * kbmap.C (find1keybinding): new method, only used by LyX/Mac with @@ -40,16 +57,16 @@ * tex-strings.C: add "none" to string_paperpackages[], fixes off-by-one-error in the paperpackage selection. - + * lyxlex.[Ch]: - * tex-strings.[Ch]: char const * string[n] + * tex-strings.[Ch]: char const * string[n] -> char const * const string[] 2004-06-10 Jean-Marc Lasgouttes * lyxfunc.C (getStatus): if lyx_gui::getStatus disables the command, return early. - + 2004-06-18 Lars Gullik Bjonnes * debug.h: add DEBUG to enum and fix size of ANY. diff --git a/src/frontends/gtk/ChangeLog b/src/frontends/gtk/ChangeLog index 4f26fb9d96..fee29d3083 100644 --- a/src/frontends/gtk/ChangeLog +++ b/src/frontends/gtk/ChangeLog @@ -1,3 +1,8 @@ +2004-07-21 Lars Gullik Bjonnes + + * lyx_gui.C (register_socket_callback): add stub + (unregister_socket_callback): add stub + 2004-05-26 Lars Gullik Bjonnes * Makefile.am: dont create a separate xforms.lo use he files diff --git a/src/frontends/gtk/lyx_gui.C b/src/frontends/gtk/lyx_gui.C index 4a27d6e22d..ac996808b3 100644 --- a/src/frontends/gtk/lyx_gui.C +++ b/src/frontends/gtk/lyx_gui.C @@ -49,6 +49,7 @@ #include #include #include +#include //just for xforms #include "lyx_forms.h" @@ -442,19 +443,12 @@ void lyx_gui::remove_read_callback(int fd) } -void lyx_gui::set_datasocket_callback(LyXDataSocket * /* p */) +void lyx_gui::register_socket_callback(int /*fd*/, + boost::function /*func*/) {} -void lyx_gui::remove_datasocket_callback(LyXDataSocket * /* p */) -{} - - -void lyx_gui::set_serversocket_callback(LyXServerSocket * /* p */) -{} - - -void lyx_gui::remove_serversocket_callback(LyXServerSocket * /* p */) +void lyx_gui::unregister_socket_callback(int /*fd*/) {} diff --git a/src/frontends/lyx_gui.h b/src/frontends/lyx_gui.h index 1ef368778b..3ce1729ff8 100644 --- a/src/frontends/lyx_gui.h +++ b/src/frontends/lyx_gui.h @@ -15,6 +15,8 @@ #include "FuncStatus.h" +#include + #include #include @@ -96,16 +98,14 @@ bool font_available(LyXFont const & font); * add a callback for I/O read notification */ void set_read_callback(int fd, LyXComm * comm); -void set_datasocket_callback(LyXDataSocket *); -void set_serversocket_callback(LyXServerSocket *); +void register_socket_callback(int fd, boost::function func); /** * remove a I/O read callback * @param fd file descriptor */ void remove_read_callback(int fd); -void remove_datasocket_callback(LyXDataSocket *); -void remove_serversocket_callback(LyXServerSocket *); +void unregister_socket_callback(int fd); } // namespace lyx_gui diff --git a/src/frontends/qt2/ChangeLog b/src/frontends/qt2/ChangeLog index 752aa70c6f..13f19787ac 100644 --- a/src/frontends/qt2/ChangeLog +++ b/src/frontends/qt2/ChangeLog @@ -1,10 +1,19 @@ +2004-07-21 Lars Gullik Bjonnes + + * socket_callback.C (data_received): simplify + (socket_callback): take fd and boost::function as args. + (server_received): delete function + + * lyx_gui.C (register_socket_callback): setup the callback + (unregiser_socket_callback): tear down the callback + 2004-07-05 Jean-Marc Lasgouttes * QLyXKeySym.C (qprint): like print, but return a QString (print): use qprint. * QLPopupMenu.C (getLabel): do not add the binding here anymore - (populate): changes to make bindings work on Qt/Mac. + (populate): changes to make bindings work on Qt/Mac. 2004-06-09 Jean-Marc Lasgouttes diff --git a/src/frontends/qt2/lyx_gui.C b/src/frontends/qt2/lyx_gui.C index b33ae2ecdd..7c4e874b9e 100644 --- a/src/frontends/qt2/lyx_gui.C +++ b/src/frontends/qt2/lyx_gui.C @@ -35,6 +35,7 @@ // All is well if the namespace is visible first. #include #include +#include #include "QtView.h" #include "io_callback.h" @@ -57,6 +58,8 @@ using lyx::frontend::QtView; namespace os = lyx::support::os; +using boost::shared_ptr; + #ifndef CXX_GLOBAL_CSTD using std::exit; #endif @@ -78,7 +81,7 @@ float getDPI() } map io_callbacks; -map socket_callbacks; +map > socket_callbacks; } // namespace anon @@ -250,9 +253,9 @@ FuncStatus getStatus(FuncRequest const & ev) // application can still be accessed without giving focus to // the main window. In this case, we want to disable the menu // entries that are buffer-related. - if (use_gui + if (use_gui && qApp->activeWindow() != qApp->mainWidget() - && !lyxaction.funcHasFlag(ev.action, LyXAction::NoBuffer)) + && !lyxaction.funcHasFlag(ev.action, LyXAction::NoBuffer)) flag.enabled(false); #endif @@ -301,34 +304,17 @@ void remove_read_callback(int fd) } -void set_datasocket_callback(LyXDataSocket * p) +void register_socket_callback(int fd, boost::function func) { - socket_callbacks[p->fd()] = new socket_callback(p); + socket_callbacks[fd] = shared_ptr(new socket_callback(fd, func)); } -void set_serversocket_callback(LyXServerSocket * p) -{ - socket_callbacks[p->fd()] = new socket_callback(p); -} - -void remove_socket_callback(int fd) -{ - map::iterator it = socket_callbacks.find(fd); - if (it != socket_callbacks.end()) { - delete it->second; - socket_callbacks.erase(it); - } -} -void remove_datasocket_callback(LyXDataSocket * p) +void unregister_socket_callback(int fd) { - remove_socket_callback(p->fd()); + socket_callbacks.erase(fd); } -void remove_serversocket_callback(LyXServerSocket * p) -{ - remove_socket_callback(p->fd()); -} string const roman_font_name() { diff --git a/src/frontends/qt2/socket_callback.C b/src/frontends/qt2/socket_callback.C index 55e7b306d7..89d684c0a8 100644 --- a/src/frontends/qt2/socket_callback.C +++ b/src/frontends/qt2/socket_callback.C @@ -12,32 +12,18 @@ #include -#include "lyxsocket.h" #include "socket_callback.h" -socket_callback::socket_callback(LyXServerSocket * server) - : server_(server) +socket_callback::socket_callback(int fd, boost::function func) + : func_(func) { - sn_.reset(new QSocketNotifier(server->fd(), QSocketNotifier::Read, this)); - connect(sn_.get(), SIGNAL(activated(int)), this, SLOT(server_received())); -} - -socket_callback::socket_callback(LyXDataSocket * data) - : data_(data) -{ - sn_.reset(new QSocketNotifier(data->fd(), QSocketNotifier::Read, this)); + sn_.reset(new QSocketNotifier(fd, QSocketNotifier::Read, this)); connect(sn_.get(), SIGNAL(activated(int)), this, SLOT(data_received())); } -void socket_callback::server_received() -{ - server_->serverCallback(); -} - - void socket_callback::data_received() { - data_->server()->dataCallback(data_); + func_(); } diff --git a/src/frontends/qt2/socket_callback.h b/src/frontends/qt2/socket_callback.h index 3821033db4..54f203f226 100644 --- a/src/frontends/qt2/socket_callback.h +++ b/src/frontends/qt2/socket_callback.h @@ -18,9 +18,8 @@ #include #include #include +#include -class LyXServerSocket; -class LyXDataSocket; /** * socket_callback - a simple wrapper for asynchronous socket notification @@ -34,17 +33,14 @@ class socket_callback : public QObject { Q_OBJECT public: /// connect a connection notification from the LyXServerSocket - socket_callback(LyXServerSocket * server); - socket_callback(LyXDataSocket * data); + socket_callback(int fd, boost::function func); public slots: - void server_received(); - void data_received(); + void data_received(); private: /// our notifier boost::scoped_ptr sn_; - - LyXServerSocket * server_; - LyXDataSocket * data_; + /// The callback function + boost::function func_; }; #endif // SOCKET_CALLBACK_H diff --git a/src/frontends/xforms/ChangeLog b/src/frontends/xforms/ChangeLog index d9be053ea8..e9daf80c89 100644 --- a/src/frontends/xforms/ChangeLog +++ b/src/frontends/xforms/ChangeLog @@ -1,3 +1,9 @@ +2004-07-21 Lars Gullik Bjonnes + + * lyx_gui.C (register_socket_callback): new func + (unregister_socket_callback): new func + (C_datasocket_callback,C_serversocket_callback): delete func + 2004-06-21 Jürgen Spitzmüller * FormCitation.C: Don't allow incomplete input (fix bug 1617). diff --git a/src/frontends/xforms/lyx_gui.C b/src/frontends/xforms/lyx_gui.C index df14095962..c9c27233e3 100644 --- a/src/frontends/xforms/lyx_gui.C +++ b/src/frontends/xforms/lyx_gui.C @@ -291,27 +291,26 @@ void start(string const & batch, vector const & files) lyxerr[Debug::GUI] << "Creating view: " << width << 'x' << height << '+' << xpos << '+' << ypos << endl; - boost::shared_ptr view_ptr(new XFormsView(width, height)); - LyX::ref().addLyXView(view_ptr); + boost::shared_ptr view(new XFormsView(width, height)); + LyX::ref().addLyXView(view); - XFormsView & view = *view_ptr.get(); - view.show(xpos, ypos, "LyX"); - view.init(); + view->show(xpos, ypos, "LyX"); + view->init(); // FIXME: some code below needs moving - lyxserver = new LyXServer(&view.getLyXFunc(), lyxrc.lyxpipes); - lyxsocket = new LyXServerSocket(&view.getLyXFunc(), + lyxserver = new LyXServer(&view->getLyXFunc(), lyxrc.lyxpipes); + lyxsocket = new LyXServerSocket(&view->getLyXFunc(), os::slashify_path(os::getTmpDir() + "/lyxsocket")); vector::const_iterator cit = files.begin(); vector::const_iterator end = files.end(); for (; cit != end; ++cit) - view.view()->loadLyXFile(*cit, true); + view->view()->loadLyXFile(*cit, true); // handle the batch commands the user asked for if (!batch.empty()) - view.getLyXFunc().dispatch(lyxaction.lookupFunc(batch)); + view->getLyXFunc().dispatch(lyxaction.lookupFunc(batch)); // enter the event loop while (!finished) { @@ -398,21 +397,8 @@ void C_read_callback(int, void * data) comm->read_ready(); } -extern "C" -void C_datasocket_callback(int, void * data) -{ - LyXDataSocket * client = static_cast(data); - client->server()->dataCallback(client); } -extern "C" -void C_serversocket_callback(int, void * data) -{ - LyXServerSocket * server = static_cast(data); - server->serverCallback(); -} - -} void set_read_callback(int fd, LyXComm * comm) { @@ -424,26 +410,35 @@ void remove_read_callback(int fd) fl_remove_io_callback(fd, FL_READ, C_read_callback); } -void set_datasocket_callback(LyXDataSocket * p) -{ - fl_add_io_callback(p->fd(), FL_READ, C_datasocket_callback, p); -} -void remove_datasocket_callback(LyXDataSocket * p) +namespace { + +std::map > socket_callbacks; + +extern "C" +void C_socket_callback(int fd, void *) { - fl_remove_io_callback(p->fd(), FL_READ, C_datasocket_callback); + socket_callbacks[fd](); } -void set_serversocket_callback(LyXServerSocket * p) + +} // NS anon + + +void register_socket_callback(int fd, boost::function func) { - fl_add_io_callback(p->fd(), FL_READ, C_serversocket_callback, p); + socket_callbacks[fd] = func; + fl_add_io_callback(fd, FL_READ, C_socket_callback, 0); } -void remove_serversocket_callback(LyXServerSocket * p) + +void unregister_socket_callback(int fd) { - fl_remove_io_callback(p->fd(), FL_READ, C_serversocket_callback); + fl_remove_io_callback(fd, FL_READ, C_socket_callback); + socket_callbacks.erase(fd); } + string const roman_font_name() { return "times"; diff --git a/src/lyxsocket.C b/src/lyxsocket.C index 3095d2bb31..bad14b65d1 100644 --- a/src/lyxsocket.C +++ b/src/lyxsocket.C @@ -24,9 +24,11 @@ #include "support/lyxlib.h" #include "support/socktools.h" -#include +#include + #include +using boost::shared_ptr; using std::auto_ptr; using std::endl; @@ -38,7 +40,7 @@ using std::string; // that can connect at the same time. LyXServerSocket::LyXServerSocket(LyXFunc * f, string const & addr) : func(f), - fd_(lyx::support::socktools::listen(addr, MAX_CLIENTS)), + fd_(lyx::support::socktools::listen(addr, 3)), address_(addr) { if (fd_ == -1) { @@ -52,7 +54,11 @@ LyXServerSocket::LyXServerSocket(LyXFunc * f, string const & addr) // Needed by lyxclient lyx::support::putenv("LYXSOCKET", address_); - lyx_gui::set_serversocket_callback(this); + lyx_gui::register_socket_callback( + fd_, + boost::bind(&LyXServerSocket::serverCallback, *this) + ); + lyxerr[Debug::LYXSERVER] << "lyx: New server socket " << fd_ << ' ' << address_ << endl; } @@ -61,19 +67,13 @@ LyXServerSocket::LyXServerSocket(LyXFunc * f, string const & addr) // Close the socket and remove the address of the filesystem. LyXServerSocket::~LyXServerSocket() { + lyx_gui::unregister_socket_callback(fd_); ::close(fd_); lyx::support::unlink(address_); - while (!clients.empty()) close(*clients.rbegin()); lyxerr[Debug::LYXSERVER] << "lyx: Server socket quitting" << endl; } -int LyXServerSocket::fd() const -{ - return fd_; -} - - string const & LyXServerSocket::address() const { return address_; @@ -84,23 +84,36 @@ string const & LyXServerSocket::address() const // is OK and if the number of clients does not exceed MAX_CLIENTS void LyXServerSocket::serverCallback() { - auto_ptr client(new LyXDataSocket(this)); - if (client->connected()) { - if (clients.size() == MAX_CLIENTS) { - client->writeln("BYE:Too many clients connected"); - } else { - lyx_gui::set_datasocket_callback(client.get()); - clients.insert(client.release()); - return; - } + int const client_fd = lyx::support::socktools::accept(fd_); + + if (fd_ == -1) { + lyxerr[Debug::LYXSERVER] << "lyx: Failed to accept new client" + << endl; + return; } + + if (clients.size() >= MAX_CLIENTS) { + writeln("BYE:Too many clients connected"); + return; + } + + // Register the new client. + clients[client_fd] = + shared_ptr(new LyXDataSocket(client_fd)); + lyx_gui::register_socket_callback( + client_fd, + boost::bind(&LyXServerSocket::dataCallback, + *this, client_fd) + ); } // Reads and processes input from client and check // if the connection has been closed -void LyXServerSocket::dataCallback(LyXDataSocket * client) +void LyXServerSocket::dataCallback(int fd) { + shared_ptr client = clients[fd]; + string line; string::size_type pos; bool saidbye = false; @@ -133,17 +146,30 @@ void LyXServerSocket::dataCallback(LyXDataSocket * client) } if (saidbye || (!client->connected())) { - close(client); + clients.erase(fd); } } -// Removes client callback and deletes client object -void LyXServerSocket::close(LyXDataSocket * client) +void LyXServerSocket::writeln(string const & line) { - lyx_gui::remove_datasocket_callback(client); - clients.erase(client); - delete client; + string const linen(line + '\n'); + int const size = linen.size(); + int const written = ::write(fd_, linen.c_str(), size); + if (written < size) { // Allways mean end of connection. + if ((written == -1) && (errno == EPIPE)) { + // The program will also receive a SIGPIPE + // that must be caught + lyxerr << "lyx: Server socket " << fd_ + << " connection closed while writing." << endl; + } else { + // Anything else, including errno == EAGAIN, must be + // considered IO error. EAGAIN should never happen + // when line is small + lyxerr << "lyx: Server socket " << fd_ + << " IO error: " << strerror(errno); + } + } } // Debug @@ -152,44 +178,27 @@ void LyXServerSocket::close(LyXDataSocket * client) // lyxerr << "LyXServerSocket debug dump.\n" // << "fd = " << fd_ << ", address = " << address_ << ".\n" // << "Clients: " << clients.size() << ".\n"; -// if (!clients.empty()) { -// std::set::const_iterator client = clients.begin(); -// std::set::const_iterator end = clients.end(); -// for (; client != end; ++client) -// lyxerr << "fd = " << (*client)->fd() << "\n"; -// } +// std::map >::const_iterator client = clients.begin(); +// std::map >::const_iterator end = clients.end(); +// for (; client != end; ++client) +// lyxerr << "fd = " << client->first << '\n'; // } -LyXDataSocket::LyXDataSocket(LyXServerSocket * serv) - :server_(serv), - fd_(lyx::support::socktools::accept(serv->fd())) +LyXDataSocket::LyXDataSocket(int fd) + : fd_(fd), connected_(true) { - if (fd_ == -1) { - connected_ = false; - } else { - lyxerr[Debug::LYXSERVER] << "lyx: New data socket " << fd_ << endl; - connected_ = true; - } + lyxerr[Debug::LYXSERVER] << "lyx: New data socket " << fd_ << endl; } LyXDataSocket::~LyXDataSocket() { ::close(fd_); - lyxerr[Debug::LYXSERVER] << "lyx: Data socket " << fd_ << " quitting." << endl; -} - -LyXServerSocket * LyXDataSocket::server() const -{ - return server_; -} - - -int LyXDataSocket::fd() const -{ - return fd_; + lyx_gui::unregister_socket_callback(fd_); + lyxerr[Debug::LYXSERVER] << "lyx: Data socket " << fd_ << " quitting." + << endl; } @@ -205,12 +214,10 @@ bool LyXDataSocket::readln(string & line) int const charbuf_size = 100; char charbuf[charbuf_size]; // buffer for the ::read() system call int count; - string::size_type pos; // read and store characters in buffer while ((count = ::read(fd_, charbuf, charbuf_size - 1)) > 0) { - charbuf[count] = '\0'; // turn it into a c string - buffer += charbuf; + buffer_.append(charbuf, charbuf + count); } // Error conditions. The buffer must still be @@ -226,13 +233,14 @@ bool LyXDataSocket::readln(string & line) } // Cut a line from buffer - if ((pos = buffer.find('\n')) == string::npos) { + string::size_type pos = buffer_.find('\n'); + if (pos == string::npos) { lyxerr[Debug::LYXSERVER] << "lyx: Data socket " << fd_ << ": line not completed." << endl; return false; // No complete line stored } - line = buffer.substr(0, pos); - buffer = buffer.substr(pos + 1); + line = buffer_.substr(0, pos); + buffer_.erase(0, pos + 1); return true; } @@ -240,9 +248,9 @@ bool LyXDataSocket::readln(string & line) // Write a line of the form : to the socket void LyXDataSocket::writeln(string const & line) { - string linen(line + '\n'); - int size = linen.size(); - int written = ::write(fd_, linen.c_str(), size); + string const linen(line + '\n'); + int const size = linen.size(); + int const written = ::write(fd_, linen.c_str(), size); if (written < size) { // Allways mean end of connection. if ((written == -1) && (errno == EPIPE)) { // The program will also receive a SIGPIPE diff --git a/src/lyxsocket.h b/src/lyxsocket.h index 6779ccb567..73af0683e1 100644 --- a/src/lyxsocket.h +++ b/src/lyxsocket.h @@ -17,12 +17,15 @@ #include "support/socktools.h" #include "lyxfunc.h" +#include + #include -#include +#include class LyXServerSocket; class LyXDataSocket; + /** Sockets can be in two states: listening and connected. * Connected sockets are used to transfer data, and will therefore * be called Data Sockets. Listening sockets are used to create @@ -32,24 +35,22 @@ class LyXDataSocket; * This class encapsulates local (unix) server socket operations and * manages LyXDataSockets objects that are created when clients connect. */ -class LyXServerSocket -{ +class LyXServerSocket { public: + /// LyXServerSocket(LyXFunc *, std::string const &); + /// ~LyXServerSocket(); - /// File descriptor of the socket - int fd() const; /// Address of the local socket std::string const & address() const; /// To be called when there is activity in the server socket void serverCallback(); /// To be called when there is activity in the data socket - void dataCallback(LyXDataSocket *); - + void dataCallback(int fd); private: - /// Close the connection to the argument client - void close(LyXDataSocket *); - + /// + void writeln(std::string const &); + /// LyXFunc * func; /// File descriptor for the server socket int fd_; @@ -60,37 +61,32 @@ private: MAX_CLIENTS = 10 }; /// All connections - std::set clients; + std::map > clients; }; /** This class encapsulates data socket operations. * It provides read and write IO operations on the socket. */ -class LyXDataSocket -{ +class LyXDataSocket { public: - LyXDataSocket(LyXServerSocket *); + /// + LyXDataSocket(int fd); + /// ~LyXDataSocket(); - /// The object that allocated us - LyXServerSocket * server() const; - /// File descriptor of the connection - int fd() const; /// Connection status bool connected() const; /// Line buffered input from the socket bool readln(std::string &); /// Write the string + '\n' to the socket void writeln(std::string const &); - private: - LyXServerSocket * server_; /// File descriptor for the data socket int fd_; /// True if the connection is up bool connected_; /// buffer for input data - std::string buffer; + std::string buffer_; }; #endif // LYXSOCKET_H