source: flair-src/trunk/tools/FlairGCS/src/Manager.cpp @ 244

Last change on this file since 244 was 244, checked in by Sanahuja Guillaume, 4 years ago

modifs segfault when closing connection

File size: 10.8 KB
RevLine 
[10]1// %flair:license{
[15]2// This file is part of the Flair framework distributed under the
3// CECILL-C License, Version 1.0.
[10]4// %flair:license}
[9]5#include "Manager.h"
6#include "UdtSocket.h"
7#include "ConnectionLayout.h"
8#include "communication.h"
[234]9#include "file_ui.h"
[9]10#include <QDate>
11#include <QFileDialog>
12#include <QMessageBox>
13#include <QPushButton>
14#include <QTabBar>
15#include <QTimer>
16#include <QThread>
17#include <QTextStream>
18#include <QVBoxLayout>
19#include <QModelIndex>
[234]20#include <QStatusBar>
[9]21#include <qendian.h>
22#include <iostream>
23#include <string>
24#include <fstream>
25#include <stdio.h>
26
27#ifndef WIN32
[15]28#include <arpa/inet.h>
[9]29#else
[15]30#include <winsock2.h>
31#include <ws2tcpip.h>
[9]32#endif
33
34using namespace std;
35
[15]36Manager::Manager(QString name, int port) : QWidget() {
37  qRegisterMetaType<QModelIndex>("QModelIndex"); // pour le file ui??
38  this->name = name;
[244]39//ffprintf(stderr,stderr,"Manager %x\n",thread());
[234]40  setWindowTitle(name);
[9]41
[15]42  // manager layout
43  managerLayout = new QVBoxLayout;
44  setLayout(managerLayout);
[9]45
[15]46  // tab bar for multiple connections
47  tabBar = new QTabBar();
48  managerLayout->addWidget(tabBar);
49  connect(tabBar, SIGNAL(currentChanged(int)), this,
50          SLOT(tabBarCurrentChanged(int)));
51  currentTab = 0;
[9]52
[15]53  // layout boutons
54  button_layout = new QGridLayout();
55  managerLayout->addLayout(button_layout);
[9]56
[15]57  // boutons du button_Layout
58  send_button = new QPushButton("apply all");
59  reset_button = new QPushButton("reset all");
60  load_button = new QPushButton("load all locally");
61  save_button = new QPushButton("save all locally");
62  button_layout->addWidget(send_button, 0, 0);
63  button_layout->addWidget(reset_button, 0, 1);
64  button_layout->addWidget(load_button, 0, 2);
65  button_layout->addWidget(save_button, 0, 3);
[9]66
[15]67  connect(send_button, SIGNAL(clicked(bool)), this, SLOT(send()));
68  connect(reset_button, SIGNAL(clicked(bool)), this, SLOT(reset()));
69  connect(load_button, SIGNAL(clicked(bool)), this, SLOT(load()));
70  connect(save_button, SIGNAL(clicked(bool)), this, SLOT(save()));
[9]71
[30]72  status=new QStatusBar();
73  status->setSizeGripEnabled(false);
74  button_layout->addWidget(status, 1,0);
75
[15]76  UDT::startup();
77  serv = UDT::socket(AF_INET, SOCK_DGRAM, 0);
[9]78
[15]79  // for non blocking accept
80  bool blocking = false;
81  UDT::setsockopt(serv, 0, UDT_RCVSYN, &blocking, sizeof(bool));
[234]82//UDT::setsockopt(serv, 0, UDT_CC, new CCCFactory<CUDPBlast>, sizeof(CCCFactory<CUDPBlast>));
[15]83  sockaddr_in my_addr;
84  my_addr.sin_family = AF_INET;
85  my_addr.sin_port = htons(port);
86  my_addr.sin_addr.s_addr = INADDR_ANY;
87  memset(&(my_addr.sin_zero), '\0', 8);
[9]88
[15]89  if (UDT::ERROR == UDT::bind(serv, (sockaddr *)&my_addr, sizeof(my_addr))) {
[244]90    fprintf(stderr,"bind error, %s\n", UDT::getlasterror().getErrorMessage());
[15]91  }
[9]92
[15]93  if (UDT::ERROR == UDT::listen(serv, 1)) {
[244]94    fprintf(stderr,"listen error, %s\n", UDT::getlasterror().getErrorMessage());
[15]95  }
[9]96
[15]97  QTimer *timer = new QTimer(this);
98  connect(timer, SIGNAL(timeout()), this, SLOT(acceptConnections()));
[234]99  timer->start(500);
[9]100}
101
102Manager::~Manager() {
[234]103  for (int i = 0; i < udtSockets.count(); i++) {
104    udtSockets.at(i)->kill();
105    udtSockets.at(i)->thread()->wait();
106  }
[9]107
[15]108  // delete main_layout;
109  UDT::cleanup();
[9]110}
111
112void Manager::acceptConnections(void) {
[15]113  UDTSOCKET socket;
[9]114
[15]115  sockaddr_in their_addr;
116  int namelen = sizeof(their_addr);
[9]117
[234]118  if (UDT::INVALID_SOCK ==(socket = UDT::accept(serv, (sockaddr *)&their_addr, &namelen))) {
[15]119    if (UDT::getlasterror().getErrorCode() != 6002)
[244]120      fprintf(stderr,"accept error: %s, code %i\n", UDT::getlasterror().getErrorMessage(),UDT::getlasterror().getErrorCode());
[15]121    return;
122  } else {
[234]123    QString name=QString("%1:%2").arg(inet_ntoa(their_addr.sin_addr)).arg(their_addr.sin_port);
[244]124    fprintf(stderr,"connected to %s\n",name.toLocal8Bit().constData());
[234]125   
126    QThread *thread = new QThread(this);
127    UdtSocket *udtSocket = new UdtSocket(socket,name);
128    udtSocket->moveToThread(thread);
129    udtSockets.append(udtSocket);
[15]130
[234]131    connect(udtSocket, SIGNAL(newFileUI(UDTSOCKET)), this, SLOT(newFileUI(UDTSOCKET)));
132    connect(udtSocket, SIGNAL(newConnectionLayout(QString)), this, SLOT(newConnectionLayout(QString)),Qt::BlockingQueuedConnection);
133    connect(thread, SIGNAL(started()), udtSocket, SLOT(receiveData()));
[9]134
[234]135    thread->start(); 
[15]136  }
[9]137}
138
[234]139void Manager::newConnectionLayout(QString name) {
140  UdtSocket* udtSocket=(UdtSocket *)sender();
141 
142  ConnectionLayout *newLayout = new ConnectionLayout(udtSocket, name);
[15]143  connectionsLayout.append(newLayout);
[234]144  connect(udtSocket, SIGNAL(UDTStats(QString)), newLayout, SIGNAL(UDTStats(QString)));//connection in 2 steps to get udtsocket as sender
145  connect(newLayout, SIGNAL(UDTStats(QString)), this, SLOT(printUDTStats(QString)));
146  connect(udtSocket, SIGNAL(dataReady(char *, int)), newLayout,SLOT(receive(char *, int)),Qt::BlockingQueuedConnection);
147  connect(newLayout, SIGNAL(destroyed(QObject *)), this, SLOT(layoutDestroyed(QObject *)));
[244]148  connect(udtSocket, SIGNAL(destroyed(QObject *)), this, SLOT(udtSocketDestroyed(QObject *)));
[234]149  connect(udtSocket, SIGNAL(destroyed()), newLayout, SLOT(deleteLater()));
150 
151   // widget
[15]152  QWidget *newWidget = new QWidget();
153  connectionsWidget.append(newWidget);
154  newWidget->setLayout(newLayout->getQGridLayout());
155  managerLayout->insertWidget(1, newWidget);
156  newWidget->hide();
[234]157 
158  //tab: avoid having only 1 tab (0, 2 or more)
[15]159  if (connectionsLayout.count() == 1) { // first connection
[234]160    connectionsWidget.at(0)->show();
161    hiddenTabName = name;
[15]162  }
[234]163  if (connectionsLayout.count() == 2) {
164    tabBar->addTab(hiddenTabName);
[15]165    currentTab = 0;
166  }
[234]167  if (connectionsLayout.count() > 1) {
168    tabBar->addTab(name);
[15]169  }
[9]170}
171
[244]172void Manager::udtSocketDestroyed(QObject *obj) {
173  udtSockets.removeOne((UdtSocket *)obj);
174}
175
[15]176void Manager::layoutDestroyed(QObject *obj) {
177  int index = connectionsLayout.indexOf((ConnectionLayout *)obj);
[9]178
[244]179  delete connectionsWidget.at(index);
180  connectionsWidget.removeAt(index);
181  connectionsLayout.removeOne((ConnectionLayout *)obj);
182 
[234]183  //tab: avoid having only 1 tab (0, 2 or more)
[15]184  if (tabBar->count() > 1) {
185    tabBar->removeTab(index);
186  }
[9]187
[15]188  if (connectionsLayout.count() == 1) {
189    hiddenTabName = tabBar->tabText(0);
190    tabBar->removeTab(0);
191  }
[30]192
193  if (connectionsLayout.count() == 0) {
194    status->showMessage("");
195  }
[244]196 
197 
[9]198}
199
[234]200void Manager::newFileUI(UDTSOCKET socket) {
201  //remove udtsocket as it will be automatically destroyed
202  udtSockets.removeOne((UdtSocket *)sender());
203 
204  QThread *thread = new QThread(this);
205  file_ui* fileUi = new file_ui(socket,name);
206  fileUi->moveToThread(thread);
207  connect(thread, SIGNAL(started()), fileUi, SLOT(receive()));
208  connect(fileUi, SIGNAL(finished()), this, SLOT(deleteFileUI()));
209  thread->start();
210}
211
212void Manager::deleteFileUI(void) {
213  sender()->thread()->quit();
214  delete sender();
215}
216
217void Manager::printUDTStats(QString stats) {
218  int index = connectionsLayout.indexOf((ConnectionLayout *)sender());
219  if(index==-1) return;
220 
221  if (tabBar->count() == 0) {
222    status->showMessage(stats);
223  } else if (index==tabBar->currentIndex()) {
224    status->showMessage(QString("%1: %2").arg(tabBar->tabText(index)).arg(stats));
225  }
226}
227
228void Manager::tabBarCurrentChanged(int index) {
[244]229 
[234]230  if (index >= 0) {
[244]231    //if we are coming from layout destroyed
232    if(currentTab<connectionsLayout.count()) connectionsWidget.at(currentTab)->hide();
[234]233    connectionsWidget.at(index)->show();
234    currentTab = index;
235  } else {
236    currentTab = 0;
237    connectionsWidget.at(0)->show();
238  }
239  if (tabBar->count() == 0) {
240    status->showMessage(connectionsLayout.at(0)->getUDTStats());
241  } else {
242    status->showMessage(QString("%1: %2").arg(tabBar->tabText(index)).arg(connectionsLayout.at(index)->getUDTStats()));
243  }
244}
245
[9]246void Manager::load(void) {
[15]247  QString dir_name =
248      QFileDialog::getExistingDirectory(this, "Select a directory", 0, 0);
[9]249
[15]250  if (dir_name != "") {
251    for (int i = 0; i < connectionsLayout.count(); i++) {
252      QFile *file;
253      file = new QFile(dir_name + "/" +
[234]254                       connectionsLayout.at(i)->getName() + ".xml");
[15]255      if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
256        QMessageBox::warning(this, "Warning",
257                             "Enable to load " +
[234]258                                 connectionsLayout.at(i)->getName() +
[15]259                                 ".xml");
260        continue;
261      }
[9]262
[15]263      QDomDocument doc;
264      QString errorMsg;
265      int errorLine;
266      int errorColumn;
267      if (!doc.setContent(file, &errorMsg, &errorLine, &errorColumn)) {
268        QMessageBox::critical(
269            this, "Error",
[234]270            "unable to read " + connectionsLayout.at(i)->getName() +
[15]271                ".xml" + " (" + errorMsg + " at " + QString::number(errorLine) +
272                "," + QString::number(errorColumn) + ")");
273      } else {
274        connectionsLayout.at(i)->LoadXml(doc);
275      }
276      delete file;
[9]277    }
[15]278  }
[9]279}
280
281void Manager::save(void) {
[15]282  bool isUptodate = true;
[9]283
[15]284  for (int i = 0; i < connectionsLayout.count(); i++) {
285    if (!connectionsLayout.at(i)->IsUptodate()) {
286      isUptodate = false;
287      break;
[9]288    }
[15]289  }
[9]290
[15]291  if (!isUptodate) {
292    QMessageBox msgBox;
293    msgBox.setText("There are pending modifications");
294    msgBox.setInformativeText("Apply and save?");
295    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
296    msgBox.setDefaultButton(QMessageBox::Yes);
297    int ret = msgBox.exec();
[9]298
[15]299    switch (ret) {
300    case QMessageBox::Yes:
301      send();
302      break;
303    case QMessageBox::Cancel:
304      return;
305      break;
306    default:
307      // should never be reached
308      break;
[9]309    }
[15]310  }
[9]311
[15]312  // create dirctory for storage
313  QDateTime dateTime = QDateTime::currentDateTime();
314  QString dir_name =
315      "configs_" + dateTime.toString("yyyyMMdd_hhmm") + "_" + name;
316  if (QDir().exists(dir_name) == true) {
317    dir_name = "configs_" + dateTime.toString("yyyyMMdd_hhmm_ss") + "_" + name;
318  }
319  QDir().mkdir(dir_name);
[9]320
[15]321  for (int i = 0; i < connectionsLayout.count(); i++) {
322    QDomDocument *xml = new QDomDocument("remote_ui_xml");
[9]323
[15]324    connectionsLayout.at(i)->GetFullXml((QDomElement *)xml);
[9]325
[234]326    QFile fichier(dir_name + "/" + connectionsLayout.at(i)->getName() +
[15]327                  ".xml");
328    QString write_doc = (xml->ownerDocument()).toString();
[9]329
[15]330    if (!fichier.open(QIODevice::WriteOnly)) {
331      fichier.close();
332      QMessageBox::critical(this, "Error", "Enable to write XML");
333      continue;
[9]334    }
[15]335    QTextStream stream(&fichier);
[234]336    stream << write_doc;
[15]337    fichier.close();
[9]338
[15]339    delete xml;
340  }
341
342  QMessageBox::information(this, "save all", "saved to ./" + dir_name);
[9]343}
344
345void Manager::send(void) {
[15]346  for (int i = 0; i < connectionsLayout.count(); i++) {
347    QDomDocument doc("remote_ui_xml");
348    connectionsLayout.at(i)->GetUpdateXml((QDomElement *)&doc);
[244]349    // fprintf(stderr,"merge\n%s\n",doc.toString().toLocal8Bit().constData());
[9]350
[15]351    connectionsLayout.at(i)->XmlToSend(doc);
352  }
[9]353}
354
355void Manager::reset() {
[15]356  for (int i = 0; i < connectionsLayout.count(); i++)
357    connectionsLayout.at(i)->ResetAllChilds();
[9]358}
Note: See TracBrowser for help on using the repository browser.