-
Notifications
You must be signed in to change notification settings - Fork 0
/
ATMserver.cpp
331 lines (297 loc) · 9.69 KB
/
ATMserver.cpp
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
/* A simple server in the internet domain using TCP
The port number is passed as an argument */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>
#include <string>
#include <cstring>
#include <pthread.h> // For multithreading
#include <stdint.h>
#include <sstream>
#include <iomanip>
#include "crypto.h"
#define write cwrite
#define read cread
#include "serverCommands.cpp"
struct thread_info { /* Used as argument to thread_start() */
pthread_t thread_id; /* ID returned by pthread_create() */
int sock; /* Socket. I think */
userDB *users; /* Pointer to global users object */
//session_type *sessions; // pointer to global sessions object
// CryptoPP::SecByteBlock session_key;
// string username;
};
//HashMap of usernames to a tuple of user info or user object containing {username, pin, balance}
std::string advanceCommand(const std::string& line, int &index);
void advanceSpaces(const std::string &line, int &index);
void error(const char *msg);
void* consoleThread(void *threadid);
void* socketThread(void* arg);
int main(int argc, char *argv[]) {
if (argc != 2) { // Test for correct number of arguments
std::cerr << "Usage: " << argv[0] << " <Server Port>" << std::endl;
exit(1);
}
// socket initialization
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
std::cerr << "Usage: ATMserver <Port>" << std::endl;
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
error("ERROR opening socket");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
// assign socket to port number
if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) {
error("ERROR on binding");
}
listen(sockfd,5);
clilen = sizeof(cli_addr);
pthread_t thread;
thread_info args;
userDB* users = new userDB();
init_bank(users);
args.users = users;
pthread_create(&thread, NULL, consoleThread, &args);
while (1) {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
error("ERROR on accept");
continue;
}
pthread_t thread;
// thread_info args;
args.sock = newsockfd;
// pid = fork();
pthread_create(&thread, NULL, socketThread, &args);
// close(newsockfd);
// int threadNum* ++;
} /* end of while */
close(newsockfd);
close(sockfd);
//create 2 threads, one for I/O another for incomming connections
return 0;
}
//
void error(const char *msg) {
std::cerr << msg <<std::endl;
// exit(1);
}
// Read input until we read a space, then for each character add it to the command string
std::string advanceCommand(const std::string& line, int &index) {
std::string command = "";
if (index >= line.length()) return command;
for(; line[index] != ' ' && line[index] != '\0' && index < line.length(); index++) {
command += line[index];
}
if (index != line.length()) {
advanceSpaces(line, index);
}
return command;
}
// Skip any number of spaces
void advanceSpaces(const std::string &line, int &index) {
for(; line[index] == ' ' && index < line.length(); index++);
}
std::string genSessionKey(std::string username) {
int secret = rand() % 1000 + 1;
std::stringstream ss;
ss << std::setfill('0') << std::setw(4) << secret;
return username + '_' + ss.str();
}
std::string parseCommands(char buffer[], userDB* users, std::string& sessionKey, int& sentNumber) {
int index = 0;
bool loggedIn = false;
std::string input(buffer);
userInfo *thisUser;
std::string sendStr;
int cliNumber = atoi(advanceCommand(input, index).c_str());
sentNumber ++;
if (cliNumber != sentNumber) {
return "not the message I was expecting";
}
sentNumber ++;
if (sessionKey.length() != 0) {
std::string cliSeshKey = advanceCommand(input, index);
int pos = sessionKey.find('_');
std::string someUser = sessionKey.substr(0, pos);
thisUser = users->findUser(someUser);
if (thisUser == NULL) {
return "session Key has been tampered with";
}
else {
loggedIn = thisUser->isLoggedIn();
}
// checks if user is trying to logout
if (cliSeshKey.compare("logout") == 0 && loggedIn) {
sessionKey = "";
// std::cout << "atm connection ~ : " << "user logged out" << std::endl;
thisUser->logout();
return "logged_out";
}
// checks to see if client's session key equals clients session key
if (sessionKey.compare(cliSeshKey) != 0) return "session key has been tampered with";
}
// std::cout << "session key: " << sessionKey << std::endl;
std::string command = advanceCommand(input, index);
// std::cout << "balance: " << (command.compare("balance") == 0) << " " << loggedIn << std::endl;
if (command.compare("login") == 0) {
std::string username = advanceCommand(input, index);
std::string pin = advanceCommand(input, index);
if (users->loginUser(username, pin)) {
// std::cout << username << " logged in!" << std::endl;
sessionKey = genSessionKey(username);
sendStr = "y " + sessionKey;
}
else {
sendStr = "n";
}
}
else if (command.compare("balance") == 0 && loggedIn) {
sendStr = thisUser->getBalance();
}
else if (command.compare("withdraw") == 0 && loggedIn) {
std::string amount = advanceCommand(input, index);
std::string takenOut = thisUser->withdraw(amount);
sendStr = "withdrew";
}
else if (command.compare("transfer") == 0 && loggedIn) {
std::string amount = advanceCommand(input, index);
std::string sendingTo = advanceCommand(input, index);
users->transfer(thisUser->getName(), sendingTo, amount);
sendStr = "transfered";
}
else if (command.compare("check") == 0 && loggedIn) {
std::string name = advanceCommand(input, index);
bool exists = users->userExists(name);
if (exists) sendStr = "y";
else sendStr = "n";
}
else if (command.compare("init") == 0) {
sendStr = "connected to bank";
}
else {
std::cout << "bad command" << std::endl;
sendStr = "error! bad command!";
}
std::stringstream ss;
ss << sentNumber;
return ss.str() + " " + sendStr;
}
void closeSocket(userDB* users, std::string sessionKey, int socket) {
if (sessionKey.length() != 0) {
int pos = sessionKey.find('_');
userInfo *thisUser;
std::string someUser = sessionKey.substr(0, pos);
thisUser = users->findUser(someUser);
thisUser->logout();
}
std::cout << "atm connection ~ : " << "socket# " << socket << " disconnected" << std::endl;
close(socket);
}
void* socketThread(void* args) {
std::cout << std::endl;
struct thread_info *tinfo;
tinfo = (thread_info *) args;
int sock = tinfo->sock;
userDB *users = tinfo->users;
std::string sessionKey;
int sentNumber = 0;
bool logginIn = false;
while (1) {
int n;
char buffer[256];
char sendBuffer[256];
bzero(buffer,256);
bzero(sendBuffer,256);
n = read(sock,buffer,255);
if (n < 0) {
error("ERROR writing to socket");
closeSocket(users, sessionKey, sock);
break;
}
if (n == 0) {
closeSocket(users, sessionKey, sock);
break;
}
if (std::string(buffer).compare("1 init") == 0) {
std::cout << "atm connection ~ : ";
std::cout << "socket# " << sock << " connected" << std::endl;
} else {
#ifdef _debug
std::cout << "atm connection ~ : ";
std::cout << buffer << std::endl;
#endif
}
std::string send = parseCommands(buffer, users, sessionKey, sentNumber);
n = write(sock, send.c_str(), send.length());
if (send.compare("not the message I was expecting") == 0) {
closeSocket(users, sessionKey, sock);
break;
}
}
pthread_exit(NULL); // Ends the thread
return NULL;
}
void *consoleThread(void *args) {
struct thread_info *tinfo;
tinfo = (thread_info *) args;
userDB *users = tinfo->users;
// string that is printed to the console
std::string sendStr;
std::cout << ("bank ~ : ");
for(std::string line; getline(std::cin, line);) {
int index = 0;
std::string command = advanceCommand(line, index);
std::string username = advanceCommand(line, index);
if (command.compare("balance") != 0 && command.compare("deposit") != 0) {
sendStr = "Bank Commands: [deposit|balance] [username] <amount>";
}
else if (!users->userExists(username)) {
sendStr = "user \"" + username + "\" does not exist";
}
else if(command.compare("deposit") == 0) {
//deposit [username] [amount] Increase <username>’s balance by <amount>
std::string amount = advanceCommand(line, index);
int testNeg = atoi(amount.c_str());
bool isInt = true;
for (int i = 0; i < amount.length(); i++) {
if (!(amount[i] >= '0' && amount[i] <= '9')) {
isInt = false;
// std::cout << test[i] << " not a int!" << std::endl;
}
}
if (!isInt) {
sendStr = amount + " is not a number!!!";
}
else if (testNeg < 0) {
sendStr = "no negative deposits!!!";
} else {
sendStr = "deposited " + amount;
deposit(username, amount, users);
}
}
else if(command.compare("balance") == 0) {
//balance [username] Print the balance of <username>
sendStr = balance(username, users);
}
std::cout << sendStr << std::endl;
std::cout << ("bank ~ : ");
}
pthread_exit(NULL); // Ends the thread
}