-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.c
159 lines (135 loc) · 5.02 KB
/
server.c
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
#include <stdio.h> /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket() and bind() */
#include <arpa/inet.h> /* for sockaddr_in and inet_ntoa() */
#include <stdlib.h> /* for atoi() and exit() */
#include <string.h> /* for memset() */
#include <unistd.h> /* for close() */
#include "rpc.h" /* struct header file*/
#define ECHOMAX 255 /* Longest string to echo */
void DieWithError(char *errorMessage); /* External error handling function */
int divide(int x, int y, int *z) {
if (y == 0) {
return DIV_ZERO;
} else {
*z = x / y;
return OK;
}
}
int add(int x, int y, int *z) {
*z = x + y;
return OK;
}
int subtract(int x, int y, int *z) {
*z = x - y;
return OK;
}
int multiply(int x, int y, int *z) {
*z = x * y;
return OK;
}
int rem(int x, int y, int *z) {
if (y == 0) {
return DIV_ZERO;
} else {
*z = x % y;
return OK;
}
}
int processOperation(int lastResult, RPCMessage* request, int* status) {
//check for request type
if (request->messageType == Request) {
//bit and 0x80 for continuation
if (request->procedureId & CONT_OP)
request->arg1 = lastResult;
if (request->procedureId & ADD_OP)
*status = add(request->arg1, request->arg2, &lastResult);
if (request->procedureId & SUB_OP)
*status = subtract(request->arg1, request->arg2, &lastResult);
if (request->procedureId & MULT_OP)
*status = multiply(request->arg1, request->arg2, &lastResult);
if (request->procedureId & DIV_OP)
*status = divide(request->arg1, request->arg2, &lastResult);
if (request->procedureId & REM_OP)
*status = rem(request->arg1, request->arg2, &lastResult);
}
return lastResult;
}
void processNetworkByteOrder(RPCMessage* request) {
//re-storing from network byte order to byte order
request->RPCId = ntohl(request->RPCId);
request->messageType = ntohl(request->messageType);
request->procedureId = ntohl(request->procedureId);
request->arg1 = ntohl(request->arg1);
request->arg2 = ntohl(request->arg2);
}
void populateReply(const RPCMessage* request, int lastResult, int status, RPCMessage* reply) {
//populate reply, don't need to populate procedureId
memset(&reply, 0, sizeof(reply));
reply->RPCId = htonl(request->RPCId);
reply->messageType = htonl(Reply);
reply->arg1 = htonl(lastResult);
reply->arg2 = htonl(status);
}
void sendDataToClient(int sock, const RPCMessage* reply, const struct sockaddr_in* echoClntAddr, int recvMsgSize) {
/* Send received datagram back to the client */
if (sendto(sock, &*reply, sizeof(*reply), 0, (struct sockaddr*) &*echoClntAddr, sizeof(*echoClntAddr))
!= recvMsgSize)
DieWithError("sendto() sent a different number of bytes than expected");
}
int blockUntilMsgRecv(int recvMsgSize, int sock, unsigned int cliAddrLen, RPCMessage* request,
struct sockaddr_in* echoClntAddr) {
/* Block until receive message from a client */
if ((recvMsgSize = recvfrom(sock, &*request, sizeof(*request), 0, (struct sockaddr*) &*echoClntAddr, &cliAddrLen))
< 0)
DieWithError("recvfrom() failed");
return recvMsgSize;
}
void localAddressInitBlock(unsigned short echoServPort, struct sockaddr_in* echoServAddr) {
/* Construct local address structure */
memset(echoServAddr, 0, sizeof(struct sockaddr_in));
/* Zero out structure */
echoServAddr->sin_family = AF_INET;
echoServAddr->sin_addr.s_addr = htonl(INADDR_ANY);
echoServAddr->sin_port = htons(echoServPort);
}
int main(int argc, char **argv) {
int sock; /* Socket */
struct sockaddr_in echoServAddr; /* Local address */
struct sockaddr_in echoClntAddr; /* Client address */
unsigned int cliAddrLen; /* Length of incoming message */
RPCMessage request, reply;
unsigned short echoServPort; /* Server port */
int recvMsgSize; /* Size of received message */
int lastResult = 0;
int status;
if (argc != 2) /* Test for correct number of parameters */
{
fprintf(stderr, "Usage: %s <UDP SERVER PORT>\n", argv[0]);
exit(1);
}
echoServPort = atoi(argv[1]); /* First arg: local port */
/* Create socket for sending/receiving datagrams */
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
DieWithError("socket() failed");
/* Construct local address structure */
localAddressInitBlock(echoServPort, &echoServAddr);
/* Bind to the local address */
if (bind(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
DieWithError("bind() failed");
for (;;) { /* Run forever */
/* Set the size of the in-out parameter */
cliAddrLen = sizeof(echoClntAddr);
/* Block until receive message from a client */
recvMsgSize = blockUntilMsgRecv(recvMsgSize, sock, cliAddrLen, &request, &echoClntAddr);
//re-storing from network byte order to byte order
processNetworkByteOrder(&request);
//check for request type
lastResult = processOperation(lastResult, &request, &status);
//populate reply, don't need to populate procedureId
populateReply(&request, lastResult, status, &reply);
printf("Handling client %s\n", inet_ntoa(echoClntAddr.sin_addr));
/* Send received datagram back to the client */
sendDataToClient(sock, &reply, &echoClntAddr, recvMsgSize);
}
/* NOT REACHED */
}