28 |
|
#include <netinet/ip.h> |
29 |
|
#include <netinet/tcp.h> |
30 |
|
#include "list.h" |
31 |
– |
#include "fdlist.h" |
31 |
|
#include "s_bsd.h" |
32 |
|
#include "client.h" |
33 |
|
#include "dbuf.h" |
35 |
– |
#include "event.h" |
34 |
|
#include "irc_string.h" |
35 |
|
#include "ircd.h" |
36 |
|
#include "listener.h" |
46 |
|
#include "memory.h" |
47 |
|
#include "s_user.h" |
48 |
|
#include "msgq.h" |
49 |
+ |
#include "ioengine.h" |
50 |
|
|
51 |
|
|
52 |
|
dlink_list connection_list; |
239 |
|
|
240 |
|
if (res > -1) |
241 |
|
{ |
242 |
< |
*length_out = res; |
242 |
> |
*length_out = (unsigned int)res; |
243 |
|
return IO_SUCCESS; |
244 |
|
} |
245 |
|
|
265 |
|
|
266 |
|
if ((res = send(fd, buf, length, 0)) > -1) |
267 |
|
{ |
268 |
< |
*count_out = (unsigned) res; |
268 |
> |
*count_out = (unsigned int)res; |
269 |
|
return IO_SUCCESS; |
270 |
|
} |
271 |
|
|
304 |
|
return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE; |
305 |
|
} |
306 |
|
|
307 |
+ |
/** Attempt to write on a non-blocking UDP socket. |
308 |
+ |
* @param[in] fd File descriptor to write to. |
309 |
+ |
* @param[in] buf Output buffer to send from. |
310 |
+ |
* @param[in] length Number of bytes to write. |
311 |
+ |
* @param[out] count_out Receives number of bytes actually written. |
312 |
+ |
* @param[in] flags Flags for call to sendto(). |
313 |
+ |
* @param[in] peer Destination address of the message. |
314 |
+ |
* @return An IOResult value indicating status. |
315 |
+ |
*/ |
316 |
+ |
IOResult os_sendto_nonb(int fd, const char *buf, unsigned int length, |
317 |
+ |
unsigned int *count_out, unsigned int flags, |
318 |
+ |
struct irc_ssaddr *peer) |
319 |
+ |
{ |
320 |
+ |
int res = 0, size = 0; |
321 |
+ |
|
322 |
+ |
assert(buf); |
323 |
+ |
|
324 |
+ |
if ((res = sendto(fd, buf, length, flags, (struct sockaddr *)&peer, peer->ss_len)) > -1) |
325 |
+ |
{ |
326 |
+ |
if (count_out) |
327 |
+ |
*count_out = (unsigned int)res; |
328 |
+ |
return IO_SUCCESS; |
329 |
+ |
} |
330 |
+ |
|
331 |
+ |
if (count_out) |
332 |
+ |
*count_out = 0; |
333 |
+ |
return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE; |
334 |
+ |
} |
335 |
+ |
|
336 |
+ |
/** Start a non-blocking connection. |
337 |
+ |
* @param[in] fd Disconnected file descriptor. |
338 |
+ |
* @param[in] sin Target address for connection. |
339 |
+ |
* @return IOResult code indicating status. |
340 |
+ |
*/ |
341 |
+ |
IOResult os_connect_nonb(int fd, const struct irc_ssaddr *addr) |
342 |
+ |
{ |
343 |
+ |
int size; |
344 |
+ |
|
345 |
+ |
size = sockaddr_from_irc(&addr, sin, fd); |
346 |
+ |
if (connect(fd, (struct sockaddr*) &addr, size)) |
347 |
+ |
return (errno == EINPROGRESS) ? IO_BLOCKED : IO_FAILURE; |
348 |
+ |
return IO_SUCCESS; |
349 |
+ |
} |
350 |
+ |
|
351 |
+ |
int |
352 |
+ |
os_accept(int fd, struct irc_ssaddr *addr) |
353 |
+ |
{ |
354 |
+ |
int new_fd = 0; |
355 |
+ |
socklen_t addrlen = sizeof(struct irc_ssaddr); |
356 |
+ |
|
357 |
+ |
new_fd = accept(fd, (struct sockaddr *)addr, &addrlen); |
358 |
+ |
if (new_fd < 0) |
359 |
+ |
return -1; |
360 |
+ |
|
361 |
+ |
#ifdef IPV6 |
362 |
+ |
remove_ipv6_mapping(addr); |
363 |
+ |
#else |
364 |
+ |
addr->ss_len = addrlen; |
365 |
+ |
#endif |
366 |
+ |
setup_socket(new_fd); |
367 |
+ |
return new_fd; |
368 |
+ |
} |
369 |
+ |
|
370 |
+ |
int |
371 |
+ |
os_socket(int family, int sock_type, int proto) |
372 |
+ |
{ |
373 |
+ |
int fd; |
374 |
+ |
|
375 |
+ |
fd = socket(family, sock_type, proto); |
376 |
+ |
if (fd < 0) |
377 |
+ |
return -1; |
378 |
+ |
setup_socket(fd); |
379 |
+ |
return fd; |
380 |
+ |
} |
381 |
+ |
|
382 |
|
/* |
383 |
|
* report_error - report an error from an errno. |
384 |
|
* Record error to log and also send a copy to all *LOCAL* opers online. |
927 |
|
} |
928 |
|
|
929 |
|
/* |
856 |
– |
* comm_checktimeouts() - check the socket timeouts |
857 |
– |
* |
858 |
– |
* All this routine does is call the given callback/cbdata, without closing |
859 |
– |
* down the file descriptor. When close handlers have been implemented, |
860 |
– |
* this will happen. |
861 |
– |
*/ |
862 |
– |
void |
863 |
– |
comm_checktimeouts(void *notused) |
864 |
– |
{ |
865 |
– |
int i; |
866 |
– |
fde_t *F; |
867 |
– |
PF *hdl; |
868 |
– |
void *data; |
869 |
– |
|
870 |
– |
for (i = 0; i < FD_HASH_SIZE; i++) |
871 |
– |
for (F = fd_hash[i]; F != NULL; F = fd_next_in_loop) |
872 |
– |
{ |
873 |
– |
assert(F->flags.open); |
874 |
– |
fd_next_in_loop = F->hnext; |
875 |
– |
|
876 |
– |
/* check flush functions */ |
877 |
– |
if (F->flush_handler && F->flush_timeout > 0 && |
878 |
– |
F->flush_timeout < CurrentTime) |
879 |
– |
{ |
880 |
– |
hdl = F->flush_handler; |
881 |
– |
data = F->flush_data; |
882 |
– |
comm_setflush(F, 0, NULL, NULL); |
883 |
– |
hdl(F, data); |
884 |
– |
} |
885 |
– |
|
886 |
– |
/* check timeouts */ |
887 |
– |
if (F->timeout_handler && F->timeout > 0 && |
888 |
– |
F->timeout < CurrentTime) |
889 |
– |
{ |
890 |
– |
/* Call timeout handler */ |
891 |
– |
hdl = F->timeout_handler; |
892 |
– |
data = F->timeout_data; |
893 |
– |
comm_settimeout(F, 0, NULL, NULL); |
894 |
– |
hdl(F, data); |
895 |
– |
} |
896 |
– |
} |
897 |
– |
} |
898 |
– |
|
899 |
– |
/* |
930 |
|
* void comm_connect_tcp(int fd, const char *host, unsigned short port, |
931 |
|
* struct sockaddr *clocal, int socklen, |
932 |
|
* CNCB *callback, void *data, int aftype, int timeout) |
1128 |
|
return comm_err_str[error]; |
1129 |
|
} |
1130 |
|
|
1101 |
– |
/* |
1102 |
– |
* comm_open() - open a socket |
1103 |
– |
* |
1104 |
– |
* This is a highly highly cut down version of squid's comm_open() which |
1105 |
– |
* for the most part emulates socket(), *EXCEPT* it fails if we're about |
1106 |
– |
* to run out of file descriptors. |
1107 |
– |
*/ |
1108 |
– |
int |
1109 |
– |
comm_open(fde_t *F, int family, int sock_type, int proto, const char *note) |
1110 |
– |
{ |
1111 |
– |
int fd; |
1112 |
– |
|
1113 |
– |
/* First, make sure we aren't going to run out of file descriptors */ |
1114 |
– |
if (number_fd >= hard_fdlimit) |
1115 |
– |
{ |
1116 |
– |
errno = ENFILE; |
1117 |
– |
return -1; |
1118 |
– |
} |
1119 |
– |
|
1120 |
– |
/* |
1121 |
– |
* Next, we try to open the socket. We *should* drop the reserved FD |
1122 |
– |
* limit if/when we get an error, but we can deal with that later. |
1123 |
– |
* XXX !!! -- adrian |
1124 |
– |
*/ |
1125 |
– |
fd = socket(family, sock_type, proto); |
1126 |
– |
if (fd < 0) |
1127 |
– |
return -1; /* errno will be passed through, yay.. */ |
1128 |
– |
|
1129 |
– |
setup_socket(fd); |
1130 |
– |
|
1131 |
– |
/* update things in our fd tracking */ |
1132 |
– |
fd_open(F, fd, 1, note); |
1133 |
– |
return 0; |
1134 |
– |
} |
1135 |
– |
|
1136 |
– |
/* |
1137 |
– |
* comm_accept() - accept an incoming connection |
1138 |
– |
* |
1139 |
– |
* This is a simple wrapper for accept() which enforces FD limits like |
1140 |
– |
* comm_open() does. Returned fd must be either closed or tagged with |
1141 |
– |
* fd_open (this function no longer does it). |
1142 |
– |
*/ |
1143 |
– |
int |
1144 |
– |
comm_accept(struct Listener *lptr, struct irc_ssaddr *pn) |
1145 |
– |
{ |
1146 |
– |
int newfd; |
1147 |
– |
socklen_t addrlen = sizeof(struct irc_ssaddr); |
1148 |
– |
|
1149 |
– |
if (number_fd >= hard_fdlimit) |
1150 |
– |
{ |
1151 |
– |
errno = ENFILE; |
1152 |
– |
return -1; |
1153 |
– |
} |
1154 |
– |
|
1155 |
– |
/* |
1156 |
– |
* Next, do the accept(). if we get an error, we should drop the |
1157 |
– |
* reserved fd limit, but we can deal with that when comm_open() |
1158 |
– |
* also does it. XXX -- adrian |
1159 |
– |
*/ |
1160 |
– |
newfd = accept(lptr->fd.fd, (struct sockaddr *)pn, &addrlen); |
1161 |
– |
if (newfd < 0) |
1162 |
– |
return -1; |
1163 |
– |
|
1164 |
– |
#ifdef IPV6 |
1165 |
– |
remove_ipv6_mapping(pn); |
1166 |
– |
#else |
1167 |
– |
pn->ss_len = addrlen; |
1168 |
– |
#endif |
1169 |
– |
|
1170 |
– |
execute_callback(setup_socket_cb, newfd); |
1171 |
– |
|
1172 |
– |
/* .. and return */ |
1173 |
– |
return newfd; |
1174 |
– |
} |
1175 |
– |
|
1131 |
|
/* |
1132 |
|
* remove_ipv6_mapping() - Removes IPv4-In-IPv6 mapping from an address |
1133 |
|
* OSes with IPv6 mapping listening on both |