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

Last change on this file since 246 was 244, checked in by Sanahuja Guillaume, 7 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.