+2004-07-21 Lars Gullik Bjonnes <larsbj@gullik.net>
+
+ * 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 <lasgouttes@lyx.org>
* kbmap.C (find1keybinding): new method, only used by LyX/Mac with
* 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 <lasgouttes@lyx.org>
* lyxfunc.C (getStatus): if lyx_gui::getStatus disables the
command, return early.
-
+
2004-06-18 Lars Gullik Bjonnes <larsbj@gullik.net>
* debug.h: add DEBUG to enum and fix size of ANY.
+2004-07-21 Lars Gullik Bjonnes <larsbj@gullik.net>
+
+ * lyx_gui.C (register_socket_callback): add stub
+ (unregister_socket_callback): add stub
+
2004-05-26 Lars Gullik Bjonnes <larsbj@gullik.net>
* Makefile.am: dont create a separate xforms.lo use he files
#include <iomanip>
#include <fcntl.h>
#include <boost/bind.hpp>
+#include <boost/function.hpp>
//just for xforms
#include "lyx_forms.h"
}
-void lyx_gui::set_datasocket_callback(LyXDataSocket * /* p */)
+void lyx_gui::register_socket_callback(int /*fd*/,
+ boost::function<void()> /*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*/)
{}
#include "FuncStatus.h"
+#include <boost/function.hpp>
+
#include <string>
#include <vector>
* 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<void()> 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
+2004-07-21 Lars Gullik Bjonnes <larsbj@gullik.net>
+
+ * 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 <lasgouttes@lyx.org>
* 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 <lasgouttes@lyx.org>
// All is well if the namespace is visible first.
#include <boost/signals/signal1.hpp>
#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
#include "QtView.h"
#include "io_callback.h"
namespace os = lyx::support::os;
+using boost::shared_ptr;
+
#ifndef CXX_GLOBAL_CSTD
using std::exit;
#endif
}
map<int, io_callback *> io_callbacks;
-map<int, socket_callback *> socket_callbacks;
+map<int, shared_ptr<socket_callback> > socket_callbacks;
} // namespace anon
// 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
}
-void set_datasocket_callback(LyXDataSocket * p)
+void register_socket_callback(int fd, boost::function<void()> func)
{
- socket_callbacks[p->fd()] = new socket_callback(p);
+ socket_callbacks[fd] = shared_ptr<socket_callback>(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<int, socket_callback *>::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()
{
#include <config.h>
-#include "lyxsocket.h"
#include "socket_callback.h"
-socket_callback::socket_callback(LyXServerSocket * server)
- : server_(server)
+socket_callback::socket_callback(int fd, boost::function<void()> 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_();
}
#include <qobject.h>
#include <qsocketnotifier.h>
#include <boost/scoped_ptr.hpp>
+#include <boost/function.hpp>
-class LyXServerSocket;
-class LyXDataSocket;
/**
* socket_callback - a simple wrapper for asynchronous socket notification
Q_OBJECT
public:
/// connect a connection notification from the LyXServerSocket
- socket_callback(LyXServerSocket * server);
- socket_callback(LyXDataSocket * data);
+ socket_callback(int fd, boost::function<void()> func);
public slots:
- void server_received();
- void data_received();
+ void data_received();
private:
/// our notifier
boost::scoped_ptr<QSocketNotifier> sn_;
-
- LyXServerSocket * server_;
- LyXDataSocket * data_;
+ /// The callback function
+ boost::function<void()> func_;
};
#endif // SOCKET_CALLBACK_H
+2004-07-21 Lars Gullik Bjonnes <larsbj@gullik.net>
+
+ * 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 <j.spitzmueller@gmx.de>
* FormCitation.C: Don't allow incomplete input (fix bug 1617).
lyxerr[Debug::GUI] << "Creating view: " << width << 'x' << height
<< '+' << xpos << '+' << ypos << endl;
- boost::shared_ptr<XFormsView> view_ptr(new XFormsView(width, height));
- LyX::ref().addLyXView(view_ptr);
+ boost::shared_ptr<XFormsView> 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<string>::const_iterator cit = files.begin();
vector<string>::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) {
comm->read_ready();
}
-extern "C"
-void C_datasocket_callback(int, void * data)
-{
- LyXDataSocket * client = static_cast<LyXDataSocket *>(data);
- client->server()->dataCallback(client);
}
-extern "C"
-void C_serversocket_callback(int, void * data)
-{
- LyXServerSocket * server = static_cast<LyXServerSocket *>(data);
- server->serverCallback();
-}
-
-}
void set_read_callback(int fd, LyXComm * comm)
{
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<int, boost::function<void()> > 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<void()> 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";
#include "support/lyxlib.h"
#include "support/socktools.h"
-#include <iostream>
+#include <boost/bind.hpp>
+
#include <cerrno>
+using boost::shared_ptr;
using std::auto_ptr;
using std::endl;
// 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) {
// 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;
}
// 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_;
// is OK and if the number of clients does not exceed MAX_CLIENTS
void LyXServerSocket::serverCallback()
{
- auto_ptr<LyXDataSocket> 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<LyXDataSocket>(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<LyXDataSocket> client = clients[fd];
+
string line;
string::size_type pos;
bool saidbye = false;
}
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
// lyxerr << "LyXServerSocket debug dump.\n"
// << "fd = " << fd_ << ", address = " << address_ << ".\n"
// << "Clients: " << clients.size() << ".\n";
-// if (!clients.empty()) {
-// std::set<LyXDataSocket *>::const_iterator client = clients.begin();
-// std::set<LyXDataSocket *>::const_iterator end = clients.end();
-// for (; client != end; ++client)
-// lyxerr << "fd = " << (*client)->fd() << "\n";
-// }
+// std::map<int, shared_ptr<LyXDataSocket> >::const_iterator client = clients.begin();
+// std::map<int, shared_ptr<LyXDataSocket> >::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;
}
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
}
// 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;
}
// Write a line of the form <key>:<value> 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
#include "support/socktools.h"
#include "lyxfunc.h"
+#include <boost/shared_ptr.hpp>
+
#include <string>
-#include <set>
+#include <map>
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
* 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_;
MAX_CLIENTS = 10
};
/// All connections
- std::set<LyXDataSocket *> clients;
+ std::map<int, boost::shared_ptr<LyXDataSocket> > 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