CrisisAlgorithmChecker::CrisisAlgorithmChecker(int numberOfCities, const vector<pair<int, int> > *connections, const vector<pair<int, int> > *toCut, int capitol) : m_numberOfCities(numberOfCities), m_capitol(capitol), m_toCut(toCut), m_result(numberOfCities), m_executed(false) { m_verticles = new VertexID[m_numberOfCities]; for (int i = 0; i < m_numberOfCities; ++i) { m_verticles[i] = boost::add_vertex(m_graph); m_graph[m_verticles[i]].m_id = i; } bool exist; bool ok; EdgeID edge; for (int i = 0; i < connections->size(); ++i) { boost::tie(edge, exist) = boost::edge( m_verticles[connections->at(i).first], m_verticles[connections->at(i).second], m_graph); if (exist) { m_graph[edge].m_isDouble = true; } else { boost::tie(edge, ok) = boost::add_edge( m_verticles[connections->at(i).first], m_verticles[connections->at(i).second], m_graph); if (!ok) throw InvalidArgumentsException( "Some troubles while edge adding"); } } }
void Node::addUnusedConnection(Node *other) { if (m_unused != 0L) { m_unused[other->m_id].setNode(other); //if(m_unused[other->m_id].isDouble()) cout<<"Jest double dla "<<other->m_id<<endl; } else throw InvalidArgumentsException("Node not initialized"); }
bool Node::removeUnusedConnectionWith(int id) { if (id >= m_size) { throw InvalidArgumentsException("Id out of bounds"); } Node *node = m_unused[id].removeOne(); if (node == 0L) { if (m_directChildren[id] != 0L) { m_directChildren[id] = 0L; return true; } if (m_parent != 0L) { if (m_parent->m_id == id) { m_parent = 0L; return true; } } } return (node != 0L); }
const CrisisAlgorithmResult& CrisisAlgorithmChecker::execute() { if (m_executed) return m_result; m_executed = true; m_months = 1; clock_t timeVal = clock(); vector<int> segments(boost::num_vertices(m_graph)); int nmbOfComponents = boost::connected_components(m_graph, &segments[0]); if (nmbOfComponents != 1) { int capitolComponent = segments[m_capitol]; int connectedWithCapitol = 0; for (int i = 0; i < m_numberOfCities; ++i) { if (segments[i] != capitolComponent) { if (m_result[i] == -1) { m_result.addResult(i, 0); } } else { ++connectedWithCapitol; } } if (connectedWithCapitol == 0) { timeVal = clock() - timeVal; m_result.addExecutionTime(timeVal); return m_result; } } bool exist; EdgeID edge; for (vector<pair<int, int> >::const_iterator it = m_toCut->begin(); it != m_toCut->end(); ++it, ++m_months) { boost::tie(edge, exist) = boost::edge(m_verticles[it->first], m_verticles[it->second], m_graph); if (exist) { if (m_graph[edge].m_isDouble) { m_graph[edge].m_isDouble = false; continue; } else { m_graph.remove_edge(edge); } } else { throw InvalidArgumentsException("No such connection"); } vector<int> component(boost::num_vertices(m_graph)); int nmbOfComponents = boost::connected_components(m_graph, &component[0]); if (nmbOfComponents != 1) { int capitolComponent = component[m_capitol]; int connectedWithCapitol = 0; for (int i = 0; i < m_numberOfCities; ++i) { if (component[i] != capitolComponent) { if (m_result[i] == -1) { m_result.addResult(i, m_months); } } else { ++connectedWithCapitol; } } if (connectedWithCapitol == 0) break; } } timeVal = clock() - timeVal; m_result.addExecutionTime(timeVal); return m_result; }
/*!\brief Lese-Timeout festlegen * * Mit dieser Funktion kann ein Timeout für Lesezugriffe gesetzt werden. Normalerweise * blockiert eine Leseoperation mit "Read" solange, bis die angeforderten Daten * eingegangen sind (ausser der Socket wurde mit TCPSocket::setBlocking auf "Non-Blocking" * gesetzt). Mit dieser Funktion kann jedoch ein beliebiger mikrosekunden genauer * Timeout festgelegt werden. Der Timeout errechnet sich dabei aus * \p seconds + \p useconds. * \par * Um den Timeout wieder abzustellen, kann die Funktion mit 0 als * Wert für \p seconds und \p useconds aufgerufen werden. * * @param[in] seconds Anzahl Sekunden * @param[in] useconds Anzahl Mikrosekunden (1000000 Mikrosekunden = 1 Sekunde) * @exception NotConnectedException * @exception InvalidSocketException * @exception BadFiledescriptorException * @exception UnknownOptionException * @exception BadAddressException * @exception InvalidArgumentsException */ void UDPSocket::setTimeoutRead(int seconds, int useconds) { if (!connected) throw NotConnectedException(); struct timeval tv; tv.tv_sec = seconds; tv.tv_usec = useconds; PPLSOCKET *s = (PPLSOCKET*) socket; #ifdef WIN32 if (setsockopt(s->sd,SOL_SOCKET,SO_RCVTIMEO,(const char*)&tv,sizeof(tv))!=0) { #else if (setsockopt(s->sd, SOL_SOCKET, SO_RCVTIMEO, (void*) &tv, sizeof(tv)) != 0) { #endif throwExceptionFromErrno(errno, "setTimeoutRead"); } } /*!\brief Schreib-Timeout festlegen * * Mit dieser Funktion kann ein Timeout für Schreibzugriffe gesetzt werden. Normalerweise * blockiert eine Schreiboperation mit "Write" solange, bis alle Daten gesendet wurden. * Mit dieser Funktion kann jedoch ein beliebiger mikrosekunden genauer * Timeout festgelegt werden. Der Timeout errechnet sich dabei aus * \p seconds + \p useconds. * \par * Um den Timeout wieder abzustellen, kann die Funktion mit 0 als * Wert für \p seconds und \p useconds aufgerufen werden. * * @param[in] seconds Anzahl Sekunden * @param[in] useconds Anzahl Mikrosekunden (1000000 Mikrosekunden = 1 Sekunde) * @exception NotConnectedException * @exception InvalidSocketException * @exception BadFiledescriptorException * @exception UnknownOptionException * @exception BadAddressException * @exception InvalidArgumentsException */ void UDPSocket::setTimeoutWrite(int seconds, int useconds) { if (!connected) throw NotConnectedException(); struct timeval tv; tv.tv_sec = seconds; tv.tv_usec = useconds; PPLSOCKET *s = (PPLSOCKET*) socket; #ifdef WIN32 if (setsockopt(s->sd,SOL_SOCKET,SO_SNDTIMEO,(const char*)&tv,sizeof(tv))!=0) { #else if (setsockopt(s->sd, SOL_SOCKET, SO_SNDTIMEO, (void*) &tv, sizeof(tv)) != 0) { #endif throwExceptionFromErrno(errno, "setTimeoutRead"); } } /*!\brief Auf eingehende Daten warten * * \desc * Diese Funktion prüft, ob Daten eingegangen sind. Ist dies der Fall, * kehrt sie sofort wieder zurück. Andernfalls wartet sie solange, bis * Daten eingehen, maximal aber die mit \p seconds und \p useconds * angegebene Zeitspanne. Falls \p seconds und \p useconds Null sind, und * keine Daten bereitstehen, kehrt die Funktion sofort zurück. * * @param[in] seconds Anzahl Sekunden, die gewartet werden soll * @param[in] useconds Anzahl Mikrosekunden, die gewartet werden soll * @return Die Funktion gibt \b true zurück, wenn Daten zum Lesen bereitstehen, * sonst \b false. Im Fehlerfall wird eine Exception geworfen. * @exception Diverse */ bool UDPSocket::waitForIncomingData(int seconds, int useconds) { if (!connected) throw NotConnectedException(); PPLSOCKET *s=(PPLSOCKET*)socket; fd_set rset, wset, eset; struct timeval timeout; timeout.tv_sec=seconds; timeout.tv_usec=useconds; FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset); FD_SET(s->sd,&rset); // Wir wollen nur prüfen, ob was zu lesen da ist int ret=select(s->sd+1,&rset,&wset,&eset,&timeout); if (ret<0) { throwExceptionFromErrno(errno, "UDPSocket::waitForIncomingData"); } if (FD_ISSET(s->sd,&eset)) { throw OutOfBandDataReceivedException("UDPSocket::waitForIncomingData"); } // Falls Daten zum Lesen bereitstehen, könnte dies auch eine Verbindungstrennung anzeigen if (FD_ISSET(s->sd,&rset)) { char buf[2]; ret=recv(s->sd, buf,1, MSG_PEEK|MSG_DONTWAIT); // Kommt hier ein Fehler zurück? if (ret<0) { throwExceptionFromErrno(errno, "UDPSocket::isReadable"); } // Ein Wert von 0 zeigt an, dass die Verbindung getrennt wurde if (ret==0) { throw BrokenPipeException(); } return true; } return false; } /*!\brief Warten, bis der Socket beschreibbar ist * * \desc * Diese Funktion prüft, ob Daten auf den Socket geschrieben werden können. * Ist dies der Fall, kehrt sie sofort wieder zurück. Andernfalls wartet * sie solange, bis der Socket beschrieben werden kann, maximal aber die * mit \p seconds und \p useconds angegebene Zeitspanne. * Falls \p seconds und \p useconds Null sind, und * keine Daten gesendet werden können, kehrt die Funktion sofort zurück. * * @param[in] seconds Anzahl Sekunden, die gewartet werden soll * @param[in] useconds Anzahl Mikrosekunden, die gewartet werden soll * @return Die Funktion gibt \b true zurück, wenn Daten geschrieben werden können, * sonst \b false. Im Fehlerfall wird eine Exception geworfen. * @exception Diverse * */ bool UDPSocket::waitForOutgoingData(int seconds, int useconds) { if (!connected) throw NotConnectedException(); PPLSOCKET *s=(PPLSOCKET*)socket; fd_set rset, wset, eset; struct timeval timeout; timeout.tv_sec=seconds; timeout.tv_usec=useconds; FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset); FD_SET(s->sd,&wset); // Wir wollen nur prüfen, ob wir schreiben können int ret=select(s->sd+1,&rset,&wset,&eset,&timeout); if (ret<0) { throwExceptionFromErrno(errno, "UDPSocket::waitForOutgoingData"); } if (FD_ISSET(s->sd,&eset)) { throw OutOfBandDataReceivedException("UDPSocket::waitForIncomingData"); } if (FD_ISSET(s->sd,&wset)) { return true; } return false; } /*!\brief Bei Lesezugriffen blockieren * * \desc * Durch Aufruf dieser Funktion kann festgelegt werden, ob der Socket bei Lesezugriffen * blockieren soll. Nach dem Öffnen des Sockets ist dieser defaultmäßig so * eingestellt, dass er bei Lesezugriffen solange blockiert (wartet), bis Daten zur * Verfügung stehen. Wird er auf "Non-Blocking" gestellt, kehren die Lese-Funktionen * sofort mit einer Fehlermeldung zurück, wenn noch keine Daten bereitstehen. * * @param[in] value Der Wert "true" setzt den Socket in den Blocking-Modus, was auch der * Default ist. Durch den Wert "false" wird er in den Non-Blocking-Modus gesetzt. * @exception Diverse */ void UDPSocket::setBlocking(bool value) { PPLSOCKET *s=(PPLSOCKET*)socket; if((!s) || (!s->sd)) throw NotConnectedException(); int ret=0; #ifdef _WIN32 u_long v; if (value) { v=0; ret=ioctlsocket(s->sd,FIONBIO,NULL); } else { v=1; ret=ioctlsocket(s->sd,FIONBIO,&v); } if (ret==0) return; throwExceptionFromErrno(errno, "UDPSocket::setBlocking"); #else if (value) ret=fcntl(s->sd,F_SETFL,fcntl(s->sd,F_GETFL,0)&(~O_NONBLOCK)); // Blocking else ret=fcntl(s->sd,F_SETFL,fcntl(s->sd,F_GETFL,0)|O_NONBLOCK);// NON-Blocking if (ret<0) throwExceptionFromErrno(errno, "UDPSocket::setBlocking"); #endif } /*!\brief Socket auf eine IP-Adresse und Port binden * * \desc * Diese Funktion muss aufgerufen werden, bevor man mit CTCPSocket::Listen einen TCP-Server starten kann. Dabei wird mit \p host * die IP-Adresse festgelegt, auf die sich der Server binden soll und mit \p port der TCP-Port. * Es ist nicht möglich einen Socket auf mehrere Adressen zu binden. * * @param[in] host IP-Adresse, Hostname oder "*". Bei Angabe von "*" bindet sich der Socket auf alle * Interfaces des Servers. * @param[in] port Der gewünschte TCP-Port * @exception OutOfMemoryException * @exception ResolverException * @exception SettingSocketOptionException * @exception CouldNotBindToInterfaceException * @exception CouldNotOpenSocketException */ void UDPSocket::bind(const String &host, int port) { //int addrlen=0; if (!socket) { socket=malloc(sizeof(PPLSOCKET)); if (!socket) throw OutOfMemoryException(); PPLSOCKET *s=(PPLSOCKET*)socket; s->sd=0; s->proto=6; s->ipname=NULL; s->port=port; //s->addrlen=0; } #ifdef _WIN32 SOCKET listenfd=0; #else int listenfd=0; #endif PPLSOCKET *s=(PPLSOCKET*)socket; if (s->sd) disconnect(); if (s->ipname) free(s->ipname); s->ipname=NULL; struct addrinfo hints; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_flags=AI_PASSIVE; hints.ai_family=AF_UNSPEC; hints.ai_socktype=SOCK_DGRAM; int on=1; // Prüfen, ob host ein Wildcard ist struct addrinfo *res; if (host.notEmpty()==true && host!="*") { char portstr[10]; sprintf(portstr,"%i",port); int n; if ((n=getaddrinfo(host,portstr,&hints,&res))!=0) { throw ResolverException("%s, %s",(const char*)host,gai_strerror(n)); } struct addrinfo *ressave=res; do { listenfd=::socket(res->ai_family,res->ai_socktype,res->ai_protocol); if (listenfd<0) continue; // Error, try next one #ifdef _WIN32 if (setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,(const char*)&on,sizeof(on))!=0) { #else if (setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))!=0) { #endif freeaddrinfo(ressave); throw SettingSocketOptionException(); } if (::bind(listenfd,res->ai_addr,res->ai_addrlen)==0) { //addrlen=res->ai_addrlen; break; } ::shutdown(listenfd,2); #ifdef _WIN32 closesocket(listenfd); #else close(listenfd); #endif listenfd=0; } while ((res=res->ai_next)!=NULL); freeaddrinfo(ressave); } else { // Auf alle Interfaces binden listenfd=::socket(AF_INET, SOCK_STREAM, 0); if (listenfd>=0) { struct sockaddr_in addr; memset(&addr,0,sizeof(addr)); addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(port); addr.sin_family = AF_INET; /* bind server port */ if(::bind(listenfd, (struct sockaddr *) &addr, sizeof(addr))!=0) { ::shutdown(listenfd,2); #ifdef _WIN32 closesocket(listenfd); #else close(listenfd); #endif throw CouldNotBindToInterfaceException("Host: *, Port: %d",port); } s->sd=listenfd; connected=1; return; } } if (listenfd<0) { throw CouldNotOpenSocketException("Host: %s, Port: %d",(const char*)host,port); } if (res==NULL) { throw CouldNotBindToInterfaceException("Host: %s, Port: %d",(const char*)host,port); } s->sd=listenfd; connected=1; } /*!\brief Daten schreiben * * \desc * Mit dieser Funktionen werden \p bytes Bytes aus dem Speicherbereich \p buffer an die Gegenstelle * gesendet. * * @param[in] buffer Pointer auf die zu sendenden Daten * @param[in] bytes Anzahl zu sendender Bytes * @return Wenn die Daten erfolgreich geschrieben wurden, gibt die Funktion die Anzahl geschriebener * Bytes zurück. Im Fehlerfall wird eine Exception geworfen. */ size_t UDPSocket::write(const void *buffer, size_t bytes) { if (!connected) throw NotConnectedException(); PPLSOCKET *s = (PPLSOCKET*) socket; if (!buffer) throw InvalidArgumentsException(); size_t BytesWritten = 0; if (bytes) { size_t rest = bytes; ssize_t b = 0; while (rest) { b = ::send(s->sd, (char *) buffer, rest, 0); if (b > 0) { BytesWritten += b; rest -= b; buffer = ((const char*) buffer) + b; } #ifdef WIN32 if (b==SOCKET_ERROR) { #else if (b < 0) { #endif if (errno == EAGAIN) { waitForOutgoingData(0, 100000); } else { throwExceptionFromErrno(errno, "UDPSocket::write"); } } } } return BytesWritten; } size_t UDPSocket::write(const String &str, size_t bytes) { if (bytes>0 && bytes<=str.size()) { return write(str.getPtr(),bytes); } return write(str.getPtr(),str.size()); } size_t UDPSocket::write(const WideString &str, size_t bytes) { if (bytes>0 && bytes<=str.byteLength()) { return write(str.getPtr(),bytes); } return write(str.getPtr(),str.byteLength()); } size_t UDPSocket::write(const ByteArrayPtr &bin, size_t bytes) { if (bytes>0 && bytes<=bin.size()) { return write(bin.ptr(),bytes); } return write(bin.ptr(),bin.size()); } size_t UDPSocket::writef(const char *fmt, ...) { if (!fmt) throw IllegalArgumentException(); String str; va_list args; va_start(args, fmt); str.vasprintf(fmt,args); va_end(args); return write(str); } #ifdef TODO void UDPSocket::setTimeoutRead(int seconds, int useconds) /*! \brief Timeout setzen * * \header \#include <ppl6.h> * \desc * Mit dieser Funktion wird der Timeout für das Empfangen von Daten gesetzt. * * \param seconds Anzahl Sekunden * \param useconds Anzahl Millisekunden * \note Diese Funktion hat zur Zeit noch keine Auswirkungen * \since Wurde mit Version 6.0.19 eingeführt */ { timeout_sec=seconds; timeout_usec=useconds; } #endif #ifdef TODO size_t UDPSocket::sendTo(const String &host, int port, const String &buffer) /*! \brief UDP-Packet verschicken * * \header \#include <ppl6.h> * \desc * Mit dieser Funktion wird ein UDP-Paket an den angegebenen Host verschickt. * * \param host Der Name oder die IP-Adresse des Zielrechners * \param port Der Port des Zielrechners * \param buffer Ein Pointer auf eine String-Klasse, die die zu sendenden Daten enthält * \returns Im Erfolgsfall liefert die Funktion die Anzahl gesendeter Bytes zurück, im Fehlerfall -1. * Der Fehlercode kann über die üblichen Fehler-Funktionen ausgelesen werden * * \since Wurde mit Version 6.0.19 eingeführt */ { return sendTo(host,port,(const void *)buffer.getPtr(),buffer.len()); } size_t UDPSocket::sendTo(const String &host, int port, const void *buffer, size_t bytes) /*! \brief UDP-Packet verschicken * * \header \#include <ppl6.h> * \desc * Mit dieser Funktion wird ein UDP-Paket an den angegebenen Host verschickt. * * \param host Der Name oder die IP-Adresse des Zielrechners * \param port Der Port des Zielrechners * \param buffer Ein Pointer auf den Puffer, der die zu sendenden Daten enthält * \param bytes Die Anzahl Bytes im Puffer, die gesendet werden sollen * \returns Im Erfolgsfall liefert die Funktion die Anzahl gesendeter Bytes zurück, im Fehlerfall -1. * Der Fehlercode kann über die üblichen Fehler-Funktionen ausgelesen werden * * \since Wurde mit Version 6.0.19 eingeführt */ { if (!host) { ppl6::SetError(194,"int UDPSocket::SendTo(==> char *host <== , int port, void *buffer, int bytes)"); return -1; } if (!port) { ppl6::SetError(194,"int UDPSocket::SendTo(char *host, ==> int port <== , void *buffer, int bytes)"); return -1; } if (!buffer) { ppl6::SetError(194,"int UDPSocket::SendTo(char *host, int port, ==> void *buffer <== , int bytes)"); return -1; } if (bytes<0) { ppl6::SetError(194,"int UDPSocket::SendTo(char *host, int port, void *buffer, ==> int bytes <== )"); return -1; } ppl6::CAssocArray res, *a; ppl6::CBinary *bin; if (!ppl6::GetHostByName(host,&res)) return -1; a=res.GetFirstArray(); //a->List(); int domain, type, protocol; domain=ppl6::atoi(a->Get("ai_family")); type=ppl6::atoi(a->Get("ai_socktype")); //protocol=ppl6::atoi(a->Get("ai_protocol")); struct protoent *proto=getprotobyname("UDP"); if (!proto) { ppl6::SetError(395); return -1; } protocol=proto->p_proto; bin=a->GetBinary("ai_addr"); //a->List(); const struct sockaddr *to=(const struct sockaddr *)bin->GetPtr(); ((sockaddr_in*)to)->sin_port=htons(port); PPLSOCKET *s=(PPLSOCKET*)socket; if (!s) { socket=malloc(sizeof(PPLSOCKET)); s=(PPLSOCKET*)socket; s->sd=-1; } else if ((int)s->sd>-1) { ppl_closesocket(s->sd); } s->sd=::socket(domain,SOCK_DGRAM,protocol); //sockfd=::socket(AF_INET,SOCK_DGRAM,0); if (s->sd<0) { SetSocketError(); return -1; } #ifdef _WIN32 int ret=::sendto(s->sd,(const char*)buffer,bytes,0,to,bin->GetSize()); #else ssize_t ret=::sendto(s->sd,(const void*)buffer,(size_t)bytes,0,to,(socklen_t) bin->GetSize()); #endif if (ret<0) { printf ("ret: %i\n",(int)ret); SetSocketError(); return -1; } //close(sockfd); return ret; } int UDPSocket::RecvFrom(CString &buffer, int maxlen) /*! \brief UDP-Packet empfangen * * \header \#include <ppl6.h> * \desc * Diese Funktion wartet auf ein UDP-Packet * * \param buffer Ein Pointer auf eine String-Klasse, in die die Daten geschrieben werden sollen * \param maxlen Die maximale Anzahl Bytes, die in den Puffer geschrieben werden können * \returns Im Erfolgsfall liefert die Funktion die Anzahl gelesener Bytes zurück, im Fehlerfall -1. * Der Fehlercode kann über die üblichen Fehler-Funktionen ausgelesen werden * * \since Wurde mit Version 6.0.19 eingeführt */ { char *b=(char*)malloc(maxlen+1); if (!b) { SetError(2); return 0; } int ret=RecvFrom((void*)b,maxlen); buffer.ImportBuffer(b,maxlen); return ret; }