/*************************************************************************** kssocketio.cpp ------------------- begin : Tue Jun 13 2000 copyright : (C) 2000 by Kamil Dobkowski email : kamildobk@friko.onet.pl ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include // P_tmpdir #include // unlink #include #include #include #include //#include #include #include #include"kssocketio.h" #include"ksmatrix.h" #include"kmatplotshell.h" #include"kscommands.h" #include"widgets/qsconsole.h" #include"widgets/qsaxes2d.h" #include"widgets/qsaxes3d.h" #include"widgets/qscurve.h" #include"widgets/qsimage.h" #include"widgets/qscontour.h" #include"widgets/qssurface.h" #include"widgets/qsfigure.h" //--------------------------------------------------------------// KSSocketIO::KSSocketIO(QObject *parent, const char *name ) : QObject(parent,name), app_number( 0 ), socket_fd( -1 ), socket_notifier( NULL ) { connection.socket_notifier = NULL; connection.socket_fd = -1; msg.data = NULL; m_shell = NULL; new_message(); available_axes_id = 0; } //--------------------------------------------------------------// KSSocketIO::~KSSocketIO() { cleanup(); } //--------------------------------------------------------------// void KSSocketIO::setShell( KMatplotShell *shell ) { if ( m_shell ) { QObject::disconnect( m_shell->workbook(), SIGNAL(sigObjectAdded(QSCObject*)), this, SLOT(object_added(QSCObject*)) ); QObject::disconnect( m_shell->workbook(), SIGNAL(sigObjectRemoved(QSCObject*)), this, SLOT(object_removed(QSCObject*)) ); } m_shell = shell; m_workbook = m_shell->workbook(); if ( m_shell ) { QObject::connect( m_shell->workbook(), SIGNAL(sigObjectAdded(QSCObject*)), this, SLOT(object_added(QSCObject*)) ); QObject::connect( m_shell->workbook(), SIGNAL(sigObjectRemoved(QSCObject*)), this, SLOT(object_removed(QSCObject*)) ); } if ( socket_fd == -1 ) open_socket(); } //--------------------------------------------------------------// void KSSocketIO::setFileDescriptor( int fd ) { assert( socket_fd == -1 ); struct sockaddr_un addr; unsigned int len = sizeof(addr); memset( (char *)&addr, 0, sizeof(addr) ); if ( getsockname( fd, (struct sockaddr *)&addr, &len ) == 0 ) { socket_name = QCString( addr.sun_path, sizeof(addr.sun_path) ); QCString number = socket_name; number.remove( 0, name_prefix().length() ); app_number = number.toUInt(); // listen already called by a parent process setup_socket( fd ); } else { QSConsole::write( tr("File descriptor %1 does not point on a valid unix socket.").arg(fd) ); perror(""); } } //--------------------------------------------------------------// int KSSocketIO::axesId( QSAxes *axes ) const { QMap::ConstIterator it; for( it = m_axes.begin(); it != m_axes.end(); ++it ) if ( it.data() == axes ) return it.key(); return -1; } //--------------------------------------------------------------// int KSSocketIO::registerAxes( QSAxes *axes, int id ) { assert( axes ); assert( id >= 0 ); //cout << " Registered axes " << axes << " id " << id << endl; m_axes[id] = axes; return id; } //--------------------------------------------------------------// void KSSocketIO::unregisterAxes( int id ) { assert( id >= 0 ); m_axes.remove( id ); } //--------------------------------------------------------------// void KSSocketIO::open_socket() { assert( socket_fd == -1 ); int socket_fd = socket( AF_UNIX, SOCK_STREAM, 0 ); assert( socket_fd >= 0 ); struct sockaddr_un addr; do { app_number ++; QCString number; socket_name = name_prefix() + number.setNum(app_number); memset( (char *)&addr, 0, sizeof(addr) ); addr.sun_family = AF_UNIX; strcpy( addr.sun_path, (const char *)socket_name ); } while( bind(socket_fd,(struct sockaddr *)&addr,strlen(addr.sun_path)+sizeof(addr.sun_family)) < 0 ); listen( socket_fd, 1 ); setup_socket( socket_fd ); } //--------------------------------------------------------------// void KSSocketIO::setup_socket( int fd ) { socket_fd = fd; fcntl( fd, F_SETFL, O_NONBLOCK ); socket_notifier = new QSocketNotifier( fd, QSocketNotifier::Read, this ); connect( socket_notifier, SIGNAL(activated(int)), this, SLOT(connection_requested(int)) ); connect( qApp, SIGNAL(aboutToQuit()), this, SLOT(cleanup()) ); } //--------------------------------------------------------------// void KSSocketIO::close_socket() { if ( socket_fd >= 0 ) { close( socket_fd ); delete socket_notifier; socket_notifier = NULL; socket_fd = -1; unlink( (const char *)socket_name ); app_number = 0; socket_name = QCString(); } } //--------------------------------------------------------------// void KSSocketIO::cleanup() { disconnect(); close_socket(); } //--------------------------------------------------------------// void KSSocketIO::connection_requested(int) { accept_connection(); } //--------------------------------------------------------------// void KSSocketIO::connection_lost() { disconnect(); } //--------------------------------------------------------------// void KSSocketIO::accept_connection() { socket_notifier->setEnabled(false); assert( socket_fd >= 0 ); assert( connection.socket_fd == -1 ); struct sockaddr_un addr; unsigned int len = sizeof(addr); connection.socket_fd = accept( socket_fd, (struct sockaddr *)&addr, &len ); fcntl( connection.socket_fd, F_SETFL, O_NONBLOCK ); if ( connection.socket_fd >= 0 ) { connection.socket_notifier = new QSocketNotifier( connection.socket_fd, QSocketNotifier::Read, this ); connect( connection.socket_notifier, SIGNAL(activated(int)), this, SLOT(read_data(int)) ); } } //--------------------------------------------------------------// void KSSocketIO::disconnect() { if ( connection.socket_fd >= 0 ) { delete connection.socket_notifier; connection.socket_notifier = NULL; close( connection.socket_fd ); connection.socket_fd = -1; } new_message(); if ( socket_notifier ) socket_notifier->setEnabled(true); } //--------------------------------------------------------------// void KSSocketIO::read_data( int ) { int nread = 0; int hsize = sizeof(msg.header); // // read a message header // if ( msg.nread < hsize ) { nread = read( connection.socket_fd, (char *)&msg.header + msg.nread, hsize - msg.nread ); } // // read a message body // else if ( msg.nread < msg.dlen ) { nread = read( connection.socket_fd, msg.data + msg.nread - hsize, msg.dlen - msg.nread ); } if ( nread <= 0 ) { perror(""); connection_lost(); return; } else msg.nread += nread; // // header is read // if ( msg.nread == hsize ) { msg.dlen = sizeof(msg.header) + msg.header.h.dlen; msg.data = new char[msg.header.h.dlen]; } // // message is read. // if ( msg.nread >= hsize && msg.nread == msg.dlen ) { int reply_code = message_ready(); new_message(); reply( reply_code ); } } //--------------------------------------------------------------// int KSSocketIO::message_ready() { int reply_code = -1; // // Add plot the app is run as a standalone one. //if ( !parts.contains(msg.header.h.plot) ) return reply_code; //KMatplotShell *shell = m_shell; if ( !m_shell ) return reply_code; QSAxes *axes = m_axes[msg.header.h.plot]; if ( msg.header.h.type == MsgAddAxes ) { if ( msg.header.a.axes ) { QSAxes *new_axes = new QSAxes3D(); if ( m_workbook->page(0) ) m_workbook->execute( new KSCmdAddCObject(new_axes->shadowObject(),m_workbook->page(0)->objects()) ); } else { QSAxes *new_axes = new QSAxes2D(); if ( m_workbook->page(0) ) m_workbook->execute( new KSCmdAddCObject(new_axes->shadowObject(),m_workbook->page(0)->objects()) ); } reply_code = available_axes_id; } else if ( msg.header.h.type == MsgRemoveAxes ) { if ( !axes ) return reply_code; bool ok = m_shell->workbook()->execute( new KSCmdRemoveCObject(axes->shadowObject()) ); if ( ok ) reply_code = 0; } else if ( msg.header.h.type == MsgChannel ) { if ( !axes ) return reply_code; KSMatrix *m = KSMatrix::create( (EType )msg.header.c.etype ); assert( m ); m->setRawData( msg.data, msg.header.c.rows, msg.header.c.cols, true, msg.header.c.lineo, msg.header.c.pixelo ); if ( axes->plot(msg.header.c.dnum) ) { axes->plot(msg.header.c.dnum)->setMatrix( msg.header.c.chan, m ); reply_code = 0; } else delete m; // don't delete it. msg.data = NULL; } else if ( msg.header.h.type == MsgProperty ) { if ( !axes ) return reply_code; } else if ( msg.header.h.type == MsgAddDataset ) { if ( !axes ) return reply_code; QSPlot *p = NULL; // int plots_number = axes->plotsCount(); // Ooopss ! switch ( msg.header.t.ptype ) { case PlotCurve: p = new QSCurve( axes ); break; case PlotImage: p = new QSImage( axes ); break; case PlotContour: p = new QSGriddedContour( axes ); break; case PlotSurface: p = new QSSurface( axes ); break; case PlotFigure: p = new QSFigure( axes ); break; } if ( p ) { axes->plotAdd( p ); reply_code = axes->plotCount()-1; } else { reply_code = -1; } } else if ( msg.header.h.type == MsgRemoveDataset ) { if ( !axes ) return reply_code; if ( axes->plot(msg.header.t.dnum) ) { QSPlot *p = axes->plot(msg.header.t.dnum); axes->plotRemove( p ); delete p; reply_code = 0; } } else if ( msg.header.h.type == MsgRemoveAllDatasets ) { if ( !axes ) return reply_code; while( axes->plot(0) ) { QSPlot *p = axes->plot(0); axes->plotRemove( p ); delete p; } reply_code = 0; } return reply_code; } //--------------------------------------------------------------// void KSSocketIO::new_message() { delete msg.data; msg.dlen = 0; msg.nread = 0; msg.data = NULL; } //--------------------------------------------------------------// void KSSocketIO::reply( int code ) { _write_data( connection.socket_fd, (const char *)&code, sizeof(code) ); } //--------------------------------------------------------------// QCString KSSocketIO::name_prefix() { return QCString(P_tmpdir) + "/" + ".kmatplot." + getenv("USER") + "."; } //--------------------------------------------------------------// int KSSocketIO::_write_data( int fd, const char *data, int len ) { int nleft; int bytes; const char *ptr; ptr = data; nleft = len; while( nleft > 0 ) { bytes = write( fd, ptr, nleft ); if ( bytes < 0 ) break; /* error */ nleft -= bytes; ptr += bytes; } return(len - nleft); } //--------------------------------------------------------------// void KSSocketIO::object_added( QSCObject *object ) { if ( object->isAxesShadow() ) { QSAxes *axes = object->parentAxes(); ++available_axes_id; registerAxes( axes, available_axes_id ); } } //--------------------------------------------------------------// void KSSocketIO::object_removed( QSCObject *object ) { if ( object->isAxesShadow() ) { QSAxes *axes= object->parentAxes(); int axes_id = axesId(axes); if ( axes_id >= 0 ) unregisterAxes( axes_id ); } }