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

Last change on this file since 247 was 247, checked in by Sanahuja Guillaume, 6 years ago

improve gcs disconnections

File size: 11.5 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 //tabBar->setTabsClosable(true);
49 managerLayout->addWidget(tabBar);
50 connect(tabBar, SIGNAL(currentChanged(int)), this,
51 SLOT(tabBarCurrentChanged(int)));
52 currentTab = 0;
53
54 // layout boutons
55 button_layout = new QGridLayout();
56 managerLayout->addLayout(button_layout);
57
58 // boutons du button_Layout
59 send_button = new QPushButton("apply all");
60 reset_button = new QPushButton("reset all");
61 load_button = new QPushButton("load all locally");
62 save_button = new QPushButton("save all locally");
63 button_layout->addWidget(send_button, 0, 0);
64 button_layout->addWidget(reset_button, 0, 1);
65 button_layout->addWidget(load_button, 0, 2);
66 button_layout->addWidget(save_button, 0, 3);
67
68 connect(send_button, SIGNAL(clicked(bool)), this, SLOT(send()));
69 connect(reset_button, SIGNAL(clicked(bool)), this, SLOT(reset()));
70 connect(load_button, SIGNAL(clicked(bool)), this, SLOT(load()));
71 connect(save_button, SIGNAL(clicked(bool)), this, SLOT(save()));
72
73 status=new QStatusBar();
74 status->setSizeGripEnabled(false);
75 button_layout->addWidget(status, 1,0);
76
77 UDT::startup();
78 serv = UDT::socket(AF_INET, SOCK_DGRAM, 0);
79
80 // for non blocking accept
81 bool blocking = false;
82 UDT::setsockopt(serv, 0, UDT_RCVSYN, &blocking, sizeof(bool));
83//UDT::setsockopt(serv, 0, UDT_CC, new CCCFactory<CUDPBlast>, sizeof(CCCFactory<CUDPBlast>));
84 sockaddr_in my_addr;
85 my_addr.sin_family = AF_INET;
86 my_addr.sin_port = htons(port);
87 my_addr.sin_addr.s_addr = INADDR_ANY;
88 memset(&(my_addr.sin_zero), '\0', 8);
89
90 if (UDT::ERROR == UDT::bind(serv, (sockaddr *)&my_addr, sizeof(my_addr))) {
91 fprintf(stderr,"bind error, %s\n", UDT::getlasterror().getErrorMessage());
92 }
93
94 if (UDT::ERROR == UDT::listen(serv, 1)) {
95 fprintf(stderr,"listen error, %s\n", UDT::getlasterror().getErrorMessage());
96 }
97
98
99 icon_ok = QIcon(":green.png");
100 icon_ko = QIcon(":red.png");
101
102
103 QTimer *timer = new QTimer(this);
104 connect(timer, SIGNAL(timeout()), this, SLOT(acceptConnections()));
105 timer->start(500);
106}
107
108Manager::~Manager() {
109 for (int i = 0; i < connections.count(); i++) {
110 connections.at(i).socket->kill();
111 connections.at(i).socket->thread()->wait();
112 }
113
114 // delete main_layout;
115 UDT::cleanup();
116}
117
118void Manager::acceptConnections(void) {
119 UDTSOCKET socket;
120
121 sockaddr_in their_addr;
122 int namelen = sizeof(their_addr);
123
124 if (UDT::INVALID_SOCK ==(socket = UDT::accept(serv, (sockaddr *)&their_addr, &namelen))) {
125 if (UDT::getlasterror().getErrorCode() != 6002)
126 fprintf(stderr,"accept error: %s, code %i\n", UDT::getlasterror().getErrorMessage(),UDT::getlasterror().getErrorCode());
127 return;
128 } else {
129 QString name=QString("%1:%2").arg(inet_ntoa(their_addr.sin_addr)).arg(their_addr.sin_port);
130 fprintf(stderr,"connected to %s\n",name.toLocal8Bit().constData());
131
132 QThread *thread = new QThread(this);
133 UdtSocket *udtSocket = new UdtSocket(socket,name);
134 udtSocket->moveToThread(thread);
135
136 connect(udtSocket, SIGNAL(newFileUI(UDTSOCKET)), this, SLOT(newFileUI(UDTSOCKET)));
137 connect(udtSocket, SIGNAL(newConnectionLayout(QString)), this, SLOT(newConnectionLayout(QString)),Qt::BlockingQueuedConnection);
138 connect(thread, SIGNAL(started()), udtSocket, SLOT(receiveData()));
139
140 thread->start();
141 }
142}
143
144void Manager::newConnectionLayout(QString name) {
145 UdtSocket* udtSocket=(UdtSocket *)sender();
146
147 ConnectionLayout *newLayout = new ConnectionLayout(udtSocket, name);
148 connect(udtSocket, SIGNAL(UDTStats(QString)), newLayout, SIGNAL(UDTStats(QString)));//connection in 2 steps to get udtsocket as sender
149 connect(newLayout, SIGNAL(UDTStats(QString)), this, SLOT(printUDTStats(QString)));
150 connect(udtSocket, SIGNAL(dataReady(char *, int)), newLayout,SLOT(receive(char *, int)),Qt::BlockingQueuedConnection);
151 connect(newLayout, SIGNAL(destroyed(QObject *)), this, SLOT(layoutDestroyed(QObject *)));
152 connect(udtSocket, SIGNAL(destroyed(QObject *)), this, SLOT(udtSocketDestroyed(QObject *)));
153
154 // widget
155 QWidget *newWidget = new QWidget();
156 newWidget->setLayout(newLayout->getQGridLayout());
157 managerLayout->insertWidget(1, newWidget);
158 newWidget->hide();
159
160 connections_t connection;
161 connection.layout=newLayout;
162 connection.widget=newWidget;
163 connection.socket=udtSocket;
164 connections.append(connection);
165
166 //tab: avoid having only 1 tab (0, 2 or more)
167 if (connections.count() == 1) { // first connection
168 newWidget->show();
169 hiddenTabName = name;
170 }
171 if (connections.count() == 2) {
172 tabBar->addTab(icon_ok,hiddenTabName);
173 currentTab = 0;
174 }
175 if (connections.count() > 1) {
176 tabBar->addTab(icon_ok,name);
177 }
178}
179
180void Manager::udtSocketDestroyed(QObject *obj) {
181 fprintf(stderr,"sockets -1\n");
182 //mark socket as not valid, it can be a connection lost
183 //in this case we keep the layout for reading, and mark it as problematic
184 fprintf(stderr,"change icon\n");
185 for(int i=0;i<connections.count();i++) {
186 if(connections.at(i).socket==(UdtSocket *)obj) {
187 connections[i].socket=NULL;
188 break;
189 }
190 }
191}
192
193void Manager::layoutDestroyed(QObject *obj) {
194 fprintf(stderr,"layout -1\n");
195 //remove the connection, it comes from a proper close
196 int index=-1;
197 for(int i=0;i<connections.count();i++) {
198 if(connections.at(i).layout==(ConnectionLayout *)obj) {
199 delete connections.at(i).widget;
200 //connections[i].widget=NULL;
201 //connections[i].layout=NULL;
202 connections.removeAt(i);
203 index=i;
204 break;
205 }
206 }
207
208 if(index==-1) {
209 fprintf(stderr,"layoutDestroyed: error, layout not found!\n");
210 return;
211 }
212
213 //tab: avoid having only 1 tab (only 0, 2 or more)
214 if (tabBar->count() > 1) {
215 tabBar->removeTab(index);
216 }
217
218 if (connections.count() == 1) {
219 hiddenTabName = tabBar->tabText(0);
220 tabBar->removeTab(0);
221 }
222
223 if (connections.count() == 0) {
224 status->showMessage("");
225 }
226}
227
228void Manager::newFileUI(UDTSOCKET socket) {
229 QThread *thread = new QThread(this);
230 file_ui* fileUi = new file_ui(socket,name);
231 fileUi->moveToThread(thread);
232 connect(thread, SIGNAL(started()), fileUi, SLOT(receive()));
233 connect(fileUi, SIGNAL(finished()), this, SLOT(deleteFileUI()));
234 thread->start();
235}
236
237void Manager::deleteFileUI(void) {
238 sender()->thread()->quit();
239 delete sender();
240}
241
242void Manager::printUDTStats(QString stats) {
243 int index = -1;
244 for(int i=0;i<connections.count();i++) {
245 if(connections.at(i).layout==(ConnectionLayout *)sender()) {
246 index=i;
247 break;
248 }
249 }
250
251 if(index==-1) return;
252
253 if (tabBar->count() == 0) {
254 status->showMessage(stats);
255 } else if (index==tabBar->currentIndex()) {
256 status->showMessage(QString("%1: %2").arg(tabBar->tabText(index)).arg(stats));
257 }
258}
259
260void Manager::tabBarCurrentChanged(int index) {
261
262 if (index >= 0) {
263 //if we are coming from layout destroyed
264 if(currentTab<connections.count()) connections.at(currentTab).widget->hide();
265 connections.at(index).widget->show();
266 currentTab = index;
267 } else {
268 currentTab = 0;
269 connections.at(0).widget->show();
270 }
271 QString msg="not connected";
272 if (tabBar->count() == 0) {
273 if(connections.at(0).socket!=NULL) msg=connections.at(0).socket->getUDTStats();
274
275 } else {
276 if(connections.at(index).socket!=NULL) msg=QString("%1: %2").arg(tabBar->tabText(index)).arg(connections.at(index).socket->getUDTStats());
277 }
278 status->showMessage(msg);
279}
280
281void Manager::load(void) {
282 QString dir_name =
283 QFileDialog::getExistingDirectory(this, "Select a directory", 0, 0);
284
285 if (dir_name != "") {
286 for (int i = 0; i < connections.count(); i++) {
287 QFile *file;
288 file = new QFile(dir_name + "/" +
289 connections.at(i).layout->getName() + ".xml");
290 if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
291 QMessageBox::warning(this, "Warning",
292 "Enable to load " +
293 connections.at(i).layout->getName() +
294 ".xml");
295 continue;
296 }
297
298 QDomDocument doc;
299 QString errorMsg;
300 int errorLine;
301 int errorColumn;
302 if (!doc.setContent(file, &errorMsg, &errorLine, &errorColumn)) {
303 QMessageBox::critical(
304 this, "Error",
305 "unable to read " + connections.at(i).layout->getName() +
306 ".xml" + " (" + errorMsg + " at " + QString::number(errorLine) +
307 "," + QString::number(errorColumn) + ")");
308 } else {
309 connections.at(i).layout->LoadXml(doc);
310 }
311 delete file;
312 }
313 }
314}
315
316void Manager::save(void) {
317 bool isUptodate = true;
318
319 for (int i = 0; i < connections.count(); i++) {
320 if (!connections.at(i).layout->IsUptodate()) {
321 isUptodate = false;
322 break;
323 }
324 }
325
326 if (!isUptodate) {
327 QMessageBox msgBox;
328 msgBox.setText("There are pending modifications");
329 msgBox.setInformativeText("Apply and save?");
330 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
331 msgBox.setDefaultButton(QMessageBox::Yes);
332 int ret = msgBox.exec();
333
334 switch (ret) {
335 case QMessageBox::Yes:
336 send();
337 break;
338 case QMessageBox::Cancel:
339 return;
340 break;
341 default:
342 // should never be reached
343 break;
344 }
345 }
346
347 // create dirctory for storage
348 QDateTime dateTime = QDateTime::currentDateTime();
349 QString dir_name =
350 "configs_" + dateTime.toString("yyyyMMdd_hhmm") + "_" + name;
351 if (QDir().exists(dir_name) == true) {
352 dir_name = "configs_" + dateTime.toString("yyyyMMdd_hhmm_ss") + "_" + name;
353 }
354 QDir().mkdir(dir_name);
355
356 for (int i = 0; i < connections.count(); i++) {
357 QDomDocument *xml = new QDomDocument("remote_ui_xml");
358
359 connections.at(i).layout->GetFullXml((QDomElement *)xml);
360
361 QFile fichier(dir_name + "/" + connections.at(i).layout->getName() +
362 ".xml");
363 QString write_doc = (xml->ownerDocument()).toString();
364
365 if (!fichier.open(QIODevice::WriteOnly)) {
366 fichier.close();
367 QMessageBox::critical(this, "Error", "Enable to write XML");
368 continue;
369 }
370 QTextStream stream(&fichier);
371 stream << write_doc;
372 fichier.close();
373
374 delete xml;
375 }
376
377 QMessageBox::information(this, "save all", "saved to ./" + dir_name);
378}
379
380void Manager::send(void) {
381 for (int i = 0; i < connections.count(); i++) {
382 QDomDocument doc("remote_ui_xml");
383 connections.at(i).layout->GetUpdateXml((QDomElement *)&doc);
384 // fprintf(stderr,"merge\n%s\n",doc.toString().toLocal8Bit().constData());
385
386 connections.at(i).layout->XmlToSend(doc);
387 }
388}
389
390void Manager::reset() {
391 for (int i = 0; i < connections.count(); i++)
392 connections.at(i).layout->ResetAllChilds();
393}
Note: See TracBrowser for help on using the repository browser.