-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNetworkProgramming.txt
More file actions
386 lines (296 loc) · 11.2 KB
/
NetworkProgramming.txt
File metadata and controls
386 lines (296 loc) · 11.2 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
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
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
server client
-----------------------------------------
getaddrinfo()
socket()
bind()
listen()
getaddrinfo()
socket()
accept() connect()
send() & recv() send() & recv()
close() close()
DATA STRUCTURES & FUNCTIONS
-----
struct addrinfo {
int ai_flags; // AI_PASSIVE, AI_CANONNAME, etc.
int ai_family; // AF_INET, AF_INET6, AF_UNSPEC
int ai_socktype; // SOCK_STREAM, SOCK_DGRAM
int ai_protocol; // use 0 for "any"
size_t ai_addrlen; // size of ai_addr in bytes
struct sockaddr *ai_addr; // struct sockaddr_in or _in6
char *ai_canonname; // full canonical hostname
struct addrinfo *ai_next; // linked list, next node
};
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
// (IPv4 only--see struct sockaddr_in6 for IPv6)
struct sockaddr_in {
short int sin_family; // Address family, AF_INET
unsigned short int sin_port; // Port number
struct in_addr sin_addr; // IP addr
unsigned char sin_zero[8]; // Same size as struct sockaddr
};
// Internet address (a structure for historical reasons)
struct in_addr {
uint32_t s_addr; // that's a 32-bit int (4 bytes)
};
// (IPv6 only--see struct sockaddr_in and struct in_addr for IPv4)
struct sockaddr_in6 {
u_int16_t sin6_family; // address family, AF_INET6
u_int16_t sin6_port; // port number, Network Byte Order
u_int32_t sin6_flowinfo; // IPv6 flow information
struct in6_addr sin6_addr; // IPv6 address
u_int32_t sin6_scope_id; // Scope ID
};
struct in6_addr {
unsigned char s6_addr[16]; // IPv6 address
};
// In some cases, we don't know if v4 or v6 structure is returned. So,
// using below struct, pass both v4 and v6 structs in parallel and
// depending on family type (ss_family), cast to sockaddr_in or _in6.
struct sockaddr_storage {
sa_family_t ss_family; // address family
// all this is padding, implementation specific, ignore it:
char __ss_pad1[_SS_PAD1SIZE];
int64_t __ss_align;
char __ss_pad2[_SS_PAD2SIZE];
};
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
int socket(int domain, int type, int protocol);
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
int listen(int sockfd, int backlog);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int send(int sockfd, const void *msg, int len, int flags);
int recv(int sockfd, void *buf, int len, int flags);
sendto() and recvfrom() - DGRAM sockets
close(sockfd);
int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);
int gethostname(char *hostname, size_t size);
int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
inet_pton()
inet_ntop()
FD_SET(int fd, fd_set *set)
FD_CLR(int fd, fd_set *set)
FD_ISSET(int fd, fd_set *set)
FD_ZERO(fd_set *set)
NOTES [1]
-----
Socket descriptor type: int
struct addrinfo
- Above struct is filled and then getaddrinfo() is called. OS will return
a pointer to linked list of above structs filled with all required data.
struct sockaddr
- sa_data within this struct contains destination IP and port number and
is not easy to use. So, sockaddr_in is created to use interchangeably
with sockaddr (typecast between the two).
// (IPv4 only--see struct sockaddr_in6 for IPv6)
struct sockaddr_in
- sin_zero is zero'd out. Its only used as padding to match sockaddr size.
- sin_family in sockaddr_in corresponds to sa_family in sockaddr
// Internet address (a structure for historical reasons)
struct in_addr
- Now for below variable, accessing IP address is:
struct sockaddr_in ina;
ina.sin_addr.s_addr;
// (IPv6 only--see struct sockaddr_in and struct in_addr for IPv4)
struct sockaddr_in6
struct in6_addr
SYSTEM CALLS
-------
[1]
/*
* node = host name or IP to connect to.
* service = Port number or any service such as http, ftp, telnet etc. It
* can be found in /etc/services file.
* hints = structure that we fill out
* res = pointer to linked list of results
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int getaddrinfo(const char *node, // e.g. "www.example.com" or IP
const char *service, // e.g. "http" or port number
const struct addrinfo *hints,
struct addrinfo **res);
- Workhorse of a function. It helps setup structs that will be used later
on.
[2]
/*
* domain = AF type (AF_INET, AF_INET6) etc.
* type = Socket type (SOCK_STREAM, SOCK_DGRAM) etc.
* protocol =
*/
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
- Returns a socket descriptor that can be used in later sys calls. Its not
useful by itself, but is a pre-req before calling other sys calls.
[3]
/*
* sockfd = File descriptor returned by socket() call.
* my_addr = Contains info about your IP addr.
* addrlen = Length in bytes of your IP addr.
*/
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
- Once we have a socket, we "may" have to associate it with a port on your
local machine (using bind()). This is required if you are going to
listen() for incoming connections on a specific port (like Servers).
Kernel uses this to match incoming packet to a process's socket
descriptor. If your process is a client, bind() is not required. Client
only needs to connect() to the Server's socket.
WARNING: Donot bind to a port below 1024 as they are reserved.
NOTE: Sometimes, bind() fails with "Address already in use" message. Its
due to an earlier socket still hanging around. You can wait for a minute
or so and retry. Alternately, set an option on the socket to reuse the
address, as follows:
int yes=1;
//char yes='1'; // Solaris people use this
// lose the pesky "Address already in use" error message
if (setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
NOTE2: Sometimes bind() call is unnecessary. When connecting to remote
machine (as in telnet), where local port number is unimportant, you can
call connect(). It will check if socket is unbound and bind() it to unused
local port, if required.
[4]
/* sockfd =
* serv_addr = Destination IP addr info
* addrlen =
*/
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
- Helps a program to connect to remote host. No need to call bind() as we
don't care about local port number. Kernel will choose a local port for
us. Remote will get this info from us automatically.
[5]
/* sockfd =
* backlog = Number of connections allowed on incoming queue until we
* accept() them.
*/
int listen(int sockfd, int backlog);
- Servers listen() on certain ports for incoming connections. To establish
the connection, they have to make following calls:
getaddrinfo()
socket()
bind()
listen()
accept()
[6]
/*
* sockfd =
* addr =
* addrlen =
* return value = Its a socket descriptor to handle new connection.
*/
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- Here is the scenario: A Client tries to connect() to us, the Server and
is waiting in queue. Server is listen()'ing on a port and accept()'s the
incoming connection which will return a 'new socket descriptor' to use
for this connection. TWO new socket descriptors: First one listen()'s on
incoming connection and second one send()'s and recv()'s data on the new
connection.
[7]
/* sockfd = SD to send data to.
* msg =
* len =
* flags = Set it to 0.
*/
int send(int sockfd, const void *msg, int len, int flags);
- sockfd is SD you want to send data to (whether it's one returned by
socket() call or accept() call). It returns number of bytes of data
actually sent out.
/*
* sockfd = SD to read from
* buf = buffer to read data in to
* len = max len of buffer.
* flags = set to 0.
*/
int recv(int sockfd, void *buf, int len, int flags);
- Reads data in to buffer and returns number of bytes read. It can be
zero, meaning remote has closed connection.
NOTE: send() and recv() transfer data over STREAM sockets.
[8]
sendto() and recvfrom() - DGRAM sockets
[9]
close(sockfd);
- Close the socket. Both send() and recv() are not allowed anymore and
will return an error.
/* how = indicates HOW to shutdown
* 0 = further receives are not allowed
* 1 = further sends are not allowed
* 2 = Both send and receives are not allowed
*/
int shutdown(int sockfd, int how);
- shutdown() does not close the SD. It only changes its usability. To
close it, you have to call close().
[10]
#include <sys/socket.h>
int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);
[11]
#include <unistd.h>
int gethostname(char *hostname, size_t size);
ADVANCE TOPICS
------
- socket() returns descriptor that blocks on read/accept calls. It can be
set to NON-BLOCKING using fcntl() function as follows:
sockfd = socket(PF_INET, SOCK_STREAM, 0);
fcntl(sockfd, F_SETFL, O_NONBLOCK);
- We can then 'poll' the socket for data. But it's inefficient.
[12]
/*
* numfds = largest sockfd+1
* readfds = set of fd's to be read
* writefds = set of fd's to be written to
* exceptfds = set of fd's to be monitored for exception
* timeout =
*/
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int numfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
- select() allows to monitor several sockets at once. It indicates which
sockets are ready to read, write and threw exceptions. However, its
slow. 'libevent' is a popular alternative.
- Use FD_SET/CLR/ISSET/ZERO() macros to manipulate fd sets.
UTILITY FUNCTIONS
-------
inet_pton()
----------
- Converts an IP addr in to 'struct in_addr' or 'struct in6_addr' form,
depending on AF_INET or AF_INET6.
Example:
struct sockaddr_in sa; // IPv4
struct sockaddr_in6 sa6; // IPv6
inet_pton(AF_INET, "192.0.2.1", &(sa.sin_addr)); // IPv4
inet_pton(AF_INET6, "2001:db8:63b3:1::3490", &(sa6.sin6_addr)); // IPv6
inet_ntop()
----------
- Does opposite of inet_pton()
Example:
// IPv4:
char ip4[INET_ADDRSTRLEN]; // space to hold the IPv4 string
struct sockaddr_in sa; // pretend this is loaded with something
inet_ntop(AF_INET, &(sa.sin_addr), ip4, INET_ADDRSTRLEN);
printf("The IPv4 address is: %s\n", ip4);
// IPv6:
char ip6[INET6_ADDRSTRLEN]; // space to hold the IPv6 string
struct sockaddr_in6 sa6; // pretend this is loaded with something
inet_ntop(AF_INET6, &(sa6.sin6_addr), ip6, INET6_ADDRSTRLEN);
printf("The address is: %s\n", ip6);
FD_SET(int fd, fd_set *set) Add fd to 'set'
FD_CLR(int fd, fd_set *set) Remove fd from 'set'
FD_ISSET(int fd, fd_set *set) Return true if fd is in 'set'
FD_ZERO(fd_set *set) Clear all entries from 'set'
Reference:
[1] http://www.beej.us/guide/bgnet/