Coverage Report

Created: 2026-04-01 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/lib/util_tsock.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   Utilities around tsocket
4
   Copyright (C) Volker Lendecke 2009
5
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3 of the License, or
9
   (at your option) any later version.
10
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
*/
19
20
#include "replace.h"
21
#include "system/network.h"
22
#include <tevent.h>
23
#include "lib/util_tsock.h"
24
#include "../lib/tsocket/tsocket.h"
25
#include "../lib/util/tevent_unix.h"
26
27
struct tstream_read_packet_state {
28
  struct tevent_context *ev;
29
  struct tstream_context *stream;
30
  ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
31
  void *private_data;
32
  uint8_t *buf;
33
  struct iovec iov;
34
};
35
36
static void tstream_read_packet_done(struct tevent_req *subreq);
37
38
struct tevent_req *tstream_read_packet_send(TALLOC_CTX *mem_ctx,
39
              struct tevent_context *ev,
40
              struct tstream_context *stream,
41
              size_t initial,
42
              ssize_t (*more)(uint8_t *buf,
43
                  size_t buflen,
44
                  void *private_data),
45
              void *private_data)
46
0
{
47
0
  struct tevent_req *req, *subreq;
48
0
  struct tstream_read_packet_state *state;
49
50
0
  req = tevent_req_create(mem_ctx, &state,
51
0
        struct tstream_read_packet_state);
52
0
  if (req == NULL) {
53
0
    return NULL;
54
0
  }
55
0
  state->buf = talloc_array(state, uint8_t, initial);
56
0
  if (tevent_req_nomem(state->buf, req)) {
57
0
    return tevent_req_post(req, ev);
58
0
  }
59
0
  state->iov.iov_base = (void *)state->buf;
60
0
  state->iov.iov_len = initial;
61
62
0
  state->ev = ev;
63
0
  state->stream = stream;
64
0
  state->more = more;
65
0
  state->private_data = private_data;
66
67
0
  subreq = tstream_readv_send(state, ev, stream, &state->iov, 1);
68
0
  if (tevent_req_nomem(subreq, req)) {
69
0
    return tevent_req_post(req, ev);
70
0
  }
71
0
  tevent_req_set_callback(subreq, tstream_read_packet_done, req);
72
73
0
  return req;
74
0
}
75
76
static void tstream_read_packet_done(struct tevent_req *subreq)
77
0
{
78
0
  struct tevent_req *req = tevent_req_callback_data(
79
0
    subreq, struct tevent_req);
80
0
  struct tstream_read_packet_state *state = tevent_req_data(
81
0
    req, struct tstream_read_packet_state);
82
0
  int ret, err;
83
0
  size_t total;
84
0
  ssize_t more;
85
0
  uint8_t *tmp;
86
87
0
  ret = tstream_readv_recv(subreq, &err);
88
0
  TALLOC_FREE(subreq);
89
0
  if (ret == 0) {
90
0
    err = EPIPE;
91
0
  }
92
0
  if (ret <= 0) {
93
0
    tevent_req_error(req, err);
94
0
    return;
95
0
  }
96
97
0
  if (state->more == NULL) {
98
    /* Nobody to ask, this is a async read_data */
99
0
    tevent_req_done(req);
100
0
    return;
101
0
  }
102
0
  total = talloc_array_length(state->buf);
103
104
0
  more = state->more(state->buf, total, state->private_data);
105
0
  if (more == -1) {
106
    /* We got an invalid packet, tell the caller */
107
0
    tevent_req_error(req, EIO);
108
0
    return;
109
0
  }
110
0
  if (more == 0) {
111
    /* We're done, full packet received */
112
0
    tevent_req_done(req);
113
0
    return;
114
0
  }
115
116
0
  if (total + more < total) {
117
0
    tevent_req_error(req, EMSGSIZE);
118
0
    return;
119
0
  }
120
121
0
  tmp = talloc_realloc(state, state->buf, uint8_t, total+more);
122
0
  if (tevent_req_nomem(tmp, req)) {
123
0
    return;
124
0
  }
125
0
  state->buf = tmp;
126
127
0
  state->iov.iov_base = (void *)(state->buf + total);
128
0
  state->iov.iov_len = more;
129
130
0
  subreq = tstream_readv_send(state, state->ev, state->stream,
131
0
            &state->iov, 1);
132
0
  if (tevent_req_nomem(subreq, req)) {
133
0
    return;
134
0
  }
135
0
  tevent_req_set_callback(subreq, tstream_read_packet_done, req);
136
0
}
137
138
ssize_t tstream_read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
139
         uint8_t **pbuf, int *perrno)
140
0
{
141
0
  struct tstream_read_packet_state *state =
142
0
    tevent_req_data(req, struct tstream_read_packet_state);
143
144
0
  if (tevent_req_is_unix_error(req, perrno)) {
145
0
    return -1;
146
0
  }
147
0
  *pbuf = talloc_move(mem_ctx, &state->buf);
148
0
  return talloc_array_length(*pbuf);
149
0
}