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