-
Notifications
You must be signed in to change notification settings - Fork 362
Expand file tree
/
Copy pathsocket-posix.c
More file actions
169 lines (140 loc) · 4.18 KB
/
socket-posix.c
File metadata and controls
169 lines (140 loc) · 4.18 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
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#if !defined(_WIN32)
#include "libsocket.h"
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
libsocket_t socket_listen(const char* address, uint16_t port) {
libsocket_t fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
return INVALID_SOCKET;
}
int arg = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg));
int flags = fcntl(fd, F_GETFL, 0);
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
close(fd);
return INVALID_SOCKET;
}
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(address);
serv_addr.sin_port = htons(port);
if (bind(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
close(fd);
return INVALID_SOCKET;
}
listen(fd, 256);
return fd;
}
libsocket_t socket_accept(libsocket_t fd) {
libsocket_t client_fd = accept(fd, NULL, 0);
if (client_fd < 0) {
return INVALID_SOCKET;
}
#ifdef __APPLE__
int arg = 1;
setsockopt(client_fd, SOL_SOCKET, SO_NOSIGPIPE, &arg, sizeof(arg));
#endif
int flags = fcntl(client_fd, F_GETFL, 0);
if (fcntl(client_fd, F_SETFL, flags | O_NONBLOCK) == -1) {
close(client_fd);
return INVALID_SOCKET;
}
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
close(fd);
return INVALID_SOCKET;
}
return client_fd;
}
libsocket_t socket_connect(const char* address, uint16_t port) {
struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
hint.ai_family = AF_UNSPEC;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = IPPROTO_TCP;
char portbuf[6];
snprintf(portbuf, sizeof(portbuf), "%d", port);
struct addrinfo* result;
if (getaddrinfo (address, portbuf, &hint, &result) != 0) {
return INVALID_SOCKET;
}
libsocket_t fd;
struct addrinfo* addr;
for (addr = result; addr != NULL; addr = addr->ai_next) {
fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (fd < 0) {
continue;
}
if (connect(fd, addr->ai_addr, addr->ai_addrlen) != 0) {
close(fd);
continue;
}
break;
}
freeaddrinfo(result);
if (addr == NULL) {
return INVALID_SOCKET;
}
#ifdef __APPLE__
int arg = 1;
setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &arg, sizeof(arg));
#endif
int flags = fcntl(fd, F_GETFL, 0);
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
close(fd);
return INVALID_SOCKET;
}
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
close(fd);
return INVALID_SOCKET;
}
return fd;
}
ssize_t socket_send(libsocket_t fd, const uint8_t* data, size_t length) {
ssize_t remaining = length;
while (remaining > 0) {
#ifdef __APPLE__
ssize_t rv = send(fd, data, remaining, 0);
#else
ssize_t rv = send(fd, data, remaining, MSG_NOSIGNAL);
#endif
if (rv <= 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
return rv;
} else {
return length - remaining;
}
}
remaining -= rv;
data += rv;
}
return length;
}
ssize_t socket_recv(libsocket_t fd, uint8_t* data, size_t length) {
return read(fd, data, length);
}
int socket_shutdown(libsocket_t socket) {
return shutdown(socket, SHUT_RDWR);
}
int socket_close(libsocket_t fd) {
return close(fd);
}
#endif