Пример #1
0
    static void *queue (void *ctx)
    {
        int rc;

        void* be = zmq_socket(ctx, ZMQ_XREQ);
        assert (be);
        rc = zmq_bind(be, transport_be);
        assert (rc == 0);

        void* fe = zmq_socket(ctx, ZMQ_XREP);
        assert (fe);
        rc = zmq_bind(fe, transport_fe);
        assert (rc == 0);
        
        zmq_pollitem_t items[2];

        items[0].socket = be;
        items[0].events = ZMQ_POLLIN;
        items[1].socket = fe;
        items[1].events = ZMQ_POLLIN;

        while (true)
        {
            items[0].revents = 0;
            items[1].revents = 0;
            int rc = zmq_poll(items, 2, 5000);
            if (rc < 0)
            {
                break;
            }
            if (rc > 0)
            {
                if (items[0].revents == ZMQ_POLLIN)
                {
                    copy_msg(items[0].socket, items[1].socket);
                }
                if (items[1].revents == ZMQ_POLLIN)
                {
                    copy_msg (items[1].socket, items[0].socket);
                }
            }
        }

        zmq_close(fe);
        zmq_close(be);

        return NULL;
    }
Пример #2
0
/** dump lruhash msg cache */
static int
dump_msg_lruhash(SSL* ssl, struct worker* worker, struct lruhash* h)
{
	struct lruhash_entry* e;
	struct query_info* k;
	struct reply_info* d;

	/* lruhash already locked by caller */
	/* walk in order of lru; best first */
	for(e=h->lru_start; e; e = e->lru_next) {
		regional_free_all(worker->scratchpad);
		lock_rw_rdlock(&e->lock);
		/* make copy of rrset in worker buffer */
		if(!copy_msg(worker->scratchpad, e, &k, &d)) {
			lock_rw_unlock(&e->lock);
			return 0;
		}
		lock_rw_unlock(&e->lock);
		/* release lock so we can lookup the rrset references 
		 * in the rrset cache */
		if(!dump_msg(ssl, k, d, *worker->env.now)) {
			return 0;
		}
	}
	return 1;
}
Пример #3
0
static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
			 const unsigned char *new_sha1, const char *msg)
{
	int logfd, written, oflags = O_APPEND | O_WRONLY;
	unsigned maxlen, len;
	int msglen;
	char *log_file, *logrec;
	const char *committer;

	if (log_all_ref_updates < 0)
		log_all_ref_updates = !is_bare_repository();

	log_file = git_path("logs/%s", ref_name);

	if (log_all_ref_updates &&
	    (!prefixcmp(ref_name, "refs/heads/") ||
	     !prefixcmp(ref_name, "refs/remotes/") ||
	     !strcmp(ref_name, "HEAD"))) {
		if (safe_create_leading_directories(log_file) < 0)
			return error("unable to create directory for %s",
				     log_file);
		oflags |= O_CREAT;
	}

	logfd = open(log_file, oflags, 0666);
	if (logfd < 0) {
		if (!(oflags & O_CREAT) && errno == ENOENT)
			return 0;

		if ((oflags & O_CREAT) && errno == EISDIR) {
			if (remove_empty_directories(log_file)) {
				return error("There are still logs under '%s'",
					     log_file);
			}
			logfd = open(log_file, oflags, 0666);
		}

		if (logfd < 0)
			return error("Unable to append to %s: %s",
				     log_file, strerror(errno));
	}

	adjust_shared_perm(log_file);

	msglen = msg ? strlen(msg) : 0;
	committer = git_committer_info(0);
	maxlen = strlen(committer) + msglen + 100;
	logrec = xmalloc(maxlen);
	len = sprintf(logrec, "%s %s %s\n",
		      sha1_to_hex(old_sha1),
		      sha1_to_hex(new_sha1),
		      committer);
	if (msglen)
		len += copy_msg(logrec + len - 1, msg) - 1;
	written = len <= maxlen ? write_in_full(logfd, logrec, len) : -1;
	free(logrec);
	if (close(logfd) != 0 || written != len)
		return error("Unable to append to %s", log_file);
	return 0;
}
Пример #4
0
static int
msgs_flags_set( sync_vars_t *svars, int t )
{
	message_t *tmsg;
	copy_vars_t *cv;

	if (!(svars->state[t] & ST_SENT_FLAGS) || svars->flags_done[t] < svars->flags_total[t])
		return 0;

	if ((svars->chan->ops[t] & OP_EXPUNGE) &&
	    (svars->ctx[t]->conf->trash || (svars->ctx[1-t]->conf->trash && svars->ctx[1-t]->conf->trash_remote_new))) {
		debug( "trashing in %s\n", str_ms[t] );
		for (tmsg = svars->ctx[t]->msgs; tmsg; tmsg = tmsg->next)
			if (tmsg->flags & F_DELETED) {
				if (svars->ctx[t]->conf->trash) {
					if (!svars->ctx[t]->conf->trash_only_new || !tmsg->srec || tmsg->srec->uid[1-t] < 0) {
						debug( "%s: trashing message %d\n", str_ms[t], tmsg->uid );
						svars->trash_total[t]++;
						stats( svars );
						sync_ref( svars );
						svars->drv[t]->trash_msg( svars->ctx[t], tmsg, msg_trashed, AUX );
						if (deref_check_cancel( svars ))
							return -1;
					} else
						debug( "%s: not trashing message %d - not new\n", str_ms[t], tmsg->uid );
				} else {
					if (!tmsg->srec || tmsg->srec->uid[1-t] < 0) {
						if (!svars->ctx[1-t]->conf->max_size || tmsg->size <= svars->ctx[1-t]->conf->max_size) {
							debug( "%s: remote trashing message %d\n", str_ms[t], tmsg->uid );
							svars->trash_total[t]++;
							stats( svars );
							cv = nfmalloc( sizeof(*cv) );
							cv->cb = msg_rtrashed;
							cv->aux = INV_AUX;
							cv->srec = 0;
							cv->msg = tmsg;
							if (copy_msg( cv ))
								return -1;
						} else
							debug( "%s: not remote trashing message %d - too big\n", str_ms[t], tmsg->uid );
					} else
						debug( "%s: not remote trashing message %d - not new\n", str_ms[t], tmsg->uid );
				}
			}
	}
	svars->state[t] |= ST_SENT_TRASH;
	sync_close( svars, t );
	return 0;
}
Пример #5
0
static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
			 const unsigned char *new_sha1, const char *msg)
{
	int logfd, result, written, oflags = O_APPEND | O_WRONLY;
	unsigned maxlen, len;
	int msglen;
	char log_file[PATH_MAX];
	char *logrec;
	const char *committer;

	if (log_all_ref_updates < 0)
		log_all_ref_updates = !is_bare_repository();

	result = log_ref_setup(ref_name, log_file, sizeof(log_file));
	if (result)
		return result;

	logfd = open(log_file, oflags);
	if (logfd < 0)
		return 0;
	msglen = msg ? strlen(msg) : 0;
	committer = git_committer_info(0);
	maxlen = strlen(committer) + msglen + 100;
	logrec = xmalloc(maxlen);
	len = sprintf(logrec, "%s %s %s\n",
		      sha1_to_hex(old_sha1),
		      sha1_to_hex(new_sha1),
		      committer);
	if (msglen)
		len += copy_msg(logrec + len - 1, msg) - 1;
	written = len <= maxlen ? write_in_full(logfd, logrec, len) : -1;
	free(logrec);
	if (close(logfd) != 0 || written != len)
		return error("Unable to append to %s", log_file);
	return 0;
}
Пример #6
0
static void
box_loaded( int sts, void *aux )
{
	DECL_SVARS;
	sync_rec_t *srec;
	sync_rec_map_t *srecmap;
	message_t *tmsg;
	copy_vars_t *cv;
	flag_vars_t *fv;
	int uid, minwuid, *mexcs, nmexcs, rmexcs, no[2], del[2], todel, t1, t2;
	int sflags, nflags, aflags, dflags, nex;
	unsigned hashsz, idx;
	char fbuf[16]; /* enlarge when support for keywords is added */

	if (check_ret( sts, aux ))
		return;
	INIT_SVARS(aux);
	svars->state[t] |= ST_LOADED;
	info( "%s: %d messages, %d recent\n", str_ms[t], svars->ctx[t]->count, svars->ctx[t]->recent );

	if (svars->state[t] & S_FIND) {
		svars->state[t] &= ~S_FIND;
		debug( "matching previously copied messages on %s\n", str_ms[t] );
		match_tuids( svars, t );
	}

	debug( "matching messages on %s against sync records\n", str_ms[t] );
	hashsz = bucketsForSize( svars->nsrecs * 3 );
	srecmap = nfcalloc( hashsz * sizeof(*srecmap) );
	for (srec = svars->srecs; srec; srec = srec->next) {
		if (srec->status & S_DEAD)
			continue;
		uid = srec->uid[t];
		idx = (unsigned)((unsigned)uid * 1103515245U) % hashsz;
		while (srecmap[idx].uid)
			if (++idx == hashsz)
				idx = 0;
		srecmap[idx].uid = uid;
		srecmap[idx].srec = srec;
	}
	for (tmsg = svars->ctx[t]->msgs; tmsg; tmsg = tmsg->next) {
		if (tmsg->srec) /* found by TUID */
			continue;
		uid = tmsg->uid;
		if (DFlags & DEBUG) {
			make_flags( tmsg->flags, fbuf );
			printf( svars->ctx[t]->opts & OPEN_SIZE ? "  message %5d, %-4s, %6lu: " : "  message %5d, %-4s: ", uid, fbuf, tmsg->size );
		}
		idx = (unsigned)((unsigned)uid * 1103515245U) % hashsz;
		while (srecmap[idx].uid) {
			if (srecmap[idx].uid == uid) {
				srec = srecmap[idx].srec;
				goto found;
			}
			if (++idx == hashsz)
				idx = 0;
		}
		tmsg->srec = 0;
		debug( "new\n" );
		continue;
	  found:
		tmsg->srec = srec;
		srec->msg[t] = tmsg;
		debug( "pairs %5d\n", srec->uid[1-t] );
	}
	free( srecmap );

	if ((t == S) && svars->smaxxuid) {
		debug( "preparing master selection - max expired slave uid is %d\n", svars->smaxxuid );
		mexcs = 0;
		nmexcs = rmexcs = 0;
		minwuid = INT_MAX;
		for (srec = svars->srecs; srec; srec = srec->next) {
			if (srec->status & S_DEAD)
				continue;
			if (srec->status & S_EXPIRED) {
				if (!srec->uid[S] || ((svars->ctx[S]->opts & OPEN_OLD) && !srec->msg[S])) {
					srec->status |= S_EXP_S;
					continue;
				}
			} else {
				if (svars->smaxxuid >= srec->uid[S])
					continue;
			}
			if (minwuid > srec->uid[M])
				minwuid = srec->uid[M];
		}
		debug( "  min non-orphaned master uid is %d\n", minwuid );
		for (srec = svars->srecs; srec; srec = srec->next) {
			if (srec->status & S_DEAD)
				continue;
			if (srec->status & S_EXP_S) {
				if (minwuid > srec->uid[M] && svars->maxuid[M] >= srec->uid[M]) {
					debug( "  -> killing (%d,%d)\n", srec->uid[M], srec->uid[S] );
					srec->status = S_DEAD;
					Fprintf( svars->jfp, "- %d %d\n", srec->uid[M], srec->uid[S] );
				} else if (srec->uid[S]) {
					debug( "  -> orphaning (%d,[%d])\n", srec->uid[M], srec->uid[S] );
					Fprintf( svars->jfp, "> %d %d 0\n", srec->uid[M], srec->uid[S] );
					srec->uid[S] = 0;
				}
			} else if (minwuid > srec->uid[M]) {
				if (srec->uid[S] < 0) {
					if (svars->maxuid[M] >= srec->uid[M]) {
						debug( "  -> killing (%d,%d)\n", srec->uid[M], srec->uid[S] );
						srec->status = S_DEAD;
						Fprintf( svars->jfp, "- %d %d\n", srec->uid[M], srec->uid[S] );
					}
				} else if (srec->uid[M] > 0 && srec->uid[S] && (svars->ctx[M]->opts & OPEN_OLD) &&
				           (!(svars->ctx[M]->opts & OPEN_NEW) || svars->maxuid[M] >= srec->uid[M])) {
					if (nmexcs == rmexcs) {
						rmexcs = rmexcs * 2 + 100;
						mexcs = nfrealloc( mexcs, rmexcs * sizeof(int) );
					}
					mexcs[nmexcs++] = srec->uid[M];
				}
			}
		}
		debugn( "  exception list is:" );
		for (t = 0; t < nmexcs; t++)
			debugn( " %d", mexcs[t] );
		debug( "\n" );
		load_box( svars, M, minwuid, mexcs, nmexcs );
		return;
	}

	if (!(svars->state[1-t] & ST_LOADED))
		return;

	if (svars->uidval[M] < 0 || svars->uidval[S] < 0) {
		svars->uidval[M] = svars->ctx[M]->uidvalidity;
		svars->uidval[S] = svars->ctx[S]->uidvalidity;
		Fprintf( svars->jfp, "| %d %d\n", svars->uidval[M], svars->uidval[S] );
	}

	info( "Synchronizing...\n" );

	debug( "synchronizing new entries\n" );
	svars->osrecadd = svars->srecadd;
	for (t = 0; t < 2; t++) {
		Fprintf( svars->jfp, "%c %d\n", "{}"[t], svars->ctx[t]->uidnext );
		for (tmsg = svars->ctx[1-t]->msgs; tmsg; tmsg = tmsg->next)
			if (tmsg->srec ? tmsg->srec->uid[t] < 0 && (tmsg->srec->uid[t] == -1 ? (svars->chan->ops[t] & OP_RENEW) : (svars->chan->ops[t] & OP_NEW)) : (svars->chan->ops[t] & OP_NEW)) {
				debug( "new message %d on %s\n", tmsg->uid, str_ms[1-t] );
				if ((svars->chan->ops[t] & OP_EXPUNGE) && (tmsg->flags & F_DELETED))
					debug( "  -> not %sing - would be expunged anyway\n", str_hl[t] );
				else {
					if (tmsg->srec) {
						srec = tmsg->srec;
						srec->status |= S_DONE;
						debug( "  -> pair(%d,%d) exists\n", srec->uid[M], srec->uid[S] );
					} else {
						srec = nfmalloc( sizeof(*srec) );
						srec->next = 0;
						*svars->srecadd = srec;
						svars->srecadd = &srec->next;
						svars->nsrecs++;
						srec->status = S_DONE;
						srec->flags = 0;
						srec->tuid[0] = 0;
						srec->uid[1-t] = tmsg->uid;
						srec->uid[t] = -2;
						Fprintf( svars->jfp, "+ %d %d\n", srec->uid[M], srec->uid[S] );
						debug( "  -> pair(%d,%d) created\n", srec->uid[M], srec->uid[S] );
					}
					if ((tmsg->flags & F_FLAGGED) || !svars->chan->stores[t]->max_size || tmsg->size <= svars->chan->stores[t]->max_size) {
						if (tmsg->flags) {
							srec->flags = tmsg->flags;
							Fprintf( svars->jfp, "* %d %d %u\n", srec->uid[M], srec->uid[S], srec->flags );
							debug( "  -> updated flags to %u\n", tmsg->flags );
						}
						for (t1 = 0; t1 < TUIDL; t1++) {
							t2 = arc4_getbyte() & 0x3f;
							srec->tuid[t1] = t2 < 26 ? t2 + 'A' : t2 < 52 ? t2 + 'a' - 26 : t2 < 62 ? t2 + '0' - 52 : t2 == 62 ? '+' : '/';
						}
						svars->new_total[t]++;
						stats( svars );
						cv = nfmalloc( sizeof(*cv) );
						cv->cb = msg_copied;
						cv->aux = AUX;
						cv->srec = srec;
						cv->msg = tmsg;
						Fprintf( svars->jfp, "# %d %d %." stringify(TUIDL) "s\n", srec->uid[M], srec->uid[S], srec->tuid );
						if (FSyncLevel >= FSYNC_THOROUGH)
							fdatasync( fileno( svars->jfp ) );
						debug( "  -> %sing message, TUID %." stringify(TUIDL) "s\n", str_hl[t], srec->tuid );
						if (copy_msg( cv ))
							return;
					} else {
						if (tmsg->srec) {
							debug( "  -> not %sing - still too big\n", str_hl[t] );
							continue;
						}
						debug( "  -> not %sing - too big\n", str_hl[t] );
						msg_copied_p2( svars, srec, t, tmsg, -1 );
					}
				}
			}
		svars->state[t] |= ST_SENT_NEW;
		msgs_copied( svars, t );
	}

	debug( "synchronizing old entries\n" );
	for (srec = svars->srecs; srec != *svars->osrecadd; srec = srec->next) {
		if (srec->status & (S_DEAD|S_DONE))
			continue;
		debug( "pair (%d,%d)\n", srec->uid[M], srec->uid[S] );
		no[M] = !srec->msg[M] && (svars->ctx[M]->opts & OPEN_OLD);
		no[S] = !srec->msg[S] && (svars->ctx[S]->opts & OPEN_OLD);
		if (no[M] && no[S]) {
			debug( "  vanished\n" );
			/* d.1) d.5) d.6) d.10) d.11) */
			srec->status = S_DEAD;
			Fprintf( svars->jfp, "- %d %d\n", srec->uid[M], srec->uid[S] );
		} else {
			del[M] = no[M] && (srec->uid[M] > 0);
			del[S] = no[S] && (srec->uid[S] > 0);

			for (t = 0; t < 2; t++) {
				srec->aflags[t] = srec->dflags[t] = 0;
				if (srec->msg[t] && (srec->msg[t]->flags & F_DELETED))
					srec->status |= S_DEL(t);
				/* excludes (push) c.3) d.2) d.3) d.4) / (pull) b.3) d.7) d.8) d.9) */
				if (!srec->uid[t]) {
					/* b.1) / c.1) */
					debug( "  no more %s\n", str_ms[t] );
				} else if (del[1-t]) {
					/* c.4) d.9) / b.4) d.4) */
					if (srec->msg[t] && (srec->msg[t]->status & M_FLAGS) && srec->msg[t]->flags != srec->flags)
						info( "Info: conflicting changes in (%d,%d)\n", srec->uid[M], srec->uid[S] );
					if (svars->chan->ops[t] & OP_DELETE) {
						debug( "  %sing delete\n", str_hl[t] );
						svars->flags_total[t]++;
						stats( svars );
						fv = nfmalloc( sizeof(*fv) );
						fv->aux = AUX;
						fv->srec = srec;
						DRIVER_CALL(set_flags( svars->ctx[t], srec->msg[t], srec->uid[t], F_DELETED, 0, flags_set_del, fv ));
					} else
						debug( "  not %sing delete\n", str_hl[t] );
				} else if (!srec->msg[1-t])
					/* c.1) c.2) d.7) d.8) / b.1) b.2) d.2) d.3) */
					;
				else if (srec->uid[t] < 0)
					/* b.2) / c.2) */
					; /* handled as new messages (sort of) */
				else if (!del[t]) {
					/* a) & b.3) / c.3) */
					if (svars->chan->ops[t] & OP_FLAGS) {
						sflags = srec->msg[1-t]->flags;
						if ((srec->status & (S_EXPIRE|S_EXPIRED)) && !t)
							sflags &= ~F_DELETED;
						srec->aflags[t] = sflags & ~srec->flags;
						srec->dflags[t] = ~sflags & srec->flags;
						if (DFlags & DEBUG) {
							char afbuf[16], dfbuf[16]; /* enlarge when support for keywords is added */
							make_flags( srec->aflags[t], afbuf );
							make_flags( srec->dflags[t], dfbuf );
							debug( "  %sing flags: +%s -%s\n", str_hl[t], afbuf, dfbuf );
						}
					} else
						debug( "  not %sing flags\n", str_hl[t] );
				} /* else b.4) / c.4) */
			}
		}
	}

	if ((svars->chan->ops[S] & (OP_NEW|OP_RENEW|OP_FLAGS)) && svars->chan->max_messages) {
		/* Flagged and not yet synced messages older than the first not
		 * expired message are not counted. */
		todel = svars->ctx[S]->count + svars->new_total[S] - svars->chan->max_messages;
		debug( "scheduling %d excess messages for expiration\n", todel );
		for (tmsg = svars->ctx[S]->msgs; tmsg && todel > 0; tmsg = tmsg->next)
			if (!(tmsg->status & M_DEAD) && (srec = tmsg->srec) &&
			    ((tmsg->flags | srec->aflags[S]) & ~srec->dflags[S] & F_DELETED) &&
			    !(srec->status & (S_EXPIRE|S_EXPIRED)))
				todel--;
		debug( "%d non-deleted excess messages\n", todel );
		for (tmsg = svars->ctx[S]->msgs; tmsg; tmsg = tmsg->next) {
			if (tmsg->status & M_DEAD)
				continue;
			if (!(srec = tmsg->srec) || srec->uid[M] <= 0)
				todel--;
			else {
				nflags = (tmsg->flags | srec->aflags[S]) & ~srec->dflags[S];
				if (!(nflags & F_DELETED) || (srec->status & (S_EXPIRE|S_EXPIRED))) {
					if (nflags & F_FLAGGED)
						todel--;
					else if ((!(tmsg->status & M_RECENT) || (tmsg->flags & F_SEEN)) &&
					         (todel > 0 ||
					          ((srec->status & (S_EXPIRE|S_EXPIRED)) == (S_EXPIRE|S_EXPIRED)) ||
					          ((srec->status & (S_EXPIRE|S_EXPIRED)) && (tmsg->flags & F_DELETED)))) {
						srec->status |= S_NEXPIRE;
						debug( "  pair(%d,%d)\n", srec->uid[M], srec->uid[S] );
						todel--;
					}
				}
			}
		}
		debug( "%d excess messages remain\n", todel );
		for (srec = svars->srecs; srec; srec = srec->next) {
			if ((srec->status & (S_DEAD|S_DONE)) || !srec->msg[S])
				continue;
			nex = (srec->status / S_NEXPIRE) & 1;
			if (nex != ((srec->status / S_EXPIRED) & 1)) {
				if (nex != ((srec->status / S_EXPIRE) & 1)) {
					Fprintf( svars->jfp, "~ %d %d %d\n", srec->uid[M], srec->uid[S], nex );
					debug( "  pair(%d,%d): %d (pre)\n", srec->uid[M], srec->uid[S], nex );
					srec->status = (srec->status & ~S_EXPIRE) | (nex * S_EXPIRE);
				} else
					debug( "  pair(%d,%d): %d (pending)\n", srec->uid[M], srec->uid[S], nex );
			}
		}
	}

	debug( "synchronizing flags\n" );
	for (srec = svars->srecs; srec != *svars->osrecadd; srec = srec->next) {
		if (srec->status & (S_DEAD|S_DONE))
			continue;
		for (t = 0; t < 2; t++) {
			aflags = srec->aflags[t];
			dflags = srec->dflags[t];
			if ((t == S) && ((mvBit(srec->status, S_EXPIRE, S_EXPIRED) ^ srec->status) & S_EXPIRED)) {
				if (srec->status & S_NEXPIRE)
					aflags |= F_DELETED;
				else
					dflags |= F_DELETED;
			}
			if ((svars->chan->ops[t] & OP_EXPUNGE) && (((srec->msg[t] ? srec->msg[t]->flags : 0) | aflags) & ~dflags & F_DELETED) &&
			    (!svars->ctx[t]->conf->trash || svars->ctx[t]->conf->trash_only_new))
			{
				srec->aflags[t] &= F_DELETED;
				aflags &= F_DELETED;
				srec->dflags[t] = dflags = 0;
			}
			if (srec->msg[t] && (srec->msg[t]->status & M_FLAGS)) {
				aflags &= ~srec->msg[t]->flags;
				dflags &= srec->msg[t]->flags;
			}
			if (aflags | dflags) {
				svars->flags_total[t]++;
				stats( svars );
				fv = nfmalloc( sizeof(*fv) );
				fv->aux = AUX;
				fv->srec = srec;
				fv->aflags = aflags;
				fv->dflags = dflags;
				DRIVER_CALL(set_flags( svars->ctx[t], srec->msg[t], srec->uid[t], aflags, dflags, flags_set_sync, fv ));
			} else
				flags_set_sync_p2( svars, srec, t );
		}
	}
	for (t = 0; t < 2; t++) {
		svars->drv[t]->commit( svars->ctx[t] );
		svars->state[t] |= ST_SENT_FLAGS;
		if (msgs_flags_set( svars, t ))
			return;
	}
}
Пример #7
0
int8_t ipc_handle_syscall(ProcessId_t o, uint8_t call_type, message_t* msg) {
	Process_t* src = process_manager_current_process;
	Process_t* dst = NULL;

	if (src->pid == o) {
		return IPC_DEADLOCK;
	}

	if (call_type == IPC_RECEIVE_ASYNC && src->ipc.sender.head == NULL) {
		return IPC_NOTHING_RECEIVED;
	}

	if (o == PROCESS_STDIN) {
		o = src->stdin;
	} else if (o == PROCESS_STDOUT) {
		o = src->stdout;
	}

	if (o == PROCESS_INVALID_ID) {
		return IPC_OTHER_NOT_FOUND;
	} else if ((call_type & IPC_RECEIVE) != IPC_RECEIVE || o != PROCESS_ANY) { /* allow ANY only on receive */
		dst = process_manager_get_process_byid(o);

		if (dst == NULL) {
			return IPC_OTHER_NOT_FOUND;
		}
	}

	src->ipc.other = o;
	src->ipc.msg = mmu_get_physical_address(src->page_table, msg);

	switch (call_type) {
		case IPC_SEND:
		case IPC_SENDREC: /* SEND is falling through here */
			_disable_interrupts();
			if (dst->state == PROCESS_ZOMBIE) {
				_enable_interrupts();
				return IPC_DEAD;
			}
			if (dst->state == PROCESS_BLOCKED && dst->ipc.call_type == IPC_RECEIVE && (dst->ipc.other == src->pid || dst->ipc.other == PROCESS_ANY)) {
				logger_debug("IPC: SEND-copying src=%i:%s dst=%i:%s", src->pid, src->name, o, (dst != NULL) ? dst->name : "<ANY>");
				if (dst->ipc.other == PROCESS_ANY) {
					dst->ipc.other = src->pid;
				}
				_enable_interrupts();
				/* both process are now BLOCKED */
				copy_msg(src, dst);
				dst->ipc.call_type = IPC_NOOP;
				process_manager_set_process_ready(dst);
			} else {
				logger_debug("IPC: SEND-blocked src=%i:%s dst=%i:%s", src->pid, src->name, o, (dst != NULL) ? dst->name : "<ANY>");
				if (dst->ipc.other == src->pid && dst->ipc.call_type & IPC_SEND) {
					return IPC_DEADLOCK;
				}

				src->ipc.call_type = IPC_SEND;

				/* place msg for later delivery into the IPC queue of the destination */
				linked_list_add(&dst->ipc.sender, src); /* TODO: check for too less memory */

				/* pause process */
				process_manager_block_current_process();
				process_manager_run_process(dst);
				_enable_interrupts();
			}

			/* msg delivered, falling through receive except for send only */
			if (call_type == IPC_SEND) {
				break;
			}

		case IPC_RECEIVE: /* SENDREC and SEND are falling through here */
		case IPC_RECEIVE_ASYNC:
			_disable_interrupts();
			if (dst != NULL) {
				if (dst->state == PROCESS_ZOMBIE) {
					_enable_interrupts();
					return IPC_DEAD;
				}
			} else {
				/* receiving from ANY, maybe someone is already sending to this process */
				linked_list_node_t* node;
				do {
					node = linked_list_pop_head(&src->ipc.sender);
					if (node != NULL) {
						dst = node->value;
						free(node);
					}
				} while (dst != NULL && dst->state == PROCESS_ZOMBIE);
			}
			if (dst != NULL && dst->state == PROCESS_BLOCKED && (dst->ipc.call_type & IPC_SEND) == IPC_SEND && dst->ipc.other == src->pid) {
				logger_debug("IPC: RECIEVED-copying src=%i:%s dst=%i:%s", src->pid, src->name, o, (dst != NULL) ? dst->name : "<ANY>");
				/* both process are now BLOCKED */
				_enable_interrupts();

				/* remove sender out of sender list */
				if (o != PROCESS_ANY) {
					linked_list_node_t* node = src->ipc.sender.head;
					while (node != NULL) {
						Process_t* p = node->value;
						if (p->pid == o) {
							linked_list_remove(&src->ipc.sender, node);
							break;
						}

						node = node->next;
					}
				}

				copy_msg(dst, src);
				dst->ipc.call_type = IPC_NOOP;
				process_manager_set_process_ready(dst);
			} else {
				if (dst != NULL && dst->ipc.other == src->pid && dst->ipc.call_type == IPC_RECEIVE) {
					return IPC_DEADLOCK;
				}

				src->ipc.call_type = IPC_RECEIVE;

				/* wait for msg delivery */
				process_manager_block_current_process();
				process_manager_run_process(dst);
				if (dst->state == PROCESS_ZOMBIE) {
					_enable_interrupts();
					return IPC_DEAD;
				}
				logger_debug("IPC: RECIEVED-blocked src=%i:%s dst=%i:%s", src->pid, src->name, o, (dst != NULL) ? dst->name : "<ANY>");
				_enable_interrupts();

				/* msg received */
			}
			break;
	}

	return IPC_OK;
}