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
|
#include "libmmbackend.h"
void mmbackend_parse_hostspec(char* spec, char** host, char** port){
size_t u = 0;
if(!spec || !host || !port){
return;
}
*port = NULL;
//skip leading spaces
for(; spec[u] && isspace(spec[u]); u++){
}
if(!spec[u]){
*host = NULL;
return;
}
*host = spec + u;
//scan until string end or space
for(; spec[u] && !isspace(spec[u]); u++){
}
//if space, the rest should be the port
if(spec[u]){
spec[u] = 0;
*port = spec + u + 1;
}
}
int mmbackend_parse_sockaddr(char* host, char* port, struct sockaddr_storage* addr, socklen_t* len){
struct addrinfo* head;
struct addrinfo hints = {
.ai_family = AF_UNSPEC
};
int error = getaddrinfo(host, port, &hints, &head);
if(error || !head){
fprintf(stderr, "Failed to parse address %s port %s: %s\n", host, port, gai_strerror(error));
return 1;
}
memcpy(addr, head->ai_addr, head->ai_addrlen);
if(len){
*len = head->ai_addrlen;
}
freeaddrinfo(head);
return 0;
}
int mmbackend_socket(char* host, char* port, int socktype, uint8_t listener){
int fd = -1, status, yes = 1;
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = socktype,
.ai_flags = (listener ? AI_PASSIVE : 0)
};
struct addrinfo *info, *addr_it;
status = getaddrinfo(host, port, &hints, &info);
if(status){
fprintf(stderr, "Failed to parse address %s port %s: %s\n", host, port, gai_strerror(status));
return -1;
}
//traverse the result list
for(addr_it = info; addr_it; addr_it = addr_it->ai_next){
fd = socket(addr_it->ai_family, addr_it->ai_socktype, addr_it->ai_protocol);
if(fd < 0){
continue;
}
//set required socket options
yes = 1;
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(yes)) < 0){
fprintf(stderr, "Failed to enable SO_REUSEADDR on socket\n");
}
yes = 1;
if(setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (void*)&yes, sizeof(yes)) < 0){
fprintf(stderr, "Failed to enable SO_BROADCAST on socket\n");
}
yes = 0;
if(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void*)&yes, sizeof(yes)) < 0){
fprintf(stderr, "Failed to disable IP_MULTICAST_LOOP on socket: %s\n", strerror(errno));
}
status = bind(fd, addr_it->ai_addr, addr_it->ai_addrlen);
if(status < 0){
close(fd);
continue;
}
break;
}
freeaddrinfo(info);
if(!addr_it){
fprintf(stderr, "Failed to create socket for %s port %s\n", host, port);
return -1;
}
//set nonblocking
#ifdef _WIN32
u_long mode = 1;
if(ioctlsocket(fd, FIONBIO, &mode) != NO_ERROR){
closesocket(fd);
return 1;
}
#else
int flags = fcntl(fd, F_GETFL, 0);
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0){
fprintf(stderr, "Failed to set socket nonblocking\n");
close(fd);
return -1;
}
#endif
return fd;
}
|