aboutsummaryrefslogblamecommitdiffstats
path: root/libglouglou/sendbuf.c
blob: 1b8c7a2b15cbc4ab9a12983f0f7397c74f4c3ed1 (plain) (tree)
1
2
3
4
5
6
7


                   

                    

                                                     





                   

                
                                                                      
                                                                 
 




















                                                        

    

                           


    
                                  
 






                                            


  






                                                           


                                                         
 

                                                             
 
                    




                                                  


                                                     
                                                
 
                    
 


                                                         
 

                                                   
 
                     


  
                         

                                                                        
                                      
   

                                   
 





















                                                                 

 




          
           

                                                   
                             
 


                                                        
 
#include <stdlib.h>
#include <string.h>

#include "sendbuf.h"

static void cb_timer(evutil_socket_t, short, void *);

/*
 * Public
 */

/*
 * Create a sendbuf
 */
struct sendbuf *
sendbuf_new(struct event_base *ev_base, int buffer_size, int msec_max,
	    int (*send_func)(void *, int, void *), void *usrdata)
{
	struct sendbuf *sbuf = NULL;
	struct event *ev_timer;

	sbuf = calloc(1, sizeof(struct sendbuf));
	if (!sbuf)
		return NULL;
	sbuf->ev_base = ev_base;
	sbuf->msec_max = msec_max;
	sbuf->buffer_size = buffer_size;
	sbuf->send_func = send_func;
	sbuf->usrdata = usrdata;
	sbuf->buffer = malloc(sbuf->buffer_size);
	if (!sbuf->buffer)
		goto err;

	ev_timer = evtimer_new(ev_base, cb_timer, sbuf);
	sbuf->ev_timer = ev_timer;
	sbuf->ev_timer_tv.tv_usec = msec_max * 1000;
	evtimer_add(ev_timer, &sbuf->ev_timer_tv);

	return sbuf;

err:
	sendbuf_free(sbuf);
	return NULL;
}

void
sendbuf_free(struct sendbuf *sbuf)
{
	if (sbuf->ev_timer)
		event_del(sbuf->ev_timer);
	if (sbuf->buffer && sbuf->send_func)
		sendbuf_flush(sbuf);
	if (sbuf->buffer)
		free(sbuf->buffer);
	free(sbuf);
}

/*
 * Append to the token buffer data to be sent
 * uses a memcpy, in contrary to sendbuf_gettoken().
 * return size on success, -1 on error
 */
int
sendbuf_append(struct sendbuf *sbuf, void *token, int size)
{
	if (sbuf->buffer_pos + size >= sbuf->buffer_size)
		if (sendbuf_flush(sbuf) == -1)
			return -1;

	memcpy(sbuf->buffer + sbuf->buffer_pos, token, size);
	sbuf->buffer_pos = sbuf->buffer_pos + size;

	return size;
}

/*
 * Returns a token buffer to write data to be sent
 * avoids memcpy, in contrary to sendbuf_append().
 * might return NULL if the sendbuf is temporary full
 */
void *
sendbuf_gettoken(struct sendbuf *sbuf, int size)
{
	void *token;

	if (sbuf->buffer_pos + size >= sbuf->buffer_size)
		if (sendbuf_flush(sbuf) == -1)
			return NULL;

	token = sbuf->buffer + sbuf->buffer_pos;
	sbuf->buffer_pos = sbuf->buffer_pos + size;

	return token;
}

/*
 * Send buffer immediatly
 * Note that you can still add data to the buffer even if flushing is in
 * progress
 * returns 0 on success or -1 on error
 */
int
sendbuf_flush(struct sendbuf *sbuf)
{
	int tosend, sent;

	if (sbuf->buffer_pos == 0)
		return 0;

	sbuf->flushing = 1;

	tosend = sbuf->buffer_pos - sbuf->flushing_pos;
	sent = sbuf->send_func(sbuf->buffer + sbuf->flushing_pos,
			tosend, sbuf->usrdata);
	if (sent == -1) {
		// XXX handle error
		return -1;
	} else if (sent < tosend) {
		sbuf->flushing_pos = sbuf->flushing_pos + sent;
		return -1;
	}
	sbuf->buffer_pos = 0;

	sbuf->flushing = 0;
	sbuf->flushing_pos = 0;
	return 0;
}


/*
 * Private
 */

static void
cb_timer(evutil_socket_t fd, short what, void *arg)
{
	struct sendbuf *sbuf;

	sbuf = arg;
	sendbuf_flush(sbuf);
	evtimer_add(sbuf->ev_timer, &sbuf->ev_timer_tv);
}