Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
wsssh
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexlab
wsssh
Commits
8ac50290
Commit
8ac50290
authored
Sep 21, 2025
by
Stefy Lanza (nextime / spora )
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update templates and add test applications
parent
e9d62e2d
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
399 additions
and
0 deletions
+399
-0
test_client.c
test_client.c
+228
-0
test_server.c
test_server.c
+171
-0
No files found.
test_client.c
0 → 100644
View file @
8ac50290
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <signal.h>
#include <fcntl.h>
#include <getopt.h>
volatile
int
running
=
1
;
void
sigint_handler
(
int
sig
)
{
running
=
0
;
}
// Simple base64 encoding function
char
*
base64_encode
(
const
unsigned
char
*
data
,
size_t
input_length
)
{
static
const
char
base64_chars
[]
=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
;
size_t
output_length
=
4
*
((
input_length
+
2
)
/
3
);
char
*
encoded_data
=
malloc
(
output_length
+
1
);
if
(
encoded_data
==
NULL
)
return
NULL
;
for
(
size_t
i
=
0
,
j
=
0
;
i
<
input_length
;)
{
uint32_t
octet_a
=
i
<
input_length
?
data
[
i
++
]
:
0
;
uint32_t
octet_b
=
i
<
input_length
?
data
[
i
++
]
:
0
;
uint32_t
octet_c
=
i
<
input_length
?
data
[
i
++
]
:
0
;
uint32_t
triple
=
(
octet_a
<<
0x10
)
+
(
octet_b
<<
0x08
)
+
octet_c
;
encoded_data
[
j
++
]
=
base64_chars
[(
triple
>>
3
*
6
)
&
0x3F
];
encoded_data
[
j
++
]
=
base64_chars
[(
triple
>>
2
*
6
)
&
0x3F
];
encoded_data
[
j
++
]
=
base64_chars
[(
triple
>>
1
*
6
)
&
0x3F
];
encoded_data
[
j
++
]
=
base64_chars
[(
triple
>>
0
*
6
)
&
0x3F
];
}
// Add padding
size_t
padding
=
(
3
-
(
input_length
%
3
))
%
3
;
for
(
size_t
i
=
0
;
i
<
padding
;
i
++
)
{
encoded_data
[
output_length
-
1
-
i
]
=
'='
;
}
encoded_data
[
output_length
]
=
'\0'
;
return
encoded_data
;
}
int
main
(
int
argc
,
char
*
argv
[])
{
char
*
host
=
"127.0.0.1"
;
// Default host
int
port
=
8080
;
// Default port
int
timeout_seconds
=
2
;
// Default timeout
int
num_messages
=
0
;
// Default: infinite loop
int
string_length
=
0
;
// Default: random length (10-40)
// Parse command line arguments
static
struct
option
long_options
[]
=
{
{
"timeout"
,
required_argument
,
0
,
't'
},
{
"n"
,
required_argument
,
0
,
'n'
},
{
"string-length"
,
required_argument
,
0
,
's'
},
{
0
,
0
,
0
,
0
}
};
int
opt
;
int
option_index
=
0
;
while
((
opt
=
getopt_long
(
argc
,
argv
,
"t:n:s:"
,
long_options
,
&
option_index
))
!=
-
1
)
{
switch
(
opt
)
{
case
't'
:
timeout_seconds
=
atoi
(
optarg
);
if
(
timeout_seconds
<
0
)
{
fprintf
(
stderr
,
"Invalid timeout value: %s
\n
"
,
optarg
);
return
1
;
}
break
;
case
'n'
:
num_messages
=
atoi
(
optarg
);
if
(
num_messages
<
0
)
{
fprintf
(
stderr
,
"Invalid number of messages: %s
\n
"
,
optarg
);
return
1
;
}
break
;
case
's'
:
string_length
=
atoi
(
optarg
);
if
(
string_length
<
1
||
string_length
>
1000
)
{
fprintf
(
stderr
,
"Invalid string length: %s (must be 1-1000)
\n
"
,
optarg
);
return
1
;
}
break
;
default:
fprintf
(
stderr
,
"Usage: %s [options] [host] [port]
\n
"
,
argv
[
0
]);
fprintf
(
stderr
,
"Options:
\n
"
);
fprintf
(
stderr
,
" --timeout, -t <seconds> Timeout between messages (default: 2)
\n
"
);
fprintf
(
stderr
,
" --n, -n <count> Number of messages to send (0 for infinite, default: 0)
\n
"
);
fprintf
(
stderr
,
" --string-length, -s <len> String length to generate (1-1000, default: random 10-40)
\n
"
);
fprintf
(
stderr
,
"Arguments:
\n
"
);
fprintf
(
stderr
,
" host Server host (default: 127.0.0.1)
\n
"
);
fprintf
(
stderr
,
" port Server port (default: 8080)
\n
"
);
return
1
;
}
}
// Parse positional arguments for host and port
if
(
optind
<
argc
)
{
host
=
argv
[
optind
++
];
}
if
(
optind
<
argc
)
{
port
=
atoi
(
argv
[
optind
++
]);
}
if
(
port
<=
0
||
port
>
65535
)
{
fprintf
(
stderr
,
"Invalid port: %d
\n
"
,
port
);
return
1
;
}
printf
(
"Connecting to %s:%d
\n
"
,
host
,
port
);
printf
(
"Timeout: %d seconds
\n
"
,
timeout_seconds
);
printf
(
"Number of messages: %s
\n
"
,
num_messages
==
0
?
"infinite"
:
"limited"
);
printf
(
"String length: %s
\n
"
,
string_length
>
0
?
"fixed"
:
"random (10-40)"
);
if
(
string_length
>
0
)
{
printf
(
"Fixed string length: %d
\n
"
,
string_length
);
}
signal
(
SIGINT
,
sigint_handler
);
int
sock
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
if
(
sock
<
0
)
{
perror
(
"socket"
);
return
1
;
}
struct
sockaddr_in
addr
;
memset
(
&
addr
,
0
,
sizeof
(
addr
));
addr
.
sin_family
=
AF_INET
;
addr
.
sin_port
=
htons
(
port
);
if
(
inet_pton
(
AF_INET
,
host
,
&
addr
.
sin_addr
)
<=
0
)
{
perror
(
"inet_pton"
);
close
(
sock
);
return
1
;
}
if
(
connect
(
sock
,
(
struct
sockaddr
*
)
&
addr
,
sizeof
(
addr
))
<
0
)
{
perror
(
"connect"
);
close
(
sock
);
return
1
;
}
// Make socket non-blocking
int
flags
=
fcntl
(
sock
,
F_GETFL
,
0
);
fcntl
(
sock
,
F_SETFL
,
flags
|
O_NONBLOCK
);
int
message_count
=
0
;
while
(
running
)
{
// Check if we've sent the required number of messages
if
(
num_messages
>
0
&&
message_count
>=
num_messages
)
{
printf
(
"Sent %d messages as requested. Exiting.
\n
"
,
num_messages
);
break
;
}
// Generate string
srand
(
time
(
NULL
)
+
message_count
);
// Add message_count to avoid same seed
int
len
;
if
(
string_length
>
0
)
{
len
=
string_length
;
}
else
{
len
=
rand
()
%
31
+
10
;
// 10 to 40
}
char
str
[
len
+
1
];
for
(
int
i
=
0
;
i
<
len
;
i
++
)
{
str
[
i
]
=
'A'
+
rand
()
%
26
;
}
str
[
len
]
=
'\0'
;
char
*
b64_sent
=
base64_encode
((
unsigned
char
*
)
str
,
len
);
printf
(
"(SENT) %s <-> %s
\n
"
,
str
,
b64_sent
?
b64_sent
:
"ERROR"
);
write
(
sock
,
str
,
len
);
message_count
++
;
if
(
b64_sent
)
free
(
b64_sent
);
// Wait for response with specified timeout
fd_set
read_set
;
FD_ZERO
(
&
read_set
);
FD_SET
(
sock
,
&
read_set
);
struct
timeval
timeout
;
timeout
.
tv_sec
=
timeout_seconds
;
timeout
.
tv_usec
=
0
;
int
ret
=
select
(
sock
+
1
,
&
read_set
,
NULL
,
NULL
,
&
timeout
);
if
(
ret
>
0
&&
FD_ISSET
(
sock
,
&
read_set
))
{
char
buffer
[
1024
];
int
n
=
read
(
sock
,
buffer
,
sizeof
(
buffer
)
-
1
);
if
(
n
>
0
)
{
buffer
[
n
]
=
'\0'
;
// Remove trailing newline if present
if
(
n
>
0
&&
buffer
[
n
-
1
]
==
'\n'
)
{
buffer
[
n
-
1
]
=
'\0'
;
n
--
;
}
char
*
b64_recv
=
base64_encode
((
unsigned
char
*
)
buffer
,
n
);
printf
(
"(RECV) %s <-> %s
\n
"
,
buffer
,
b64_recv
?
b64_recv
:
"ERROR"
);
if
(
b64_recv
)
free
(
b64_recv
);
}
else
if
(
n
==
0
)
{
// Connection closed
printf
(
"Connection closed by server
\n
"
);
break
;
}
else
{
perror
(
"read"
);
break
;
}
}
else
if
(
ret
==
0
)
{
printf
(
"Timeout waiting for response
\n
"
);
}
else
{
perror
(
"select"
);
break
;
}
// Add delay between messages based on timeout parameter
if
(
timeout_seconds
>
0
)
{
sleep
(
timeout_seconds
);
}
else
{
usleep
(
100000
);
// 100ms delay for 0 timeout
}
}
close
(
sock
);
return
0
;
}
\ No newline at end of file
test_server.c
0 → 100644
View file @
8ac50290
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
volatile
int
running
=
1
;
void
sigint_handler
(
int
sig
)
{
running
=
0
;
}
// Simple base64 encoding function
char
*
base64_encode
(
const
unsigned
char
*
data
,
size_t
input_length
)
{
static
const
char
base64_chars
[]
=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
;
size_t
output_length
=
4
*
((
input_length
+
2
)
/
3
);
char
*
encoded_data
=
malloc
(
output_length
+
1
);
if
(
encoded_data
==
NULL
)
return
NULL
;
for
(
size_t
i
=
0
,
j
=
0
;
i
<
input_length
;)
{
uint32_t
octet_a
=
i
<
input_length
?
data
[
i
++
]
:
0
;
uint32_t
octet_b
=
i
<
input_length
?
data
[
i
++
]
:
0
;
uint32_t
octet_c
=
i
<
input_length
?
data
[
i
++
]
:
0
;
uint32_t
triple
=
(
octet_a
<<
0x10
)
+
(
octet_b
<<
0x08
)
+
octet_c
;
encoded_data
[
j
++
]
=
base64_chars
[(
triple
>>
3
*
6
)
&
0x3F
];
encoded_data
[
j
++
]
=
base64_chars
[(
triple
>>
2
*
6
)
&
0x3F
];
encoded_data
[
j
++
]
=
base64_chars
[(
triple
>>
1
*
6
)
&
0x3F
];
encoded_data
[
j
++
]
=
base64_chars
[(
triple
>>
0
*
6
)
&
0x3F
];
}
// Add padding
size_t
padding
=
(
3
-
(
input_length
%
3
))
%
3
;
for
(
size_t
i
=
0
;
i
<
padding
;
i
++
)
{
encoded_data
[
output_length
-
1
-
i
]
=
'='
;
}
encoded_data
[
output_length
]
=
'\0'
;
return
encoded_data
;
}
int
main
(
int
argc
,
char
*
argv
[])
{
if
(
argc
!=
2
)
{
fprintf
(
stderr
,
"Usage: %s <port>
\n
"
,
argv
[
0
]);
return
1
;
}
int
port
=
atoi
(
argv
[
1
]);
if
(
port
<=
0
||
port
>
65535
)
{
fprintf
(
stderr
,
"Invalid port number
\n
"
);
return
1
;
}
signal
(
SIGINT
,
sigint_handler
);
int
server_fd
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
if
(
server_fd
<
0
)
{
perror
(
"socket"
);
return
1
;
}
// Set SO_REUSEADDR to allow immediate reuse of the port
int
opt
=
1
;
if
(
setsockopt
(
server_fd
,
SOL_SOCKET
,
SO_REUSEADDR
,
&
opt
,
sizeof
(
opt
))
<
0
)
{
perror
(
"setsockopt"
);
close
(
server_fd
);
return
1
;
}
struct
sockaddr_in
addr
;
memset
(
&
addr
,
0
,
sizeof
(
addr
));
addr
.
sin_family
=
AF_INET
;
addr
.
sin_addr
.
s_addr
=
INADDR_ANY
;
addr
.
sin_port
=
htons
(
port
);
if
(
bind
(
server_fd
,
(
struct
sockaddr
*
)
&
addr
,
sizeof
(
addr
))
<
0
)
{
perror
(
"bind"
);
close
(
server_fd
);
return
1
;
}
if
(
listen
(
server_fd
,
10
)
<
0
)
{
perror
(
"listen"
);
close
(
server_fd
);
return
1
;
}
printf
(
"Listening on 0.0.0.0:%d
\n
"
,
port
);
fd_set
master_set
,
read_set
;
FD_ZERO
(
&
master_set
);
FD_SET
(
server_fd
,
&
master_set
);
int
max_fd
=
server_fd
;
while
(
running
)
{
read_set
=
master_set
;
struct
timeval
timeout
;
timeout
.
tv_sec
=
1
;
// 1 second timeout to check running flag
timeout
.
tv_usec
=
0
;
int
ret
=
select
(
max_fd
+
1
,
&
read_set
,
NULL
,
NULL
,
&
timeout
);
if
(
ret
<
0
)
{
if
(
running
)
perror
(
"select"
);
break
;
}
else
if
(
ret
==
0
)
{
// Timeout - check if we should still be running
continue
;
}
for
(
int
i
=
0
;
i
<=
max_fd
;
i
++
)
{
if
(
FD_ISSET
(
i
,
&
read_set
))
{
if
(
i
==
server_fd
)
{
// New connection
struct
sockaddr_in
client_addr
;
socklen_t
client_len
=
sizeof
(
client_addr
);
int
client_fd
=
accept
(
server_fd
,
(
struct
sockaddr
*
)
&
client_addr
,
&
client_len
);
if
(
client_fd
<
0
)
{
perror
(
"accept"
);
continue
;
}
printf
(
"CONNECTION FROM %s:%d
\n
"
,
inet_ntoa
(
client_addr
.
sin_addr
),
ntohs
(
client_addr
.
sin_port
));
FD_SET
(
client_fd
,
&
master_set
);
if
(
client_fd
>
max_fd
)
max_fd
=
client_fd
;
}
else
{
// Data from client
char
buffer
[
1024
];
int
n
=
read
(
i
,
buffer
,
sizeof
(
buffer
)
-
1
);
if
(
n
<=
0
)
{
// Connection closed or error
close
(
i
);
FD_CLR
(
i
,
&
master_set
);
printf
(
"CONNECTION CLOSED
\n
"
);
}
else
{
buffer
[
n
]
=
'\0'
;
// Remove trailing newline if present
if
(
n
>
0
&&
buffer
[
n
-
1
]
==
'\n'
)
{
buffer
[
n
-
1
]
=
'\0'
;
n
--
;
}
char
*
b64
=
base64_encode
((
unsigned
char
*
)
buffer
,
n
);
printf
(
"(RECEIVED) %s <-> %s
\n
"
,
buffer
,
b64
?
b64
:
"ERROR"
);
char
response
[
1024
+
100
];
char
*
response_b64
=
base64_encode
((
unsigned
char
*
)
buffer
,
n
);
snprintf
(
response
,
sizeof
(
response
),
"RECEIVED: %s <-> %s"
,
buffer
,
response_b64
?
response_b64
:
"ERROR"
);
write
(
i
,
response
,
strlen
(
response
));
if
(
b64
)
free
(
b64
);
if
(
response_b64
)
free
(
response_b64
);
}
}
}
}
}
// Close all sockets
for
(
int
i
=
0
;
i
<=
max_fd
;
i
++
)
{
if
(
FD_ISSET
(
i
,
&
master_set
))
{
close
(
i
);
}
}
printf
(
"Exiting...
\n
"
);
return
0
;
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment