tsocket: rewrite tsocket_guide.txt to reflect the current APIs
[ira/wip.git] / lib / tsocket / tsocket.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher 2009
5
6      ** NOTE! The following LGPL license applies to the tevent
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
29 int tsocket_simple_int_recv(struct tevent_req *req, int *perrno)
30 {
31         enum tevent_req_state state;
32         uint64_t error;
33
34         if (!tevent_req_is_error(req, &state, &error)) {
35                 return 0;
36         }
37
38         switch (state) {
39         case TEVENT_REQ_NO_MEMORY:
40                 *perrno = ENOMEM;
41                 return -1;
42         case TEVENT_REQ_TIMED_OUT:
43                 *perrno = ETIMEDOUT;
44                 return -1;
45         case TEVENT_REQ_USER_ERROR:
46                 *perrno = (int)error;
47                 return -1;
48         default:
49                 *perrno = EIO;
50                 return -1;
51         }
52
53         *perrno = EIO;
54         return -1;
55 }
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 {
64         void **ppstate = (void **)pstate;
65         struct tsocket_address *addr;
66
67         addr = talloc_zero(mem_ctx, struct tsocket_address);
68         if (!addr) {
69                 return NULL;
70         }
71         addr->ops = ops;
72         addr->location = location;
73         addr->private_data = talloc_size(addr, psize);
74         if (!addr->private_data) {
75                 talloc_free(addr);
76                 return NULL;
77         }
78         talloc_set_name_const(addr->private_data, type);
79
80         *ppstate = addr->private_data;
81         return addr;
82 }
83
84 char *tsocket_address_string(const struct tsocket_address *addr,
85                              TALLOC_CTX *mem_ctx)
86 {
87         if (!addr) {
88                 return talloc_strdup(mem_ctx, "NULL");
89         }
90         return addr->ops->string(addr, mem_ctx);
91 }
92
93 struct tsocket_address *_tsocket_address_copy(const struct tsocket_address *addr,
94                                               TALLOC_CTX *mem_ctx,
95                                               const char *location)
96 {
97         return addr->ops->copy(addr, mem_ctx, location);
98 }
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 {
111         if (dgram->recvfrom_req) {
112                 tevent_req_received(dgram->recvfrom_req);
113         }
114
115         if (dgram->sendto_req) {
116                 tevent_req_received(dgram->sendto_req);
117         }
118
119         return 0;
120 }
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 {
129         struct tdgram_context *dgram;
130         void **ppstate = (void **)pstate;
131         void *state;
132
133         dgram = talloc(mem_ctx, struct tdgram_context);
134         if (dgram == NULL) {
135                 return NULL;
136         }
137         dgram->location         = location;
138         dgram->ops              = ops;
139         dgram->recvfrom_req     = NULL;
140         dgram->sendto_req       = NULL;
141
142         state = talloc_size(dgram, psize);
143         if (state == NULL) {
144                 talloc_free(dgram);
145                 return NULL;
146         }
147         talloc_set_name_const(state, type);
148
149         dgram->private_data = state;
150
151         talloc_set_destructor(dgram, tdgram_context_destructor);
152
153         *ppstate = state;
154         return dgram;
155 }
156
157 void *_tdgram_context_data(struct tdgram_context *dgram)
158 {
159         return dgram->private_data;
160 }
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 int tdgram_recvfrom_destructor(struct tdgram_recvfrom_state *state)
171 {
172         if (state->dgram) {
173                 state->dgram->recvfrom_req = NULL;
174         }
175
176         return 0;
177 }
178
179 static void tdgram_recvfrom_done(struct tevent_req *subreq);
180
181 struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx,
182                                         struct tevent_context *ev,
183                                         struct tdgram_context *dgram)
184 {
185         struct tevent_req *req;
186         struct tdgram_recvfrom_state *state;
187         struct tevent_req *subreq;
188
189         req = tevent_req_create(mem_ctx, &state,
190                                 struct tdgram_recvfrom_state);
191         if (req == NULL) {
192                 return NULL;
193         }
194
195         state->ops = dgram->ops;
196         state->dgram = dgram;
197         state->buf = NULL;
198         state->len = 0;
199         state->src = NULL;
200
201         if (dgram->recvfrom_req) {
202                 tevent_req_error(req, EBUSY);
203                 goto post;
204         }
205         dgram->recvfrom_req = req;
206
207         talloc_set_destructor(state, tdgram_recvfrom_destructor);
208
209         subreq = state->ops->recvfrom_send(state, ev, dgram);
210         if (tevent_req_nomem(subreq, req)) {
211                 goto post;
212         }
213         tevent_req_set_callback(subreq, tdgram_recvfrom_done, req);
214
215         return req;
216
217  post:
218         tevent_req_post(req, ev);
219         return req;
220 }
221
222 static void tdgram_recvfrom_done(struct tevent_req *subreq)
223 {
224         struct tevent_req *req = tevent_req_callback_data(subreq,
225                                  struct tevent_req);
226         struct tdgram_recvfrom_state *state = tevent_req_data(req,
227                                               struct tdgram_recvfrom_state);
228         ssize_t ret;
229         int sys_errno;
230
231         ret = state->ops->recvfrom_recv(subreq, &sys_errno, state,
232                                         &state->buf, &state->src);
233         if (ret == -1) {
234                 tevent_req_error(req, sys_errno);
235                 return;
236         }
237
238         state->len = ret;
239
240         tevent_req_done(req);
241 }
242
243 ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
244                              int *perrno,
245                              TALLOC_CTX *mem_ctx,
246                              uint8_t **buf,
247                              struct tsocket_address **src)
248 {
249         struct tdgram_recvfrom_state *state = tevent_req_data(req,
250                                               struct tdgram_recvfrom_state);
251         ssize_t ret;
252
253         ret = tsocket_simple_int_recv(req, perrno);
254         if (ret == 0) {
255                 *buf = talloc_move(mem_ctx, &state->buf);
256                 ret = state->len;
257                 if (src) {
258                         *src = talloc_move(mem_ctx, &state->src);
259                 }
260         }
261
262         tevent_req_received(req);
263         return ret;
264 }
265
266 struct tdgram_sendto_state {
267         const struct tdgram_context_ops *ops;
268         struct tdgram_context *dgram;
269         ssize_t ret;
270 };
271
272 static int tdgram_sendto_destructor(struct tdgram_sendto_state *state)
273 {
274         if (state->dgram) {
275                 state->dgram->sendto_req = NULL;
276         }
277
278         return 0;
279 }
280
281 static void tdgram_sendto_done(struct tevent_req *subreq);
282
283 struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
284                                       struct tevent_context *ev,
285                                       struct tdgram_context *dgram,
286                                       const uint8_t *buf, size_t len,
287                                       const struct tsocket_address *dst)
288 {
289         struct tevent_req *req;
290         struct tdgram_sendto_state *state;
291         struct tevent_req *subreq;
292
293         req = tevent_req_create(mem_ctx, &state,
294                                 struct tdgram_sendto_state);
295         if (req == NULL) {
296                 return NULL;
297         }
298
299         state->ops = dgram->ops;
300         state->dgram = dgram;
301         state->ret = -1;
302
303         if (len == 0) {
304                 tevent_req_error(req, EINVAL);
305                 goto post;
306         }
307
308         if (dgram->sendto_req) {
309                 tevent_req_error(req, EBUSY);
310                 goto post;
311         }
312         dgram->sendto_req = req;
313
314         talloc_set_destructor(state, tdgram_sendto_destructor);
315
316         subreq = state->ops->sendto_send(state, ev, dgram,
317                                          buf, len, dst);
318         if (tevent_req_nomem(subreq, req)) {
319                 goto post;
320         }
321         tevent_req_set_callback(subreq, tdgram_sendto_done, req);
322
323         return req;
324
325  post:
326         tevent_req_post(req, ev);
327         return req;
328 }
329
330 static void tdgram_sendto_done(struct tevent_req *subreq)
331 {
332         struct tevent_req *req = tevent_req_callback_data(subreq,
333                                  struct tevent_req);
334         struct tdgram_sendto_state *state = tevent_req_data(req,
335                                             struct tdgram_sendto_state);
336         ssize_t ret;
337         int sys_errno;
338
339         ret = state->ops->sendto_recv(subreq, &sys_errno);
340         if (ret == -1) {
341                 tevent_req_error(req, sys_errno);
342                 return;
343         }
344
345         state->ret = ret;
346
347         tevent_req_done(req);
348 }
349
350 ssize_t tdgram_sendto_recv(struct tevent_req *req,
351                            int *perrno)
352 {
353         struct tdgram_sendto_state *state = tevent_req_data(req,
354                                             struct tdgram_sendto_state);
355         ssize_t ret;
356
357         ret = tsocket_simple_int_recv(req, perrno);
358         if (ret == 0) {
359                 ret = state->ret;
360         }
361
362         tevent_req_received(req);
363         return ret;
364 }
365
366 struct tdgram_disconnect_state {
367         const struct tdgram_context_ops *ops;
368 };
369
370 static void tdgram_disconnect_done(struct tevent_req *subreq);
371
372 struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
373                                           struct tevent_context *ev,
374                                           struct tdgram_context *dgram)
375 {
376         struct tevent_req *req;
377         struct tdgram_disconnect_state *state;
378         struct tevent_req *subreq;
379
380         req = tevent_req_create(mem_ctx, &state,
381                                 struct tdgram_disconnect_state);
382         if (req == NULL) {
383                 return NULL;
384         }
385
386         state->ops = dgram->ops;
387
388         if (dgram->recvfrom_req || dgram->sendto_req) {
389                 tevent_req_error(req, EBUSY);
390                 goto post;
391         }
392
393         subreq = state->ops->disconnect_send(state, ev, dgram);
394         if (tevent_req_nomem(subreq, req)) {
395                 goto post;
396         }
397         tevent_req_set_callback(subreq, tdgram_disconnect_done, req);
398
399         return req;
400
401  post:
402         tevent_req_post(req, ev);
403         return req;
404 }
405
406 static void tdgram_disconnect_done(struct tevent_req *subreq)
407 {
408         struct tevent_req *req = tevent_req_callback_data(subreq,
409                                  struct tevent_req);
410         struct tdgram_disconnect_state *state = tevent_req_data(req,
411                                                 struct tdgram_disconnect_state);
412         int ret;
413         int sys_errno;
414
415         ret = state->ops->disconnect_recv(subreq, &sys_errno);
416         if (ret == -1) {
417                 tevent_req_error(req, sys_errno);
418                 return;
419         }
420
421         tevent_req_done(req);
422 }
423
424 int tdgram_disconnect_recv(struct tevent_req *req,
425                            int *perrno)
426 {
427         int ret;
428
429         ret = tsocket_simple_int_recv(req, perrno);
430
431         tevent_req_received(req);
432         return ret;
433 }
434
435 struct tstream_context {
436         const char *location;
437         const struct tstream_context_ops *ops;
438         void *private_data;
439
440         struct tevent_req *readv_req;
441         struct tevent_req *writev_req;
442 };
443
444 static int tstream_context_destructor(struct tstream_context *stream)
445 {
446         if (stream->readv_req) {
447                 tevent_req_received(stream->readv_req);
448         }
449
450         if (stream->writev_req) {
451                 tevent_req_received(stream->writev_req);
452         }
453
454         return 0;
455 }
456
457 struct tstream_context *_tstream_context_create(TALLOC_CTX *mem_ctx,
458                                         const struct tstream_context_ops *ops,
459                                         void *pstate,
460                                         size_t psize,
461                                         const char *type,
462                                         const char *location)
463 {
464         struct tstream_context *stream;
465         void **ppstate = (void **)pstate;
466         void *state;
467
468         stream = talloc(mem_ctx, struct tstream_context);
469         if (stream == NULL) {
470                 return NULL;
471         }
472         stream->location        = location;
473         stream->ops             = ops;
474         stream->readv_req       = NULL;
475         stream->writev_req      = NULL;
476
477         state = talloc_size(stream, psize);
478         if (state == NULL) {
479                 talloc_free(stream);
480                 return NULL;
481         }
482         talloc_set_name_const(state, type);
483
484         stream->private_data = state;
485
486         talloc_set_destructor(stream, tstream_context_destructor);
487
488         *ppstate = state;
489         return stream;
490 }
491
492 void *_tstream_context_data(struct tstream_context *stream)
493 {
494         return stream->private_data;
495 }
496
497 ssize_t tstream_pending_bytes(struct tstream_context *stream)
498 {
499         return stream->ops->pending_bytes(stream);
500 }
501
502 struct tstream_readv_state {
503         const struct tstream_context_ops *ops;
504         struct tstream_context *stream;
505         int ret;
506 };
507
508 static int tstream_readv_destructor(struct tstream_readv_state *state)
509 {
510         if (state->stream) {
511                 state->stream->readv_req = NULL;
512         }
513
514         return 0;
515 }
516
517 static void tstream_readv_done(struct tevent_req *subreq);
518
519 struct tevent_req *tstream_readv_send(TALLOC_CTX *mem_ctx,
520                                       struct tevent_context *ev,
521                                       struct tstream_context *stream,
522                                       struct iovec *vector,
523                                       size_t count)
524 {
525         struct tevent_req *req;
526         struct tstream_readv_state *state;
527         struct tevent_req *subreq;
528         int to_read = 0;
529         size_t i;
530
531         req = tevent_req_create(mem_ctx, &state,
532                                 struct tstream_readv_state);
533         if (req == NULL) {
534                 return NULL;
535         }
536
537         state->ops = stream->ops;
538         state->stream = stream;
539         state->ret = -1;
540
541         /* first check if the input is ok */
542 #ifdef IOV_MAX
543         if (count > IOV_MAX) {
544                 tevent_req_error(req, EMSGSIZE);
545                 goto post;
546         }
547 #endif
548
549         for (i=0; i < count; i++) {
550                 int tmp = to_read;
551                 tmp += vector[i].iov_len;
552
553                 if (tmp < to_read) {
554                         tevent_req_error(req, EMSGSIZE);
555                         goto post;
556                 }
557
558                 to_read = tmp;
559         }
560
561         if (to_read == 0) {
562                 tevent_req_error(req, EINVAL);
563                 goto post;
564         }
565
566         if (stream->readv_req) {
567                 tevent_req_error(req, EBUSY);
568                 goto post;
569         }
570         stream->readv_req = req;
571
572         talloc_set_destructor(state, tstream_readv_destructor);
573
574         subreq = state->ops->readv_send(state, ev, stream, vector, count);
575         if (tevent_req_nomem(subreq, req)) {
576                 goto post;
577         }
578         tevent_req_set_callback(subreq, tstream_readv_done, req);
579
580         return req;
581
582  post:
583         tevent_req_post(req, ev);
584         return req;
585 }
586
587 static void tstream_readv_done(struct tevent_req *subreq)
588 {
589         struct tevent_req *req = tevent_req_callback_data(subreq,
590                                  struct tevent_req);
591         struct tstream_readv_state *state = tevent_req_data(req,
592                                             struct tstream_readv_state);
593         ssize_t ret;
594         int sys_errno;
595
596         ret = state->ops->readv_recv(subreq, &sys_errno);
597         TALLOC_FREE(subreq);
598         if (ret == -1) {
599                 tevent_req_error(req, sys_errno);
600                 return;
601         }
602
603         state->ret = ret;
604
605         tevent_req_done(req);
606 }
607
608 int tstream_readv_recv(struct tevent_req *req,
609                        int *perrno)
610 {
611         struct tstream_readv_state *state = tevent_req_data(req,
612                                             struct tstream_readv_state);
613         int ret;
614
615         ret = tsocket_simple_int_recv(req, perrno);
616         if (ret == 0) {
617                 ret = state->ret;
618         }
619
620         tevent_req_received(req);
621         return ret;
622 }
623
624 struct tstream_writev_state {
625         const struct tstream_context_ops *ops;
626         struct tstream_context *stream;
627         int ret;
628 };
629
630 static int tstream_writev_destructor(struct tstream_writev_state *state)
631 {
632         if (state->stream) {
633                 state->stream->writev_req = NULL;
634         }
635
636         return 0;
637 }
638
639 static void tstream_writev_done(struct tevent_req *subreq);
640
641 struct tevent_req *tstream_writev_send(TALLOC_CTX *mem_ctx,
642                                        struct tevent_context *ev,
643                                        struct tstream_context *stream,
644                                        const struct iovec *vector,
645                                        size_t count)
646 {
647         struct tevent_req *req;
648         struct tstream_writev_state *state;
649         struct tevent_req *subreq;
650         int to_write = 0;
651         size_t i;
652
653         req = tevent_req_create(mem_ctx, &state,
654                                 struct tstream_writev_state);
655         if (req == NULL) {
656                 return NULL;
657         }
658
659         state->ops = stream->ops;
660         state->stream = stream;
661         state->ret = -1;
662
663         /* first check if the input is ok */
664 #ifdef IOV_MAX
665         if (count > IOV_MAX) {
666                 tevent_req_error(req, EMSGSIZE);
667                 goto post;
668         }
669 #endif
670
671         for (i=0; i < count; i++) {
672                 int tmp = to_write;
673                 tmp += vector[i].iov_len;
674
675                 if (tmp < to_write) {
676                         tevent_req_error(req, EMSGSIZE);
677                         goto post;
678                 }
679
680                 to_write = tmp;
681         }
682
683         if (to_write == 0) {
684                 tevent_req_error(req, EINVAL);
685                 goto post;
686         }
687
688         if (stream->writev_req) {
689                 tevent_req_error(req, EBUSY);
690                 goto post;
691         }
692         stream->writev_req = req;
693
694         talloc_set_destructor(state, tstream_writev_destructor);
695
696         subreq = state->ops->writev_send(state, ev, stream, vector, count);
697         if (tevent_req_nomem(subreq, req)) {
698                 goto post;
699         }
700         tevent_req_set_callback(subreq, tstream_writev_done, req);
701
702         return req;
703
704  post:
705         tevent_req_post(req, ev);
706         return req;
707 }
708
709 static void tstream_writev_done(struct tevent_req *subreq)
710 {
711         struct tevent_req *req = tevent_req_callback_data(subreq,
712                                  struct tevent_req);
713         struct tstream_writev_state *state = tevent_req_data(req,
714                                              struct tstream_writev_state);
715         ssize_t ret;
716         int sys_errno;
717
718         ret = state->ops->writev_recv(subreq, &sys_errno);
719         if (ret == -1) {
720                 tevent_req_error(req, sys_errno);
721                 return;
722         }
723
724         state->ret = ret;
725
726         tevent_req_done(req);
727 }
728
729 int tstream_writev_recv(struct tevent_req *req,
730                        int *perrno)
731 {
732         struct tstream_writev_state *state = tevent_req_data(req,
733                                              struct tstream_writev_state);
734         int ret;
735
736         ret = tsocket_simple_int_recv(req, perrno);
737         if (ret == 0) {
738                 ret = state->ret;
739         }
740
741         tevent_req_received(req);
742         return ret;
743 }
744
745 struct tstream_disconnect_state {
746         const struct tstream_context_ops *ops;
747 };
748
749 static void tstream_disconnect_done(struct tevent_req *subreq);
750
751 struct tevent_req *tstream_disconnect_send(TALLOC_CTX *mem_ctx,
752                                            struct tevent_context *ev,
753                                            struct tstream_context *stream)
754 {
755         struct tevent_req *req;
756         struct tstream_disconnect_state *state;
757         struct tevent_req *subreq;
758
759         req = tevent_req_create(mem_ctx, &state,
760                                 struct tstream_disconnect_state);
761         if (req == NULL) {
762                 return NULL;
763         }
764
765         state->ops = stream->ops;
766
767         if (stream->readv_req || stream->writev_req) {
768                 tevent_req_error(req, EBUSY);
769                 goto post;
770         }
771
772         subreq = state->ops->disconnect_send(state, ev, stream);
773         if (tevent_req_nomem(subreq, req)) {
774                 goto post;
775         }
776         tevent_req_set_callback(subreq, tstream_disconnect_done, req);
777
778         return req;
779
780  post:
781         tevent_req_post(req, ev);
782         return req;
783 }
784
785 static void tstream_disconnect_done(struct tevent_req *subreq)
786 {
787         struct tevent_req *req = tevent_req_callback_data(subreq,
788                                  struct tevent_req);
789         struct tstream_disconnect_state *state = tevent_req_data(req,
790                                                  struct tstream_disconnect_state);
791         int ret;
792         int sys_errno;
793
794         ret = state->ops->disconnect_recv(subreq, &sys_errno);
795         if (ret == -1) {
796                 tevent_req_error(req, sys_errno);
797                 return;
798         }
799
800         tevent_req_done(req);
801 }
802
803 int tstream_disconnect_recv(struct tevent_req *req,
804                            int *perrno)
805 {
806         int ret;
807
808         ret = tsocket_simple_int_recv(req, perrno);
809
810         tevent_req_received(req);
811         return ret;
812 }
813