static BOOL retrieve_all_messages(char **msgs_buf, size_t *total_len) { TDB_DATA kbuf; TDB_DATA dbuf; TDB_DATA null_dbuf; ZERO_STRUCT(null_dbuf); *msgs_buf = NULL; *total_len = 0; kbuf = message_key_pid(pid_to_procid(sys_getpid())); if (tdb_chainlock(tdb, kbuf) == -1) return False; dbuf = tdb_fetch(tdb, kbuf); /* * Replace with an empty record to keep the allocated * space in the tdb. */ tdb_store(tdb, kbuf, null_dbuf, TDB_REPLACE); tdb_chainunlock(tdb, kbuf); if (dbuf.dptr == NULL || dbuf.dsize == 0) { SAFE_FREE(dbuf.dptr); return False; } *msgs_buf = dbuf.dptr; *total_len = dbuf.dsize; return True; }
unsigned int messages_pending_for_pid(struct process_id pid) { TDB_DATA kbuf; TDB_DATA dbuf; char *buf; unsigned int message_count = 0; kbuf = message_key_pid(pid); dbuf = tdb_fetch(tdb, kbuf); if (dbuf.dptr == NULL || dbuf.dsize == 0) { SAFE_FREE(dbuf.dptr); return 0; } for (buf = dbuf.dptr; dbuf.dsize > sizeof(struct message_rec);) { struct message_rec rec; memcpy(&rec, buf, sizeof(rec)); buf += (sizeof(rec) + rec.len); dbuf.dsize -= (sizeof(rec) + rec.len); message_count++; } SAFE_FREE(dbuf.dptr); return message_count; }
static BOOL message_notify(pid_t pid) { if (kill(pid, SIGUSR1) == -1) { if (errno == ESRCH) { DEBUG(2,("pid %d doesn't exist - deleting messages record\n", (int)pid)); tdb_delete(tdb, message_key_pid(pid)); } else { DEBUG(2,("message to process %d failed - %s\n", (int)pid, strerror(errno))); } return False; } return True; }
static BOOL message_recv(int *msg_type, pid_t *src, void **buf, size_t *len) { TDB_DATA kbuf; TDB_DATA dbuf; struct message_rec rec; kbuf = message_key_pid(sys_getpid()); tdb_chainlock(tdb, kbuf); dbuf = tdb_fetch(tdb, kbuf); if (dbuf.dptr == NULL || dbuf.dsize == 0) goto failed; memcpy(&rec, dbuf.dptr, sizeof(rec)); if (rec.msg_version != MESSAGE_VERSION) { DEBUG(0,("message version %d received (expected %d)\n", rec.msg_version, MESSAGE_VERSION)); goto failed; } if (rec.len > 0) { (*buf) = (void *)malloc(rec.len); if (!(*buf)) goto failed; memcpy(*buf, dbuf.dptr+sizeof(rec), rec.len); } else { *buf = NULL; } *len = rec.len; *msg_type = rec.msg_type; *src = rec.src; if (dbuf.dsize - (sizeof(rec)+rec.len) > 0) memmove(dbuf.dptr, dbuf.dptr+sizeof(rec)+rec.len, dbuf.dsize - (sizeof(rec)+rec.len)); dbuf.dsize -= sizeof(rec)+rec.len; if (dbuf.dsize == 0) tdb_delete(tdb, kbuf); else tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return True; failed: tdb_chainunlock(tdb, kbuf); return False; }
static BOOL message_notify(struct process_id procid) { pid_t pid = procid.pid; /* * Doing kill with a non-positive pid causes messages to be * sent to places we don't want. */ SMB_ASSERT(pid > 0); if (kill(pid, SIGUSR1) == -1) { if (errno == ESRCH) { DEBUG(2,("pid %d doesn't exist - deleting messages record\n", (int)pid)); tdb_delete(tdb, message_key_pid(procid)); } else { DEBUG(2,("message to process %d failed - %s\n", (int)pid, strerror(errno))); } return False; } return True; }
BOOL message_send_pid(pid_t pid, int msg_type, const void *buf, size_t len, BOOL duplicates_allowed) { TDB_DATA kbuf; TDB_DATA dbuf; struct message_rec rec; void *p; rec.msg_version = MESSAGE_VERSION; rec.msg_type = msg_type; rec.dest = pid; rec.src = sys_getpid(); rec.len = len; kbuf = message_key_pid(pid); /* lock the record for the destination */ tdb_chainlock(tdb, kbuf); dbuf = tdb_fetch(tdb, kbuf); if (!dbuf.dptr) { /* its a new record */ p = (void *)malloc(len + sizeof(rec)); if (!p) goto failed; memcpy(p, &rec, sizeof(rec)); if (len > 0) memcpy((void *)((char*)p+sizeof(rec)), buf, len); dbuf.dptr = p; dbuf.dsize = len + sizeof(rec); tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); SAFE_FREE(p); goto ok; } if (!duplicates_allowed) { char *ptr; struct message_rec prec; for(ptr = (char *)dbuf.dptr; ptr < dbuf.dptr + dbuf.dsize; ) { /* * First check if the message header matches, then, if it's a non-zero * sized message, check if the data matches. If so it's a duplicate and * we can discard it. JRA. */ if (!memcmp(ptr, &rec, sizeof(rec))) { if (!len || (len && !memcmp( ptr + sizeof(rec), buf, len))) { DEBUG(10,("message_send_pid: discarding duplicate message.\n")); SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return True; } } memcpy(&prec, ptr, sizeof(prec)); ptr += sizeof(rec) + prec.len; } } /* we're adding to an existing entry */ p = (void *)malloc(dbuf.dsize + len + sizeof(rec)); if (!p) goto failed; memcpy(p, dbuf.dptr, dbuf.dsize); memcpy((void *)((char*)p+dbuf.dsize), &rec, sizeof(rec)); if (len > 0) memcpy((void *)((char*)p+dbuf.dsize+sizeof(rec)), buf, len); SAFE_FREE(dbuf.dptr); dbuf.dptr = p; dbuf.dsize += len + sizeof(rec); tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); SAFE_FREE(dbuf.dptr); ok: tdb_chainunlock(tdb, kbuf); errno = 0; /* paranoia */ return message_notify(pid); failed: tdb_chainunlock(tdb, kbuf); errno = 0; /* paranoia */ return False; }
static BOOL message_send_pid_internal(struct process_id pid, int msg_type, const void *buf, size_t len, BOOL duplicates_allowed, unsigned int timeout) { TDB_DATA kbuf; TDB_DATA dbuf; TDB_DATA old_dbuf; struct message_rec rec; char *ptr; struct message_rec prec; /* NULL pointer means implicit length zero. */ if (!buf) { SMB_ASSERT(len == 0); } /* * Doing kill with a non-positive pid causes messages to be * sent to places we don't want. */ SMB_ASSERT(procid_to_pid(&pid) > 0); rec.msg_version = MESSAGE_VERSION; rec.msg_type = msg_type; rec.dest = pid; rec.src = procid_self(); rec.len = buf ? len : 0; kbuf = message_key_pid(pid); dbuf.dptr = (void *)SMB_MALLOC(len + sizeof(rec)); if (!dbuf.dptr) return False; memcpy(dbuf.dptr, &rec, sizeof(rec)); if (len > 0 && buf) memcpy((void *)((char*)dbuf.dptr+sizeof(rec)), buf, len); dbuf.dsize = len + sizeof(rec); if (duplicates_allowed) { /* If duplicates are allowed we can just append the message and return. */ /* lock the record for the destination */ if (timeout) { if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) { DEBUG(0,("message_send_pid_internal: failed to get chainlock with timeout %ul.\n", timeout)); return False; } } else { if (tdb_chainlock(tdb, kbuf) == -1) { DEBUG(0,("message_send_pid_internal: failed to get chainlock.\n")); return False; } } tdb_append(tdb, kbuf, dbuf); tdb_chainunlock(tdb, kbuf); SAFE_FREE(dbuf.dptr); errno = 0; /* paranoia */ return message_notify(pid); } /* lock the record for the destination */ if (timeout) { if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) { DEBUG(0,("message_send_pid_internal: failed to get chainlock with timeout %ul.\n", timeout)); return False; } } else { if (tdb_chainlock(tdb, kbuf) == -1) { DEBUG(0,("message_send_pid_internal: failed to get chainlock.\n")); return False; } } old_dbuf = tdb_fetch(tdb, kbuf); if (!old_dbuf.dptr) { /* its a new record */ tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); tdb_chainunlock(tdb, kbuf); SAFE_FREE(dbuf.dptr); errno = 0; /* paranoia */ return message_notify(pid); } /* Not a new record. Check for duplicates. */ for(ptr = (char *)old_dbuf.dptr; ptr < old_dbuf.dptr + old_dbuf.dsize; ) { /* * First check if the message header matches, then, if it's a non-zero * sized message, check if the data matches. If so it's a duplicate and * we can discard it. JRA. */ if (!memcmp(ptr, &rec, sizeof(rec))) { if (!len || (len && !memcmp( ptr + sizeof(rec), buf, len))) { tdb_chainunlock(tdb, kbuf); DEBUG(10,("message_send_pid_internal: discarding duplicate message.\n")); SAFE_FREE(dbuf.dptr); SAFE_FREE(old_dbuf.dptr); return True; } } memcpy(&prec, ptr, sizeof(prec)); ptr += sizeof(rec) + prec.len; } /* we're adding to an existing entry */ tdb_append(tdb, kbuf, dbuf); tdb_chainunlock(tdb, kbuf); SAFE_FREE(old_dbuf.dptr); SAFE_FREE(dbuf.dptr); errno = 0; /* paranoia */ return message_notify(pid); }