예제 #1
0
int cell_main(int argc, char **argv) {
    struct disk_message *msg;
    int status;
    unsigned long disk_size, sector;

    msg = malloc(DISK_MESSAGE_SIZE);

    // Query the disk to get its size so we know how to do our
    // reads.
    msg->type = DISK_MSG_GET_SIZE;
    if ((status = channel_send(to_disk1, msg))) {
        printf("[cell1] Could not send disk message: %d\n", status);
        return 1;
    } else
        printf("[cell1] sent size request\n");

    if ((status = channel_recv(from_disk1, msg))) {
        printf("[cell1] Could not get disk reply: %d\n", status);
        return 1;
    }

    if (msg->type != DISK_MSG_GET_SIZE) {
        printf("[cell1] Something bad happened; got non-size reply (type %d)\n",
               msg->type);
        return 1;
    }

    disk_size = msg->body.device_size;
    sector = 0;

    // Loop forever, reading sectors from disk one at a time and
    // sending them to the neighboring cell.  When we reach the end of
    // the disk, start over.
    while (1) {
        msg->type = DISK_MSG_IO_REQUEST;
        msg->body.io_request.type = DISK_IO_REQUEST_READ;
        msg->body.io_request.num_sectors = 1;
        msg->body.io_request.start_sector = sector;

        if ((status = channel_send(to_disk1, msg))) {
            printf("[cell1] Could not send disk read for sector %ld: %d\n", sector, status);
            return 1;
        }

        if ((status = channel_recv(from_disk1, msg))) {
            printf("[cell1] Could not receive disk read result: %d\n", status);
            return 1;
        }

        if ((status = channel_send(middle, msg))) {
            printf("[cell1] Could not send disk data to cell 2: %d\n", status);
            return 1;
        }

        sector = (sector + 1) % (disk_size / SECTOR_SIZE);
    }

    return 0;
}
예제 #2
0
int disk_client_write(struct disk_client *c, size_t num_sectors,
		      unsigned long start_sector, unsigned char *buf,
		      write_callback_t cb, error_callback_t err)
{
    int slot_num, status;
    struct disk_client_slot *slot;

    if (channel_can_send(c->req_chan) && next_free_slot(c) >= 0) {
	slot_num = alloc_slot(c);
	slot = get_slot(c, slot_num);

	slot->cb.write = cb;
	slot->err = err;
	slot->msg.type = DISK_WRITE;
	slot->msg.start_sector = start_sector;
	slot->msg.num_sectors = num_sectors;
	slot->msg.handle = slot_num;

	memcpy(slot->msg.payload, buf, num_sectors * SECTOR_SIZE);

	status = channel_send(c->req_chan, &(slot->msg));
	if (status == CHANNEL_OK) {
	    return DISK_OK;
	} else {
	    printf("Error in channel send (write): %d\n", status);
	    return DISK_ERROR;
	}
    }

    return DISK_BUSY;
}
예제 #3
0
int cell_main(int argc, char ** argv) {
    unsigned char msg;

#if defined(SEL4_DEBUG_KERNEL)
    SET_MUSLC_SYSCALL_TABLE;
    platsupport_serial_setup_bootinfo_failsafe();
#endif

    // Read characater data from the input memory region, filter it (remove
    // vowels), and then emit it to the output memory region.
    //
    // This implementation uses a sequence number paired with each character to
    // facilitate data loss detection when scheduling interferes with memory
    // read/write operations in adjacent cells.
    while (1) {
        channel_recv(chan1, &msg);

        if (msg > 0) {
            if (msg == 'a' ||
                msg == 'e' ||
                msg == 'i' ||
                msg == 'o' ||
                msg == 'u')
                    msg = '*';

            channel_send(chan2, &msg);
        }
    }

    return 0;
}
예제 #4
0
int disk_client_get_size(struct disk_client *c, size_callback_t cb, error_callback_t err)
{
    int slot_num, status;
    struct disk_client_slot *slot;

    if (channel_can_send(c->req_chan) && next_free_slot(c) >= 0) {
	slot_num = alloc_slot(c);
	slot = get_slot(c, slot_num);

	slot->cb.size = cb;
	slot->err = err;
	slot->msg.type = DISK_SIZE;
	slot->msg.handle = slot_num;

	status = channel_send(c->req_chan, &(slot->msg));
	if (status == CHANNEL_OK) {
	    return DISK_OK;
	} else {
	    printf("Error in channel send (size): %d\n", status);
	    return DISK_ERROR;
	}
    }

    return DISK_BUSY;
}
예제 #5
0
int disk_client_read(struct disk_client *c, size_t num_sectors,
		     unsigned long start_sector,
		     read_callback_t cb, error_callback_t err)
{
    int slot_num, status;
    struct disk_client_slot *slot;

    if (channel_can_send(c->req_chan) && next_free_slot(c) >= 0) {
	slot_num = alloc_slot(c);
	slot = get_slot(c, slot_num);

	slot->cb.read = cb;
	slot->err = err;
	slot->msg.type = DISK_READ;
	slot->msg.start_sector = start_sector;
	slot->msg.num_sectors = num_sectors;
	slot->msg.handle = slot_num;

	status =channel_send(c->req_chan, &(slot->msg));
	if (status == CHANNEL_OK) {
	    return DISK_OK;
	} else {
	    printf("Error in channel send (read): %d\n", status);
	    return DISK_ERROR;
	}
    }

    return DISK_BUSY;
}
예제 #6
0
파일: rpc.c 프로젝트: Hooman3/minix
/*===========================================================================*
 *				rpc_query				     *
 *===========================================================================*/
int rpc_query(void)
{
/* Send a HGFS RPC query over the backdoor channel. Return OK upon success, or
 * a negative error code otherwise; EAGAIN is returned if shared folders are
 * disabled. In general, we make the assumption that the sender (= VMware)
 * speaks the protocol correctly. Hence, the callers of this function do not
 * check for lengths.
 */
  int r, len, id, err;

  len = RPC_LEN;

  /* A more robust version of this call could reopen the channel and
   * retry the request upon low-level failure.
   */
  r = channel_send(&rpc_chan, rpc_buf, len);
  if (r < 0) return r;

  r = channel_recv(&rpc_chan, rpc_buf, sizeof(rpc_buf));
  if (r < 0) return r;
  if (r < 2 || (len > 2 && r < 10)) return EIO;

  RPC_RESET;

  if (RPC_NEXT8 != '1') return EAGAIN;
  if (RPC_NEXT8 != ' ') return EAGAIN;

  if (len <= 2) return OK;

  id = RPC_NEXT32;
  err = RPC_NEXT32;

  return error_convert(err);
}
예제 #7
0
void
rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer,
		      uint32 length)
{
	uint8 magic[4] = "rDCI";
	STREAM s;

#ifdef WITH_SCARD
	scard_lock(SCARD_LOCK_RDPDR);
#endif
	s = channel_init(rdpdr_channel, 20 + length);
	out_uint8a(s, magic, 4);
	out_uint32_le(s, device);
	out_uint32_le(s, id);
	out_uint32_le(s, status);
	out_uint32_le(s, result);
	out_uint8p(s, buffer, length);
	s_mark_end(s);
	/* JIF */
#ifdef WITH_DEBUG_RDP5
	printf("--> rdpdr_send_completion\n");
	/* hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */
#endif
	channel_send(s, rdpdr_channel);
#ifdef WITH_SCARD
	scard_unlock(SCARD_LOCK_RDPDR);
#endif
}
예제 #8
0
파일: rdpdr.c 프로젝트: hoangduit/reactos
static void
rdpdr_send_available(RDPCLIENT * This)
{

	uint8 magic[4] = "rDAD";
	uint32 driverlen, printerlen, bloblen;
	int i;
	STREAM s;
	PRINTER *printerinfo;

	s = channel_init(This, This->rdpdr.channel, announcedata_size(This));
	out_uint8a(s, magic, 4);
	out_uint32_le(s, This->num_devices);

	for (i = 0; i < This->num_devices; i++)
	{
		out_uint32_le(s, This->rdpdr_device[i].device_type);
		out_uint32_le(s, i);	/* RDP Device ID */
		/* Is it possible to use share names longer than 8 chars?
		   /astrand */
		out_uint8p(s, This->rdpdr_device[i].name, 8);

		switch (This->rdpdr_device[i].device_type)
		{
			case DEVICE_TYPE_PRINTER:
				printerinfo = (PRINTER *) This->rdpdr_device[i].pdevice_data;

				driverlen = 2 * strlen(printerinfo->driver) + 2;
				printerlen = 2 * strlen(printerinfo->printer) + 2;
				bloblen = printerinfo->bloblen;

				out_uint32_le(s, 24 + driverlen + printerlen + bloblen);	/* length of extra info */
				out_uint32_le(s, printerinfo->default_printer ? 2 : 0);
				out_uint8s(s, 8);	/* unknown */
				out_uint32_le(s, driverlen);
				out_uint32_le(s, printerlen);
				out_uint32_le(s, bloblen);
				rdp_out_unistr(This, s, printerinfo->driver, driverlen - 2);
				rdp_out_unistr(This, s, printerinfo->printer, printerlen - 2);
				out_uint8a(s, printerinfo->blob, bloblen);

				if (printerinfo->blob)
					xfree(printerinfo->blob);	/* Blob is sent twice if reconnecting */
				break;
			default:
				out_uint32(s, 0);
		}
	}
#if 0
	out_uint32_le(s, 0x20);	/* Device type 0x20 - smart card */
	out_uint32_le(s, 0);
	out_uint8p(s, "SCARD", 5);
	out_uint8s(s, 3);
	out_uint32(s, 0);
#endif

	s_mark_end(s);
	channel_send(This, s, This->rdpdr.channel);
}
예제 #9
0
static void
rdpusb_send(STREAM s)
{
#ifdef RDPUSB_DEBUG
	Log(("RDPUSB send:\n"));
	hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
#endif

	channel_send(s, rdpusb_channel);
}
예제 #10
0
파일: rdpsnd.c 프로젝트: z0x010/rdesktop
void
rdpsnd_send(STREAM s)
{
#ifdef RDPSND_DEBUG
	printf("RDPSND send:\n");
	hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
#endif

	channel_send(s, rdpsnd_channel);
}
예제 #11
0
void finished_read(size_t num_sectors, unsigned long start_sector,
		   unsigned char *buf) {
    struct disk_msg msg;

    printf("Got read response; sending to cell2\n");

    msg.type = DISK_WRITE;
    msg.start_sector = start_sector;
    msg.num_sectors = num_sectors;

    memcpy(msg.payload, buf, num_sectors * SECTOR_SIZE);

    while (channel_send(forward, &msg) == CHANNEL_FULL) {}
}
예제 #12
0
파일: rdpdr.c 프로젝트: hoangduit/reactos
static void
rdpdr_send_connect(RDPCLIENT * This)
{
	uint8 magic[4] = "rDCC";
	STREAM s;

	s = channel_init(This, This->rdpdr.channel, 12);
	out_uint8a(s, magic, 4);
	out_uint16_le(s, 1);	/* unknown */
	out_uint16_le(s, 5);
	out_uint32_be(s, 0x815ed39d);	/* IP address (use 127.0.0.1) 0x815ed39d */
	s_mark_end(s);
	channel_send(This, s, This->rdpdr.channel);
}
예제 #13
0
파일: profiling.c 프로젝트: dmjio/ghc
static int write_block(FILE *p, blkif_sector_t sector, size_t amt)
{
  static uint64_t next_reqid = 1;
  blkif_response_t *rsp;
  blkif_request_t *req;
  int notify, work_to_do;
  uint64_t reqid;
  RING_IDX i;

  /* wait until we can write something */
  while(RING_FULL(&p->ring)) runtime_block(1);

  /* write out the request */
  i = p->ring.req_prod_pvt++;
  req = RING_GET_REQUEST(&p->ring, i);
  memset(req, 0, sizeof(blkif_request_t));
  req->operation         = BLKIF_OP_WRITE;
  req->nr_segments       = 1;
  req->handle            = p->disk_handle;
  req->id                = reqid = next_reqid++;
  req->sector_number     = sector;
  req->seg[0].gref       = p->block_grant;
  req->seg[0].first_sect = 0;
  req->seg[0].last_sect  = (amt - 1) / 512;
  wmb();
  RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&p->ring, notify);
  if(notify) channel_send(p->chan);

  /* wait for it to be satisfied */
  do {
    while(!RING_HAS_UNCONSUMED_RESPONSES(&p->ring))
      runtime_block(1);
    i = p->ring.rsp_cons++;
    rsp = RING_GET_RESPONSE(&p->ring, i);
  } while(rsp->id != reqid);

  /* was it successful? */
  if(rsp->status != BLKIF_RSP_OKAY) {
    printf("PROFILING: Block write failed!\n");
    return 0;
  }

  /* we do writes one at a time, synchronously, so work_to_do should always
     be false */
  RING_FINAL_CHECK_FOR_RESPONSES(&p->ring, work_to_do);
  assert(!work_to_do);

  return 1;
}
예제 #14
0
void * sendm(void * ptr)
{
    channel_set chset;
    int err, nb = 0;
    msg_t tmp;

    tmp.pid = getpid();
    sprintf(tmp.content," %ld @ %d !\n",pthread_self(),tmp.pid);

    chset.chan = chan_s;
    chset.events = CHANNEL_EVENT_WRITE|CHANNEL_EVENT_CLOSE;
    chset.revents = CHANNEL_EVENT_NOEVT;

    while(nb < MAX_MSG)
    {
        chset.revents = CHANNEL_EVENT_NOEVT;

        err = channel_select(&chset,1,CHANNEL_TIME_WAIT);

        if(err == -1)
        {
            perror("channel_select()");
        }
        else if(err == 0)
            continue;

        if(CHAN_WRITE_EVT(chset.revents))
        {
            err = channel_send(chan_s,&tmp);

            if(err == -1)
            {
                if(errno == EWOULDBLOCK)
                    continue;

                perror("sendm channel_send()");
                channel_close(chan_s);
                break;
            }
            nb++;
        }

        if(CHAN_CLOSE_EVT(chset.revents))
            break;
    }

    pthread_exit(NULL);
}
예제 #15
0
파일: cliprdr.c 프로젝트: z0x010/rdesktop
static void
cliprdr_send_packet(uint16 type, uint16 status, uint8 * data, uint32 length)
{
	STREAM s;

	DEBUG_CLIPBOARD(("CLIPRDR send: type=%d, status=%d, length=%d\n", type, status, length));

	s = channel_init(cliprdr_channel, length + 12);
	out_uint16_le(s, type);
	out_uint16_le(s, status);
	out_uint32_le(s, length);
	out_uint8p(s, data, length);
	out_uint32(s, 0);	/* pad? */
	s_mark_end(s);
	channel_send(s, cliprdr_channel);
}
예제 #16
0
파일: lspci.c 프로젝트: z0x010/rdesktop
/* Send data to channel */
static void
lspci_send(const char *output)
{
	STREAM s;
	size_t len;

	len = strlen(output);
	s = channel_init(lspci_channel, len);
	out_uint8p(s, output, len) s_mark_end(s);

#if 0
	printf("lspci send:\n");
	hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
#endif

	channel_send(s, lspci_channel);
}
예제 #17
0
파일: profiling.c 프로젝트: dmjio/ghc
static uint32_t xenstore_write(uint32_t type, uint32_t len, void *inbuf)
{
  static uint32_t req_id = 1;
  struct xsd_sockmsg m;
  void *buffer, *cur;
  uint32_t prod;

  /* build out the header and adjust the final length */
  m.type   = type;
  m.req_id = req_id++;
  m.tx_id  = 0;
  m.len    = len;
  len += sizeof(struct xsd_sockmsg);

  /* wait until we can send out the data all at once */
  while( (XENSTORE_RING_SIZE - (xsint->req_prod - xsint->req_cons)) < len )
    runtime_block(1);
  assert( (xsint->req_prod + len - xsint->req_cons) < XENSTORE_RING_SIZE);

  /* Combine the data into one block */
  cur = buffer = malloc(len);
  memcpy(buffer, &m, sizeof(struct xsd_sockmsg));
  memcpy((void*)((uintptr_t)buffer + sizeof(struct xsd_sockmsg)), inbuf, m.len);

  /* dump it out to the ring */
  prod = xsint->req_prod;
  while(len != 0) {
    uint32_t nextbit = min(len, XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
    memcpy(xsint->req + MASK_XENSTORE_IDX(prod), cur, nextbit);
    prod += nextbit;
    cur   = (void*)((uintptr_t)cur + nextbit);
    len  -= nextbit;
  }

  /* notify the other size */
  wmb();
  xsint->req_prod = prod;
  channel_send(system_start_info->store_evtchn);

  /* free our buffer and return the request id */
  free(buffer);
  return m.req_id;
}
예제 #18
0
int mwChannel_sendEncrypted(struct mwChannel *chan,
			    guint32 type, struct mwOpaque *data,
			    gboolean encrypt) {

  struct mwMsgChannelSend *msg;

  g_return_val_if_fail(chan != NULL, -1);

  msg = (struct mwMsgChannelSend *) mwMessage_new(mwMessage_CHANNEL_SEND);
  msg->head.channel = chan->id;
  msg->type = type;

  mwOpaque_clone(&msg->data, data);

  if(encrypt && chan->cipher) {
    msg->head.options = mwMessageOption_ENCRYPT;
    mwCipherInstance_encrypt(chan->cipher, &msg->data);
  }

  return channel_send(chan, msg);  
}
예제 #19
0
int32_t _send( struct session * self, char * buf, uint32_t nbytes )
{
    int32_t rc = 0;

    if ( self->status&SESSION_EXITING )
    {
        // 等待关闭的连接
        return -1;
    }

    // 判断session是否繁忙
    if ( !(self->status&SESSION_WRITING)
            && session_sendqueue_count(self) == 0 )
    {
        // 直接发送
        rc = channel_send( self, buf, nbytes );
        if ( rc == nbytes )
        {
            // 全部发送出去
            return rc;
        }

        // 为什么发送错误没有直接终止会话呢?
        // 该接口有可能在ioservice_t中调用, 直接终止会话后, 会引发后续对会话的操作崩溃
    }

    // 创建message, 添加到发送队列中
    struct message * message = message_create();
    if ( message == NULL )
    {
        return -2;
    }

    message_add_buffer( message, buf+rc, nbytes-rc );
    message_add_receiver( message, self->id );
    QUEUE_PUSH(sendqueue)(&self->sendqueue, &message);
    session_add_event( self, EV_WRITE );

    return rc;
}
예제 #20
0
파일: rdpdr.c 프로젝트: hoangduit/reactos
static void
rdpdr_send_clientcapabilty(RDPCLIENT * This)
{
	uint8 magic[4] = "rDPC";
	STREAM s;

	s = channel_init(This, This->rdpdr.channel, 0x50);
	out_uint8a(s, magic, 4);
	out_uint32_le(s, 5);	/* count */
	out_uint16_le(s, 1);	/* first */
	out_uint16_le(s, 0x28);	/* length */
	out_uint32_le(s, 1);
	out_uint32_le(s, 2);
	out_uint16_le(s, 2);
	out_uint16_le(s, 5);
	out_uint16_le(s, 1);
	out_uint16_le(s, 5);
	out_uint16_le(s, 0xFFFF);
	out_uint16_le(s, 0);
	out_uint32_le(s, 0);
	out_uint32_le(s, 3);
	out_uint32_le(s, 0);
	out_uint32_le(s, 0);
	out_uint16_le(s, 2);	/* second */
	out_uint16_le(s, 8);	/* length */
	out_uint32_le(s, 1);
	out_uint16_le(s, 3);	/* third */
	out_uint16_le(s, 8);	/* length */
	out_uint32_le(s, 1);
	out_uint16_le(s, 4);	/* fourth */
	out_uint16_le(s, 8);	/* length */
	out_uint32_le(s, 1);
	out_uint16_le(s, 5);	/* fifth */
	out_uint16_le(s, 8);	/* length */
	out_uint32_le(s, 1);

	s_mark_end(s);
	channel_send(This, s, This->rdpdr.channel);
}
예제 #21
0
파일: rdpdr.c 프로젝트: hoangduit/reactos
static void
rdpdr_send_completion(RDPCLIENT * This, uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer,
		      uint32 length)
{
	uint8 magic[4] = "rDCI";
	STREAM s;

	s = channel_init(This, This->rdpdr.channel, 20 + length);
	out_uint8a(s, magic, 4);
	out_uint32_le(s, device);
	out_uint32_le(s, id);
	out_uint32_le(s, status);
	out_uint32_le(s, result);
	out_uint8p(s, buffer, length);
	s_mark_end(s);
	/* JIF */
#ifdef WITH_DEBUG_RDP5
	printf("--> rdpdr_send_completion\n");
	/* hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */
#endif
	channel_send(This, s, This->rdpdr.channel);
}
예제 #22
0
파일: rdpdr.c 프로젝트: hoangduit/reactos
static void
rdpdr_send_name(RDPCLIENT * This)
{
	uint8 magic[4] = "rDNC";
	STREAM s;
	uint32 hostlen;

	if (NULL == This->rdpdr_clientname)
	{
		This->rdpdr_clientname = This->hostname;
	}
	hostlen = (strlen(This->rdpdr_clientname) + 1) * 2;

	s = channel_init(This, This->rdpdr.channel, 16 + hostlen);
	out_uint8a(s, magic, 4);
	out_uint16_le(s, 0x63);	/* unknown */
	out_uint16_le(s, 0x72);
	out_uint32(s, 0);
	out_uint32_le(s, hostlen);
	rdp_out_unistr(This, s, This->rdpdr_clientname, hostlen - 2);
	s_mark_end(s);
	channel_send(This, s, This->rdpdr.channel);
}
예제 #23
0
static void
rdpdr_send_name(void)
{
	uint8 magic[4] = "rDNC";
	STREAM s;
	uint32 hostlen;

	if (NULL == g_rdpdr_clientname)
	{
		g_rdpdr_clientname = g_hostname;
	}
	hostlen = (strlen(g_rdpdr_clientname) + 1) * 2;

	s = channel_init(rdpdr_channel, 16 + hostlen);
	out_uint8a(s, magic, 4);
	out_uint16_le(s, 0x63);	/* unknown */
	out_uint16_le(s, 0x72);
	out_uint32(s, 0);
	out_uint32_le(s, hostlen);
	rdp_out_unistr(s, g_rdpdr_clientname, hostlen - 2);
	s_mark_end(s);
	channel_send(s, rdpdr_channel);
}
예제 #24
0
void * sendm(void * ptr)
{
    int err, nb = 0;
    msg_t tmp;

    tmp.pid = getpid();
    sprintf(tmp.content," %ld @ %d !\n",pthread_self(),tmp.pid);

    while(nb < MAX_MSG)
    {
        err = channel_send(chan_s,&tmp);

        if(err == -1)
        {
            channel_close(chan_s);
            break;
        }

        nb++;
    }

    pthread_exit(NULL);
}
예제 #25
0
static void
rdpsnd_send(STREAM s)
{
	channel_send(s, rdpsnd_channel);
}
예제 #26
0
void producer(void *data)
    /*@
    requires
        [1/2]info(data, ?channel_, ?space_, ?termScope, ?level_, ?creditObject_) &*& [1/2]info_nextToSend(data, 0) &*& debits(10, creditObject_) &*&
        channel_send_tokens(10, channel_, space_, termScope, level_, creditObject_, channel_inv(data)) &*&
        [_]obspace_credit_object_info(creditObject_, space_, level_) &*& obspace_joinee(space_) &*&
        [1/3]obligation_space(space_, termScope) &*& obspace_obligation_set(space_, n_times(nat_of_int(10), level_));
    @*/
    //@ ensures stop_perm(termScope);
    //@ terminates;
{
    info info = data;
    channel channel = info->channel;
    //@ int space = info->space;
    //@ level level = info->level;
    //@ int creditObject = info->creditObject;
    for (unsigned int i = 0; i < 10; i = i + 1)
        /*@
        invariant
            i <= 10 &*&
            debits(10 - i, creditObject_) &*&
            channel_send_tokens(10 - i, channel, space, termScope, level, creditObject, channel_inv(info)) &*&
            [_]obspace_credit_object_info(creditObject_, space_, level_) &*&
            i < 10 ?
                obspace_obligation_set(space, n_times(nat_of_int(10 - i), level)) &*&
                [1/2]info(info, _, space, termScope, _, _) &*&
                [1/3]obligation_space(space, termScope) &*&
                [1/2]info->nextToSend |-> i &*&
                obspace_joinee(space_)
            :
                stop_perm(termScope);
        @*/
        //@ decreases 10 - (int)i;
    {
        //@ open channel_send_tokens(10 - i, channel, space, termScope, level, creditObject, channel_inv(info));
        //@ level_all_above_or_eq_n_times(nat_of_int(10 - i), level);
        {
            /*@
            predicate P() = [1/2]info->nextToSend |-> i &*& i == 9 ? [1/2]info(info, _, space, termScope, _, _) &*& [1/3]obligation_space(space, termScope) : true;
            predicate Q() = i < 9 ? [1/2]info->nextToSend |-> i + 1 : true;
            lemma void op()
                requires channel_inv(info)(?elems) &*& P();
                ensures channel_inv(info)(append(elems, {(void *)i})) &*& Q();
            {
                open channel_inv(info)(elems);
                open P();
                is_range_append(info->nextToReceive, elems, info->nextToSend, {(void *)i}, info->nextToSend + 1);
                info->nextToSend++;
                close Q();
                close channel_inv(info)(append(elems, {(void *)i}));
            }
            @*/
            //@ produce_lemma_function_pointer_chunk(op) : channel_send_ghost_op(channel_inv(info), (void *)i, P, Q)() { call(); };
            //@ close P();
            //@ close exists(i == 9);
            //@ succ_int(0);
            //@ if (i == 9) { open debits(_, _); }
            channel_send(channel, (void *)i);
            //@ open Q();
        }
        //@ succ_int(i);
        //@ succ_int(10 - i - 1);
        /*@
        if (i < 9) {
            open debits(_, _);
            obspace_debit_dispose();
        }
        @*/
    }
    //@ open channel_send_tokens(0, _, _, _, _, _, _);
    //@ open debits(0, _);
}
예제 #27
0
void * forward(void * ptr)
{
    int err;
    msg_t tmp;
    channel_set s_chset, r_chset;

    s_chset.chan = chan_s;
    s_chset.events = CHANNEL_EVENT_READ|CHANNEL_EVENT_CLOSE;

    r_chset.chan = chan_r;
    r_chset.events = CHANNEL_EVENT_WRITE|CHANNEL_EVENT_CLOSE;

    while(n < MAX_FWD_MSG)
    {
        s_chset.revents = CHANNEL_EVENT_NOEVT;
        r_chset.revents = CHANNEL_EVENT_NOEVT;

        err = channel_select(&s_chset,1,CHANNEL_TIME_WAIT);

        if(err == -1)
        {
            perror("FWD - 1 channel_select()");
            channel_close(chan_s);
            channel_close(chan_r);
            break;
        }
        else if(err == 0)
            continue;

        if(CHAN_READ_EVT(s_chset.revents))
        {
            err = channel_recv(chan_s,&tmp);

            if(err == -1)
            {
                perror("FWD - error channel_recv");
                channel_close(chan_s);
                channel_close(chan_r);
                break;
            }
        }
        else if(CHAN_CLOSE_EVT(s_chset.revents))
        {
            channel_close(chan_r);
            break;
        }

        err = channel_select(&r_chset,1,CHANNEL_TIME_WAIT);

        if(err == -1)
        {
            perror("FWD - 1 channel_select()");
            channel_close(chan_s);
            channel_close(chan_r);
            break;
        }
        else if(err == 0)
            continue;

        if(CHAN_WRITE_EVT(r_chset.revents))
        {
            err = channel_send(chan_r,&tmp);

            if(err == -1)
            {
                perror("FWD - error channel_send");
                channel_close(chan_s);
                channel_close(chan_r);
                break;
            }

            n += 1;

            if(n >= MAX_FWD_MSG)
            {
                //printf("n : %d OK \n",n);
                channel_close(chan_s);
                channel_close(chan_r);
            }
        }
        else if(CHAN_CLOSE_EVT(r_chset.revents))
        {
            channel_close(chan_s);
            break;
        }
    }

  pthread_exit(NULL);
}
예제 #28
0
	void Environment::run(RunningContext *context)
	{
		const Instruction &ins = m_ipos;
		m_context = context;
		if (!context)
		{
			m_running = false;
		} else if (!m_running)
		{
			clear_vstore();
			TRACE_PRINTF(TRACE_VM, TRACE_INFO, "Entering running state with %p\n", context);
			m_running = true;
			const SourcePos *last_pos = NULL; // used for debug output below.
			const Instruction *ipos;
			while (m_context && (ipos = m_context->next()))
			{
				size_t output = -1;
				size_t expected = -1;
#				define CHECK_STACK(in, out) TRACE_OUT(TRACE_VM, TRACE_SPAM) {\
					assert(m_context->stack_count() >= (size_t)(in)); \
					if ((out) != -1) { assert((long)(expected = m_context->stack_count() - (size_t)(in) + (size_t)(out)) >= 0); } \
					tprintf("Stack info: before(%d), in(%d), out(%d), expected(%d)\n", (int)m_context->stack_count(), (int)(in), (int)(out), (int)expected); \
					output = (out); \
				}

				m_ipos = *ipos;

				TRACE_DO(TRACE_VM, TRACE_INFO) {
					const SourcePos &pos = m_context->m_instructions->source_pos(ipos);
					if (!last_pos || *last_pos != pos)
						tprintf("Source Position: %s:%d:%d (%s)\n", pos.file.c_str(), (int)pos.line_num, (int)pos.column, pos.annotation.c_str());
					last_pos = &pos;
				}
				TRACE_OUT(TRACE_VM, TRACE_SPAM) {
					tprintf("Instruction: %s@%d\n",
						inspect(ins).c_str(),
						(int)(ipos - &*m_context->instructions().begin())
						);
					tprintf("Stack: %d deep", (int)m_context->stack_count());

					const Value *it;
					for (it = m_context->stack_begin(); it != m_context->stack_pos(); it++)
					{
						tprintf("\n   %s", inspect(*it).c_str());
					}
					tprintf(" <--\n");
				}

				switch(ins.instruction)
				{
				case NOP:
					CHECK_STACK(0, 0);
					break;
				case DEBUGGER:
					CHECK_STACK(0, 0);
					{
						String *action = ptr<String>(ins.arg1);
						if (*action == "interrupt")
						{
							DO_DEBUG __asm__("int3");
						} else if (*action == "trace_enable") {
							trace_mute = false;
						} else if (*action == "trace_disable") {
							trace_mute = true;
						}
					}
					break;

				case POP:
					CHECK_STACK(1, 0);
					m_context->pop();
					break;
				case PUSH:
					CHECK_STACK(0, 1);
					m_context->push(ins.arg1);
					break;
				case SWAP: {
					CHECK_STACK(2, 2);
					Value tmp1 = m_context->top();
					m_context->pop();
					Value tmp2 = m_context->top();
					m_context->pop();
					m_context->push(tmp1);
					m_context->push(tmp2);
					}
					break;
				case DUP_TOP:
					CHECK_STACK(1, 2);
					m_context->push(m_context->top());
					break;

				case IS: {
					CHECK_STACK(1, 1);
					Value res = bvalue(ins.arg1 == m_context->top());
					m_context->pop();
					m_context->push(res);
					}
					break;
				case IS_EQ: {
					CHECK_STACK(2, 1);
					Value first = m_context->top();
					m_context->pop();
					Value second = m_context->top();
					m_context->pop();
					m_context->push(bvalue(first == second));
					}
					break;
				case IS_NOT: {
					CHECK_STACK(1, 1);
					Value res = bvalue(ins.arg1 != m_context->top());
					m_context->pop();
					m_context->push(res);
					}
					break;
				case IS_NOT_EQ:{
					CHECK_STACK(2, 1);
					Value first = m_context->top();
					m_context->pop();
					Value second = m_context->top();
					m_context->pop();
					m_context->push(bvalue(first != second));
					}
					break;
				case JMP:
					CHECK_STACK(0, 0);

					GC::safe_point();

					m_context->jump(ins.cache.machine_num);
					break;
				case JMP_IF:
					CHECK_STACK(1, 0);

					GC::safe_point();

					if (is_truthy(m_context->top()))
						m_context->jump(ins.cache.machine_num);
					m_context->pop();
					break;
				case JMP_IF_NOT:
					CHECK_STACK(1, 0);

					GC::safe_point();

					if (!is_truthy(m_context->top()))
						m_context->jump(ins.cache.machine_num);
					m_context->pop();
					break;

				case LEXICAL_CLEAN_SCOPE: {
					CHECK_STACK(0, 0);
					VariableFrame *frame = new_variable_frame(m_context->m_instructions);
					m_context->new_scope(frame);
					}
					break;
				case LEXICAL_LINKED_SCOPE: {
					CHECK_STACK(0, 0);
					VariableFrame *frame = new_variable_frame(m_context->m_instructions);
					frame->link_frame(m_context->m_lexicalvars);
					m_context->new_scope(frame);
					}
					break;
				case FRAME_GET: {
					CHECK_STACK(0, 1);
					size_t frameid = (size_t)ins.cache.machine_num;
					TRACE_PRINTF(TRACE_VM, TRACE_SPAM, "Getting frame var %s (%d)\n", ptr<String>(ins.arg1)->c_str(), (int)frameid);
					m_context->push(m_context->get_framevar(frameid));
					}
					break;
				case FRAME_SET: {
					CHECK_STACK(1, 0);
					size_t frameid = (size_t)ins.cache.machine_num;
					TRACE_PRINTF(TRACE_VM, TRACE_SPAM, "Setting frame var %s (%d) to: %s\n", ptr<String>(ins.arg1)->c_str(), (int)frameid, inspect(m_context->top()).c_str());
					m_context->set_framevar(frameid, m_context->top());
					m_context->pop();
					}
					break;
				case LOCAL_GET: {
					CHECK_STACK(0, 1);
					size_t localid = (size_t)ins.cache.machine_num;
					TRACE_PRINTF(TRACE_VM, TRACE_SPAM, "Getting local var %s (%d)\n", ptr<String>(ins.arg1)->c_str(), (int)localid);
					m_context->push(m_context->get_localvar(localid));
					}
					break;
				case LOCAL_SET: {
					CHECK_STACK(1, 0);
					size_t localid = (size_t)ins.cache.machine_num;
					TRACE_PRINTF(TRACE_VM, TRACE_SPAM, "Setting local var %s (%d) to: %s\n", ptr<String>(ins.arg1)->c_str(), (int)localid, inspect(m_context->top()).c_str());
					m_context->set_localvar(localid, m_context->top());
					m_context->pop();
					}
					break;
				case LEXICAL_GET: {
					CHECK_STACK(0, 1);
					size_t depth = ins.arg1.machine_num;
					size_t localid = (size_t)ins.cache.machine_num;
					TRACE_PRINTF(TRACE_VM, TRACE_SPAM, "lexical_get %u@%u: %i\n", (unsigned)localid, (unsigned)depth, type(m_context->get_lexicalvar(localid, depth)));
					if (depth == 0)
						m_context->push(m_context->get_lexicalvar(localid));
					else
						m_context->push(m_context->get_lexicalvar(localid, depth));
					}
					break;
				case LEXICAL_SET: {
					CHECK_STACK(1, 0);
					size_t depth = ins.arg1.machine_num;
					size_t localid = (size_t)ins.cache.machine_num;
					TRACE_PRINTF(TRACE_VM, TRACE_SPAM, "lexical_set %u@%u: %i\n", (unsigned)localid, (unsigned)depth, type(m_context->top()));
					if (depth == 0)
						m_context->set_lexicalvar(localid, m_context->top());
					else
						m_context->set_lexicalvar(localid, depth, m_context->top());
					m_context->pop();
					}
					break;

				case CHANNEL_NEW: {
					CHECK_STACK(0, 1);
					const Value &octx = vstore(value(m_context));
					RunnableContext *nctx = new_context(octx);
					nctx->jump(ins.cache.machine_num);
					m_context->push(value(nctx));
					clear_vstore();
					}
					break;
				case CHANNEL_SPECIAL:
					CHECK_STACK(0, 1);
					m_context->push(special_channel(*ptr<String>(ins.arg1)));
					break;
				case CHANNEL_SEND: {
					CHECK_STACK(3, -1);

					GC::safe_point();

					const Value &val = vstore(m_context->top()); m_context->pop();
					const Value &ret = vstore(m_context->top()); m_context->pop();
					const Value &channel = vstore(m_context->top()); m_context->pop();

					// A context that's been channel_sended from should never be returned to,
					// so invalidate it.
					m_context->invalidate();
					channel_send(this, channel, val, ret);
					clear_vstore();
					}
					break;
				case CHANNEL_CALL:{
					CHECK_STACK(2, -1);

					GC::safe_point();

					const Value &val = vstore(m_context->top()); m_context->pop();
					const Value &channel = vstore(m_context->top()); m_context->pop();
					const Value &ret = vstore(value(m_context));

					channel_send(this, channel, val, ret);
					clear_vstore();
					}
					break;
				case CHANNEL_RET:{
					CHECK_STACK(2, -1);
					const Value &val = vstore(m_context->top()); m_context->pop();
					const Value &channel = vstore(m_context->top()); m_context->pop();

					// A context that's been channel_reted from should never be returned to,
					// so invalidate it.
					m_context->invalidate();
					channel_send(this, channel, val, value(&no_return_ctx));
					clear_vstore();
					}
					break;

				case MESSAGE_NEW: {
					long long id = ins.cache.machine_num;
					long long sysarg_count = ins.arg2.machine_num, sysarg_counter = sysarg_count - 1;
					long long arg_count = ins.arg3.machine_num, arg_counter = arg_count - 1;
					CHECK_STACK(sysarg_count + arg_count, 1);

					Message *msg = new_message(id, sysarg_count, arg_count);

					while (arg_count > 0 && arg_counter >= 0)
					{
						msg->args()[arg_counter] = m_context->top();
						m_context->pop();
						--arg_counter;
					}
					while (sysarg_count > 0 && sysarg_counter >= 0)
					{
						msg->sysargs()[sysarg_counter] = m_context->top();
						m_context->pop();
						--sysarg_counter;
					}

					m_context->push(value(msg));
					}
					break;
				case MESSAGE_SPLAT: {
					CHECK_STACK(2, 1);
					const Tuple &tuple = *ptr<Tuple>(m_context->top()); m_context->pop();
					const Message &msg = *ptr<Message>(m_context->top()); m_context->pop();

					Message *nmsg = new_message(msg.m_id, msg.sysarg_count(), msg.arg_count() + tuple.size());
					std::copy(msg.sysargs(), msg.sysargs_end(), nmsg->sysargs());
					std::copy(msg.args(), msg.args_end(), nmsg->args());
					std::copy(tuple.begin(), tuple.end(), nmsg->args() + msg.arg_count());
					m_context->push(value(nmsg));
					}
					break;
				case MESSAGE_ADD: {
					long long count = ins.arg1.machine_num, counter = 0;
					CHECK_STACK(1 + count, 1);
					const Message &msg = *ptr<Message>(*(m_context->stack_pos() - 1 - count));

					Message *nmsg = new_message(msg.m_id, msg.sysarg_count(), msg.arg_count() + count);
					std::copy(msg.sysargs(), msg.sysargs_end(), nmsg->sysargs());
					std::copy(msg.args(), msg.args_end(), nmsg->args());

					Message::iterator out = nmsg->args() + msg.arg_count();
					while (count > 0 && counter < count)
					{
						*out++ = m_context->top();
						m_context->pop();
						++counter;
					}
					m_context->pop(); // this is the message we pulled directly off the stack before.

					m_context->push(value(nmsg));
					}
					break;
				case MESSAGE_COUNT:
					CHECK_STACK(1, 2);
					m_context->push(value((long long)ptr<Message>(m_context->top())->arg_count()));
					break;
				case MESSAGE_IS:
					CHECK_STACK(1, 2);
					m_context->push(bvalue(ptr<Message>(m_context->top())->m_id == (uint64_t)ins.cache.machine_num));
					break;
				case MESSAGE_IS_PROTO:
					CHECK_STACK(1, 2);
					m_context->push(bvalue(ptr<Message>(m_context->top())->protocol_id() == (uint64_t)ins.cache.machine_num));
					break;
				case MESSAGE_ID:
					{
					CHECK_STACK(1, 2);
					Message *msg = ptr<Message>(m_context->top());
					m_context->push(value((long long)msg->m_id));
					}
					break;
				case MESSAGE_SPLIT_ID:
					{
					CHECK_STACK(1, 3);
					Message *msg = ptr<Message>(m_context->top());
					m_context->push(value((long long)msg->message_id()));
					m_context->push(value((long long)msg->protocol_id()));
					}
					break;
				case MESSAGE_CHECK:
					CHECK_STACK(1, 1);
					if (!is(m_context->top(), MESSAGE))
					{
						m_context->pop();
						m_context->push(False);
					}
					break;
				case MESSAGE_FORWARD: {
					CHECK_STACK(1, 1);

					long long id = ins.cache.machine_num;
					const Message &msg = *ptr<Message>(m_context->top());
					Message *nmsg = new_message(id, msg.sysarg_count(), msg.arg_count() + 1);
					std::copy(msg.sysargs(), msg.sysargs_end(), nmsg->sysargs());
					nmsg->args()[0] = value(new_string(msg.name()));
					std::copy(msg.args(), msg.args_end(), nmsg->args() + 1);
					m_context->pop();
					m_context->push(value(nmsg));
					break;
				}
				case MESSAGE_SYS_PREFIX: {
					long long count = ins.arg1.machine_num, counter = 0;
					CHECK_STACK(1 + count, 1);

					const Value *sdata = m_context->stack_pos() - 1 - count;
					const Message &msg = *ptr<Message>(*sdata++);
					Message *nmsg = new_message(msg.m_id, msg.sysarg_count() + count, msg.arg_count());
					Message::iterator to = nmsg->sysargs();
					while (counter++ < count)
					{
						*to++ = *sdata++;
					}
					std::copy(msg.sysargs(), msg.sysargs_end(), to);
					std::copy(msg.args(), msg.args_end(), nmsg->args());
					while (--counter != 0)
					{
						m_context->pop();
					}
					m_context->pop(); // message we read off stack before.
					m_context->push(value(nmsg));
					break;
				}
				case MESSAGE_SYS_UNPACK: {
					long long count = ins.arg1.machine_num, pos = count - 1;
					CHECK_STACK(1, 1 + count);

					const Message *msg = ptr<Message>(m_context->top());
					Message::const_iterator args = msg->sysargs();
					long long len = (long long)msg->sysarg_count();

					while (pos >= 0)
					{
						if (pos >= len)
							m_context->push(Undef);
						else
							m_context->push(args[pos]);

						pos -= 1;
					}
					}
					break;
				case MESSAGE_UNPACK: {
					long long first_count = ins.arg1.machine_num, first_counter = 0;
					long long splat = ins.arg2.machine_num;
					long long last_count = ins.arg3.machine_num, last_counter = 0;
					CHECK_STACK(1, 1 + first_count + last_count + (splat?1:0));

					const Message *msg = ptr<Message>(m_context->top());
					Message::const_iterator args = msg->args();
					long long len = (long long)msg->arg_count(), pos = len - 1;

					while (last_counter < last_count && pos >= first_count)
					{
						if (pos >= len)
							m_context->push(Nil);
						else
							m_context->push(args[pos]);

						pos -= 1;
						last_counter += 1;
					}

					if (splat != 0)
					{
						if (pos >= first_count)
						{
							Tuple *splat_tuple = new_tuple(pos - first_count + 1);
							Tuple::iterator out = splat_tuple->end();
							while (pos >= first_count)
							{
								--out;
								*out = args[pos];
								pos -= 1;
							}
							m_context->push(value(splat_tuple));
						} else {
							m_context->push(value(new_tuple(0)));
						}
					}

					pos = first_count - 1;

					while (first_counter < first_count && pos >= 0)
					{
						if (pos >= len)
							m_context->push(Nil);
						else
							m_context->push(args[pos]);

						pos -= 1;
						first_counter += 1;
					}
					}
					break;

				case STRING_COERCE: {
					const Value &coerce = ins.arg1;
					const Value &val = vstore(m_context->top());
					if (is(val, STRING))
					{
						CHECK_STACK(1, 2);
						// push a nil like we called the method.
						m_context->push(Nil);
					} else {
						CHECK_STACK(1, -1);
						m_context->pop();
						channel_send(this, val, value(new_message(coerce)), value(m_context));
					}
					}
					clear_vstore();
					break;

				case STRING_NEW: {
					long long count = ins.arg1.machine_num, counter = 0;
					CHECK_STACK(count, 1);
					const Value *sp = m_context->stack_pos() - 1;
					size_t len = 0;
					while (count > 0 && counter < count)
					{
						assert(is(sp[-counter], STRING));
						len += ptr<String>(sp[-counter])->length();
						++counter;
					}
					String *res = new_string(len);
					String::iterator out = res->begin();
					counter = 0;
					while (count > 0 && counter < count)
					{
						const String *val = ptr<String>(m_context->top());
						out = std::copy(val->begin(), val->end(), out);
						m_context->pop();
						++counter;
					}
					m_context->push(value(res));
					}
					break;

				case TUPLE_NEW: {
					long long count = ins.arg1.machine_num, counter = 0;
					CHECK_STACK(count, 1);
					Tuple *tuple = new_tuple(count);
					Tuple::iterator out = tuple->begin();
					while (count > 0 && counter < count)
					{
						*out++ = m_context->top();
						m_context->pop();
						++counter;
					}
					m_context->push(value(tuple));
					}
					break;
				case TUPLE_SPLAT: {
					CHECK_STACK(2, 1);
					const Tuple *tuple2 = ptr<Tuple>(m_context->top()); m_context->pop();
					const Tuple *tuple1 = ptr<Tuple>(m_context->top()); m_context->pop();
					Tuple *tuple = join_tuple(tuple1, tuple2);
					m_context->push(value(tuple));
					}
					break;
				case TUPLE_UNPACK: {
					long long first_count = ins.arg1.machine_num, first_counter = 0;
					long long splat = ins.arg2.machine_num;
					long long last_count = ins.arg3.machine_num, last_counter = 0;
					CHECK_STACK(1, 1 + first_count + last_count + (splat?1:0));

					const Tuple &tuple = *ptr<Tuple>(m_context->top());
					long long len = tuple.size(), pos = tuple.size() - 1;
					while (last_counter < last_count && pos >= first_count)
					{
						if (pos >= len)
							m_context->push(Nil);
						else
							m_context->push(tuple[pos]);

						pos -= 1;
						last_counter += 1;
					}

					if (splat != 0)
					{
						if (pos >= first_count)
						{
							Tuple *splat_tuple = new_tuple(pos - first_count + 1);
							Tuple::iterator out = splat_tuple->end();
							while (pos >= first_count)
							{
								--out;
								*out = tuple[pos];
								pos -= 1;
							}
							m_context->push(value(splat_tuple));
						} else {
							m_context->push(value(new_tuple(0)));
						}
					}

					pos = first_count - 1;

					while (first_counter < first_count && pos >= 0)
					{
						if (pos >= len)
							m_context->push(Nil);
						else
							m_context->push(tuple[pos]);

						pos -= 1;
						first_counter += 1;
					}
					}
					break;
				default:
					printf("Panic! Unknown instruction %d\n", ins.instruction);
					exit(1);
				}

				TRACE_OUT(TRACE_VM, TRACE_SPAM) {
					tprintf("Output: %d", (int)output);
					if ((long)output > 0)
					{
						const Value *it = std::max(
							m_context->stack_begin(), m_context->stack_pos() - output);
						for (; it != m_context->stack_pos(); it++)
						{
							tprintf("\n   %s", inspect(*it).c_str());
						}
					}
					tprintf(" <--\n");
					tprintf("----------------\n");
				}
예제 #29
0
파일: libnet.c 프로젝트: luozy/evnet
void evnet_channelsend(void* c, char *data, int size)
{
    channel_send((channel_t*)c, data, size);
}
예제 #30
0
파일: m_ntopic.c 프로젝트: darcyg/chaosircd
/* -------------------------------------------------------------------------- *
 * argv[0] - prefix                                                           *
 * argv[1] - 'ntopic'                                                         *
 * argv[2] - channel                                                          *
 * argv[3] - channel ts                                                       *
 * argv[4] - topic info                                                       *
 * argv[5] - topic time                                                       *
 * argv[6] - topic                                                            *
 * -------------------------------------------------------------------------- */
static void ms_ntopic(struct lclient *lcptr, struct client *cptr,
                      int             argc,  char         **argv)
{
  struct channel *chptr;
  time_t          ts;
  time_t          topic_ts;
  int             changed = 0;
  char            topic[IRCD_TOPICLEN];

  topic[0] = '\0';

  if(argc == 7)
    strlcpy(topic, argv[6], sizeof(topic));

  if((chptr = channel_find_name(argv[2])) == NULL)
  {
    log(client_log, L_warning, "Dropping invalid NTOPIC for channel %s.",
        argv[2]);
    return;
  }

  ts = str_toul(argv[3], NULL, 10);

  if(ts > chptr->ts || chptr->topic[0])
  {
    log(client_log, L_verbose, "Dropping NTOPIC for %s with too recent TS",
        chptr->name);
    return;
  }

  topic_ts = str_toul(argv[5], NULL, 10);

  if(chptr->ts == ts)
  {
    if(chptr->topic_ts > topic_ts)
    {
      log(client_log, L_verbose, "Dropping NTOPIC for %s because its older",
          chptr->name);
      return;
    }

    if(chptr->topic_ts == topic_ts)
    {
      size_t nlen;
      size_t olen;

      nlen = topic[0] ? str_len(topic) : 0;
      olen = str_len(chptr->topic);

      if(nlen < olen)
      {
        log(client_log, L_warning, "TOPIC collision on %s, ignoring.",
            chptr->name);
        return;
      }

      if(nlen == olen)
      {
        if((topic == NULL && chptr->topic[0] == '\0'))
          return;

        if(!str_cmp(topic, chptr->topic))
          return;
      }
    }
  }

  if(chptr->ts != ts)
  {
    log(channel_log, L_warning, "TS for channel %s changed from %lu to %lu.",
        chptr->name, chptr->ts, ts);

    chptr->ts = ts;
  }

  if(str_cmp(chptr->topic, topic))
    changed = 1;

  if(changed)
  {
    if(topic[0])
      strlcpy(chptr->topic, topic, sizeof(chptr->topic));
    else
      chptr->topic[0] = '\0';
  }

  strlcpy(chptr->topic_info, argv[4], sizeof(chptr->topic_info));
  chptr->topic_ts = topic_ts;

  if(chptr->topic[0])
    server_send(lcptr, NULL, CAP_NONE, CAP_NONE,
                ":%C NTOPIC %s %lu %s %lu :%s",
                cptr, chptr->name, chptr->ts,
                chptr->topic_info, chptr->topic_ts, chptr->topic);
  else
    server_send(lcptr, NULL, CAP_NONE, CAP_NONE,
                ":%C NTOPIC %s %lu %s %lu",
                cptr, chptr->name, chptr->ts,
                chptr->topic_info, chptr->topic_ts);

  if(changed)
  {
    channel_send(NULL, chptr, CHFLG(NONE), CHFLG(NONE),
                 ":%C TOPIC %s :%s",
                 cptr, chptr->name, chptr->topic);
  }
}