the lyxsocket changes

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8841 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Lars Gullik Bjønnes 2004-07-21 19:03:21 +00:00
parent 26c248361f
commit cfd21e6a2a
12 changed files with 183 additions and 185 deletions

View File

@ -1,3 +1,20 @@
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
@ -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 <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.

View File

@ -1,3 +1,8 @@
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

View File

@ -49,6 +49,7 @@
#include <iomanip>
#include <fcntl.h>
#include <boost/bind.hpp>
#include <boost/function.hpp>
//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<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*/)
{}

View File

@ -15,6 +15,8 @@
#include "FuncStatus.h"
#include <boost/function.hpp>
#include <string>
#include <vector>
@ -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<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

View File

@ -1,10 +1,19 @@
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>

View File

@ -35,6 +35,7 @@
// 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"
@ -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<int, io_callback *> io_callbacks;
map<int, socket_callback *> socket_callbacks;
map<int, shared_ptr<socket_callback> > 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<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)
void unregister_socket_callback(int fd)
{
socket_callbacks[p->fd()] = new socket_callback(p);
socket_callbacks.erase(fd);
}
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)
{
remove_socket_callback(p->fd());
}
void remove_serversocket_callback(LyXServerSocket * p)
{
remove_socket_callback(p->fd());
}
string const roman_font_name()
{

View File

@ -12,32 +12,18 @@
#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_();
}

View File

@ -18,9 +18,8 @@
#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
@ -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<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

View File

@ -1,3 +1,9 @@
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).

View File

@ -291,27 +291,26 @@ void start(string const & batch, vector<string> const & files)
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) {
@ -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<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)
{
@ -424,25 +410,34 @@ void remove_read_callback(int fd)
fl_remove_io_callback(fd, FL_READ, C_read_callback);
}
void set_datasocket_callback(LyXDataSocket * p)
namespace {
std::map<int, boost::function<void()> > socket_callbacks;
extern "C"
void C_socket_callback(int fd, void *)
{
fl_add_io_callback(p->fd(), FL_READ, C_datasocket_callback, p);
socket_callbacks[fd]();
}
void remove_datasocket_callback(LyXDataSocket * p)
} // NS anon
void register_socket_callback(int fd, boost::function<void()> func)
{
fl_remove_io_callback(p->fd(), FL_READ, C_datasocket_callback);
socket_callbacks[fd] = func;
fl_add_io_callback(fd, FL_READ, C_socket_callback, 0);
}
void set_serversocket_callback(LyXServerSocket * p)
void unregister_socket_callback(int fd)
{
fl_add_io_callback(p->fd(), FL_READ, C_serversocket_callback, p);
fl_remove_io_callback(fd, FL_READ, C_socket_callback);
socket_callbacks.erase(fd);
}
void remove_serversocket_callback(LyXServerSocket * p)
{
fl_remove_io_callback(p->fd(), FL_READ, C_serversocket_callback);
}
string const roman_font_name()
{

View File

@ -24,9 +24,11 @@
#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;
@ -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<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;
@ -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<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;
}
@ -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 <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

View File

@ -17,12 +17,15 @@
#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
@ -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<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