#include <sys/epoll.h>
#include <curl/curl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int socket_callback(CURL* easy, curl_socket_t s, int action, int* ep, void* socketp);
int debug_callback(CURL* c, curl_infotype type, char* text, size_t bytes, void* p);
size_t write_function(char* ptr, size_t size, size_t nmemb, void* p);

int main()
{
	curl_global_init(CURL_GLOBAL_SSL);
	CURLM* curlm = curl_multi_init();
	int epoll = epoll_create(5);
	
	curl_multi_setopt(curlm, CURLMOPT_SOCKETFUNCTION, socket_callback);
	curl_multi_setopt(curlm, CURLMOPT_SOCKETDATA, &epoll);
	
	CURL* easy = curl_easy_init();
	
	curl_easy_setopt(easy, CURLOPT_URL, "sftp://user:pass@localhost/tmp/file.txt"); // "http://www.google.com" would work
	curl_easy_setopt(easy, CURLOPT_DEBUGFUNCTION, debug_callback);
	curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, write_function);
	
	curl_multi_add_handle(curlm, easy);
	
	while(1)
	{
		struct epoll_event events[5];
		int nfds, dummy;
		
		nfds = epoll_wait(epoll, events, sizeof(events)/sizeof(events[0]), 500);
		
		if(!nfds)
		{
			puts("curl_multi_socket_action - CURL_SOCKET_TIMEOUT");
			curl_multi_socket_action(curlm, CURL_SOCKET_TIMEOUT, 0, &dummy);
		}
		
		int i;
		for(i=0;i<nfds;i++)
		{
			int mask = 0;
			
			if(events[i].events & EPOLLIN)
				mask |= CURL_CSELECT_IN;
			if(events[i].events & EPOLLOUT)
				mask |= CURL_CSELECT_OUT;
			if(events[i].events & (EPOLLERR | EPOLLHUP))
				mask |= CURL_CSELECT_ERR;
			
			printf("curl_multi_socket_action socket=%d\n", events[i].data.fd);
			curl_multi_socket_action(curlm, events[i].data.fd, mask, &dummy);
		}
	}
	
	return 0;
}

size_t write_function(char* ptr, size_t size, size_t nmemb, void* p)
{
	printf("Would write %d bytes\n", size*nmemb);
	return size*nmemb;
}

int debug_callback(CURL* c, curl_infotype type, char* text, size_t bytes, void* p)
{
	char* ztext = malloc(bytes+1);
	memcpy(ztext, text, bytes);
	ztext[bytes] = 0;
	
	printf("DEBUG: %s\n", ztext);
	free(ztext);
	
	return 0;
}

int socket_callback(CURL* easy, curl_socket_t s, int action, int* ep, void* socketp)
{
	struct epoll_event event;
	
	event.events = 0;
	event.data.fd = s;
	
	if(action == CURL_POLL_IN || action == CURL_POLL_INOUT)
		event.events |= EPOLLIN;
	if(action == CURL_POLL_OUT || action == CURL_POLL_INOUT)
		event.events |= EPOLLOUT;
	
	if(action == CURL_POLL_REMOVE)
	{
		printf("remove socket=%d\n", s);
		epoll_ctl(*ep, EPOLL_CTL_DEL, s, 0);
	}
	else
	{
		printf("add/mod socket=%d, action=%d\n", s, action);
		if(epoll_ctl(*ep, EPOLL_CTL_MOD, s, &event))
		{
			if(errno == ENOENT)
			{
				if(epoll_ctl(*ep, EPOLL_CTL_ADD, s, &event))
					return errno;
			}
			else
				return errno;
		}
	}
	
	return 0;
}

