-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathsocket.c
107 lines (93 loc) · 2.22 KB
/
socket.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
#include "socket.h"
#include <stdio.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define TCP_BACKLOG SOMAXCONN
/* adapted from
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html
*
* svc: either a name like "ftp" or a port number as string
*
* Returns: socket file desciptor, or negative error value
*/
int negotiate_listen(const char *svc)
{
int sock, e, reuseaddr=1;
struct addrinfo hints = {0}, *addrs, *ap;
hints.ai_family = AF_INET; /* IPv4 required for PASV command */
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = IPPROTO_TCP;
if ((e = getaddrinfo(NULL, svc, &hints, &addrs)) != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(e));
return -1;
}
for (ap = addrs; ap != NULL; ap = ap->ai_next)
{
sock = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol);
if (sock < 0)
continue;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
&reuseaddr,sizeof(reuseaddr)) < 0)
perror("setsockopt(REUSEADDR)");
if (bind(sock, ap->ai_addr, ap->ai_addrlen) == 0)
break; /* noice */
perror("Failed to bind");
close(sock);
}
freeaddrinfo(addrs);
if (ap == NULL)
{
fprintf(stderr, "Could not bind\n");
return -1;
}
if (listen(sock, TCP_BACKLOG) < 0)
{
perror("listen()");
close(sock);
return -1;
}
return sock;
}
int get_ip_port(int sock, int *ip, int *port)
{
struct sockaddr_in addr = {0};
socklen_t addr_len = sizeof addr;
int matched;
char *dotted;
if (getsockname(sock, (struct sockaddr*)&addr, &addr_len) != 0)
{
perror("getsockname");
return -1;
}
if (ip != NULL)
{
dotted = inet_ntoa(addr.sin_addr);
matched = sscanf(dotted, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]);
if (matched < 4)
{
fprintf(stderr, "Unable to parse IPv4 in %s\n", dotted);
return -1;
}
}
if (port != NULL)
*port = addr.sin_port;
return 0;
}
FILE *sock_stream(int sock, const char *mode)
{
FILE *ret;
if((ret = fdopen(sock, mode)) == NULL)
{
perror("fdopen()");
return NULL;
}
/* just a preference */
if (setvbuf(ret, NULL, _IOLBF, BUFSIZ) != 0)
perror("Warning: unable to change socket buffering");
return ret;
}