LCOV - code coverage report
Current view: top level - source3/torture - test_messaging_send_all.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 109 154 70.8 %
Date: 2024-04-21 15:09:00 Functions: 4 5 80.0 %

          Line data    Source code
       1             : /*
       2             :  * Unix SMB/CIFS implementation.
       3             :  * Test for a messaging_send_all bug
       4             :  * Copyright (C) Volker Lendecke 2017
       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 "includes.h"
      21             : #include "torture/proto.h"
      22             : #include "lib/util/tevent_unix.h"
      23             : #include "messages.h"
      24             : #include "lib/async_req/async_sock.h"
      25             : #include "lib/util/sys_rw.h"
      26             : 
      27           5 : static pid_t fork_responder(struct messaging_context *msg_ctx,
      28             :                             int exit_pipe[2])
      29             : {
      30           5 :         struct tevent_context *ev = messaging_tevent_context(msg_ctx);
      31           5 :         struct tevent_req *req;
      32           5 :         pid_t child_pid;
      33           5 :         int ready_pipe[2];
      34           5 :         char c = 0;
      35           5 :         bool ok;
      36           5 :         int ret, err;
      37           5 :         NTSTATUS status;
      38           5 :         ssize_t nwritten;
      39             : 
      40           5 :         ret = pipe(ready_pipe);
      41           5 :         if (ret == -1) {
      42           0 :                 perror("pipe failed");
      43           0 :                 return -1;
      44             :         }
      45             : 
      46           5 :         child_pid = fork();
      47          10 :         if (child_pid == -1) {
      48           0 :                 perror("fork failed");
      49           0 :                 close(ready_pipe[0]);
      50           0 :                 close(ready_pipe[1]);
      51           0 :                 return -1;
      52             :         }
      53             : 
      54          10 :         if (child_pid != 0) {
      55           5 :                 ssize_t nread;
      56           5 :                 close(ready_pipe[1]);
      57           5 :                 nread = read(ready_pipe[0], &c, 1);
      58           5 :                 close(ready_pipe[0]);
      59           5 :                 if (nread != 1) {
      60           0 :                         perror("read failed");
      61           0 :                         return -1;
      62             :                 }
      63           0 :                 return child_pid;
      64             :         }
      65             : 
      66           5 :         close(ready_pipe[0]);
      67           5 :         close(exit_pipe[1]);
      68             : 
      69           5 :         status = messaging_reinit(msg_ctx);
      70           5 :         if (!NT_STATUS_IS_OK(status)) {
      71           0 :                 fprintf(stderr, "messaging_reinit failed: %s\n",
      72             :                         nt_errstr(status));
      73           0 :                 close(ready_pipe[1]);
      74           0 :                 exit(1);
      75             :         }
      76             : 
      77           5 :         nwritten = sys_write(ready_pipe[1], &c, 1);
      78           5 :         if (nwritten != 1) {
      79           0 :                 fprintf(stderr, "write failed: %s\n", strerror(errno));
      80           0 :                 exit(1);
      81             :         }
      82             : 
      83           5 :         close(ready_pipe[1]);
      84             : 
      85           5 :         req = wait_for_read_send(ev, ev, exit_pipe[0], false);
      86           5 :         if (req == NULL) {
      87           0 :                 fprintf(stderr, "wait_for_read_send failed\n");
      88           0 :                 exit(1);
      89             :         }
      90             : 
      91           5 :         ok = tevent_req_poll_unix(req, ev, &err);
      92           5 :         if (!ok) {
      93           0 :                 fprintf(stderr, "tevent_req_poll_unix failed: %s\n",
      94             :                         strerror(err));
      95           0 :                 exit(1);
      96             :         }
      97             : 
      98           5 :         exit(0);
      99             : }
     100             : 
     101             : struct messaging_send_all_state {
     102             :         struct tevent_context *ev;
     103             :         struct messaging_context *msg;
     104             :         pid_t *senders;
     105             :         size_t num_received;
     106             : };
     107             : 
     108             : static void collect_pong_received(struct tevent_req *subreq);
     109             : 
     110           1 : static struct tevent_req *collect_pong_send(TALLOC_CTX *mem_ctx,
     111             :                                             struct tevent_context *ev,
     112             :                                             struct messaging_context *msg,
     113             :                                             const pid_t *senders,
     114             :                                             size_t num_senders)
     115             : {
     116           1 :         struct tevent_req *req, *subreq;
     117           1 :         struct messaging_send_all_state *state;
     118             : 
     119           1 :         req = tevent_req_create(mem_ctx, &state,
     120             :                                 struct messaging_send_all_state);
     121           1 :         if (req == NULL) {
     122           0 :                 return NULL;
     123             :         }
     124           1 :         state->senders = talloc_memdup(
     125             :                 state, senders, num_senders * sizeof(pid_t));
     126           1 :         if (tevent_req_nomem(state->senders, req)) {
     127           0 :                 return tevent_req_post(req, ev);
     128             :         }
     129           1 :         state->ev = ev;
     130           1 :         state->msg = msg;
     131             : 
     132           1 :         subreq = messaging_read_send(state, state->ev, state->msg, MSG_PONG);
     133           1 :         if (tevent_req_nomem(subreq, req)) {
     134           0 :                 return tevent_req_post(req, ev);
     135             :         }
     136           1 :         tevent_req_set_callback(subreq, collect_pong_received, req);
     137           1 :         return req;
     138             : }
     139             : 
     140           5 : static void collect_pong_received(struct tevent_req *subreq)
     141             : {
     142           5 :         struct tevent_req *req = tevent_req_callback_data(
     143             :                 subreq, struct tevent_req);
     144           5 :         struct messaging_send_all_state *state = tevent_req_data(
     145             :                 req, struct messaging_send_all_state);
     146           5 :         size_t num_senders = talloc_array_length(state->senders);
     147           5 :         size_t i;
     148           5 :         struct messaging_rec *rec;
     149           5 :         int ret;
     150             : 
     151           5 :         ret = messaging_read_recv(subreq, state, &rec);
     152           5 :         TALLOC_FREE(subreq);
     153           5 :         if (tevent_req_error(req, ret)) {
     154           1 :                 return;
     155             :         }
     156             : 
     157             :         /*
     158             :          * We need to make sure we don't receive our own broadcast!
     159             :          */
     160             : 
     161           5 :         if (rec->src.pid == (uint64_t)getpid()) {
     162           0 :                 fprintf(stderr, "Received my own broadcast!\n");
     163           0 :                 tevent_req_error(req, EMULTIHOP);
     164           0 :                 return;
     165             :         }
     166             : 
     167          15 :         for (i=0; i<num_senders; i++) {
     168          15 :                 if (state->senders[i] == (pid_t)rec->src.pid) {
     169           5 :                         printf("got message from %"PRIu64"\n", rec->src.pid);
     170           5 :                         state->senders[i] = 0;
     171           5 :                         state->num_received += 1;
     172           5 :                         break;
     173             :                 }
     174             :         }
     175             : 
     176           5 :         if (state->num_received == num_senders) {
     177           1 :                 printf("done\n");
     178           1 :                 tevent_req_done(req);
     179           1 :                 return;
     180             :         }
     181             : 
     182           4 :         subreq = messaging_read_send(state, state->ev, state->msg, MSG_PONG);
     183           4 :         if (tevent_req_nomem(subreq, req)) {
     184           0 :                 return;
     185             :         }
     186           4 :         tevent_req_set_callback(subreq, collect_pong_received, req);
     187             : }
     188             : 
     189           1 : static int collect_pong_recv(struct tevent_req *req)
     190             : {
     191           1 :         return tevent_req_simple_recv_unix(req);
     192             : }
     193             : 
     194             : extern int torture_nprocs;
     195             : 
     196           1 : bool run_messaging_send_all(int dummy)
     197           1 : {
     198           1 :         struct tevent_context *ev = NULL;
     199           1 :         struct messaging_context *msg_ctx = NULL;
     200           1 :         int exit_pipe[2];
     201           1 :         pid_t children[MAX(5, torture_nprocs)];
     202           1 :         struct tevent_req *req;
     203           1 :         size_t i;
     204           1 :         bool ok;
     205           1 :         int ret, err;
     206             : 
     207           1 :         ev = samba_tevent_context_init(talloc_tos());
     208           1 :         if (ev == NULL) {
     209           0 :                 fprintf(stderr, "tevent_context_init failed\n");
     210           0 :                 return false;
     211             :         }
     212           1 :         msg_ctx = messaging_init(ev, ev);
     213           1 :         if (msg_ctx == NULL) {
     214           0 :                 fprintf(stderr, "messaging_init failed\n");
     215           0 :                 return false;
     216             :         }
     217           1 :         ret = pipe(exit_pipe);
     218           1 :         if (ret != 0) {
     219           0 :                 perror("parent: pipe failed for exit_pipe");
     220           0 :                 return false;
     221             :         }
     222             : 
     223           6 :         for (i=0; i<ARRAY_SIZE(children); i++) {
     224           5 :                 children[i] = fork_responder(msg_ctx, exit_pipe);
     225           5 :                 if (children[i] == -1) {
     226           0 :                         fprintf(stderr, "fork_responder(%zu) failed\n", i);
     227           0 :                         return false;
     228             :                 }
     229             :         }
     230             : 
     231           1 :         req = collect_pong_send(ev, ev, msg_ctx, children,
     232           0 :                                 ARRAY_SIZE(children));
     233           1 :         if (req == NULL) {
     234           0 :                 perror("collect_pong failed");
     235           0 :                 return false;
     236             :         }
     237             : 
     238           1 :         ok = tevent_req_set_endtime(req, ev,
     239             :                                     tevent_timeval_current_ofs(10, 0));
     240           1 :         if (!ok) {
     241           0 :                 perror("tevent_req_set_endtime failed");
     242           0 :                 return false;
     243             :         }
     244             : 
     245           1 :         messaging_send_all(msg_ctx, MSG_PING, NULL, 0);
     246             : 
     247           1 :         ok = tevent_req_poll_unix(req, ev, &err);
     248           1 :         if (!ok) {
     249           0 :                 perror("tevent_req_poll_unix failed");
     250           0 :                 return false;
     251             :         }
     252             : 
     253           1 :         ret = collect_pong_recv(req);
     254           1 :         TALLOC_FREE(req);
     255             : 
     256           1 :         if (ret != 0) {
     257           0 :                 fprintf(stderr, "collect_pong_send returned %s\n",
     258             :                         strerror(ret));
     259           0 :                 return false;
     260             :         }
     261             : 
     262           1 :         close(exit_pipe[1]);
     263             : 
     264           7 :         for (i=0; i<ARRAY_SIZE(children); i++) {
     265           5 :                 pid_t child;
     266           5 :                 int status;
     267             : 
     268           5 :                 do {
     269           5 :                         child = waitpid(children[i], &status, 0);
     270           5 :                 } while ((child == -1) && (errno == EINTR));
     271             : 
     272           5 :                 if (child != children[i]) {
     273           0 :                         printf("waitpid(%d) failed\n", children[i]);
     274           0 :                         return false;
     275             :                 }
     276             :         }
     277             : 
     278           0 :         return true;
     279             : }

Generated by: LCOV version 1.14