Coverage Report

Created: 2025-07-23 07:04

/src/samba/lib/tsocket/tsocket.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   Unix SMB/CIFS implementation.
3
4
   Copyright (C) Stefan Metzmacher 2009
5
6
     ** NOTE! The following LGPL license applies to the tsocket
7
     ** library. This does NOT imply that all of Samba is released
8
     ** under the LGPL
9
10
   This library is free software; you can redistribute it and/or
11
   modify it under the terms of the GNU Lesser General Public
12
   License as published by the Free Software Foundation; either
13
   version 3 of the License, or (at your option) any later version.
14
15
   This library is distributed in the hope that it will be useful,
16
   but WITHOUT ANY WARRANTY; without even the implied warranty of
17
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
   Lesser General Public License for more details.
19
20
   You should have received a copy of the GNU Lesser General Public
21
   License along with this library; if not, see <http://www.gnu.org/licenses/>.
22
*/
23
24
#include "replace.h"
25
#include "system/filesys.h"
26
#include "tsocket.h"
27
#include "tsocket_internal.h"
28
#include "lib/util/iov_buf.h"
29
30
int tsocket_simple_int_recv(struct tevent_req *req, int *perrno)
31
0
{
32
0
  enum tevent_req_state state;
33
0
  uint64_t error;
34
35
0
  if (!tevent_req_is_error(req, &state, &error)) {
36
0
    return 0;
37
0
  }
38
39
0
  switch (state) {
40
0
  case TEVENT_REQ_NO_MEMORY:
41
0
    *perrno = ENOMEM;
42
0
    return -1;
43
0
  case TEVENT_REQ_TIMED_OUT:
44
0
    *perrno = ETIMEDOUT;
45
0
    return -1;
46
0
  case TEVENT_REQ_USER_ERROR:
47
0
    *perrno = (int)error;
48
0
    return -1;
49
0
  default:
50
0
    break;
51
0
  }
52
53
0
  *perrno = EIO;
54
0
  return -1;
55
0
}
56
57
struct tsocket_address *_tsocket_address_create(TALLOC_CTX *mem_ctx,
58
            const struct tsocket_address_ops *ops,
59
            void *pstate,
60
            size_t psize,
61
            const char *type,
62
            const char *location)
63
0
{
64
0
  void **ppstate = (void **)pstate;
65
0
  struct tsocket_address *addr;
66
67
0
  addr = talloc_zero(mem_ctx, struct tsocket_address);
68
0
  if (!addr) {
69
0
    return NULL;
70
0
  }
71
0
  addr->ops = ops;
72
0
  addr->location = location;
73
0
  addr->private_data = talloc_size(addr, psize);
74
0
  if (!addr->private_data) {
75
0
    talloc_free(addr);
76
0
    return NULL;
77
0
  }
78
0
  talloc_set_name_const(addr->private_data, type);
79
80
0
  *ppstate = addr->private_data;
81
0
  return addr;
82
0
}
83
84
char *tsocket_address_string(const struct tsocket_address *addr,
85
           TALLOC_CTX *mem_ctx)
86
0
{
87
0
  if (!addr) {
88
0
    return talloc_strdup(mem_ctx, "NULL");
89
0
  }
90
0
  return addr->ops->string(addr, mem_ctx);
91
0
}
92
93
struct tsocket_address *_tsocket_address_copy(const struct tsocket_address *addr,
94
                TALLOC_CTX *mem_ctx,
95
                const char *location)
96
0
{
97
0
  return addr->ops->copy(addr, mem_ctx, location);
98
0
}
99
100
struct tdgram_context {
101
  const char *location;
102
  const struct tdgram_context_ops *ops;
103
  void *private_data;
104
105
  struct tevent_req *recvfrom_req;
106
  struct tevent_req *sendto_req;
107
};
108
109
static int tdgram_context_destructor(struct tdgram_context *dgram)
110
0
{
111
0
  if (dgram->recvfrom_req) {
112
0
    tevent_req_received(dgram->recvfrom_req);
113
0
  }
114
115
0
  if (dgram->sendto_req) {
116
0
    tevent_req_received(dgram->sendto_req);
117
0
  }
118
119
0
  return 0;
120
0
}
121
122
struct tdgram_context *_tdgram_context_create(TALLOC_CTX *mem_ctx,
123
          const struct tdgram_context_ops *ops,
124
          void *pstate,
125
          size_t psize,
126
          const char *type,
127
          const char *location)
128
0
{
129
0
  struct tdgram_context *dgram;
130
0
  void **ppstate = (void **)pstate;
131
0
  void *state;
132
133
0
  dgram = talloc(mem_ctx, struct tdgram_context);
134
0
  if (dgram == NULL) {
135
0
    return NULL;
136
0
  }
137
0
  dgram->location   = location;
138
0
  dgram->ops    = ops;
139
0
  dgram->recvfrom_req = NULL;
140
0
  dgram->sendto_req = NULL;
141
142
0
  state = talloc_size(dgram, psize);
143
0
  if (state == NULL) {
144
0
    talloc_free(dgram);
145
0
    return NULL;
146
0
  }
147
0
  talloc_set_name_const(state, type);
148
149
0
  dgram->private_data = state;
150
151
0
  talloc_set_destructor(dgram, tdgram_context_destructor);
152
153
0
  *ppstate = state;
154
0
  return dgram;
155
0
}
156
157
void *_tdgram_context_data(struct tdgram_context *dgram)
158
0
{
159
0
  return dgram->private_data;
160
0
}
161
162
struct tdgram_recvfrom_state {
163
  const struct tdgram_context_ops *ops;
164
  struct tdgram_context *dgram;
165
  uint8_t *buf;
166
  size_t len;
167
  struct tsocket_address *src;
168
};
169
170
static void tdgram_recvfrom_cleanup(struct tevent_req *req,
171
            enum tevent_req_state req_state)
172
0
{
173
0
  struct tdgram_recvfrom_state *state = tevent_req_data(req,
174
0
                struct tdgram_recvfrom_state);
175
176
0
  if (state->dgram) {
177
0
    state->dgram->recvfrom_req = NULL;
178
0
    state->dgram = NULL;
179
0
  }
180
0
}
181
182
static void tdgram_recvfrom_done(struct tevent_req *subreq);
183
184
struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx,
185
          struct tevent_context *ev,
186
          struct tdgram_context *dgram)
187
0
{
188
0
  struct tevent_req *req;
189
0
  struct tdgram_recvfrom_state *state;
190
0
  struct tevent_req *subreq;
191
192
0
  req = tevent_req_create(mem_ctx, &state,
193
0
        struct tdgram_recvfrom_state);
194
0
  if (req == NULL) {
195
0
    return NULL;
196
0
  }
197
198
0
  state->ops = dgram->ops;
199
0
  state->dgram = dgram;
200
0
  state->buf = NULL;
201
0
  state->len = 0;
202
0
  state->src = NULL;
203
204
0
  if (dgram->recvfrom_req) {
205
0
    tevent_req_error(req, EBUSY);
206
0
    goto post;
207
0
  }
208
0
  dgram->recvfrom_req = req;
209
210
0
  tevent_req_set_cleanup_fn(req, tdgram_recvfrom_cleanup);
211
212
0
  subreq = state->ops->recvfrom_send(state, ev, dgram);
213
0
  if (tevent_req_nomem(subreq, req)) {
214
0
    goto post;
215
0
  }
216
0
  tevent_req_set_callback(subreq, tdgram_recvfrom_done, req);
217
0
  if (!tevent_req_is_in_progress(subreq)) {
218
    /*
219
     * Allow the caller of
220
     * tdgram_recvfrom_send() to
221
     * see tevent_req_is_in_progress()
222
     * reporting false too.
223
     *
224
     * Useful for callers using
225
     * tdgram_bsd_optimize_recvfrom(true)
226
     * in order to check if data
227
     * was already waiting in the
228
     * receice buffer.
229
     */
230
0
    tdgram_recvfrom_done(subreq);
231
0
    goto post;
232
0
  }
233
234
0
  return req;
235
236
0
 post:
237
0
  tevent_req_post(req, ev);
238
0
  return req;
239
0
}
240
241
static void tdgram_recvfrom_done(struct tevent_req *subreq)
242
0
{
243
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
244
0
         struct tevent_req);
245
0
  struct tdgram_recvfrom_state *state = tevent_req_data(req,
246
0
                struct tdgram_recvfrom_state);
247
0
  ssize_t ret;
248
0
  int sys_errno;
249
250
0
  ret = state->ops->recvfrom_recv(subreq, &sys_errno, state,
251
0
          &state->buf, &state->src);
252
0
  if (ret == -1) {
253
0
    tevent_req_error(req, sys_errno);
254
0
    return;
255
0
  }
256
257
0
  state->len = ret;
258
259
0
  tevent_req_done(req);
260
0
}
261
262
ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
263
           int *perrno,
264
           TALLOC_CTX *mem_ctx,
265
           uint8_t **buf,
266
           struct tsocket_address **src)
267
0
{
268
0
  struct tdgram_recvfrom_state *state = tevent_req_data(req,
269
0
                struct tdgram_recvfrom_state);
270
0
  ssize_t ret;
271
272
0
  ret = tsocket_simple_int_recv(req, perrno);
273
0
  if (ret == 0) {
274
0
    *buf = talloc_move(mem_ctx, &state->buf);
275
0
    ret = state->len;
276
0
    if (src) {
277
0
      *src = talloc_move(mem_ctx, &state->src);
278
0
    }
279
0
  }
280
281
0
  tevent_req_received(req);
282
0
  return ret;
283
0
}
284
285
struct tdgram_sendto_state {
286
  const struct tdgram_context_ops *ops;
287
  struct tdgram_context *dgram;
288
  ssize_t ret;
289
};
290
291
static void tdgram_sendto_cleanup(struct tevent_req *req,
292
          enum tevent_req_state req_state)
293
0
{
294
0
  struct tdgram_sendto_state *state = tevent_req_data(req,
295
0
              struct tdgram_sendto_state);
296
297
0
  if (state->dgram) {
298
0
    state->dgram->sendto_req = NULL;
299
0
    state->dgram = NULL;
300
0
  }
301
0
}
302
303
static void tdgram_sendto_done(struct tevent_req *subreq);
304
305
struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
306
              struct tevent_context *ev,
307
              struct tdgram_context *dgram,
308
              const uint8_t *buf, size_t len,
309
              const struct tsocket_address *dst)
310
0
{
311
0
  struct tevent_req *req;
312
0
  struct tdgram_sendto_state *state;
313
0
  struct tevent_req *subreq;
314
315
0
  req = tevent_req_create(mem_ctx, &state,
316
0
        struct tdgram_sendto_state);
317
0
  if (req == NULL) {
318
0
    return NULL;
319
0
  }
320
321
0
  state->ops = dgram->ops;
322
0
  state->dgram = dgram;
323
0
  state->ret = -1;
324
325
0
  if (len == 0) {
326
0
    tevent_req_error(req, EINVAL);
327
0
    goto post;
328
0
  }
329
330
0
  if (dgram->sendto_req) {
331
0
    tevent_req_error(req, EBUSY);
332
0
    goto post;
333
0
  }
334
0
  dgram->sendto_req = req;
335
336
0
  tevent_req_set_cleanup_fn(req, tdgram_sendto_cleanup);
337
338
0
  subreq = state->ops->sendto_send(state, ev, dgram,
339
0
           buf, len, dst);
340
0
  if (tevent_req_nomem(subreq, req)) {
341
0
    goto post;
342
0
  }
343
0
  tevent_req_set_callback(subreq, tdgram_sendto_done, req);
344
345
0
  return req;
346
347
0
 post:
348
0
  tevent_req_post(req, ev);
349
0
  return req;
350
0
}
351
352
static void tdgram_sendto_done(struct tevent_req *subreq)
353
0
{
354
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
355
0
         struct tevent_req);
356
0
  struct tdgram_sendto_state *state = tevent_req_data(req,
357
0
              struct tdgram_sendto_state);
358
0
  ssize_t ret;
359
0
  int sys_errno;
360
361
0
  ret = state->ops->sendto_recv(subreq, &sys_errno);
362
0
  if (ret == -1) {
363
0
    tevent_req_error(req, sys_errno);
364
0
    return;
365
0
  }
366
367
0
  state->ret = ret;
368
369
0
  tevent_req_done(req);
370
0
}
371
372
ssize_t tdgram_sendto_recv(struct tevent_req *req,
373
         int *perrno)
374
0
{
375
0
  struct tdgram_sendto_state *state = tevent_req_data(req,
376
0
              struct tdgram_sendto_state);
377
0
  ssize_t ret;
378
379
0
  ret = tsocket_simple_int_recv(req, perrno);
380
0
  if (ret == 0) {
381
0
    ret = state->ret;
382
0
  }
383
384
0
  tevent_req_received(req);
385
0
  return ret;
386
0
}
387
388
struct tdgram_disconnect_state {
389
  const struct tdgram_context_ops *ops;
390
};
391
392
static void tdgram_disconnect_done(struct tevent_req *subreq);
393
394
struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
395
            struct tevent_context *ev,
396
            struct tdgram_context *dgram)
397
0
{
398
0
  struct tevent_req *req;
399
0
  struct tdgram_disconnect_state *state;
400
0
  struct tevent_req *subreq;
401
402
0
  req = tevent_req_create(mem_ctx, &state,
403
0
        struct tdgram_disconnect_state);
404
0
  if (req == NULL) {
405
0
    return NULL;
406
0
  }
407
408
0
  state->ops = dgram->ops;
409
410
0
  if (dgram->recvfrom_req || dgram->sendto_req) {
411
0
    tevent_req_error(req, EBUSY);
412
0
    goto post;
413
0
  }
414
415
0
  subreq = state->ops->disconnect_send(state, ev, dgram);
416
0
  if (tevent_req_nomem(subreq, req)) {
417
0
    goto post;
418
0
  }
419
0
  tevent_req_set_callback(subreq, tdgram_disconnect_done, req);
420
421
0
  return req;
422
423
0
 post:
424
0
  tevent_req_post(req, ev);
425
0
  return req;
426
0
}
427
428
static void tdgram_disconnect_done(struct tevent_req *subreq)
429
0
{
430
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
431
0
         struct tevent_req);
432
0
  struct tdgram_disconnect_state *state = tevent_req_data(req,
433
0
            struct tdgram_disconnect_state);
434
0
  int ret;
435
0
  int sys_errno;
436
437
0
  ret = state->ops->disconnect_recv(subreq, &sys_errno);
438
0
  if (ret == -1) {
439
0
    tevent_req_error(req, sys_errno);
440
0
    return;
441
0
  }
442
443
0
  tevent_req_done(req);
444
0
}
445
446
int tdgram_disconnect_recv(struct tevent_req *req,
447
         int *perrno)
448
0
{
449
0
  int ret;
450
451
0
  ret = tsocket_simple_int_recv(req, perrno);
452
453
0
  tevent_req_received(req);
454
0
  return ret;
455
0
}
456
457
struct tstream_context {
458
  const char *location;
459
  const struct tstream_context_ops *ops;
460
  void *private_data;
461
462
  struct tevent_req *readv_req;
463
  struct tevent_req *writev_req;
464
  struct tevent_req *disconnect_req;
465
  struct tevent_req *monitor_req;
466
};
467
468
static void tstream_monitor_disconnect(struct tstream_context *stream, int err);
469
470
static int tstream_context_destructor(struct tstream_context *stream)
471
0
{
472
0
  if (stream->readv_req) {
473
0
    tevent_req_received(stream->readv_req);
474
0
  }
475
476
0
  if (stream->writev_req) {
477
0
    tevent_req_received(stream->writev_req);
478
0
  }
479
480
0
  if (stream->disconnect_req != NULL) {
481
0
    tevent_req_received(stream->disconnect_req);
482
0
  }
483
484
0
  if (stream->monitor_req != NULL) {
485
0
    tevent_req_received(stream->monitor_req);
486
0
  }
487
488
0
  return 0;
489
0
}
490
491
struct tstream_context *_tstream_context_create(TALLOC_CTX *mem_ctx,
492
          const struct tstream_context_ops *ops,
493
          void *pstate,
494
          size_t psize,
495
          const char *type,
496
          const char *location)
497
0
{
498
0
  struct tstream_context *stream;
499
0
  void **ppstate = (void **)pstate;
500
0
  void *state;
501
502
0
  stream = talloc(mem_ctx, struct tstream_context);
503
0
  if (stream == NULL) {
504
0
    return NULL;
505
0
  }
506
0
  stream->location  = location;
507
0
  stream->ops   = ops;
508
0
  stream->readv_req = NULL;
509
0
  stream->writev_req  = NULL;
510
0
  stream->disconnect_req  = NULL;
511
0
  stream->monitor_req = NULL;
512
513
0
  state = talloc_size(stream, psize);
514
0
  if (state == NULL) {
515
0
    talloc_free(stream);
516
0
    return NULL;
517
0
  }
518
0
  talloc_set_name_const(state, type);
519
520
0
  stream->private_data = state;
521
522
0
  talloc_set_destructor(stream, tstream_context_destructor);
523
524
0
  *ppstate = state;
525
0
  return stream;
526
0
}
527
528
void *_tstream_context_data(struct tstream_context *stream)
529
0
{
530
0
  return stream->private_data;
531
0
}
532
533
ssize_t tstream_pending_bytes(struct tstream_context *stream)
534
0
{
535
0
  ssize_t ret;
536
537
0
  ret = stream->ops->pending_bytes(stream);
538
0
  if (ret == -1) {
539
0
    int sys_errno = errno;
540
0
    tstream_monitor_disconnect(stream, sys_errno);
541
0
    errno = sys_errno;
542
0
  }
543
544
0
  return ret;
545
0
}
546
547
struct tstream_readv_state {
548
  const struct tstream_context_ops *ops;
549
  struct tstream_context *stream;
550
  int ret;
551
};
552
553
static void tstream_readv_cleanup(struct tevent_req *req,
554
          enum tevent_req_state req_state)
555
0
{
556
0
  struct tstream_readv_state *state = tevent_req_data(req,
557
0
              struct tstream_readv_state);
558
559
0
  if (state->stream) {
560
0
    state->stream->readv_req = NULL;
561
0
    state->stream = NULL;
562
0
  }
563
0
}
564
565
static void tstream_readv_done(struct tevent_req *subreq);
566
567
struct tevent_req *tstream_readv_send(TALLOC_CTX *mem_ctx,
568
              struct tevent_context *ev,
569
              struct tstream_context *stream,
570
              struct iovec *vector,
571
              size_t count)
572
0
{
573
0
  struct tevent_req *req;
574
0
  struct tstream_readv_state *state;
575
0
  struct tevent_req *subreq;
576
0
  ssize_t to_read;
577
578
0
  req = tevent_req_create(mem_ctx, &state,
579
0
        struct tstream_readv_state);
580
0
  if (req == NULL) {
581
0
    return NULL;
582
0
  }
583
584
0
  state->ops = stream->ops;
585
0
  state->stream = stream;
586
0
  state->ret = -1;
587
588
  /* first check if the input is ok */
589
0
#ifdef IOV_MAX
590
0
  if (count > IOV_MAX) {
591
0
    tevent_req_error(req, EMSGSIZE);
592
0
    goto post;
593
0
  }
594
0
#endif
595
596
0
  to_read = iov_buflen(vector, count);
597
598
0
  if (to_read < 0) {
599
0
    tevent_req_error(req, EMSGSIZE);
600
0
    goto post;
601
0
  }
602
603
0
  if (to_read == 0) {
604
0
    tevent_req_error(req, EINVAL);
605
0
    goto post;
606
0
  }
607
608
0
  if (stream->disconnect_req != NULL) {
609
0
    tevent_req_error(req, ECONNABORTED);
610
0
    goto post;
611
0
  }
612
613
0
  if (stream->readv_req) {
614
0
    tevent_req_error(req, EBUSY);
615
0
    goto post;
616
0
  }
617
0
  stream->readv_req = req;
618
619
0
  tevent_req_set_cleanup_fn(req, tstream_readv_cleanup);
620
621
0
  subreq = state->ops->readv_send(state, ev, stream, vector, count);
622
0
  if (tevent_req_nomem(subreq, req)) {
623
0
    goto post;
624
0
  }
625
0
  tevent_req_set_callback(subreq, tstream_readv_done, req);
626
627
0
  return req;
628
629
0
 post:
630
0
  tevent_req_post(req, ev);
631
0
  return req;
632
0
}
633
634
static void tstream_readv_done(struct tevent_req *subreq)
635
0
{
636
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
637
0
         struct tevent_req);
638
0
  struct tstream_readv_state *state = tevent_req_data(req,
639
0
              struct tstream_readv_state);
640
0
  ssize_t ret;
641
0
  int sys_errno;
642
643
0
  ret = state->ops->readv_recv(subreq, &sys_errno);
644
0
  TALLOC_FREE(subreq);
645
0
  if (ret == -1) {
646
0
    tstream_monitor_disconnect(state->stream, sys_errno);
647
0
    tevent_req_error(req, sys_errno);
648
0
    return;
649
0
  }
650
651
0
  state->ret = ret;
652
653
0
  tevent_req_done(req);
654
0
}
655
656
int tstream_readv_recv(struct tevent_req *req,
657
           int *perrno)
658
0
{
659
0
  struct tstream_readv_state *state = tevent_req_data(req,
660
0
              struct tstream_readv_state);
661
0
  int ret;
662
663
0
  ret = tsocket_simple_int_recv(req, perrno);
664
0
  if (ret == 0) {
665
0
    ret = state->ret;
666
0
  }
667
668
0
  tevent_req_received(req);
669
0
  return ret;
670
0
}
671
672
struct tstream_writev_state {
673
  const struct tstream_context_ops *ops;
674
  struct tstream_context *stream;
675
  int ret;
676
};
677
678
static void tstream_writev_cleanup(struct tevent_req *req,
679
           enum tevent_req_state req_state)
680
0
{
681
0
  struct tstream_writev_state *state = tevent_req_data(req,
682
0
               struct tstream_writev_state);
683
684
0
  if (state->stream) {
685
0
    state->stream->writev_req = NULL;
686
0
    state->stream = NULL;
687
0
  }
688
0
}
689
690
static void tstream_writev_done(struct tevent_req *subreq);
691
692
struct tevent_req *tstream_writev_send(TALLOC_CTX *mem_ctx,
693
               struct tevent_context *ev,
694
               struct tstream_context *stream,
695
               const struct iovec *vector,
696
               size_t count)
697
0
{
698
0
  struct tevent_req *req;
699
0
  struct tstream_writev_state *state;
700
0
  struct tevent_req *subreq;
701
0
  ssize_t to_write;
702
703
0
  req = tevent_req_create(mem_ctx, &state,
704
0
        struct tstream_writev_state);
705
0
  if (req == NULL) {
706
0
    return NULL;
707
0
  }
708
709
0
  state->ops = stream->ops;
710
0
  state->stream = stream;
711
0
  state->ret = -1;
712
713
  /* first check if the input is ok */
714
0
#ifdef IOV_MAX
715
0
  if (count > IOV_MAX) {
716
0
    tevent_req_error(req, EMSGSIZE);
717
0
    goto post;
718
0
  }
719
0
#endif
720
721
0
  to_write = iov_buflen(vector, count);
722
0
  if (to_write < 0) {
723
0
    tevent_req_error(req, EMSGSIZE);
724
0
    goto post;
725
0
  }
726
727
0
  if (to_write == 0) {
728
0
    tevent_req_error(req, EINVAL);
729
0
    goto post;
730
0
  }
731
732
0
  if (stream->disconnect_req != NULL) {
733
0
    tevent_req_error(req, ECONNABORTED);
734
0
    goto post;
735
0
  }
736
737
0
  if (stream->writev_req) {
738
0
    tevent_req_error(req, EBUSY);
739
0
    goto post;
740
0
  }
741
0
  stream->writev_req = req;
742
743
0
  tevent_req_set_cleanup_fn(req, tstream_writev_cleanup);
744
745
0
  subreq = state->ops->writev_send(state, ev, stream, vector, count);
746
0
  if (tevent_req_nomem(subreq, req)) {
747
0
    goto post;
748
0
  }
749
0
  tevent_req_set_callback(subreq, tstream_writev_done, req);
750
751
0
  return req;
752
753
0
 post:
754
0
  tevent_req_post(req, ev);
755
0
  return req;
756
0
}
757
758
static void tstream_writev_done(struct tevent_req *subreq)
759
0
{
760
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
761
0
         struct tevent_req);
762
0
  struct tstream_writev_state *state = tevent_req_data(req,
763
0
               struct tstream_writev_state);
764
0
  ssize_t ret;
765
0
  int sys_errno;
766
767
0
  ret = state->ops->writev_recv(subreq, &sys_errno);
768
0
  if (ret == -1) {
769
0
    tstream_monitor_disconnect(state->stream, sys_errno);
770
0
    tevent_req_error(req, sys_errno);
771
0
    return;
772
0
  }
773
774
0
  state->ret = ret;
775
776
0
  tevent_req_done(req);
777
0
}
778
779
int tstream_writev_recv(struct tevent_req *req,
780
           int *perrno)
781
0
{
782
0
  struct tstream_writev_state *state = tevent_req_data(req,
783
0
               struct tstream_writev_state);
784
0
  int ret;
785
786
0
  ret = tsocket_simple_int_recv(req, perrno);
787
0
  if (ret == 0) {
788
0
    ret = state->ret;
789
0
  }
790
791
0
  tevent_req_received(req);
792
0
  return ret;
793
0
}
794
795
struct tstream_disconnect_state {
796
  const struct tstream_context_ops *ops;
797
  struct tstream_context *stream;
798
};
799
800
static void tstream_disconnect_cleanup(struct tevent_req *req,
801
               enum tevent_req_state req_state)
802
0
{
803
0
  struct tstream_disconnect_state *state = tevent_req_data(req,
804
0
             struct tstream_disconnect_state);
805
806
0
  if (state->stream != NULL) {
807
0
    state->stream->disconnect_req = NULL;
808
0
    state->stream = NULL;
809
0
  }
810
811
0
  return;
812
0
}
813
814
static void tstream_disconnect_done(struct tevent_req *subreq);
815
816
struct tevent_req *tstream_disconnect_send(TALLOC_CTX *mem_ctx,
817
             struct tevent_context *ev,
818
             struct tstream_context *stream)
819
0
{
820
0
  struct tevent_req *req;
821
0
  struct tstream_disconnect_state *state;
822
0
  struct tevent_req *subreq;
823
824
0
  req = tevent_req_create(mem_ctx, &state,
825
0
        struct tstream_disconnect_state);
826
0
  if (req == NULL) {
827
0
    return NULL;
828
0
  }
829
830
0
  state->ops = stream->ops;
831
0
  state->stream = stream;
832
833
0
  if (stream->readv_req || stream->writev_req) {
834
0
    tevent_req_error(req, EBUSY);
835
0
    goto post;
836
0
  }
837
838
0
  if (stream->disconnect_req != NULL) {
839
0
    tevent_req_error(req, EALREADY);
840
0
    goto post;
841
0
  }
842
0
  stream->disconnect_req = req;
843
844
0
  tevent_req_set_cleanup_fn(req, tstream_disconnect_cleanup);
845
846
0
  subreq = state->ops->disconnect_send(state, ev, stream);
847
0
  if (tevent_req_nomem(subreq, req)) {
848
0
    goto post;
849
0
  }
850
0
  tevent_req_set_callback(subreq, tstream_disconnect_done, req);
851
852
0
  return req;
853
854
0
 post:
855
0
  tevent_req_post(req, ev);
856
0
  return req;
857
0
}
858
859
static void tstream_disconnect_done(struct tevent_req *subreq)
860
0
{
861
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
862
0
         struct tevent_req);
863
0
  struct tstream_disconnect_state *state = tevent_req_data(req,
864
0
             struct tstream_disconnect_state);
865
0
  int ret;
866
0
  int sys_errno;
867
868
0
  ret = state->ops->disconnect_recv(subreq, &sys_errno);
869
0
  if (ret == -1) {
870
0
    tstream_monitor_disconnect(state->stream, sys_errno);
871
0
    tevent_req_error(req, sys_errno);
872
0
    return;
873
0
  }
874
875
0
  tstream_monitor_disconnect(state->stream, ECONNABORTED);
876
877
0
  tevent_req_done(req);
878
0
}
879
880
int tstream_disconnect_recv(struct tevent_req *req,
881
         int *perrno)
882
0
{
883
0
  int ret;
884
885
0
  ret = tsocket_simple_int_recv(req, perrno);
886
887
0
  tevent_req_received(req);
888
0
  return ret;
889
0
}
890
891
struct tstream_monitor_state {
892
  const struct tstream_context_ops *ops;
893
  struct tstream_context *stream;
894
  struct tevent_req *subreq;
895
  int ret;
896
};
897
898
static void tstream_monitor_cleanup(struct tevent_req *req,
899
            enum tevent_req_state req_state)
900
0
{
901
0
  struct tstream_monitor_state *state =
902
0
    tevent_req_data(req,
903
0
    struct tstream_monitor_state);
904
905
0
  TALLOC_FREE(state->subreq);
906
907
0
  if (state->stream != NULL) {
908
0
    state->stream->monitor_req = NULL;
909
0
    state->stream = NULL;
910
0
  }
911
0
}
912
913
static void tstream_monitor_done(struct tevent_req *subreq);
914
915
struct tevent_req *tstream_monitor_send(TALLOC_CTX *mem_ctx,
916
          struct tevent_context *ev,
917
          struct tstream_context *stream)
918
0
{
919
0
  struct tevent_req *req = NULL;
920
0
  struct tstream_monitor_state *state = NULL;
921
0
  struct tevent_req *subreq = NULL;
922
0
  ssize_t pending;
923
924
0
  req = tevent_req_create(mem_ctx, &state,
925
0
        struct tstream_monitor_state);
926
0
  if (req == NULL) {
927
0
    return NULL;
928
0
  }
929
930
0
  state->ops = stream->ops;
931
0
  state->stream = stream;
932
0
  state->ret = -1;
933
934
0
  if (stream->disconnect_req != NULL) {
935
0
    tevent_req_error(req, ECONNABORTED);
936
0
    return tevent_req_post(req, ev);
937
0
  }
938
939
0
  if (stream->monitor_req != NULL) {
940
0
    tevent_req_error(req, EALREADY);
941
0
    return tevent_req_post(req, ev);
942
0
  }
943
0
  stream->monitor_req = req;
944
945
0
  tevent_req_set_cleanup_fn(req, tstream_monitor_cleanup);
946
0
  tevent_req_defer_callback(req, ev);
947
948
0
  if (state->ops->monitor_send != NULL) {
949
0
    subreq = state->ops->monitor_send(state,
950
0
              ev,
951
0
              stream);
952
0
    if (tevent_req_nomem(subreq, req)) {
953
0
      return tevent_req_post(req, ev);
954
0
    }
955
0
    tevent_req_set_callback(subreq, tstream_monitor_done, req);
956
957
0
    state->subreq = subreq;
958
0
    return req;
959
0
  }
960
961
0
  pending = stream->ops->pending_bytes(stream);
962
0
  if (pending < 0) {
963
0
    tevent_req_error(req, errno);
964
0
    return tevent_req_post(req, ev);
965
0
  }
966
967
  /*
968
   * just remain forever pending until
969
   * tstream_monitor_disconnect() is triggered
970
   * in any way.
971
   */
972
0
  return req;
973
0
}
974
975
static void tstream_monitor_done(struct tevent_req *subreq)
976
0
{
977
0
  struct tevent_req *req =
978
0
    tevent_req_callback_data(subreq,
979
0
    struct tevent_req);
980
0
  struct tstream_monitor_state *state =
981
0
    tevent_req_data(req,
982
0
    struct tstream_monitor_state);
983
0
  ssize_t ret;
984
0
  int sys_errno;
985
986
0
  state->subreq = NULL;
987
988
0
  ret = state->ops->monitor_recv(subreq, &sys_errno);
989
0
  TALLOC_FREE(subreq);
990
0
  if (ret == -1) {
991
0
    tevent_req_error(req, sys_errno);
992
0
    return;
993
0
  }
994
995
0
  state->ret = ret;
996
997
0
  tevent_req_done(req);
998
0
}
999
1000
static void tstream_monitor_disconnect(struct tstream_context *stream, int err)
1001
0
{
1002
0
  if (stream == NULL) {
1003
0
    return;
1004
0
  }
1005
1006
0
  if (stream->monitor_req == NULL) {
1007
0
    return;
1008
0
  }
1009
1010
  /*
1011
   * tevent_req_defer_callback() was used
1012
   * so it's safe to call
1013
   */
1014
0
  tevent_req_error(stream->monitor_req, err);
1015
0
}
1016
1017
int tstream_monitor_recv(struct tevent_req *req, int *perrno)
1018
0
{
1019
0
  struct tstream_monitor_state *state =
1020
0
    tevent_req_data(req,
1021
0
    struct tstream_monitor_state);
1022
0
  int ret;
1023
1024
0
  ret = tsocket_simple_int_recv(req, perrno);
1025
0
  if (ret == 0) {
1026
0
    ret = state->ret;
1027
0
  }
1028
1029
0
  tevent_req_received(req);
1030
0
  return ret;
1031
0
}