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
Line 
1// %flair:license{
2// This file is part of the Flair framework distributed under the
3// CECILL-C License, Version 1.0.
4// %flair:license}
5#include "Manager.h"
6#include "UdtSocket.h"
7#include "ConnectionLayout.h"
8#include "communication.h"
9#include "file_ui.h"
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>
20#include <QStatusBar>
21#include <qendian.h>
22#include <iostream>
23#include <string>
24#include <fstream>
25#include <stdio.h>
26
27#ifndef WIN32
28#include <arpa/inet.h>
29#else
30#include <winsock2.h>
31#include <ws2tcpip.h>
32#endif
33
34using namespace std;
35
36Manager::Manager(QString name, int port) : QWidget() {
37  qRegisterMetaType<QModelIndex>("QModelIndex"); // pour le file ui??
38  this->name = name;
39//ffprintf(stderr,stderr,"Manager %x\n",thread());
40  setWindowTitle(name);
41
42  // manager layout
43  managerLayout = new QVBoxLayout;
44  setLayout(managerLayout);
45
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;
52
53  // layout boutons
54  button_layout = new QGridLayout();
55  managerLayout->addLayout(button_layout);
56
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);
66
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()));
71
72  status=new QStatusBar();
73  status->setSizeGripEnabled(false);
74  button_layout->addWidget(status, 1,0);
75
76  UDT::startup();
77  serv = UDT::socket(AF_INET, SOCK_DGRAM, 0);
78
79  // for non blocking accept
80  bool blocking = false;
81  UDT::setsockopt(serv, 0, UDT_RCVSYN, &blocking, sizeof(bool));
82//UDT::setsockopt(serv, 0, UDT_CC, new CCCFactory<CUDPBlast>, sizeof(CCCFactory<CUDPBlast>));
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);
88
89  if (UDT::ERROR == UDT::bind(serv, (sockaddr *)&my_addr, sizeof(my_addr))) {
90    fprintf(stderr,"bind error, %s\n", UDT::getlasterror().getErrorMessage());
91  }
92
93  if (UDT::ERROR == UDT::listen(serv, 1)) {
94    fprintf(stderr,"listen error, %s\n", UDT::getlasterror().getErrorMessage());
95  }
96
97  QTimer *timer = new QTimer(this);
98  connect(timer, SIGNAL(timeout()), this, SLOT(acceptConnections()));
99  timer->start(500);
100}
101
102Manager::~Manager() {
103  for (int i = 0; i < udtSockets.count(); i++) {
104    udtSockets.at(i)->kill();
105    udtSockets.at(i)->thread()->wait();
106  }
107
108  // delete main_layout;
109  UDT::cleanup();
110}
111
112void Manager::acceptConnections(void) {
113  UDTSOCKET socket;
114
115  sockaddr_in their_addr;
116  int namelen = sizeof(their_addr);
117
118  if (UDT::INVALID_SOCK ==(socket = UDT::accept(serv, (sockaddr *)&their_addr, &namelen))) {
119    if (UDT::getlasterror().getErrorCode() != 6002)
120      fprintf(stderr,"accept error: %s, code %i\n", UDT::getlasterror().getErrorMessage(),UDT::getlasterror().getErrorCode());
121    return;
122  } else {
123    QString name=QString("%1:%2").arg(inet_ntoa(their_addr.sin_addr)).arg(their_addr.sin_port);
124    fprintf(stderr,"connected to %s\n",name.toLocal8Bit().constData());
125   
126    QThread *thread = new QThread(this);
127    UdtSocket *udtSocket = new UdtSocket(socket,name);
128    udtSocket->moveToThread(thread);
129    udtSockets.append(udtSocket);
130
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()));
134
135    thread->start(); 
136  }
137}
138
139void Manager::newConnectionLayout(QString name) {
140  UdtSocket* udtSocket=(UdtSocket *)sender();
141 
142  ConnectionLayout *newLayout = new ConnectionLayout(udtSocket, name);
143  connectionsLayout.append(newLayout);
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 *)));
148  connect(udtSocket, SIGNAL(destroyed(QObject *)), this, SLOT(udtSocketDestroyed(QObject *)));
149  connect(udtSocket, SIGNAL(destroyed()), newLayout, SLOT(deleteLater()));
150 
151   // widget
152  QWidget *newWidget = new QWidget();
153  connectionsWidget.append(newWidget);
154  newWidget->setLayout(newLayout->getQGridLayout());
155  managerLayout->insertWidget(1, newWidget);
156  newWidget->hide();
157 
158  //tab: avoid having only 1 tab (0, 2 or more)
159  if (connectionsLayout.count() == 1) { // first connection
160    connectionsWidget.at(0)->show();
161    hiddenTabName = name;
162  }
163  if (connectionsLayout.count() == 2) {
164    tabBar->addTab(hiddenTabName);
165    currentTab = 0;
166  }
167  if (connectionsLayout.count() > 1) {
168    tabBar->addTab(name);
169  }
170}
171
172void Manager::udtSocketDestroyed(QObject *obj) {
173  udtSockets.removeOne((UdtSocket *)obj);
174}
175
176void Manager::layoutDestroyed(QObject *obj) {
177  int index = connectionsLayout.indexOf((ConnectionLayout *)obj);
178
179  delete connectionsWidget.at(index);
180  connectionsWidget.removeAt(index);
181  connectionsLayout.removeOne((ConnectionLayout *)obj);
182 
183  //tab: avoid having only 1 tab (0, 2 or more)
184  if (tabBar->count() > 1) {
185    tabBar->removeTab(index);
186  }
187
188  if (connectionsLayout.count() == 1) {
189    hiddenTabName = tabBar->tabText(0);
190    tabBar->removeTab(0);
191  }
192
193  if (connectionsLayout.count() == 0) {
194    status->showMessage("");
195  }
196 
197 
198}
199
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) {
229 
230  if (index >= 0) {
231    //if we are coming from layout destroyed
232    if(currentTab<connectionsLayout.count()) connectionsWidget.at(currentTab)->hide();
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
246void Manager::load(void) {
247  QString dir_name =
248      QFileDialog::getExistingDirectory(this, "Select a directory", 0, 0);
249
250  if (dir_name != "") {
251    for (int i = 0; i < connectionsLayout.count(); i++) {
252      QFile *file;
253      file = new QFile(dir_name + "/" +
254                       connectionsLayout.at(i)->getName() + ".xml");
255      if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
256        QMessageBox::warning(this, "Warning",
257                             "Enable to load " +
258                                 connectionsLayout.at(i)->getName() +
259                                 ".xml");
260        continue;
261      }
262
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",
270            "unable to read " + connectionsLayout.at(i)->getName() +
271                ".xml" + " (" + errorMsg + " at " + QString::number(errorLine) +
272                "," + QString::number(errorColumn) + ")");
273      } else {
274        connectionsLayout.at(i)->LoadXml(doc);
275      }
276      delete file;
277    }
278  }
279}
280
281void Manager::save(void) {
282  bool isUptodate = true;
283
284  for (int i = 0; i < connectionsLayout.count(); i++) {
285    if (!connectionsLayout.at(i)->IsUptodate()) {
286      isUptodate = false;
287      break;
288    }
289  }
290
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();
298
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;
309    }
310  }
311
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);
320
321  for (int i = 0; i < connectionsLayout.count(); i++) {
322    QDomDocument *xml = new QDomDocument("remote_ui_xml");
323
324    connectionsLayout.at(i)->GetFullXml((QDomElement *)xml);
325
326    QFile fichier(dir_name + "/" + connectionsLayout.at(i)->getName() +
327                  ".xml");
328    QString write_doc = (xml->ownerDocument()).toString();
329
330    if (!fichier.open(QIODevice::WriteOnly)) {
331      fichier.close();
332      QMessageBox::critical(this, "Error", "Enable to write XML");
333      continue;
334    }
335    QTextStream stream(&fichier);
336    stream << write_doc;
337    fichier.close();
338
339    delete xml;
340  }
341
342  QMessageBox::information(this, "save all", "saved to ./" + dir_name);
343}
344
345void Manager::send(void) {
346  for (int i = 0; i < connectionsLayout.count(); i++) {
347    QDomDocument doc("remote_ui_xml");
348    connectionsLayout.at(i)->GetUpdateXml((QDomElement *)&doc);
349    // fprintf(stderr,"merge\n%s\n",doc.toString().toLocal8Bit().constData());
350
351    connectionsLayout.at(i)->XmlToSend(doc);
352  }
353}
354
355void Manager::reset() {
356  for (int i = 0; i < connectionsLayout.count(); i++)
357    connectionsLayout.at(i)->ResetAllChilds();
358}
Note: See TracBrowser for help on using the repository browser.