-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathtcp.c
147 lines (114 loc) · 3.97 KB
/
tcp.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
#include <malloc.h>
#include <netstack/api/tcp.h>
#include <netstack/tcp/tcp.h>
#include <netstack/col/alist.h>
#include <netinet/tcp.h>
#include <netstack/inet/route.h>
int socket_tcp(int domain, int type, int protocol) {
// elem is a pointer to the list element
struct inet_sock **elem = NULL, *sock;
int fd = (int) alist_add(&ns_sockets, (void **) &elem);
fd += NS_MIN_FD;
*elem = calloc(1, sizeof(struct tcp_sock));
sock = *elem;
sock->locaddr.proto = PROTO_IPV4;
sock->remaddr.proto = PROTO_IPV4;
tcp_sock_init((struct tcp_sock *) sock);
LOG(LVERB, "creating new TCP/IPv4 socket %p (fd %d)", sock, fd);
// Append optional socket flags if specified in type
if (type & SOCK_CLOEXEC)
sock->flags |= O_CLOEXEC;
if (type & SOCK_NONBLOCK)
sock->flags |= O_NONBLOCK;
sock->type = SOCK_STREAM;
return fd;
}
ssize_t recv_tcp(struct inet_sock *inet, void *buf, size_t len, int flags) {
struct tcp_sock *sock = (struct tcp_sock *) inet;
retns(tcp_user_recv(sock, buf, len, flags));
}
ssize_t send_tcp(struct inet_sock *inet, const void *buf, size_t len, int flags) {
struct tcp_sock *sock = (struct tcp_sock *) inet;
retns(tcp_user_send(sock, buf, len, flags));
}
int connect_tcp(struct inet_sock *inet, const struct sockaddr *addr,
socklen_t len) {
struct tcp_sock *sock = (struct tcp_sock *) inet;
// Store remote address in sock->inet
addr_from_sa(&inet->remaddr, &inet->remport, addr);
// Look up route and find local address to use
struct route_entry *rt = route_lookup(&inet->remaddr);
if (rt == NULL)
returnerr(EHOSTUNREACH);
addr_t *locaddr = (addr_t *) llist_peek(&rt->intf->inet);
if (locaddr == NULL)
returnerr(EADDRNOTAVAIL);
inet->intf = rt->intf;
inet->locaddr = *locaddr;
// Extract the local port
addr_from_sa(NULL, &inet->locport, addr);
// Choose a random outgoing port if one isn't specified
if (inet->locport == 0)
inet->locport = tcp_randomport();
// TODO: Ensure chosen outgoing TCP port isn't in use already
retns(tcp_user_open(sock));
}
int getsockopt_tcp(struct inet_sock *inet, int level, int opt, void *val,
socklen_t *restrict len) {
struct tcp_sock *sock = (struct tcp_sock *) inet;
// See tcp(7) for descriptions of these options
switch (opt) {
case TCP_CONGESTION:
case TCP_CORK:
case TCP_DEFER_ACCEPT:
case TCP_KEEPCNT:
case TCP_KEEPIDLE:
case TCP_KEEPINTVL:
case TCP_LINGER2:
case TCP_MAXSEG:
case TCP_INFO:
case TCP_USER_TIMEOUT:
case TCP_WINDOW_CLAMP:
default:
// These options are not implemented so just throw an error
returnerr(ENOPROTOOPT);
case TCP_NODELAY:
// Is always disabled
val = 0;
break;
}
return 0;
}
int setsockopt_tcp(struct inet_sock *inet, int level, int opt, const void *val,
socklen_t len) {
struct tcp_sock *sock = (struct tcp_sock *) inet;
// See tcp(7) for descriptions of these options
switch (opt) {
case TCP_CONGESTION:
case TCP_CORK:
case TCP_DEFER_ACCEPT:
case TCP_KEEPCNT:
case TCP_KEEPIDLE:
case TCP_KEEPINTVL:
case TCP_LINGER2:
case TCP_MAXSEG:
case TCP_INFO:
case TCP_USER_TIMEOUT:
case TCP_WINDOW_CLAMP:
default:
// These options are not implemented so just throw an error
returnerr(ENOPROTOOPT);
case TCP_NODELAY:
// Disables TCP Nagle's algorithm
// Return success as there's nothing to turn off
return 0;
}
}
int shutdown_tcp(struct inet_sock *inet, int how) {
struct tcp_sock *sock = (struct tcp_sock *) inet;
if (how == SHUT_WR || how == SHUT_RDWR) {
retns(tcp_user_close(sock));
}
// TODO: Handle SHUT_RD in shutdown_tcp
return 0;
}