-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuici.c
158 lines (144 loc) · 4.4 KB
/
uici.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* uici.c sockets implementation */
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/socket.h>
#include "uici.h"
#include "uiciname.h"
#ifndef MAXBACKLOG
#define MAXBACKLOG 50
#endif
/*
* u_igniore_sigpipe
* Ignore SIGPIPE if the default action is in effect.
*
* returns: 0 if successful
* -1 on error and sets errno
*/
static int u_ignore_sigpipe() {
struct sigaction act;
if (sigaction(SIGPIPE, (struct sigaction *)NULL, &act) == -1)
return -1;
if (act.sa_handler == SIG_DFL) {
act.sa_handler = SIG_IGN;
if (sigaction(SIGPIPE, &act, (struct sigaction *)NULL) == -1)
return -1;
}
return 0;
}
/*
* u_open
* Return a file descriptor, which is bound to the given port.
*
* parameter:
* s = number of port to bind to
* returns: file descriptor if successful
* -1 on error and sets errno
*/
int u_open(u_port_t port) {
int error;
struct sockaddr_in server;
int sock;
int true = 1;
if ((u_ignore_sigpipe() == -1) ||
((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1))
return -1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&true,
sizeof(true)) == -1) {
error = errno;
while ((close(sock) == -1) && (errno == EINTR));
errno = error;
return -1;
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons((short)port);
if ((bind(sock, (struct sockaddr *)&server, sizeof(server)) == -1) ||
(listen(sock, MAXBACKLOG) == -1)) {
error = errno;
while ((close(sock) == -1) && (errno == EINTR));
errno = error;
return -1;
}
return sock;
}
/*
* u_accept
* Wait for a connection request from a host on a specified port.
*
* parameters:
* fd = file descriptor previously bound to listening port
* hostn = a buffer that will hold the name of the remote host
* hostnsize = size of hostn buffer
* returns: a communication file descriptor on success
* hostn is filled with the name of the remote host.
* -1 on error with errno set
*
* comments: This function is used by the server to wait for a
* communication. It blocks until a remote request is received
* from the port bound to the given file descriptor.
* hostn is filled with an ASCII string containing the remote
* host name. It must point to a buffer of size at least hostnsize.
* If the name does not fit, as much of the name as is possible is put
* into the buffer.
* If hostn is NULL or hostnsize <= 0, no hostname is copied.
*/
int u_accept(int fd, char *hostn, int hostnsize) {
int len = sizeof(struct sockaddr);
struct sockaddr_in netclient;
int retval;
while (((retval =
accept(fd, (struct sockaddr *)(&netclient), &len)) == -1) &&
(errno == EINTR))
;
if ((retval == -1) || (hostn == NULL) || (hostnsize <= 0))
return retval;
addr2name(netclient.sin_addr, hostn, hostnsize);
return retval;
}
/*
* u_connect
* Initiate communication with a remote server.
*
* parameters:
* port = well-known port on remote server
* hostn = character string giving the Internet name of remote host
* returns: a communication file descriptor if successful
* -1 on error with errno set
*/
int u_connect(u_port_t port, char *hostn) {
int error;
int retval;
struct sockaddr_in server;
int sock;
fd_set sockset;
if (name2addr(hostn,&(server.sin_addr.s_addr)) == -1) {
errno = EINVAL;
return -1;
}
server.sin_port = htons((short)port);
server.sin_family = AF_INET;
if ((u_ignore_sigpipe() == -1) ||
((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1))
return -1;
if (((retval =
connect(sock, (struct sockaddr *)&server, sizeof(server))) == -1) &&
((errno == EINTR) || (errno == EALREADY))) {
FD_ZERO(&sockset);
FD_SET(sock, &sockset);
while ( ((retval = select(sock+1, NULL, &sockset, NULL, NULL)) == -1) &&
(errno == EINTR) ) {
FD_ZERO(&sockset);
FD_SET(sock, &sockset);
}
}
if (retval == -1) {
error = errno;
while ((close(sock) == -1) && (errno == EINTR));
errno = error;
return -1;
}
return sock;
}