-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclientInputHandler.c
More file actions
274 lines (226 loc) · 9.66 KB
/
clientInputHandler.c
File metadata and controls
274 lines (226 loc) · 9.66 KB
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
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdint.h>
#include <ctype.h>
#include "clientInputHandler.h"
#include "PDUTransmit.h"
#include "pollLib.h"
#include "handleTable.h"
//returns the line read from STDin, can only parse one line at once since line is static
char* retrieveLine(){
static char* line = NULL; //declare line as static so it can be used by function that calls this (wont lose scope).
size_t len = 0;
ssize_t read = getline(&line, &len, stdin); //will continue to re-use line, so no need to free.
if (read == -1) {
return NULL;
}
if(read>1400){
printf("\rinput cmd exceeds maximum length of 1400 characters\n");
return NULL;
}
if (line[read - 1] == '\n') { // Remove trailing newline
line[read - 1] = '\0';
}
return line;
}
//helper function for reqeusting the handler (send the actual message)
void sendHandlerRequest(int socketNum, char* handleName, int8_t handleSize);
//reqeusts its handle name with the server. blocks until it recieves a response, and exits if server denies request
void requestHandler(int socketNum,char* handleName){
int handleSizeLong=strlen(handleName);
if(handleSizeLong>maxHandleLen){
printf("\ryour handle name exceeds maximum length of 100, unable to add\n");
exit(-1);
}
uint8_t handleSize=handleSizeLong;
sendHandlerRequest(socketNum,handleName, handleSize);
int returnedFlag=-1;
while(returnedFlag!=FLAG_SEND_ACCEPTED){
if(pollCall(-1)==socketNum){ //wait for a message from server
uint8_t buffer[MaxIPMsgSize]={0};
int msgLen=recvPDU(socketNum, buffer, MaxIPMsgSize);
if(msgLen==0){ //client is closed
close(socketNum);
removeFromPollSet(socketNum);
printf("\rserver closed, exiting\n");
exit(1);
}
struct PDUMsg* msg=(struct PDUMsg*) buffer;
//checkFlag of message
if(msgLen==1 && msg->flag==FLAG_SEND_ACCEPTED){
returnedFlag=FLAG_SEND_ACCEPTED;
}else if(msgLen==1 && msg->flag==FLAG_SEND_REJECTED){
printf("\rHandle already in use: %s\n", handleName);
exit(-1);
}
}
}
//prompt user for input
printf("\r$: ");
fflush(stdout);
}
void sendHandlerRequest(int socketNum, char* handleName, int8_t handleSize){
uint8_t dataBuffer[handleSize+1];
dataBuffer[0]=handleSize;
memcpy(dataBuffer+1,handleName, handleSize);
sendPDUWithFlag(socketNum, FLAG_CLIENT_INITIAL,dataBuffer,handleSize+1);
}
//functions for handling each kind of message from server post-initialization
void parseUnicastCmd(int socketNum, char* flags, char* myName);
void parseMulticastCmd(int socketNum, char* flags, char* myName);
void handleBroadcastCmd(int socketNum, char* flags, char* myName);
void sendUnicastCmd(int socketNum, char* srcHandle, int numTargs, char* destHandles); //send unicast or multicast message
//helper functions
void sendMessage(int socketNum, uint8_t flag, char* handleBuffer, uint8_t handleBufferLen, char* text);
int insertSrcName(char* srcHandle, char* handleBuffer);
int countWords(const char* str);
//parse which command the user inputted. redirect to appropriate handler function
void processUserCommand(int socketNum, char* line, char* myName) {
if(strlen(line)<2){
printf("\rall commands are at least 2 characters!\n");
return;
}
if (line[0] != '%') {
printf("\rInvalid command. Must start with %%\n");
return;
}
char command = toupper(line[1]);
// Skip "%X " and get the command details
char* flags = line + 2;
switch (command) {
case 'M':
parseUnicastCmd(socketNum, flags, myName);
break;
case 'C':
parseMulticastCmd(socketNum, flags, myName);
break;
case 'B':
handleBroadcastCmd(socketNum, flags, myName);
break;
case 'L':
sendResponseFlag(socketNum, FLAG_REQUEST_HANDLE_LIST);
break;
default:
printf("\rUnknown command: %c\n", command);
}
}
void parseUnicastCmd(int socketNum, char* flags, char* myName) {
// const char* space = " "; // tokenize on spaces
char* destHandle= flags;
if(countWords(destHandle)<1){
printf("\ryou need to provide a handle name to send a message to\n");
return;
}
sendUnicastCmd(socketNum, myName, 1, destHandle);
}
void parseMulticastCmd(int socketNum, char* flags, char* myName) {
while(flags[0]==' '){ flags++;}
if (*flags < '2' || *flags > '9') {
printf("\rInvalid number of targets (must be 2–9).\n");
return;
}
uint8_t numTargs = *flags - '0'; //convert ASCII to a digit
flags++; //start flags at destination
int numNames;
if((numNames=countWords(flags))<numTargs){
printf("\rYou did not provide enough targets to send the message to. You claimed to send: %d, but only gave %d names. Cancelling msg\n",numTargs,numNames);
return;
}
sendUnicastCmd(socketNum, myName, numTargs, flags);
}
//sends a unicast or multicast message (its the same for both)
void sendUnicastCmd(int socketNum, char* srcHandle, int numTargs, char* destHandles){
char handleBuffer[MaxIPMsgSize]={0};
int handleBufferIndex=insertSrcName(srcHandle, handleBuffer); //atach src Handler
//number of target Handlers
handleBuffer[handleBufferIndex]=numTargs;
handleBufferIndex+=sizeof(uint8_t);
int destHandlesIndex=0;
while(destHandles[destHandlesIndex]==' '){ destHandlesIndex++;}
//targetHandlers
for(int i=0;i<numTargs;i++){
while(destHandles[destHandlesIndex]==' '){ destHandlesIndex++;} //ignore repeated whitespace
char* targHandlerName=destHandles + destHandlesIndex;
int destHandlesInitialIndex=destHandlesIndex;
while(destHandles[destHandlesIndex]!=' '&& (destHandles[destHandlesIndex]!='\0')){ destHandlesIndex++;}
int targHandlerLenLong=destHandlesIndex-destHandlesInitialIndex;
if(targHandlerLenLong>100){
printf("\ra target Handler is too long, not sending the message\n");
return;
}
uint8_t targHandlerLen=targHandlerLenLong;
handleBuffer[handleBufferIndex]=targHandlerLen;
handleBufferIndex+=sizeof(targHandlerLen);
memcpy(handleBuffer + handleBufferIndex, targHandlerName, targHandlerLen);
handleBufferIndex+=targHandlerLen;
}
while(destHandles[destHandlesIndex]==' '){ destHandlesIndex++;}
char* text=destHandles+destHandlesIndex;
sendMessage(socketNum, FLAG_DIRECT_MESSAGE, handleBuffer, handleBufferIndex, text); //this function adds the text to the handler buffer and then sends
}
//parses a broadcast message and sends it to server
void handleBroadcastCmd(int socketNum, char* flags, char* myName) {
char handleBuffer[MaxIPMsgSize]={0}; //handleBuffer includes 1 byte handleLen + handle
int handleBufferIndex=insertSrcName(myName, handleBuffer);
while(flags[0]==' '){ flags++;} //ignore white space
sendMessage(socketNum, FLAG_BROADCAST_MESSAGE, handleBuffer, handleBufferIndex, flags); //this function adds the text to the handler buffer and then sends
}
//helper function. takes in the headerBuffer (typically holdinghandler), and attaches text to it in maxTextLen blocks, sending each as a seperate message.
void sendMessage(int socketNum, uint8_t flag, char* handleBuffer, uint8_t handleBufferLen, char* text){
int maxMsgLen=handleBufferLen+maxTextLen;
//handlerInfo^ //text^
uint8_t msgBuffer[maxMsgLen]; //create buffer for msg
memcpy(msgBuffer,handleBuffer,handleBufferLen); //put handleBuffer at start of msg buffer
//send text in groups of maxTextLen bytes
int textLen=strlen(text);
do { //run at least once to send empty message if needed
int copySize= (textLen>= maxTextLen)? maxTextLen-1 : textLen; //pick max of our current remaining text length, or the maxTextLength
int msgLen=handleBufferLen + copySize + 1; //how long dataBuffer of the message we will send is
//incude null term. ^
memcpy(msgBuffer+handleBufferLen,text,copySize); //copy text into our msg Buffer. dont copy null byte
msgBuffer[handleBufferLen+copySize]='\0';//Null terminate the text
sendPDUWithFlag(socketNum, flag, msgBuffer,msgLen); //send Message
text+=copySize; //move up text ptr after sending that text
textLen=strlen(text);
}while(textLen!=0);
}
//helper function for inserting a handlelength + handleName at the start of a buffer
int insertSrcName(char* srcHandle, char* handleBuffer){
uint8_t srcHandleLen=strlen(srcHandle);
int handleBufferIndex=0;
// src handler len
handleBuffer[handleBufferIndex]=srcHandleLen;
handleBufferIndex+=sizeof(srcHandleLen);
//src handler
memcpy(handleBuffer+handleBufferIndex, srcHandle,srcHandleLen);
handleBufferIndex+=srcHandleLen;
return handleBufferIndex;
}
//count number of words in a string. Used for checking correct number of arguements
int countWords(const char* str) {
int count = 0;
int inWord = 0;
while (*str) {
if (*str != ' ') {
if (!inWord) {
count++;
inWord = 1;
}
} else {
inWord = 0;
}
str++;
}
return count;
}