· 7 years ago · Apr 24, 2018, 12:00 AM
1//--------------------------------------------------------
2// Project 5 - smalld.cpp
3//--------------------------------------------------------
4// COURSE: CS 270
5// DATE: April 23rd 2018
6// PURPOSE: This is a SERVER
7//--------------------------------------------------------
8
9#include "smStructs.h"
10#include <iostream>
11#include <map>
12#include <string>
13
14extern "C"
15{
16 #include "csapp.h"
17};
18
19const int SET_REQUEST_SIZE = 18;
20const int INIT_RESPONSE_FIXED = 4;
21const int INIT_REQUEST_FIXED = 8;
22const int DIGEST_BUF_ADJUST = 6;
23const int COMMAND_BUF_SIZE = 100;
24const int PATH_BUF_SIZE = 1035;
25const int SET = 0;
26const int GET = 1;
27const int DIGEST = 2;
28const int RUN = 3;
29
30using namespace std;
31
32/**********************START OF SERVER FOR smallSet***************************/
33int readInit(int connfd, unsigned int secretKey, map<string, string> & vars);
34void readSetRequest(int connfd, map<string, string> & vars);
35void modifyVars(map<string, string> & shellVars, string varName, string newVal)
36{
37 // if var doesn't exist, add new var and value
38 if(shellVars.find(varName) == shellVars.end())
39 {
40 shellVars.insert(make_pair(varName,newVal));
41 }
42 else
43 { // otherwise, change value of existing var
44 shellVars.find(varName)->second = newVal;
45 }
46}
47
48// getVar() is invoked to retrieve the value of a shell variable
49// It includes error checking for non-existent shell vars
50
51string getVar(const map<string,string> & shellVars, string varName)
52{
53 if(shellVars.find(varName) == shellVars.end())
54 { //var doesn't exist
55 return " ";
56 }
57 else
58 { // return value;
59 return shellVars.find(varName)->second;
60 }
61}
62/***********************END OF SERVER FOR smallSet***************************/
63
64/***********************START OF SERVER FOR smallGet*************************/
65void readGetRequest(int connfd, map<string, string> & vars)
66{
67 // Declare structs
68 get_request receivedGet;
69 init_response sendGet;
70
71 // Unless set otherwise, successful return
72 sendGet.returnCode = 0;
73 rio_t rio;
74
75 // Vars to track successful completion
76 string completion = "failure";
77 bool success = true;
78
79 // Initialize Rio connection, read getRequest
80 Rio_readinitb(&rio, connfd);
81 read(connfd, &receivedGet, sizeof(get_request));
82
83 // String manipulation for data read by Rio
84 // Invoke getVars() to find value of var
85 string varVal = getVar(vars, receivedGet.varName);
86 sendGet.valLength = htons(strlen(varVal.c_str())+1);
87 strcpy(sendGet.value, varVal.c_str());
88
89 // Error checking for return value of getVar()
90 int sendLength = varVal.length();
91 if(varVal == "")
92 {
93 sendGet.returnCode = -1;
94 success = false;
95 }
96 else
97 {
98 sendGet.returnCode = 0;
99 }
100
101 // Write and send response struct with Rio
102 Rio_writen(connfd, &sendGet, DIGEST_BUF_ADJUST+sendLength+1);
103 if (success)
104 {
105 completion = "success";
106 }
107
108 // Cout details of event
109 cout << "Request type = get" << endl;
110 cout << "Detail = " << receivedGet.varName << endl;
111 cout << "Completion = " << completion << endl;
112}
113/************************END OF SERVER FOR smallGet***********************/
114
115/**********************START OF MAIN FUNCTION FOR smalld SERVER************/
116int main(int argc, char **argv)
117{
118 // Much of main() is code provided by echoserveri from CMU libraries
119 int listenfd, connfd, port;
120 socklen_t clientlen;
121 struct sockaddr_in clientaddr;
122 /*struct hostent *hp;
123 char *haddrp;*/
124 map <string, string> vars;
125 // argument count check
126 if (argc != 3)
127 {
128 cerr << "Usage: " << argv[0] << " <port> <key>" << endl;
129 exit(0);
130 }
131 port = atoi(argv[1]);
132 listenfd = Open_listenfd(port);
133 while (1)
134 {
135 clientlen = sizeof(clientaddr);
136 connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);
137
138 // Invoke readInit() to interpret initial request header
139 // of fixed size
140 readInit(connfd, atoi(argv[2]), vars);
141 cout << "-----------------" << endl;
142 Close(connfd);
143 }
144 exit(0);
145}
146/* $end echoserverimain */
147/******************* END OF MAIN FUNCTION FOR smalld SERVER ****************/
148
149/******************* START OF SERVER FOR smallDigest ***********************/
150void readDigestRequest(int connfd)
151{
152 digest_request receivedDigest;
153 init_response sendDigest;
154
155 // declaring vars for error tracking
156 sendDigest.returnCode = 0;
157 string completion = "success";
158 bool success = true;
159
160 // Open Rio and make first read
161 rio_t rio;
162 Rio_readinitb(&rio, connfd);
163 read(connfd, &receivedDigest, 2);
164
165 // Find length of return value, then read rest of value
166 int valLength = ntohs(receivedDigest.valLength);
167 read(connfd, &receivedDigest.value, valLength);
168
169 //Declare vars for popen
170 unsigned int cmdLen;
171 char command[COMMAND_BUF_SIZE];
172 FILE * proc;
173 char path [PATH_BUF_SIZE];
174
175 // Produce string to be given as input to popoen
176 cmdLen = snprintf(command, sizeof(command), "/bin/echo %s | /usr/bin/sha256sum", receivedDigest.value);
177
178 if (cmdLen <= sizeof(command))
179 {
180 proc = popen(command, "r");
181 }
182
183 // Error checking
184 if(proc == NULL)
185 {
186 success = false;
187 return;
188 }
189 while(fgets(path, sizeof(path)-1, proc) != NULL) // Iterate over proc to path
190 {
191 }
192 pclose(proc); //pclose
193
194 // String modification for path
195 sendDigest.valLength = htons(strlen(path));
196 strcpy(sendDigest.value, path);
197
198 // Checking for errors
199 if(success == false)
200 {
201 sendDigest.returnCode = -1;
202 completion = "failed";
203 }
204
205 // Write final stages of response
206 Rio_writen(connfd, &sendDigest, DIGEST_BUF_ADJUST+strlen(path));
207
208 // Cout event details
209 cout << "Request type = digest" << endl;
210 cout << "Detail = " << receivedDigest.value << endl;
211 cout << "Completion = " << completion << endl;
212}
213/********************** END OF SERVER FOR smallDigest ***********************/
214
215/**************** Server reads initial requests (START) *********************/
216int readInit(int connfd, unsigned int secretKey, map<string,string> & vars)
217{
218 // Declaring vars for Rio
219 rio_t rio;
220 int requestType;
221
222 // Rio initialization and first reads
223 init_request initRequest;
224 Rio_readinitb(&rio, connfd);
225 read(connfd, &initRequest, INIT_REQUEST_FIXED);
226
227 // Secret key validation
228 if(ntohl(initRequest.secretKey) != secretKey)
229 {
230 cout << "Secret key: " << ntohl(initRequest.secretKey) << endl;
231 return 0;
232 }
233 cout << "Secret key: " << ntohl(initRequest.secretKey) << endl;
234 requestType = ntohs(initRequest.requestType);
235
236 // Switch based on read-in request code
237 switch(requestType)
238 {
239 case SET:
240 readSetRequest(connfd, vars);
241 break;
242
243 case GET:
244 readGetRequest(connfd, vars);
245 break;
246
247 case DIGEST:
248 readDigestRequest(connfd);
249 break;
250
251 default:
252 break;
253 }
254 return 0;
255}
256/********************** Server reads initial requests (END) ******************/
257
258/***************** Server recieved smallSet command (START) ******************/
259void readSetRequest(int connfd, map<string, string> & vars)
260{
261 // Declare structs
262 set_request receivedSet;
263 init_response sendSet;
264
265 int valLength;
266
267 // Successful return unless stated otherwise
268 sendSet.returnCode = 0;
269
270 // Failure tracking vars
271 string completion = "failure";
272 bool success = true;
273
274 // Initialize Rio connection
275 rio_t rio;
276 Rio_readinitb(&rio, connfd);
277
278 // Read fixed request size header
279 read(connfd, &receivedSet, SET_REQUEST_SIZE);
280 valLength = ntohs(receivedSet.valLength);
281
282 // Read value based on assigned valLength
283 read(connfd, &receivedSet.value, valLength);
284
285 // Modify variables by invoking modifyVars()
286 modifyVars(vars, receivedSet.varName, receivedSet.value);
287 Rio_writen(connfd, &sendSet, INIT_RESPONSE_FIXED);
288
289 if (success)
290 {
291 completion = "success";
292 }
293
294 // Cout event details to server
295 cout << "Request type = set" << endl;
296 cout << "Detail = " << receivedSet.varName << ": " << receivedSet.value << endl;
297 cout << "Completion = " << completion << endl;
298}
299/***************** Server recieved smallSet command (END) ********************/