/* _____PUBLIC FUNCTIONS_____________________________________________________ */
int main(void)
{
    // Create a timer object
    tmr_t tmr;

    // Initialise modules
    led_init();
    systmr_init();

    // Initialise timer to expire once a second
    tmr_start(&tmr, TMR_TICKS_PER_SEC);

    for(;;)
    {
        // Wait until timer has expired
        while(!tmr_has_expired(&tmr))
        {
            ;
        }
        // Reset timer
        tmr_reset(&tmr);

        // Toggle LED pin
        led_toggle();
    }
}
Exemple #2
0
static int timer_event(int dev, unsigned char *event)
{
    unsigned char cmd = event[1];
    unsigned long parm = *(int *) &event[4];

    switch (cmd)
    {
        case TMR_WAIT_REL:
            parm += prev_event_time;
        case TMR_WAIT_ABS:
            if (parm > 0)
            {
                long time;

                if (parm <= curr_ticks)    /* It's the time */
                    return TIMER_NOT_ARMED;
                time = parm;
                next_event_time = prev_event_time = time;
                return TIMER_ARMED;
            }
            break;

        case TMR_START:
            tmr_reset();
            tmr_running = 1;
            reprogram_timer();
            break;

        case TMR_STOP:
            tmr_running = 0;
            break;

        case TMR_CONTINUE:
            tmr_running = 1;
            reprogram_timer();
            break;

        case TMR_TEMPO:
            if (parm)
            {
                if (parm < 8)
                    parm = 8;
                if (parm > 250)
                    parm = 250;
                tmr_offs = tmr_ctr;
                ticks_offs += tmr2ticks(tmr_ctr);
                tmr_ctr = 0;
                curr_tempo = parm;
                reprogram_timer();
            }
            break;

        case TMR_ECHO:
            seq_copy_to_input(event, 8);
            break;

        default:;
    }
    return TIMER_NOT_ARMED;
}
Exemple #3
0
static int timer_open(int dev, int mode)
{
    if (opened)
        return -EBUSY;
    tmr_reset();
    curr_tempo = 60;
    curr_timebase = 100;
    opened = 1;
    reprogram_timer();
    return 0;
}
Exemple #4
0
static int
def_tmr_open (int dev, int mode)
{
  if (opened)
    return RET_ERROR (EBUSY);

  tmr_reset ();
  curr_tempo = 60;
  curr_timebase = HZ;
  opened = 1;

  ACTIVATE_TIMER (def_tmr, poll_def_tmr, 1);

  return 0;
}
Exemple #5
0
static int
def_tmr_open(int dev, int mode)
{
	if (opened)
		return -EBUSY;

	tmr_reset();
	curr_tempo = 60;
	curr_timebase = 100;
	opened = 1;
	{
		def_tmr.expires = (1) + jiffies;
		add_timer(&def_tmr);
	};

	return 0;
}
Exemple #6
0
/* same as sound_timer.c:timer_ioctl!? */
static int def_tmr_ioctl(int dev, unsigned int cmd, void __user *arg)
{
	int __user *p = arg;
	int val;

	switch (cmd) {
	case SNDCTL_TMR_SOURCE:
		return __put_user(TMR_INTERNAL, p);

	case SNDCTL_TMR_START:
		tmr_reset();
		tmr_running = 1;
		return 0;

	case SNDCTL_TMR_STOP:
		tmr_running = 0;
		return 0;

	case SNDCTL_TMR_CONTINUE:
		tmr_running = 1;
		return 0;

	case SNDCTL_TMR_TIMEBASE:
		if (__get_user(val, p))
			return -EFAULT;
		if (val) {
			if (val < 1)
				val = 1;
			if (val > 1000)
				val = 1000;
			curr_timebase = val;
		}
		return __put_user(curr_timebase, p);

	case SNDCTL_TMR_TEMPO:
		if (__get_user(val, p))
			return -EFAULT;
		if (val) {
			if (val < 8)
				val = 8;
			if (val > 250)
				val = 250;
			tmr_offs = tmr_ctr;
			ticks_offs += tmr2ticks(tmr_ctr);
			tmr_ctr = 0;
			curr_tempo = val;
			reprogram_timer();
		}
		return __put_user(curr_tempo, p);

	case SNDCTL_SEQ_CTRLRATE:
		if (__get_user(val, p))
			return -EFAULT;
		if (val != 0)	/* Can't change */
			return -EINVAL;
		val = ((curr_tempo * curr_timebase) + 30) / 60;
		return __put_user(val, p);
		
	case SNDCTL_SEQ_GETTIME:
		return __put_user(curr_ticks, p);
		
	case SNDCTL_TMR_METRONOME:
		/* NOP */
		break;
		
	default:;
	}
	return -EINVAL;
}
Exemple #7
0
static void
handle_read( int cnum, struct timeval* nowP )
    {
    char buf[30000];	/* must be larger than throttle / 2 */
    int bytes_to_read, bytes_read, bytes_handled;
    float elapsed;
    ClientData client_data;
    register long checksum;

    tmr_reset( nowP, connections[cnum].idle_timer );

    if ( do_throttle )
	bytes_to_read = throttle / 2.0;
    else
	bytes_to_read = sizeof(buf);
    if ( ! connections[cnum].did_response )
	{
	connections[cnum].did_response = 1;
	connections[cnum].response_at = *nowP;
	}
#ifdef USE_SSL
    if ( urls[connections[cnum].url_num].protocol == PROTO_HTTPS )
	bytes_read = SSL_read( connections[cnum].ssl, buf, bytes_to_read );
    else
	bytes_read = read( connections[cnum].conn_fd, buf, bytes_to_read );
#else
    bytes_read = read( connections[cnum].conn_fd, buf, bytes_to_read );
#endif
    if ( bytes_read <= 0 )
	{
	close_connection( cnum );
	return;
	}

    for ( bytes_handled = 0; bytes_handled < bytes_read; )
	{
	switch ( connections[cnum].conn_state )
	    {
	    case CNST_HEADERS:
	    /* State machine to read until we reach the file part.  Looks for
	    ** Content-Length header too.
	    */
	    for ( ; bytes_handled < bytes_read && connections[cnum].conn_state == CNST_HEADERS; ++bytes_handled )
		{
		switch ( connections[cnum].header_state )
		    {

		    case HDST_LINE1_PROTOCOL:
		    switch ( buf[bytes_handled] )
			{
			case ' ': case '\t':
			connections[cnum].header_state = HDST_LINE1_WHITESPACE;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			}
		    break;

		    case HDST_LINE1_WHITESPACE:
		    switch ( buf[bytes_handled] )
			{
			case ' ': case '\t':
			break;
			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9':
			connections[cnum].http_status =
			    buf[bytes_handled] - '0';
			connections[cnum].header_state = HDST_LINE1_STATUS;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_LINE1_STATUS:
		    switch ( buf[bytes_handled] )
			{
			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9':
			connections[cnum].http_status =
			    connections[cnum].http_status * 10 +
			    buf[bytes_handled] - '0';
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_BOL:
		    switch ( buf[bytes_handled] )
			{
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			case 'C': case 'c':
			connections[cnum].header_state = HDST_C;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_TEXT:
		    switch ( buf[bytes_handled] )
			{
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			break;
			}
		    break;

		    case HDST_LF:
		    switch ( buf[bytes_handled] )
			{
			case '\n':
			connections[cnum].conn_state = CNST_READING;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			case 'C': case 'c':
			connections[cnum].header_state = HDST_C;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CR:
		    switch ( buf[bytes_handled] )
			{
			case '\n':
			connections[cnum].header_state = HDST_CRLF;
			break;
			case '\r':
			connections[cnum].conn_state = CNST_READING;
			break;
			case 'C': case 'c':
			connections[cnum].header_state = HDST_C;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CRLF:
		    switch ( buf[bytes_handled] )
			{
			case '\n':
			connections[cnum].conn_state = CNST_READING;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CRLFCR;
			break;
			case 'C': case 'c':
			connections[cnum].header_state = HDST_C;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CRLFCR:
		    switch ( buf[bytes_handled] )
			{
			case '\n': case '\r':
			connections[cnum].conn_state = CNST_READING;
			break;
			case 'C': case 'c':
			connections[cnum].header_state = HDST_C;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_C:
		    switch ( buf[bytes_handled] )
			{
			case 'O': case 'o':
			connections[cnum].header_state = HDST_CO;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CO:
		    switch ( buf[bytes_handled] )
			{
			case 'N': case 'n':
			connections[cnum].header_state = HDST_CON;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CON:
		    switch ( buf[bytes_handled] )
			{
			case 'T': case 't':
			connections[cnum].header_state = HDST_CONT;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CONT:
		    switch ( buf[bytes_handled] )
			{
			case 'E': case 'e':
			connections[cnum].header_state = HDST_CONTE;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CONTE:
		    switch ( buf[bytes_handled] )
			{
			case 'N': case 'n':
			connections[cnum].header_state = HDST_CONTEN;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CONTEN:
		    switch ( buf[bytes_handled] )
			{
			case 'T': case 't':
			connections[cnum].header_state = HDST_CONTENT;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CONTENT:
		    switch ( buf[bytes_handled] )
			{
			case '-':
			connections[cnum].header_state = HDST_CONTENT_;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CONTENT_:
		    switch ( buf[bytes_handled] )
			{
			case 'L': case 'l':
			connections[cnum].header_state = HDST_CONTENT_L;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CONTENT_L:
		    switch ( buf[bytes_handled] )
			{
			case 'E': case 'e':
			connections[cnum].header_state = HDST_CONTENT_LE;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CONTENT_LE:
		    switch ( buf[bytes_handled] )
			{
			case 'N': case 'n':
			connections[cnum].header_state = HDST_CONTENT_LEN;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CONTENT_LEN:
		    switch ( buf[bytes_handled] )
			{
			case 'G': case 'g':
			connections[cnum].header_state = HDST_CONTENT_LENG;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CONTENT_LENG:
		    switch ( buf[bytes_handled] )
			{
			case 'T': case 't':
			connections[cnum].header_state = HDST_CONTENT_LENGT;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CONTENT_LENGT:
		    switch ( buf[bytes_handled] )
			{
			case 'H': case 'h':
			connections[cnum].header_state = HDST_CONTENT_LENGTH;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CONTENT_LENGTH:
		    switch ( buf[bytes_handled] )
			{
			case ':':
			connections[cnum].header_state = HDST_CONTENT_LENGTH_COLON;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CONTENT_LENGTH_COLON:
		    switch ( buf[bytes_handled] )
			{
			case ' ': case '\t':
			connections[cnum].header_state = HDST_CONTENT_LENGTH_COLON_WHITESPACE;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CONTENT_LENGTH_COLON_WHITESPACE:
		    switch ( buf[bytes_handled] )
			{
			case ' ': case '\t':
			break;
			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9':
			connections[cnum].content_length = buf[bytes_handled] - '0';
			connections[cnum].header_state = HDST_CONTENT_LENGTH_COLON_WHITESPACE_NUM;
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    case HDST_CONTENT_LENGTH_COLON_WHITESPACE_NUM:
		    switch ( buf[bytes_handled] )
			{
			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9':
			connections[cnum].content_length =
			    connections[cnum].content_length * 10 +
			    buf[bytes_handled] - '0';
			break;
			case '\n':
			connections[cnum].header_state = HDST_LF;
			break;
			case '\r':
			connections[cnum].header_state = HDST_CR;
			break;
			default:
			connections[cnum].header_state = HDST_TEXT;
			break;
			}
		    break;

		    }
		}
	    break;

	    case CNST_READING:
	    connections[cnum].bytes += bytes_read - bytes_handled;
	    if ( do_throttle )
		{
		/* Check if we're reading too fast. */
		elapsed = delta_timeval( &connections[cnum].started_at, nowP ) / 1000000.0;
		if ( elapsed > 0.01 && connections[cnum].bytes / elapsed > throttle )
		    {
		    connections[cnum].conn_state  = CNST_PAUSING;
		    client_data.i = cnum;
		    connections[cnum].wakeup_timer = tmr_create(
			nowP, wakeup_connection, client_data, 1000L, 0 );
		    }
		}
	    if ( do_checksum )
		{
		checksum = connections[cnum].checksum;
		for ( ; bytes_handled < bytes_read; ++bytes_handled )
		    {
		    if ( checksum & 1 )
			checksum = ( checksum >> 1 ) + 0x8000;
		    else
			checksum >>= 1;
		    checksum += buf[bytes_handled];
		    checksum &= 0xffff;
		    }
		connections[cnum].checksum = checksum;
		}
	    else
		bytes_handled = bytes_read;

	    if ( connections[cnum].content_length != -1 &&
		 connections[cnum].bytes >= connections[cnum].content_length )
		{
		close_connection( cnum );
		return;
		}

	    break;
	    }
static int
timer_ioctl (int dev,
	     unsigned int cmd, caddr_t arg)
{
  switch (cmd)
    {
    case SNDCTL_TMR_SOURCE:
      return snd_ioctl_return ((int *) arg, TMR_INTERNAL);
      break;

    case SNDCTL_TMR_START:
      tmr_reset ();
      tmr_running = 1;
      return 0;
      break;

    case SNDCTL_TMR_STOP:
      tmr_running = 0;
      return 0;
      break;

    case SNDCTL_TMR_CONTINUE:
      tmr_running = 1;
      return 0;
      break;

    case SNDCTL_TMR_TIMEBASE:
      {
	int             val = get_fs_long ((long *) arg);

	if (val)
	  {
	    if (val < 1)
	      val = 1;
	    if (val > 1000)
	      val = 1000;
	    curr_timebase = val;
	  }

	return snd_ioctl_return ((int *) arg, curr_timebase);
      }
      break;

    case SNDCTL_TMR_TEMPO:
      {
	int             val = get_fs_long ((long *) arg);

	if (val)
	  {
	    if (val < 8)
	      val = 8;
	    if (val > 250)
	      val = 250;
	    tmr_offs = tmr_ctr;
	    ticks_offs += tmr2ticks (tmr_ctr);
	    tmr_ctr = 0;
	    curr_tempo = val;
	    reprogram_timer ();
	  }

	return snd_ioctl_return ((int *) arg, curr_tempo);
      }
      break;

    case SNDCTL_SEQ_CTRLRATE:
      if (get_fs_long ((long *) arg) != 0)	/* Can't change */
	return -(EINVAL);

      return snd_ioctl_return ((int *) arg, ((curr_tempo * curr_timebase) + 30) / 60);
      break;

    case SNDCTL_TMR_METRONOME:
      /* NOP */
      break;

    default:;
    }

  return -(EINVAL);
}
Exemple #9
0
static int
def_tmr_ioctl (int dev,
	       unsigned int cmd, unsigned int arg)
{
  switch (cmd)
    {
    case SNDCTL_TMR_SOURCE:
      return IOCTL_OUT (arg, TMR_INTERNAL);
      break;

    case SNDCTL_TMR_START:
      tmr_reset ();
      tmr_running = 1;
      return 0;
      break;

    case SNDCTL_TMR_STOP:
      tmr_running = 0;
      return 0;
      break;

    case SNDCTL_TMR_CONTINUE:
      tmr_running = 1;
      return 0;
      break;

    case SNDCTL_TMR_TIMEBASE:
      {
	int             val = IOCTL_IN (arg);

	if (val)
	  {
	    if (val < 1)
	      val = 1;
	    if (val > 1000)
	      val = 1000;
	    curr_timebase = val;
	  }

	return IOCTL_OUT (arg, curr_timebase);
      }
      break;

    case SNDCTL_TMR_TEMPO:
      {
	int             val = IOCTL_IN (arg);

	if (val)
	  {
	    if (val < 8)
	      val = 8;
	    if (val > 250)
	      val = 250;
	    tmr_offs = tmr_ctr;
	    ticks_offs += tmr2ticks (tmr_ctr);
	    tmr_ctr = 0;
	    curr_tempo = val;
	  }

	return IOCTL_OUT (arg, curr_tempo);
      }
      break;

    case SNDCTL_SEQ_CTRLRATE:
      if (IOCTL_IN (arg) != 0)	/* Can't change */
	return RET_ERROR (EINVAL);

      return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60);
      break;

    case SNDCTL_TMR_METRONOME:
      /* NOP */
      break;

    default:;
    }

  return RET_ERROR (EINVAL);
}
Exemple #10
0
static void
handle_send( connecttab* c, struct timeval* tvP )
    {
    int sz, coast;
    ClientData client_data;
    time_t elapsed;
    httpd_conn* hc = c->hc;

    /* Do we need to write the headers first? */
    if ( hc->responselen == 0 )
	{
	/* No, just write the file. */
	sz = write(
	    hc->conn_fd, &(hc->file_address[c->bytes_sent]),
	    MIN( c->bytes_to_send - c->bytes_sent, c->limit ) );
	}
    else
	{
	/* Yes.  We'll combine headers and file into a single writev(),
	** hoping that this generates a single packet.
	*/
	struct iovec iv[2];

	iv[0].iov_base = hc->response;
	iv[0].iov_len = hc->responselen;
	iv[1].iov_base = &(hc->file_address[c->bytes_sent]);
	iv[1].iov_len = MIN( c->bytes_to_send - c->bytes_sent, c->limit );
	sz = writev( hc->conn_fd, iv, 2 );
	}

    if ( sz == 0 ||
	 ( sz < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN ) ) )
	{
	/* This shouldn't happen, but some kernels, e.g.
	** SunOS 4.1.x, are broken and select() says that
	** O_NDELAY sockets are always writable even when
	** they're actually not.
	**
	** Current workaround is to block sending on this
	** socket for a brief adaptively-tuned period.
	** Fortunately we already have all the necessary
	** blocking code, for use with throttling.
	*/
	c->wouldblock_delay += MIN_WOULDBLOCK_DELAY;
	c->conn_state = CNST_PAUSING;
	fdwatch_del_fd( hc->conn_fd );
	client_data.p = c;
	c->wakeup_timer = tmr_create(
	    tvP, wakeup_connection, client_data, c->wouldblock_delay, 0 );
	if ( c->wakeup_timer == (Timer*) 0 )
	    {
	    syslog( LOG_CRIT, "tmr_create(wakeup_connection) failed" );
	    exit( 1 );
	    }
	return;
	}
    if ( sz < 0 )
	{
	/* Something went wrong, close this connection.
	**
	** If it's just an EPIPE, don't bother logging, that
	** just means the client hung up on us.
	**
	** On some systems, write() occasionally gives an EINVAL.
	** Dunno why, something to do with the socket going
	** bad.  Anyway, we don't log those either.
	**
	** And ECONNRESET isn't interesting either.
	*/
	if ( errno != EPIPE && errno != EINVAL && errno != ECONNRESET )
	    syslog( LOG_ERR, "write - %m sending %.80s", hc->encodedurl );
	clear_connection( c, tvP );
	return;
	}

    /* Ok, we wrote something. */
    tmr_reset( tvP, c->idle_send_timer );
    /* Was this a headers + file writev()? */
    if ( hc->responselen > 0 )
	{
	/* Yes; did we write only part of the headers? */
	if ( sz < hc->responselen )
	    {
	    /* Yes; move the unwritten part to the front of the buffer. */
	    int newlen = hc->responselen - sz;
	    (void) memcpy( hc->response, &(hc->response[sz]), newlen );
	    hc->responselen = newlen;
	    sz = 0;
	    }
	else
	    {
	    /* Nope, we wrote the full headers, so adjust accordingly. */
	    sz -= hc->responselen;
	    hc->responselen = 0;
	    }
	}
    /* And update how much of the file we wrote. */
    c->bytes_sent += sz;
    c->hc->bytes_sent += sz;

    /* Are we done? */
    if ( c->bytes_sent >= c->bytes_to_send )
	{
	/* This conection is finished! */
	clear_connection( c, tvP );
	return;
	}

    /* Tune the (blockheaded) wouldblock delay. */
    if ( c->wouldblock_delay > MIN_WOULDBLOCK_DELAY )
	c->wouldblock_delay -= MIN_WOULDBLOCK_DELAY;

    /* If we're throttling, check if we're sending too fast. */
    if ( c->limit != THROTTLE_NOLIMIT )
	{
	elapsed = tvP->tv_sec - c->started_at;
	if ( elapsed == 0 || c->hc->bytes_sent / elapsed > c->limit )
	    {
	    c->conn_state = CNST_PAUSING;
	    fdwatch_del_fd( hc->conn_fd );
	    /* When should we send the next c->limit bytes
	    ** to get back on schedule?  If less than a second
	    ** (integer math rounding), use 1/8 second.
	    */
	    coast = ( c->hc->bytes_sent + c->limit ) / c->limit - elapsed;
	    client_data.p = c;
	    c->wakeup_timer = tmr_create(
		tvP, wakeup_connection, client_data,
		coast ? ( coast * 1000L ) : 125L, 0 );
	    if ( c->wakeup_timer == (Timer*) 0 )
		{
		syslog( LOG_CRIT, "tmr_create(wakeup_connection) failed" );
		exit( 1 );
		}
	    }
	}
    }