aboutsummaryrefslogtreecommitdiffstats
path: root/src/client/send_file.c
blob: 4da8412c085037e904e07ba0ffcbd5cae7417a9e (plain)
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
/* ISC license. */

#include <skalibs/sysdeps.h>

#ifdef SKALIBS_HASSENDFILE

#include <sys/types.h>
#include <sys/sendfile.h>
#include <limits.h>

#include <skalibs/uint64.h>
#include <skalibs/strerr.h>
#include <skalibs/tai.h>
#include <skalibs/unix-timed.h>

struct sendfile_s
{
  int fd ;
  buffer *out ;
  off_t pos ;  
  uint64_t n ;
} ;

static int s_getfd (void *p)
{
  struct sendfile_s *sf = p ;
  return buffer_fd(sf->out) ;
}

static int s_isnonempty (void *p)
{
  struct sendfile_s *sf = p ;
  return !!sf->n ;
}

static int s_flush (void *p)
{
  struct sendfile_s *sf = p ;
  while (sf->n)
  {
    ssize_t r = sendfile(buffer_fd(sf->out), sf->fd, &sf->pos, sf->n > SSIZE_MAX ? SSIZE_MAX : sf->n) ;
    if (r == -1) return 0 ;
    sf->n -= r ;
  }
  return 1 ;
}

void send_file (buffer *b, int fd, off_t size, char const *fn, tain const *deadline, tain *stamp)
{
  struct sendfile_s sf = { .fd = fd, .out = b, .pos = 0, .n = size } ;
  if (!buffer_timed_flush(b, deadline, stamp))
    strerr_diefu1sys(111, "write to network") ;
  if (!timed_flush(&sf, &s_getfd, &s_isnonempty, &s_flush, deadline, stamp))
    strerr_diefu3sys(111, "sendfile ", fn, " to network") ;
}

#else

#include <sys/uio.h>
#include <unistd.h>
#include <stdint.h>

#include <skalibs/uint64.h>
#include <skalibs/allreadwrite.h>
#include <skalibs/buffer.h>
#include <skalibs/strerr.h>
#include <skalibs/tai.h>
#include <skalibs/unix-timed.h>

void send_file (buffer *b, int fd, uint64_t n, char const *fn, tain const *deadline, tain *stamp)
{
  struct iovec v[2] ;
  ssize_t r ;
  if (!n) goto flushit ;
 fillit:
  buffer_wpeek(b, v) ;
  r = allreadv(fd, v, 2) ;
  if (r == -1) strerr_diefu2sys(111, "read from ", fn) ;
  if (!r) strerr_diefu3x(111, "send ", fn, ": file was truncated") ;
  if (r > n)
  {
    r = n ;
    strerr_warnw2x("sending elongated file: ", fn) ;
  }
  buffer_wseek(b, r) ;
  n -= r ;
 flushit:
  if (!buffer_timed_flush(b, deadline, stamp))
    strerr_diefu1sys(111, "write to network") ;
  if (n) goto fillit ;
}

#endif