#include "config.h"
#endif /* HAVE_CONFIG_H */
-#ifndef _XOPEN_SOURCE
-# define _XOPEN_SOURCE 600
-#endif
-#ifndef __EXTENSIONS__
-# define __EXTENSIONS__
-#endif
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE
-#endif
+#include <atalk/standards.h>
+
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
-#include <arpa/inet.h>
+#include <sys/uio.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
* @param lenght (r) how many bytes to read
* @param setnonblocking (r) when non-zero this func will enable and disable non blocking
* io mode for the socket
- * @param timeout (r) number of seconds to try reading
+ * @param timeout (r) number of seconds to try reading, 0 means no timeout
*
* @returns number of bytes actually read or -1 on timeout or error
*/
}
/* Calculate end time */
- (void)gettimeofday(&now, NULL);
- end = now;
- end.tv_sec += timeout;
+ if (timeout) {
+ (void)gettimeofday(&now, NULL);
+ end = now;
+ end.tv_sec += timeout;
+ }
while (stored < length) {
- len = read(socket, (char *) data + stored, length - stored);
+ len = recv(socket, (char *) data + stored, length - stored, 0);
if (len == -1) {
switch (errno) {
case EINTR:
continue;
case EAGAIN:
FD_SET(socket, &rfds);
- tv.tv_usec = 0;
- tv.tv_sec = timeout;
-
- while ((ret = select(socket + 1, &rfds, NULL, NULL, &tv)) < 1) {
+ if (timeout) {
+ tv.tv_usec = 0;
+ tv.tv_sec = timeout;
+ }
+
+ while ((ret = select(socket + 1, &rfds, NULL, NULL, timeout ? &tv : NULL)) < 1) {
switch (ret) {
case 0:
- LOG(log_debug, logtype_afpd, "select timeout %d s", timeout);
+ LOG(log_debug, logtype_dsi, "select timeout %d s", timeout);
errno = EAGAIN;
goto exit;
default: /* -1 */
- if (errno == EINTR) {
- (void)gettimeofday(&now, NULL);
- if (now.tv_sec >= end.tv_sec && now.tv_usec >= end.tv_usec) {
- LOG(log_warning, logtype_afpd, "select timeout %d s", timeout);
- goto exit;
- }
- if (now.tv_usec > end.tv_usec) {
- tv.tv_usec = 1000000 + end.tv_usec - now.tv_usec;
- tv.tv_sec = end.tv_sec - now.tv_sec - 1;
- } else {
- tv.tv_usec = end.tv_usec - now.tv_usec;
- tv.tv_sec = end.tv_sec - now.tv_sec;
+ switch (errno) {
+ case EINTR:
+ if (timeout) {
+ (void)gettimeofday(&now, NULL);
+ if (now.tv_sec > end.tv_sec
+ ||
+ (now.tv_sec == end.tv_sec && now.tv_usec >= end.tv_usec)) {
+ LOG(log_debug, logtype_afpd, "select timeout %d s", timeout);
+ goto exit;
+ }
+ if (now.tv_usec > end.tv_usec) {
+ tv.tv_usec = 1000000 + end.tv_usec - now.tv_usec;
+ tv.tv_sec = end.tv_sec - now.tv_sec - 1;
+ } else {
+ tv.tv_usec = end.tv_usec - now.tv_usec;
+ tv.tv_sec = end.tv_sec - now.tv_sec;
+ }
}
FD_SET(socket, &rfds);
continue;
+ case EBADF:
+ /* possibly entered disconnected state, don't spam log here */
+ LOG(log_debug, logtype_afpd, "select: %s", strerror(errno));
+ stored = -1;
+ goto exit;
+ default:
+ LOG(log_error, logtype_afpd, "select: %s", strerror(errno));
+ stored = -1;
+ goto exit;
}
- LOG(log_error, logtype_afpd, "select: %s", strerror(errno));
- stored = -1;
- goto exit;
}
} /* while (select) */
continue;
return ret;
}
-#define POLL_FD_SET_STARTSIZE 512
-#define POLL_FD_SET_INCREASE 128
/*!
* Add a fd to a dynamic pollfd array that is allocated and grown as needed
*
* This uses an additional array of struct polldata which stores type information
* (enum fdtype) and a pointer to anciliary user data.
*
- * 1. Allocate the arrays with an intial size of [POLL_FD_SET_STARTSIZE] if
- * *fdsetp is NULL.
- * 2. Grow array as needed
- * 3. Fill in both array elements and increase count of used elements
+ * 1. Allocate the arrays with the size of "maxconns" if *fdsetp is NULL.
+ * 2. Fill in both array elements and increase count of used elements
*
+ * @param maxconns (r) maximum number of connections, determines array size
* @param fdsetp (rw) pointer to callers pointer to the pollfd array
* @param polldatap (rw) pointer to callers pointer to the polldata array
* @param fdset_usedp (rw) pointer to an int with the number of used elements
* @param fdtype (r) type of fd, currently IPC_FD or LISTEN_FD
* @param data (rw) pointer to data the caller want to associate with an fd
*/
-void fdset_add_fd(struct pollfd **fdsetp,
+void fdset_add_fd(int maxconns,
+ struct pollfd **fdsetp,
struct polldata **polldatap,
int *fdset_usedp,
int *fdset_sizep,
LOG(log_debug, logtype_default, "fdset_add_fd: adding fd %i in slot %i", fd, *fdset_usedp);
if (fdset == NULL) { /* 1 */
- /* Initialize with space for 512 fds */
- fdset = calloc(POLL_FD_SET_STARTSIZE, sizeof(struct pollfd));
+ /* Initialize with space for all possibly active fds */
+ fdset = calloc(maxconns, sizeof(struct pollfd));
if (! fdset)
exit(EXITERR_SYS);
- polldata = calloc(POLL_FD_SET_STARTSIZE, sizeof(struct polldata));
+ polldata = calloc(maxconns, sizeof(struct polldata));
if (! polldata)
exit(EXITERR_SYS);
- fdset_size = 512;
- *fdset_sizep = fdset_size;
- *fdsetp = fdset;
- *polldatap = polldata;
- }
-
- if (*fdset_usedp >= fdset_size) { /* 2 */
- fdset = realloc(fdset, sizeof(struct pollfd) * (fdset_size + POLL_FD_SET_INCREASE));
- if (fdset == NULL)
- exit(EXITERR_SYS);
-
- polldata = realloc(polldata, sizeof(struct polldata) * (fdset_size + POLL_FD_SET_INCREASE));
- if (polldata == NULL)
- exit(EXITERR_SYS);
+ fdset_size = maxconns;
- fdset_size += POLL_FD_SET_INCREASE;
*fdset_sizep = fdset_size;
*fdsetp = fdset;
*polldatap = polldata;
+
+ LOG(log_debug, logtype_default, "fdset_add_fd: initialized with space for %i conncections",
+ maxconns);
}
- /* 3 */
+ /* 2 */
fdset[*fdset_usedp].fd = fd;
fdset[*fdset_usedp].events = POLLIN;
polldata[*fdset_usedp].fdtype = fdtype;
* Remove a fd from our pollfd array
*
* 1. Search fd
- * 2. If we remove the last array elemnt, just decrease count
+ * 2a Matched last (or only) in the set ? null it and return
+ * 2b If we remove the last array elemnt, just decrease count
* 3. If found move all following elements down by one
* 4. Decrease count of used elements in array
*
struct pollfd *fdset = *fdsetp;
struct polldata *polldata = *polldatap;
+ if (*fdset_usedp < 1)
+ return;
+
for (int i = 0; i < *fdset_usedp; i++) {
if (fdset[i].fd == fd) { /* 1 */
- if (i < (*fdset_usedp - 1)) { /* 2 */
- memmove(&fdset[i], &fdset[i+1], (*fdset_usedp - 1) * sizeof(struct pollfd)); /* 3 */
- memmove(&polldata[i], &polldata[i+1], (*fdset_usedp - 1) * sizeof(struct polldata)); /* 3 */
+ if ((i + 1) == *fdset_usedp) { /* 2a */
+ fdset[i].fd = -1;
+ memset(&polldata[i], 0, sizeof(struct polldata));
+ } else if (i < (*fdset_usedp - 1)) { /* 2b */
+ memmove(&fdset[i],
+ &fdset[i+1],
+ (*fdset_usedp - i - 1) * sizeof(struct pollfd)); /* 3 */
+ memmove(&polldata[i],
+ &polldata[i+1],
+ (*fdset_usedp - i - 1) * sizeof(struct polldata)); /* 3 */
}
(*fdset_usedp)--;
break;