lib/messages.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    Samba internal messaging functions
00004    Copyright (C) Andrew Tridgell 2000
00005    Copyright (C) 2001 by Martin Pool
00006    Copyright (C) 2002 by Jeremy Allison
00007    
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012    
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017    
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 */
00022 
00023 /**
00024   @defgroup messages Internal messaging framework
00025   @{
00026   @file messages.c
00027   
00028   @brief  Module for internal messaging between Samba daemons. 
00029 
00030    The idea is that if a part of Samba wants to do communication with
00031    another Samba process then it will do a message_register() of a
00032    dispatch function, and use message_send_pid() to send messages to
00033    that process.
00034 
00035    The dispatch function is given the pid of the sender, and it can
00036    use that to reply by message_send_pid().  See ping_message() for a
00037    simple example.
00038 
00039    @caution Dispatch functions must be able to cope with incoming
00040    messages on an *odd* byte boundary.
00041 
00042    This system doesn't have any inherent size limitations but is not
00043    very efficient for large messages or when messages are sent in very
00044    quick succession.
00045 
00046 */
00047 
00048 #include "includes.h"
00049 
00050 /* the locking database handle */
00051 static TDB_CONTEXT *tdb;
00052 static int received_signal;
00053 
00054 /* change the message version with any incompatible changes in the protocol */
00055 #define MESSAGE_VERSION 1
00056 
00057 struct message_rec {
00058         int msg_version;
00059         int msg_type;
00060         struct process_id dest;
00061         struct process_id src;
00062         size_t len;
00063 };
00064 
00065 /* we have a linked list of dispatch handlers */
00066 static struct dispatch_fns {
00067         struct dispatch_fns *next, *prev;
00068         int msg_type;
00069         void (*fn)(int msg_type, struct process_id pid, void *buf, size_t len,
00070                    void *private_data);
00071         void *private_data;
00072 } *dispatch_fns;
00073 
00074 /****************************************************************************
00075  Free global objects.
00076 ****************************************************************************/
00077 
00078 void gfree_messages(void)
00079 {
00080         struct dispatch_fns *dfn, *next;
00081 
00082         /* delete the dispatch_fns list */
00083         dfn = dispatch_fns;
00084         while( dfn ) {
00085                 next = dfn->next;
00086                 DLIST_REMOVE(dispatch_fns, dfn);
00087                 SAFE_FREE(dfn);
00088                 dfn = next;
00089         }
00090 }
00091 
00092 /****************************************************************************
00093  Notifications come in as signals.
00094 ****************************************************************************/
00095 
00096 static void sig_usr1(void)
00097 {
00098         received_signal = 1;
00099         sys_select_signal(SIGUSR1);
00100 }
00101 
00102 /****************************************************************************
00103  A useful function for testing the message system.
00104 ****************************************************************************/
00105 
00106 static void ping_message(int msg_type, struct process_id src,
00107                          void *buf, size_t len, void *private_data)
00108 {
00109         const char *msg = buf ? (const char *)buf : "none";
00110 
00111         DEBUG(1,("INFO: Received PING message from PID %s [%s]\n",
00112                  procid_str_static(&src), msg));
00113         message_send_pid(src, MSG_PONG, buf, len, True);
00114 }
00115 
00116 /****************************************************************************
00117  Initialise the messaging functions. 
00118 ****************************************************************************/
00119 
00120 BOOL message_init(void)
00121 {
00122         sec_init();
00123 
00124         if (tdb)
00125                 return True;
00126 
00127         tdb = tdb_open_log(lock_path("messages.tdb"), 
00128                        0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, 
00129                        O_RDWR|O_CREAT,0600);
00130 
00131         if (!tdb) {
00132                 DEBUG(0,("ERROR: Failed to initialise messages database\n"));
00133                 return False;
00134         }
00135 
00136         /* Activate the per-hashchain freelist */
00137         tdb_set_max_dead(tdb, 5);
00138 
00139         CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1);
00140 
00141         message_register(MSG_PING, ping_message, NULL);
00142 
00143         /* Register some debugging related messages */
00144 
00145         register_msg_pool_usage();
00146         register_dmalloc_msgs();
00147 
00148         return True;
00149 }
00150 
00151 /*******************************************************************
00152  Form a static tdb key from a pid.
00153 ******************************************************************/
00154 
00155 static TDB_DATA message_key_pid(struct process_id pid)
00156 {
00157         static char key[20];
00158         TDB_DATA kbuf;
00159 
00160         slprintf(key, sizeof(key)-1, "PID/%s", procid_str_static(&pid));
00161         
00162         kbuf.dptr = (char *)key;
00163         kbuf.dsize = strlen(key)+1;
00164         return kbuf;
00165 }
00166 
00167 /****************************************************************************
00168  Notify a process that it has a message. If the process doesn't exist 
00169  then delete its record in the database.
00170 ****************************************************************************/
00171 
00172 static NTSTATUS message_notify(struct process_id procid)
00173 {
00174         pid_t pid = procid.pid;
00175         int ret;
00176         uid_t euid = geteuid();
00177 
00178         /*
00179          * Doing kill with a non-positive pid causes messages to be
00180          * sent to places we don't want.
00181          */
00182 
00183         SMB_ASSERT(pid > 0);
00184 
00185         if (euid != 0) {
00186                 /* If we're not root become so to send the message. */
00187                 save_re_uid();
00188                 set_effective_uid(0);
00189         }
00190 
00191         ret = kill(pid, SIGUSR1);
00192 
00193         if (euid != 0) {
00194                 /* Go back to who we were. */
00195                 int saved_errno = errno;
00196                 restore_re_uid_fromroot();
00197                 errno = saved_errno;
00198         }
00199 
00200         if (ret == -1) {
00201                 if (errno == ESRCH) {
00202                         DEBUG(2,("pid %d doesn't exist - deleting messages record\n",
00203                                  (int)pid));
00204                         tdb_delete(tdb, message_key_pid(procid));
00205 
00206                         /*
00207                          * INVALID_HANDLE is the closest I can think of -- vl
00208                          */
00209                         return NT_STATUS_INVALID_HANDLE;
00210                 }
00211 
00212                 DEBUG(2,("message to process %d failed - %s\n", (int)pid,
00213                          strerror(errno)));
00214 
00215                 /*
00216                  * No call to map_nt_error_from_unix -- don't want to link in
00217                  * errormap.o into lots of utils.
00218                  */
00219 
00220                 if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
00221                 if (errno == EPERM)  return NT_STATUS_ACCESS_DENIED;
00222                 return NT_STATUS_UNSUCCESSFUL;
00223         }
00224 
00225         return NT_STATUS_OK;
00226 }
00227 
00228 /****************************************************************************
00229  Send a message to a particular pid.
00230 ****************************************************************************/
00231 
00232 static NTSTATUS message_send_pid_internal(struct process_id pid, int msg_type,
00233                                           const void *buf, size_t len,
00234                                           BOOL duplicates_allowed,
00235                                           unsigned int timeout)
00236 {
00237         TDB_DATA kbuf;
00238         TDB_DATA dbuf;
00239         TDB_DATA old_dbuf;
00240         struct message_rec rec;
00241         char *ptr;
00242         struct message_rec prec;
00243 
00244         /* NULL pointer means implicit length zero. */
00245         if (!buf) {
00246                 SMB_ASSERT(len == 0);
00247         }
00248 
00249         /*
00250          * Doing kill with a non-positive pid causes messages to be
00251          * sent to places we don't want.
00252          */
00253 
00254         SMB_ASSERT(procid_to_pid(&pid) > 0);
00255 
00256         rec.msg_version = MESSAGE_VERSION;
00257         rec.msg_type = msg_type;
00258         rec.dest = pid;
00259         rec.src = procid_self();
00260         rec.len = buf ? len : 0;
00261 
00262         kbuf = message_key_pid(pid);
00263 
00264         dbuf.dptr = (char *)SMB_MALLOC(len + sizeof(rec));
00265         if (!dbuf.dptr) {
00266                 return NT_STATUS_NO_MEMORY;
00267         }
00268 
00269         memcpy(dbuf.dptr, &rec, sizeof(rec));
00270         if (len > 0 && buf)
00271                 memcpy((void *)((char*)dbuf.dptr+sizeof(rec)), buf, len);
00272 
00273         dbuf.dsize = len + sizeof(rec);
00274 
00275         if (duplicates_allowed) {
00276 
00277                 /* If duplicates are allowed we can just append the message and return. */
00278 
00279                 /* lock the record for the destination */
00280                 if (timeout) {
00281                         if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) {
00282                                 DEBUG(0,("message_send_pid_internal: failed to get "
00283                                          "chainlock with timeout %ul.\n", timeout));
00284                                 SAFE_FREE(dbuf.dptr);
00285                                 return NT_STATUS_IO_TIMEOUT;
00286                         }
00287                 } else {
00288                         if (tdb_chainlock(tdb, kbuf) == -1) {
00289                                 DEBUG(0,("message_send_pid_internal: failed to get "
00290                                          "chainlock.\n"));
00291                                 SAFE_FREE(dbuf.dptr);
00292                                 return NT_STATUS_LOCK_NOT_GRANTED;
00293                         }
00294                 }       
00295                 tdb_append(tdb, kbuf, dbuf);
00296                 tdb_chainunlock(tdb, kbuf);
00297 
00298                 SAFE_FREE(dbuf.dptr);
00299                 errno = 0;                    /* paranoia */
00300                 return message_notify(pid);
00301         }
00302 
00303         /* lock the record for the destination */
00304         if (timeout) {
00305                 if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) {
00306                         DEBUG(0,("message_send_pid_internal: failed to get chainlock "
00307                                  "with timeout %ul.\n", timeout));
00308                         SAFE_FREE(dbuf.dptr);
00309                         return NT_STATUS_IO_TIMEOUT;
00310                 }
00311         } else {
00312                 if (tdb_chainlock(tdb, kbuf) == -1) {
00313                         DEBUG(0,("message_send_pid_internal: failed to get "
00314                                  "chainlock.\n"));
00315                         SAFE_FREE(dbuf.dptr);
00316                         return NT_STATUS_LOCK_NOT_GRANTED;
00317                 }
00318         }       
00319 
00320         old_dbuf = tdb_fetch(tdb, kbuf);
00321 
00322         if (!old_dbuf.dptr) {
00323                 /* its a new record */
00324 
00325                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
00326                 tdb_chainunlock(tdb, kbuf);
00327 
00328                 SAFE_FREE(dbuf.dptr);
00329                 errno = 0;                    /* paranoia */
00330                 return message_notify(pid);
00331         }
00332 
00333         /* Not a new record. Check for duplicates. */
00334 
00335         for(ptr = (char *)old_dbuf.dptr; ptr < old_dbuf.dptr + old_dbuf.dsize; ) {
00336                 /*
00337                  * First check if the message header matches, then, if it's a non-zero
00338                  * sized message, check if the data matches. If so it's a duplicate and
00339                  * we can discard it. JRA.
00340                  */
00341 
00342                 if (!memcmp(ptr, &rec, sizeof(rec))) {
00343                         if (!len || (len && !memcmp( ptr + sizeof(rec), buf, len))) {
00344                                 tdb_chainunlock(tdb, kbuf);
00345                                 DEBUG(10,("message_send_pid_internal: discarding "
00346                                           "duplicate message.\n"));
00347                                 SAFE_FREE(dbuf.dptr);
00348                                 SAFE_FREE(old_dbuf.dptr);
00349                                 return NT_STATUS_OK;
00350                         }
00351                 }
00352                 memcpy(&prec, ptr, sizeof(prec));
00353                 ptr += sizeof(rec) + prec.len;
00354         }
00355 
00356         /* we're adding to an existing entry */
00357 
00358         tdb_append(tdb, kbuf, dbuf);
00359         tdb_chainunlock(tdb, kbuf);
00360 
00361         SAFE_FREE(old_dbuf.dptr);
00362         SAFE_FREE(dbuf.dptr);
00363 
00364         errno = 0;                    /* paranoia */
00365         return message_notify(pid);
00366 }
00367 
00368 /****************************************************************************
00369  Send a message to a particular pid - no timeout.
00370 ****************************************************************************/
00371 
00372 NTSTATUS message_send_pid(struct process_id pid, int msg_type, const void *buf,
00373                           size_t len, BOOL duplicates_allowed)
00374 {
00375         return message_send_pid_internal(pid, msg_type, buf, len,
00376                                          duplicates_allowed, 0);
00377 }
00378 
00379 /****************************************************************************
00380  Send a message to a particular pid, with timeout in seconds.
00381 ****************************************************************************/
00382 
00383 NTSTATUS message_send_pid_with_timeout(struct process_id pid, int msg_type,
00384                                        const void *buf, size_t len,
00385                                        BOOL duplicates_allowed, unsigned int timeout)
00386 {
00387         return message_send_pid_internal(pid, msg_type, buf, len, duplicates_allowed,
00388                                          timeout);
00389 }
00390 
00391 /****************************************************************************
00392  Count the messages pending for a particular pid. Expensive....
00393 ****************************************************************************/
00394 
00395 unsigned int messages_pending_for_pid(struct process_id pid)
00396 {
00397         TDB_DATA kbuf;
00398         TDB_DATA dbuf;
00399         char *buf;
00400         unsigned int message_count = 0;
00401 
00402         kbuf = message_key_pid(pid);
00403 
00404         dbuf = tdb_fetch(tdb, kbuf);
00405         if (dbuf.dptr == NULL || dbuf.dsize == 0) {
00406                 SAFE_FREE(dbuf.dptr);
00407                 return 0;
00408         }
00409 
00410         for (buf = dbuf.dptr; dbuf.dsize > sizeof(struct message_rec);) {
00411                 struct message_rec rec;
00412                 memcpy(&rec, buf, sizeof(rec));
00413                 buf += (sizeof(rec) + rec.len);
00414                 dbuf.dsize -= (sizeof(rec) + rec.len);
00415                 message_count++;
00416         }
00417 
00418         SAFE_FREE(dbuf.dptr);
00419         return message_count;
00420 }
00421 
00422 /****************************************************************************
00423  Retrieve all messages for the current process.
00424 ****************************************************************************/
00425 
00426 static BOOL retrieve_all_messages(char **msgs_buf, size_t *total_len)
00427 {
00428         TDB_DATA kbuf;
00429         TDB_DATA dbuf;
00430         TDB_DATA null_dbuf;
00431 
00432         ZERO_STRUCT(null_dbuf);
00433 
00434         *msgs_buf = NULL;
00435         *total_len = 0;
00436 
00437         kbuf = message_key_pid(pid_to_procid(sys_getpid()));
00438 
00439         if (tdb_chainlock(tdb, kbuf) == -1)
00440                 return False;
00441 
00442         dbuf = tdb_fetch(tdb, kbuf);
00443         /*
00444          * Replace with an empty record to keep the allocated
00445          * space in the tdb.
00446          */
00447         tdb_store(tdb, kbuf, null_dbuf, TDB_REPLACE);
00448         tdb_chainunlock(tdb, kbuf);
00449 
00450         if (dbuf.dptr == NULL || dbuf.dsize == 0) {
00451                 SAFE_FREE(dbuf.dptr);
00452                 return False;
00453         }
00454 
00455         *msgs_buf = dbuf.dptr;
00456         *total_len = dbuf.dsize;
00457 
00458         return True;
00459 }
00460 
00461 /****************************************************************************
00462  Parse out the next message for the current process.
00463 ****************************************************************************/
00464 
00465 static BOOL message_recv(char *msgs_buf, size_t total_len, int *msg_type,
00466                          struct process_id *src, char **buf, size_t *len)
00467 {
00468         struct message_rec rec;
00469         char *ret_buf = *buf;
00470 
00471         *buf = NULL;
00472         *len = 0;
00473 
00474         if (total_len - (ret_buf - msgs_buf) < sizeof(rec))
00475                 return False;
00476 
00477         memcpy(&rec, ret_buf, sizeof(rec));
00478         ret_buf += sizeof(rec);
00479 
00480         if (rec.msg_version != MESSAGE_VERSION) {
00481                 DEBUG(0,("message version %d received (expected %d)\n", rec.msg_version, MESSAGE_VERSION));
00482                 return False;
00483         }
00484 
00485         if (rec.len > 0) {
00486                 if (total_len - (ret_buf - msgs_buf) < rec.len)
00487                         return False;
00488         }
00489 
00490         *len = rec.len;
00491         *msg_type = rec.msg_type;
00492         *src = rec.src;
00493         *buf = ret_buf;
00494 
00495         return True;
00496 }
00497 
00498 /****************************************************************************
00499  Receive and dispatch any messages pending for this process.
00500  JRA changed Dec 13 2006. Only one message handler now permitted per type.
00501  *NOTE*: Dispatch functions must be able to cope with incoming
00502  messages on an *odd* byte boundary.
00503 ****************************************************************************/
00504 
00505 void message_dispatch(void)
00506 {
00507         int msg_type;
00508         struct process_id src;
00509         char *buf;
00510         char *msgs_buf;
00511         size_t len, total_len;
00512         int n_handled;
00513 
00514         if (!received_signal)
00515                 return;
00516 
00517         DEBUG(10,("message_dispatch: received_signal = %d\n", received_signal));
00518 
00519         received_signal = 0;
00520 
00521         if (!retrieve_all_messages(&msgs_buf, &total_len))
00522                 return;
00523 
00524         for (buf = msgs_buf; message_recv(msgs_buf, total_len, &msg_type, &src, &buf, &len); buf += len) {
00525                 struct dispatch_fns *dfn;
00526 
00527                 DEBUG(10,("message_dispatch: received msg_type=%d "
00528                           "src_pid=%u\n", msg_type,
00529                           (unsigned int) procid_to_pid(&src)));
00530 
00531                 n_handled = 0;
00532                 for (dfn = dispatch_fns; dfn; dfn = dfn->next) {
00533                         if (dfn->msg_type == msg_type) {
00534                                 DEBUG(10,("message_dispatch: processing message of type %d.\n", msg_type));
00535                                 dfn->fn(msg_type, src,
00536                                         len ? (void *)buf : NULL, len,
00537                                         dfn->private_data);
00538                                 n_handled++;
00539                                 break;
00540                         }
00541                 }
00542                 if (!n_handled) {
00543                         DEBUG(5,("message_dispatch: warning: no handler registed for "
00544                                  "msg_type %d in pid %u\n",
00545                                  msg_type, (unsigned int)sys_getpid()));
00546                 }
00547         }
00548         SAFE_FREE(msgs_buf);
00549 }
00550 
00551 /****************************************************************************
00552  Register/replace a dispatch function for a particular message type.
00553  JRA changed Dec 13 2006. Only one message handler now permitted per type.
00554  *NOTE*: Dispatch functions must be able to cope with incoming
00555  messages on an *odd* byte boundary.
00556 ****************************************************************************/
00557 
00558 void message_register(int msg_type, 
00559                       void (*fn)(int msg_type, struct process_id pid,
00560                                  void *buf, size_t len,
00561                                  void *private_data),
00562                       void *private_data)
00563 {
00564         struct dispatch_fns *dfn;
00565 
00566         for (dfn = dispatch_fns; dfn; dfn = dfn->next) {
00567                 if (dfn->msg_type == msg_type) {
00568                         dfn->fn = fn;
00569                         return;
00570                 }
00571         }
00572 
00573         dfn = SMB_MALLOC_P(struct dispatch_fns);
00574 
00575         if (dfn != NULL) {
00576 
00577                 ZERO_STRUCTPN(dfn);
00578 
00579                 dfn->msg_type = msg_type;
00580                 dfn->fn = fn;
00581                 dfn->private_data = private_data;
00582 
00583                 DLIST_ADD(dispatch_fns, dfn);
00584         }
00585         else {
00586         
00587                 DEBUG(0,("message_register: Not enough memory. malloc failed!\n"));
00588         }
00589 }
00590 
00591 /****************************************************************************
00592  De-register the function for a particular message type.
00593 ****************************************************************************/
00594 
00595 void message_deregister(int msg_type)
00596 {
00597         struct dispatch_fns *dfn, *next;
00598 
00599         for (dfn = dispatch_fns; dfn; dfn = next) {
00600                 next = dfn->next;
00601                 if (dfn->msg_type == msg_type) {
00602                         DLIST_REMOVE(dispatch_fns, dfn);
00603                         SAFE_FREE(dfn);
00604                         return;
00605                 }
00606         }       
00607 }
00608 
00609 struct msg_all {
00610         int msg_type;
00611         uint32 msg_flag;
00612         const void *buf;
00613         size_t len;
00614         BOOL duplicates;
00615         int n_sent;
00616 };
00617 
00618 /****************************************************************************
00619  Send one of the messages for the broadcast.
00620 ****************************************************************************/
00621 
00622 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
00623 {
00624         struct connections_data crec;
00625         struct msg_all *msg_all = (struct msg_all *)state;
00626         NTSTATUS status;
00627 
00628         if (dbuf.dsize != sizeof(crec))
00629                 return 0;
00630 
00631         memcpy(&crec, dbuf.dptr, sizeof(crec));
00632 
00633         if (crec.cnum != -1)
00634                 return 0;
00635 
00636         /* Don't send if the receiver hasn't registered an interest. */
00637 
00638         if(!(crec.bcast_msg_flags & msg_all->msg_flag))
00639                 return 0;
00640 
00641         /* If the msg send fails because the pid was not found (i.e. smbd died), 
00642          * the msg has already been deleted from the messages.tdb.*/
00643 
00644         status = message_send_pid(crec.pid, msg_all->msg_type,
00645                                   msg_all->buf, msg_all->len,
00646                                   msg_all->duplicates);
00647 
00648         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
00649                 
00650                 /* If the pid was not found delete the entry from connections.tdb */
00651 
00652                 DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n",
00653                          procid_str_static(&crec.pid), crec.cnum, crec.servicename));
00654                 tdb_delete(the_tdb, kbuf);
00655         }
00656         msg_all->n_sent++;
00657         return 0;
00658 }
00659 
00660 /**
00661  * Send a message to all smbd processes.
00662  *
00663  * It isn't very efficient, but should be OK for the sorts of
00664  * applications that use it. When we need efficient broadcast we can add
00665  * it.
00666  *
00667  * @param n_sent Set to the number of messages sent.  This should be
00668  * equal to the number of processes, but be careful for races.
00669  *
00670  * @retval True for success.
00671  **/
00672 BOOL message_send_all(TDB_CONTEXT *conn_tdb, int msg_type,
00673                       const void *buf, size_t len,
00674                       BOOL duplicates_allowed,
00675                       int *n_sent)
00676 {
00677         struct msg_all msg_all;
00678 
00679         msg_all.msg_type = msg_type;
00680         if (msg_type < 1000)
00681                 msg_all.msg_flag = FLAG_MSG_GENERAL;
00682         else if (msg_type > 1000 && msg_type < 2000)
00683                 msg_all.msg_flag = FLAG_MSG_NMBD;
00684         else if (msg_type > 2000 && msg_type < 2100)
00685                 msg_all.msg_flag = FLAG_MSG_PRINT_NOTIFY;
00686         else if (msg_type > 2100 && msg_type < 3000)
00687                 msg_all.msg_flag = FLAG_MSG_PRINT_GENERAL;
00688         else if (msg_type > 3000 && msg_type < 4000)
00689                 msg_all.msg_flag = FLAG_MSG_SMBD;
00690         else
00691                 return False;
00692 
00693         msg_all.buf = buf;
00694         msg_all.len = len;
00695         msg_all.duplicates = duplicates_allowed;
00696         msg_all.n_sent = 0;
00697 
00698         tdb_traverse(conn_tdb, traverse_fn, &msg_all);
00699         if (n_sent)
00700                 *n_sent = msg_all.n_sent;
00701         return True;
00702 }
00703 
00704 /*
00705  * Block and unblock receiving of messages. Allows removal of race conditions
00706  * when doing a fork and changing message disposition.
00707  */
00708 
00709 void message_block(void)
00710 {
00711         BlockSignals(True, SIGUSR1);
00712 }
00713 
00714 void message_unblock(void)
00715 {
00716         BlockSignals(False, SIGUSR1);
00717 }
00718 
00719 /*
00720  * Samba4 API wrapper around the Samba3 implementation. Yes, I know, we could
00721  * import the whole Samba4 thing, but I want notify.c from Samba4 in first.
00722  */
00723 
00724 struct messaging_callback {
00725         struct messaging_callback *prev, *next;
00726         uint32 msg_type;
00727         void (*fn)(struct messaging_context *msg, void *private_data, 
00728                    uint32_t msg_type, 
00729                    struct server_id server_id, DATA_BLOB *data);
00730         void *private_data;
00731 };
00732 
00733 struct messaging_context {
00734         struct server_id id;
00735         struct messaging_callback *callbacks;
00736 };
00737 
00738 static int messaging_context_destructor(struct messaging_context *ctx)
00739 {
00740         struct messaging_callback *cb;
00741 
00742         for (cb = ctx->callbacks; cb; cb = cb->next) {
00743                 /*
00744                  * We unconditionally remove all instances of our callback
00745                  * from the tdb basis.
00746                  */
00747                 message_deregister(cb->msg_type);
00748         }
00749         return 0;
00750 }
00751 
00752 struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, 
00753                                          struct server_id server_id, 
00754                                          struct event_context *ev)
00755 {
00756         struct messaging_context *ctx;
00757 
00758         if (!(ctx = TALLOC_ZERO_P(mem_ctx, struct messaging_context))) {
00759                 return NULL;
00760         }
00761 
00762         ctx->id = server_id;
00763         talloc_set_destructor(ctx, messaging_context_destructor);
00764         return ctx;
00765 }
00766 
00767 static void messaging_callback(int msg_type, struct process_id pid,
00768                                void *buf, size_t len, void *private_data)
00769 {
00770         struct messaging_context *ctx = talloc_get_type_abort(
00771                 private_data, struct messaging_context);
00772         struct messaging_callback *cb, *next;
00773 
00774         for (cb = ctx->callbacks; cb; cb = next) {
00775                 /*
00776                  * Allow a callback to remove itself
00777                  */
00778                 next = cb->next;
00779 
00780                 if (msg_type == cb->msg_type) {
00781                         DATA_BLOB blob;
00782                         struct server_id id;
00783 
00784                         blob.data = (uint8 *)buf;
00785                         blob.length = len;
00786                         id.id = pid;
00787 
00788                         cb->fn(ctx, cb->private_data, msg_type, id, &blob);
00789                 }
00790         }
00791 }
00792 
00793 /*
00794  * Register a dispatch function for a particular message type. Allow multiple
00795  * registrants
00796 */
00797 NTSTATUS messaging_register(struct messaging_context *ctx, void *private_data,
00798                             uint32_t msg_type,
00799                             void (*fn)(struct messaging_context *msg,
00800                                        void *private_data, 
00801                                        uint32_t msg_type, 
00802                                        struct server_id server_id,
00803                                        DATA_BLOB *data))
00804 {
00805         struct messaging_callback *cb;
00806 
00807         if (!(cb = talloc(ctx, struct messaging_callback))) {
00808                 return NT_STATUS_NO_MEMORY;
00809         }
00810 
00811         cb->msg_type = msg_type;
00812         cb->fn = fn;
00813         cb->private_data = private_data;
00814 
00815         DLIST_ADD(ctx->callbacks, cb);
00816         message_register(msg_type, messaging_callback, ctx);
00817         return NT_STATUS_OK;
00818 }
00819 
00820 /*
00821   De-register the function for a particular message type.
00822 */
00823 void messaging_deregister(struct messaging_context *ctx, uint32_t msg_type,
00824                           void *private_data)
00825 {
00826         struct messaging_callback *cb, *next;
00827 
00828         for (cb = ctx->callbacks; cb; cb = next) {
00829                 next = cb->next;
00830                 if ((cb->msg_type == msg_type)
00831                     && (cb->private_data == private_data)) {
00832                         DLIST_REMOVE(ctx->callbacks, cb);
00833                         TALLOC_FREE(cb);
00834                 }
00835         }
00836 }
00837 
00838 /*
00839   Send a message to a particular server
00840 */
00841 NTSTATUS messaging_send(struct messaging_context *msg,
00842                         struct server_id server, 
00843                         uint32_t msg_type, DATA_BLOB *data)
00844 {
00845         return message_send_pid_internal(server.id, msg_type, data->data,
00846                                          data->length, True, 0);
00847 }
00848 
00849 /** @} **/

Sambaに対してSat Aug 29 21:22:58 2009に生成されました。  doxygen 1.4.7