-
Notifications
You must be signed in to change notification settings - Fork 0
/
socket.c
136 lines (113 loc) · 2.46 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
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
#define LOG_PFX SOCKET
#include "socket.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
bool
socket_connected(socket_t *s)
{
return s->fd != -1;
}
void
socket_disconnect(socket_t *s)
{
if (s->fd != -1) {
if (s->on_disconnect != NULL) {
s->on_disconnect(s);
}
close(s->fd);
s->fd = -1;
}
}
err_t
socket_handle_connect(socket_t *s)
{
socklen_t len;
int sockoptval = 1;
struct sockaddr_in cli;
if (s->fd == -1) {
len = sizeof(cli);
s->fd = accept(s->sockfd, (struct sockaddr *) &cli, &len);
if (s->fd != -1) {
setsockopt(s->fd, SOL_SOCKET, SO_NOSIGPIPE,
&sockoptval, sizeof(int));
if (s->on_connect != NULL) {
s->on_connect(s);
}
return ERR_NONE;
}
} else {
return ERR_NONE;
}
return ERR_NOT_READY;
}
err_t
socket_init(socket_t *s)
{
int sockflags;
int sockoptval = 1;
struct sockaddr_in servaddr;
s->fd = -1;
s->sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s->sockfd < 0) {
POSIX_ERROR(errno, "socket");
return ERR_POSIX;
}
sockflags = fcntl(s->sockfd, F_GETFL);
fcntl(s->sockfd, F_SETFL, sockflags | O_NONBLOCK);
setsockopt(s->sockfd, SOL_SOCKET, SO_REUSEADDR, &sockoptval, sizeof(int));
setsockopt(s->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &sockoptval, sizeof(int));
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(s->port);
if (bind(s->sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) != 0) {
POSIX_ERROR(errno, "bind");
return ERR_POSIX;
}
if (listen(s->sockfd, 1) != 0) {
POSIX_ERROR(errno, "listen");
return ERR_POSIX;
}
return ERR_NONE;
}
void
socket_out(socket_t *s,
const char *buf,
length_t len)
{
int written;
if (socket_handle_connect(s) != ERR_NONE) {
return;
}
while (len != 0) {
written = write(s->fd, buf, len);
if (written == -1) {
POSIX_ERROR(errno, "term write");
}
len -= written;
buf += written;
}
}
length_t
socket_in(socket_t *s,
char *buf,
length_t expected)
{
int ret;
if (socket_handle_connect(s) != ERR_NONE) {
return 0;
}
ret = read(s->fd, buf, expected);
if (ret == 0) {
socket_disconnect(s);
} else if (ret == -1) {
if (errno != EAGAIN) {
POSIX_ERROR(errno, "read");
}
return 0;
}
return ret;
}