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
|
/********************************************************************
* Description: sendn.c
* Provides a C file for the sendn function from the book Advanced
* Programming in the UNIX Environment by Richard Stevens.
* The sendn function calls the send function repeatedly until n bytes
* have been written to the file descriptor.
*
* Derived from a work by Fred Proctor & Will Shackleford
*
* Author:
* License: LGPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change:
********************************************************************/
#include <string.h> /* strerror */
#include <stdlib.h> /* memset() */
#include <errno.h> /* errno */
#include <math.h> /* fabs() */
#include <sys/socket.h> /* send(), recv(), socket(), accept(),
bind(), listen() */
#include <sys/time.h> /* struct timeval */
#include "sendn.h" /* sendn() */
#include "rcs_print.hh" /* rcs_print_error() */
#include "_timer.h" /* etime(), esleep() */
int sendn_timedout = 0;
int print_sendn_timeout_errors = 1;
/* Write "n" bytes to a descriptor. */
int sendn(int fd, const void *vptr, int n, int _flags, double _timeout)
{
int nleft;
long nwritten;
int select_ret;
double start_time;
char *ptr;
struct timeval timeout_tv;
fd_set send_fd_set;
timeout_tv.tv_sec = (long) _timeout;
timeout_tv.tv_usec = (long) (_timeout * 1000000.0);
if (timeout_tv.tv_usec >= 1000000) {
timeout_tv.tv_usec = timeout_tv.tv_usec % 1000000;
}
FD_ZERO(&send_fd_set);
FD_SET(fd, &send_fd_set);
ptr = (char *) vptr; /* can't do pointer arithmetic on void* */
nleft = n;
start_time = etime();
while (nleft > 0) {
if (fabs(_timeout) > 1E-6) {
if (_timeout > 0) {
double timeleft;
timeleft = start_time + _timeout - etime();
if (timeleft <= 0.0) {
if (print_sendn_timeout_errors) {
rcs_print_error
("sendn(fd=%d, vptr=%p, int n=%d, int flags=%d, double _timeout=%f) timed out.\n",
fd, vptr, n, _flags, _timeout);
}
sendn_timedout = 1;
return -1;
}
timeout_tv.tv_sec = (long) timeleft;
timeout_tv.tv_usec = (long) (timeleft * 1000000.0);
if (timeout_tv.tv_usec >= 1000000) {
timeout_tv.tv_usec = timeout_tv.tv_usec % 1000000;
}
select_ret =
select(fd + 1, (fd_set *) NULL, &send_fd_set,
(fd_set *) NULL, &timeout_tv);
} else {
select_ret =
select(fd + 1, (fd_set *) NULL, &send_fd_set,
(fd_set *) NULL, NULL);
}
switch (select_ret) {
case -1:
rcs_print_error("Error in select: %d -> %s\n", errno,
strerror(errno));
rcs_print_error
("sendn(fd=%d, vptr=%p, int n=%d, int _flags=%d, double _timeout=%f) failed.\n",
fd, vptr, n, _flags, _timeout);
return -1;
case 0:
rcs_print_error
("sendn(fd=%d, vptr=%p, int n=%d, int _flags=%d, double _timeout=%f) timed out.\n",
fd, vptr, n, _flags, _timeout);
return -1;
default:
break;
}
}
if ((nwritten = send(fd, ptr, nleft, _flags)) == -1) {
rcs_print_error("Send error: %d = %s\n", errno, strerror(errno));
return (-1); /* error */
}
nleft -= nwritten;
ptr += nwritten;
if (nleft > 0 && _timeout > 0.0) {
double duration;
duration = etime() - start_time;
if (duration > _timeout) {
rcs_print_error("sendn: timed out after %f seconds.\n", duration);
return (-1);
}
esleep(0.001);
}
}
rcs_print_debug(PRINT_SOCKET_WRITE_SIZE, "wrote %d bytes to %d\n", n, fd);
return (n);
}
|