-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlocalchat.sh
197 lines (171 loc) · 4.87 KB
/
localchat.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#!/bin/bash
port=
mode=
interface=
host_ip=
error_code_fail=2
min_port=1024
max_port=65535
declare -a output_text
function print_help_text() {
echo "
This local chat script accepts the follow flags:
Modes of operation (required)
-s|--server-mode
-c|--client-mode
...
"
}
function validate_interface() {
iface_array=$(get_available_interfaces)
if ! containsElement "$1" "${iface_array[@]}"; then
echo "Error: Invalid interface"
echo "Avalaible interfaces: ${iface_array[@]}"
exit
fi
return $? # exit status of last command
}
containsElement() {
if [[ $2 =~ $1 ]]; then
return 0
fi
return 1
}
function get_available_interfaces() {
array=()
for iface in $(ifconfig | cut -d ' ' -f1 | tr ':' '\n' | awk NF); do
array+=("$iface")
done
echo ${array[@]}
}
function determine_ip() {
host_ip=$(ip -o -4 addr show "${1}" | awk '{ split($4, ip_addr, "/"); print ip_addr[1] }')
if [[ $host_ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
output_text+=("Host Private Address: ${host_ip}.")
return 0
else
output_text+=("Error! Failed to obtain private ip for the specified interface: ${1}\n
")
return $error_code_fail
fi
}
function can_bind_port() {
# status code of this command indicates whether
# there was output (bad, means port is in use)
# or not (good, no processes using the port)
! lsof -i udp:"$1" >/dev/null
}
function find_available_port() {
echo "Checking for an available port..."
open_port_net_yet_found=true
while [ open_port_net_yet_found ]; do
temp_port=$(shuf -i${min_port}-${max_port} -n1) # generate random port number in range
echo "...Trying port ${temp_port}"
can_bind_port "$temp_port"
port_status=$? # get return status of previous command
if [ "$port_status" -eq "0" ]; then # 0 means port is safe to use
port=$temp_port
open_port_net_yet_found=false
break
fi
done
echo "Port ${port} Available! Binding..."
return 0
}
function start_server() {
echo "+-----------------------------------+"
echo " Starting Local Chat in SERVER mode"
echo "+-----------------------------------+"
echo
while IFS= read -p "Me: " -r input; do
send_message "$input"
# -l: listen mode -u use UDP protocol
done | nc "$host_ip" -p "$port" -l -u
}
function start_client() {
echo "+-----------------------------------+"
echo " Starting Local Chat in CLIENT mode"
echo "+-----------------------------------+"
echo
while IFS= read -p "Me: " -r input; do
send_message "$input"
# connect to listening server using UDP protocol
done | nc "$host_ip" "$port" -u
}
function send_message() {
payload="$*"
# Transmit message ONLY if input is not empty
if [ "$1" ]; then
if [ "$mode" = "SERVER" ]; then
printf "\nServer: %s \nMe: " "${payload}"
else # client mode
printf "\nClient: %s \nMe: " "${payload}"
fi
return 0 # payload transmitted
else
return $error_code_fail # blank input
fi
}
function init() {
POSITIONAL=()
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
-c | --client-mode)
mode="CLIENT"
shift # past argument
;;
-a | --server-address)
host_ip="$2"
shift # past argument
shift # past value
;;
-p | --server-port)
port="$2"
shift # past argument
shift # past value
;;
-i | --interface)
interface="$2"
shift # past argument
shift # past value
;;
-s | --server-mode)
mode="SERVER"
shift # past argument
;;
*) # unknown option
POSITIONAL+=("$1") # save it in an array for later
print_help_text
shift # past argument
exit
;;
esac
done
# set -- "${POSITIONAL[@]}" # restore positional parameters
case $mode in
SERVER)
validate_interface "$interface"
determine_ip "$interface"
find_available_port
for i in "${output_text[@]}"; do echo "$i"; done
start_server
;;
CLIENT)
for i in "${output_text[@]}"; do echo "$i"; done
start_client
;;
"")
echo "Error: Operation mode must be specified"
exit 1
;;
*)
echo "Internal configuration failure"
exit 1
;;
esac
}
init "$@"
# meat without all the extra fat
# while IFS= read -p "Me: " -r input; do printf "\nServer: %s \nMe: " "$input"; done | nc localhost 55555 -l
# while IFS= read -p "Me: " -r input; do printf "\nClient: %s \nMe: " "$input"; done | nc localhost 55555