#include #if !defined(CMW_WINDOWS) #include #include #include #include #include #include // chdir #endif #include #include #include #include #include #include #include #include #include #include #include using namespace cmw; sock_type connect2CMW (cmwa_config_data const& configData) { sock_type sockfd = cmw::getSocket(SOCK_STREAM); #if 0 sockaddr_in SockAddr; SockAddr.sin_family = AF_INET; SockAddr.sin_port = htons(56791); SockAddr.sin_addr.s_addr = inet_addr("10.0.0.184"); if (::connect(sockfd, (sockaddr*)(&SockAddr), sizeof(SockAddr)) == 0) { return sockfd; } #else for (;;) { #ifdef CMW_WINDOWS int const basePort = 56791; #else int const basePort = 56789; #endif ::std::string node(configData.localhost ? "127.0.0.1" : "www.webEbenezer.net"); for (int j = 0; j < 6; ++j) { addrinfo *res; getaddrinfo_wrapper(node.c_str(), basePort + j % 2, &res); if (::connect(sockfd, res->ai_addr, res->ai_addrlen) == 0) { freeaddrinfo(res); #ifdef SYSLOG_AVAILABLE syslog(LOG_INFO, "connected to CMW on port %d", basePort + j % 2); #endif return sockfd; } // 111 is connection refused and 113 is no route to host. printf("connect() failed on port %d. errno is %d\n" , basePort + j % 2, GetError()); freeaddrinfo(res); } #ifdef CMW_WINDOWS Sleep(configData.sleepseconds * 1000); #else sleep(configData.sleepseconds); #endif } #endif } void changeDirectory (char const* dir) { #ifdef CMW_WINDOWS if (!SetCurrentDirectory(dir)) { #else if (chdir(dir) == -1) { #endif throw failure("changeDirectory failed on ") << dir << " " << GetError(); } } void verifyAccountNbr (int32_t accountNbr , cmwa_config_data const& configData ) { for (auto const & it: configData.accounts) { if (it.accountnumber.value == accountNbr) { return; } } throw failure("The following account number is not logged in: ") << accountNbr; } cmw_request getRequest (uint8_t byteOrder , sock_type sock) { static ReceiveBufferTCP localbuf(4096); #ifdef CMW_ENDIAN_BIG static ReceiveBufferTCP otherlocalbuf(4096); #else static ReceiveBufferTCP otherlocalbuf(4096); #endif uint8_t clientFormat; Read(sock, &clientFormat, 1); try { if (clientFormat == byteOrder) { localbuf.sock_ = sock; while (true) { localbuf.BulkRead(); if (localbuf.GotPacket()) return cmw_request(localbuf); } } otherlocalbuf.sock_ = sock; while (true) { otherlocalbuf.BulkRead(); if (otherlocalbuf.GotPacket()) return cmw_request(otherlocalbuf); } } catch (::std::exception const& ex) { clientFormat == byteOrder ? localbuf.Reset() : otherlocalbuf.Reset(); throw; } } time_t File::lastruntime_ = 0; void cmwAmbassador::login (bool firstTime) { cmwSendbuf.sock_ = cmwBuf.sock_ = connect2CMW(configData); PersistentWrite(cmwBuf.sock_, &byteOrder, 1); remoteMessages.Marshal(cmwSendbuf, configData.accounts); while (!cmwSendbuf.Flush()) ; // Call function while waiting for reply if (firstTime) { listener = server_prep(configData.portnumber); } while (!cmwBuf.GotPacket()) ; bool reqResult; remoteMessages.Receive(cmwBuf, reqResult); if (!reqResult) { ::std::string errorMsg; remoteMessages.Receive(cmwBuf, errorMsg); throw failure("Login failed: ") << errorMsg; } } void cmwAmbassador::mediateRequest (sock_type sock) { cmw_request request = getRequest(byteOrder, sock); verifyAccountNbr(request.accountNbr.value, configData); changeDirectory(request.path.c_str()); load_lastruntime(request.filename); remoteMessages.Marshal(cmwSendbuf , request.accountNbr , cmw_user_input(request.filename.c_str()) ); pendingTransactions.push_back(::std::move(request)); } void cmwAmbassador::mediateResponse (transactions_t::iterator itr) { bool safe_sending = true; try { localsendbuf.sock_ = itr->sock; bool reqResult; remoteMessages.Receive(cmwBuf, reqResult); if (reqResult) { changeDirectory(itr->path.c_str()); static ::std::vector outputFiles; outputFiles.clear(); remoteMessages.Receive(cmwBuf, outputFiles); save_lastruntime(itr->filename, itr->time_in_seconds); safe_sending = false; localMessages.Marshal(localsendbuf, true); } else { static ::std::string errorMsg; remoteMessages.Receive(cmwBuf, errorMsg); safe_sending = false; localMessages.Marshal(localsendbuf, false, errorMsg); } localsendbuf.Flush(); } catch(::std::exception const& ex) { #ifdef SYSLOG_AVAILABLE syslog(LOG_ERR, "mediateResponse: %s", ex.what()); #endif if (safe_sending) { localMessages.Marshal(localsendbuf, false, ex.what()); localsendbuf.Flush(); } } } sock_type cmwAmbassador::reset (char const* explanation , fd_set& master ) { for (auto const& itr: pendingTransactions) { localMessages.Marshal(localsendbuf, false, explanation); localsendbuf.sock_ = itr.sock; localsendbuf.Flush(); closeSocket(itr.sock); } localsendbuf.Reset(); pendingTransactions.clear(); closeSocket(cmwBuf.sock_); cmwBuf.Reset(); cmwSendbuf.Reset(); login(false); FD_ZERO(&master); FD_SET(cmwBuf.sock_, &master); FD_SET(listener, &master); return ::std::max(listener, cmwBuf.sock_); } cmwAmbassador::cmwAmbassador (char const* configfile) : cmwBuf(1000000) , localMessages(4096) , remoteMessages(500000) #ifdef CMW_ENDIAN_BIG , byteOrder(most_significant_first) #else , byteOrder(least_significant_first) #endif , configData(configfile) { login(true); fd_set master; fd_set read_fds; fd_set masterwrite; fd_set write_fds; FD_ZERO(&master); FD_ZERO(&masterwrite); FD_SET(cmwBuf.sock_, &master); FD_SET(listener, &master); int32_t fdmax = ::std::max(listener, cmwBuf.sock_); timeval timeout; timeout.tv_usec = 0; for (;;) { timeout.tv_sec = configData.keepalive_interval; read_fds = master; write_fds = masterwrite; int selrc = select(fdmax + 1, &read_fds, &write_fds, nullptr, &timeout); if (-1 == selrc) { if (EINTR == GetError()) { continue; } throw failure("select() failed with errno of ") << GetError(); } if (0 == selrc) { remoteMessages.Marshal(cmwSendbuf); if (!cmwSendbuf.Flush()) { FD_SET(cmwSendbuf.sock_, &masterwrite); } continue; } if (FD_ISSET(cmwBuf.sock_, &read_fds)) { try { if (cmwBuf.GotPacket()) { assert(!pendingTransactions.empty()); transactions_t::iterator itr(pendingTransactions.begin()); mediateResponse(itr); closeSocket(itr->sock); FD_CLR(itr->sock, &master); pendingTransactions.pop_front(); } } catch(eof const& ex) { #ifdef SYSLOG_AVAILABLE syslog(LOG_ERR, "Got end of stream notice: %s", ex.what()); #endif fdmax = reset("CMW was stopped or crashed before your request was processed", master); continue; } catch(::std::exception const& ex) { #ifdef SYSLOG_AVAILABLE syslog(LOG_ERR, "Problem getting packet %s", ex.what()); #endif assert(!pendingTransactions.empty()); localsendbuf.sock_ = pendingTransactions.front().sock; localMessages.Marshal(localsendbuf, false, ex.what()); localsendbuf.Flush(); closeSocket(localsendbuf.sock_); FD_CLR(localsendbuf.sock_, &master); pendingTransactions.pop_front(); } if (0 == --selrc) continue; FD_CLR(cmwBuf.sock_, &read_fds); } if (FD_ISSET(cmwSendbuf.sock_, &write_fds)) { try { if (cmwSendbuf.Flush()) { FD_CLR(cmwSendbuf.sock_, &masterwrite); } } catch (::std::exception const& ex) { #ifdef SYSLOG_AVAILABLE syslog(LOG_ERR, "Problem sending data to CMW: %s", ex.what()); #endif fdmax = reset("Problem sending data to CMW", master); } if (0 == --selrc) continue; } if (FD_ISSET(listener, &read_fds)) { sock_type nusock = accept_wrapper(listener); if (0 != nusock) { PersistentWrite(nusock, &byteOrder, 1); FD_SET(nusock, &master); if (nusock > fdmax) { fdmax = nusock; } } if (0 == --selrc) continue; FD_CLR(listener, &read_fds); } for (int32_t sock = fdmax; sock > 0; --sock) { if (FD_ISSET(sock, &read_fds)) { try { mediateRequest(sock); FD_SET(cmwSendbuf.sock_, &masterwrite); } catch (::std::exception const& ex) { #ifdef SYSLOG_AVAILABLE syslog(LOG_ERR, "mediateRequest: %s", ex.what()); #endif localsendbuf.sock_ = sock; localMessages.Marshal(localsendbuf, false, ex.what()); localsendbuf.Flush(); closeSocket(sock); FD_CLR(sock, &master); } if (0 == --selrc) break; } } } } int main (int argc , char* argv[]) try { #ifdef SYSLOG_AVAILABLE openlog(argv[0] , LOG_PID | LOG_NDELAY , LOG_USER ); #endif if (argc != 2) { printf("Usage: %s config-file-name \n", argv[0]); throw failure("Incorrect usage"); } #ifdef CMW_WINDOWS WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iResult != 0) { throw failure("WSAStartup error is ") << iResult; } #endif cmwAmbassador cmwa(argv[1]); } catch (::std::exception const& ex) { printf("exception: %s\n", ex.what()); #ifdef SYSLOG_AVAILABLE syslog(LOG_ERR, "main(): %s\n", ex.what()); #endif #ifdef CMW_MAKEFILES return 0; #else return 1; #endif } catch (...) { #ifdef SYSLOG_AVAILABLE syslog(LOG_ERR, "Unknown (...) exception caught!"); #endif }