forked from mit-pdos/xv6-public
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsock.c
316 lines (247 loc) · 8.33 KB
/
sock.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
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
#include "types.h"
#include "defs.h"
#include "param.h"
#include "spinlock.h"
#include "sock.h"
#include "memlayout.h"
#include "mmu.h"
#include "x86.h"
#include "proc.h"
#include "signalcodes.h"
struct {
struct spinlock lock;
struct sock sock[NSOCK];
} stable;
int countSock;
int nextsid;
//============================helper functions declaration====================
/// sets value to socket struct
void setsockvalue(struct sock *socket, int sid, enum sockstate state, struct proc *owner, int lPort, int rPort,
bool hasfullbuffer, char *buff, bool overWriteToDef);
/// returns socket @ port, NULL if no socket exists
struct sock *getsock(int port);
/// allocates a new socket @ port, NULL if any socket already exists @ that port.
/// increments count of current socket
struct sock *allocsock(int lport);
/// removes socket ,false if no socket exists or not called by owner
/// decrements count of current socket and also releases locks
bool removesock(struct sock *socket);
/// resets socket values to default
void resetsock(struct sock *socket);
/// returns a random free port
int getfreeport();
/// returns and releases the lock
int retsockfunc(int code);
/// returns the first socket in the table associated with the process, NULL if no such found
struct sock *getprocsock(struct proc *process);
//============================================================================
void
sinit(void) {
initlock(&stable.lock, "stable");
countSock = 0;
nextsid = 0;
}
/// new ServerSocket(port).accept() // from server
int
listen(int lport) {
DISCARD_INV_PORT(lport);
acquire(&stable.lock);
if (countSock == NSOCK) {
return retsockfunc(E_FAIL);
}
struct sock *s;
if ((s = allocsock(lport)) == NULL) {
// trying to listen on opened port
return retsockfunc(E_ACCESS_DENIED);
}
s->state = LISTENING;// set socket state to listening for server
sleep(s, &stable.lock);// wait until any client connects
return retsockfunc(0);
}
/// new Socket(hostname,port) // from client
int
connect(int rport, const char *host) {
DISCARD_INV_PORT(rport);
if (strncmp(host, "localhost", (uint) strlen(host)) != 0
&& strncmp(host, "127.0.0.1", (uint) strlen(host)) != 0) {
// Allow connection to "localhost" or "127.0.0.1" host only
return E_INVALID_ARG;
}
acquire(&stable.lock);
struct sock *local;
struct sock *remote = getsock(rport);
int lport = getfreeport();
if (lport == INV_PORT) return retsockfunc(E_FAIL); // no free ports
if (remote == NULL) return retsockfunc(E_NOTFOUND); // no socket assigned on remote port
if (remote->state != LISTENING)
return retsockfunc(E_WRONG_STATE); // if server is not ready to accept new connection or already connected
if ((local = allocsock(lport)) == NULL) { // create a socket on free local port
return retsockfunc(E_FAIL);// nSocket limits crossed
}
local->state = remote->state = CONNECTED;
local->rPort = remote->lPort;
remote->rPort = local->lPort;
remote->hasfullbuffer = local->hasfullbuffer = false;
wakeup(remote);// wakeup the remote listening server
return retsockfunc(lport);
}
/// socket.getos().write(data)
int
send(int lport, const char *data, int n) {
DISCARD_INV_PORT(lport);
acquire(&stable.lock);
struct sock *local = getsock(lport);
if (local == NULL) return retsockfunc(E_NOTFOUND);
if (local->owner != myproc()) return retsockfunc(E_ACCESS_DENIED); // accessed from other process
if (local->state != CONNECTED) return retsockfunc(E_WRONG_STATE);
struct sock *remote = getsock(local->rPort);
if (remote == NULL) return retsockfunc(E_NOTFOUND);
if (remote->state != CONNECTED) return retsockfunc(E_WRONG_STATE);
if (remote->hasfullbuffer) sleep(remote, &stable.lock);// while or if not sure ???
if (getsock(local->rPort) == NULL) {// woke up due to deletion of remote
removesock(local);
return retsockfunc(E_CONNECTION_RESET_BY_REMOTE);
}
strncpy(remote->recvbuffer, data, n);
remote->hasfullbuffer = true;
wakeup(local);
return retsockfunc(0);
}
/// socket.getis().read()
int
recv(int lport, char *data, int n) {
DISCARD_INV_PORT(lport);
acquire(&stable.lock);
struct sock *local = getsock(lport);
if (local == NULL) return retsockfunc(E_NOTFOUND);
if (local->owner != myproc()) return retsockfunc(E_ACCESS_DENIED); // accessed from other process
if (local->state != CONNECTED) return retsockfunc(E_WRONG_STATE);
struct sock *remote = getsock(local->rPort);
if (remote == NULL) return retsockfunc(E_NOTFOUND);// last sent data can also be blocked here
if (remote->state != CONNECTED) return retsockfunc(E_WRONG_STATE);
if (!local->hasfullbuffer) sleep(remote, &stable.lock);// while or if not sure ???
strncpy(data, local->recvbuffer, n);
*local->recvbuffer = NULL;// empty the buffer after reading
local->hasfullbuffer = false;
wakeup(local);
// after reading last unread buffer if connection is reset then close
if (getsock(local->rPort) == NULL) {// woke up due to deletion of remote
removesock(local);
return retsockfunc(E_CONNECTION_RESET_BY_REMOTE);
}
return retsockfunc(0);
}
/// socket.close()
int
disconnect(int lport) {
DISCARD_INV_PORT(lport);
acquire(&stable.lock);
struct sock *local = getsock(lport);
if (local == NULL) return retsockfunc(E_NOTFOUND);
if (local->owner != myproc()) return retsockfunc(E_ACCESS_DENIED); // accessed from other process
removesock(local);
return retsockfunc(0);
}
//============================helper functions definition====================
struct sock *
getsock(int port) {
if (port >= 0 && port < NPORT) {
for (struct sock *s = stable.sock; s < &stable.sock[NSOCK]; ++s) {
if (s->state != CLOSED && s->lPort == port) {
return s;
}
}
}
return NULL;
}
void
resetsock(struct sock *socket) {
setsockvalue(socket, SOCK_SID_DEF, SOCK_STATE_DEF, SOCK_OWNER_DEF, SOCK_LPORT_DEF, SOCK_RPORT_DEF,
SOCK_HASDATA_DEF, SOCK_BUFFER_DEF, true);
}
struct sock *
allocsock(int lport) {
if (lport < 0 || lport >= NPORT || getsock(lport)) return NULL;
for (struct sock *s = stable.sock; s < &stable.sock[NSOCK]; ++s) {
if (s->state == CLOSED) {
setsockvalue(s, nextsid, OPENED, myproc(), lport, SOCK_RPORT_DEF, false, "", true);
countSock++;
nextsid++;
#ifdef SO_DEBUG
cprintf(">> Adding socket %d, #Socket:%d\n", s->sid, countSock);
#endif
return s;
}
}
return NULL;
}
void
setsockvalue(struct sock *socket, int sid, enum sockstate state, struct proc *owner, int lPort, int rPort,
bool hasfullbuffer, char *buff, bool overWriteToDef) {
if (!socket) return;
if (overWriteToDef) {
socket->owner = owner;
socket->state = state;
socket->lPort = lPort;
socket->rPort = rPort;
socket->hasfullbuffer = hasfullbuffer;
socket->sid = sid;
strncpy(socket->recvbuffer, buff, 1);
} else {
if (owner != SOCK_OWNER_DEF) socket->owner = owner;
if (state != SOCK_STATE_DEF) socket->state = state;
if (lPort != SOCK_LPORT_DEF) socket->lPort = lPort;
if (rPort != SOCK_RPORT_DEF) socket->rPort = rPort;
if (hasfullbuffer != SOCK_HASDATA_DEF) socket->hasfullbuffer = hasfullbuffer;
if (sid != SOCK_SID_DEF) socket->sid = sid;
if (strncmp(buff, SOCK_BUFFER_DEF, 1) != 0) strncpy(socket->recvbuffer, buff, 1);
}
}
/// basically returns the first free port from the last
int
getfreeport() {
for (int port = NPORT - 1; port; --port) {
if (getsock(port) == NULL) return port;
}
return INV_PORT;
}
bool
removesock(struct sock *socket) {
if (socket == NULL) return false;
#ifdef SO_DEBUG
cprintf(">> Removing socket %d, #Socket:%d\n", socket->sid, countSock - 1);
#endif
wakeup(socket);// wakeup all processes sleeping on this lock
resetsock(socket);
--countSock;
return true;
}
int
retsockfunc(int code) {
release(&stable.lock);
return code;
}
struct sock *
getprocsock(struct proc *process) {
for (struct sock *s = stable.sock; s < &stable.sock[NSOCK]; ++s) {
if (s->state != CLOSED && s->owner == process) {
return s;
}
}
return NULL;
}
//============================================================================
//===========================Additional functions=============================
/// close all socket owned by this process
void
closeprocsocks(struct proc *process) {
if (process == NULL) return;
struct sock *s;
acquire(&stable.lock);
while ((s = getprocsock(process)) != NULL) {
removesock(s);
// disconnect(s->lPort);// introduces recursive lock
}
release(&stable.lock);
}
//============================================================================