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
|
/* b01902062 藍挺瑋 */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "chttpd-socket.h"
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#define SOCKADDR(x) ((struct sockaddr*)(x))
#define SOCKLEN(x) ((socklen_t)(x))
int chttpd_socket_new_unix (const char* path,
struct sockaddr_un* saddr, socklen_t* saddrlen) {
struct sockaddr_un addr;
socklen_t addrlen = sizeof (addr);
size_t pathlen;
memset (&addr, 0, sizeof (addr));
pathlen = sizeof (addr) - offsetof (struct sockaddr_un, sun_path) - 1;
addr.sun_family = AF_UNIX;
strncpy (addr.sun_path, path, pathlen);
int sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0) {
return CHTTPD_SOCKET_NEW_ERROR_SOCKET;
}
if (bind (sockfd, SOCKADDR (&addr), addrlen) < 0) {
close (sockfd);
return CHTTPD_SOCKET_NEW_ERROR_BIND;
}
if (listen (sockfd, SOMAXCONN) < 0) {
close (sockfd);
return CHTTPD_SOCKET_NEW_ERROR_LISTEN;
}
if (saddr != NULL) {
*saddr = addr;
}
if (saddrlen != NULL) {
*saddrlen = addrlen;
}
return sockfd;
}
int chttpd_socket_new_inet (const char* host, const char* service, int domain,
struct sockaddr* saddr, socklen_t* saddrlen, int* error) {
if (service == NULL) {
service = "http";
}
if (domain != AF_INET && domain != AF_INET6) {
domain = AF_UNSPEC;
}
struct addrinfo hints, *result;
memset (&hints, 0, sizeof (hints));
hints.ai_family = domain;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
int gai_error = getaddrinfo (host, service, &hints, &result);
if (gai_error != 0) {
if (error != NULL) {
*error = gai_error;
}
return CHTTPD_SOCKET_NEW_ERROR_GETADDRINFO;
}
int sockfd = -1;
int bindrv = -1;
for (struct addrinfo* iter = result; iter != NULL; iter = iter->ai_next) {
sockfd = socket (iter->ai_family, SOCK_STREAM, 0);
if (sockfd < 0) {
continue;
}
if (iter->ai_family == AF_INET6) {
setsockopt (sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
&(int){ 1 }, sizeof (int));
}
bindrv = bind (sockfd, iter->ai_addr, iter->ai_addrlen);
if (bindrv < 0) {
close (sockfd);
} else if (listen (sockfd, SOMAXCONN) < 0) {
close (sockfd);
} else {
if (saddr != NULL) {
switch (iter->ai_family) {
case AF_INET:
*(struct sockaddr_in*)(saddr) =
*(struct sockaddr_in*)(iter->ai_addr);
break;
case AF_INET6:
*(struct sockaddr_in6*)(saddr) =
*(struct sockaddr_in6*)(iter->ai_addr);
break;
default:
freeaddrinfo (result);
return CHTTPD_SOCKET_NEW_ERROR_UNEXPECTED;
}
}
if (saddrlen != NULL) {
*saddrlen = iter->ai_addrlen;
}
freeaddrinfo (result);
return sockfd;
}
}
freeaddrinfo (result);
if (sockfd < 0) {
return CHTTPD_SOCKET_NEW_ERROR_SOCKET;
}
if (bindrv < 0) {
return CHTTPD_SOCKET_NEW_ERROR_BIND;
}
return CHTTPD_SOCKET_NEW_ERROR_LISTEN;
}
|