blob: 09a5b5743f4813cd7e9262c217e06185caab8cb0 [file] [log] [blame]
/**
* Copyright (C) 2013 Regents of the University of California.
* @author: Jeff Thompson <jefft0@remap.ucla.edu>
* See COPYING for copyright and distribution information.
*/
#include "socket-transport.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <poll.h>
#include "../util/ndn_memory.h"
ndn_Error ndn_SocketTransport_connect(struct ndn_SocketTransport *self, ndn_SocketType socketType, char *host, unsigned short port)
{
if (self->socketDescriptor >= 0) {
close(self->socketDescriptor);
self->socketDescriptor = -1;
}
struct addrinfo hints;
ndn_memset((uint8_t *)&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
if (socketType == SOCKET_TCP)
hints.ai_socktype = SOCK_STREAM;
else if (socketType == SOCKET_UDP)
hints.ai_socktype = SOCK_DGRAM;
else
return NDN_ERROR_unrecognized_ndn_SocketTransport;
char portString[10];
sprintf(portString, "%d", port);
struct addrinfo *serverInfo;
if (getaddrinfo(host, portString, &hints, &serverInfo) != 0)
return NDN_ERROR_SocketTransport_error_in_getaddrinfo;
// loop through all the results and connect to the first we can
struct addrinfo *p;
int socketDescriptor;
for(p = serverInfo; p != NULL; p = p->ai_next) {
if ((socketDescriptor = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
continue;
if (connect(socketDescriptor, p->ai_addr, p->ai_addrlen) == -1) {
close(socketDescriptor);
continue;
}
break;
}
if (p == NULL) {
freeaddrinfo(serverInfo);
return NDN_ERROR_SocketTransport_cannot_connect_to_socket;
}
freeaddrinfo(serverInfo);
self->socketDescriptor = socketDescriptor;
return NDN_ERROR_success;
}
ndn_Error ndn_SocketTransport_send(struct ndn_SocketTransport *self, uint8_t *data, size_t dataLength)
{
if (self->socketDescriptor < 0)
return NDN_ERROR_SocketTransport_socket_is_not_open;
int nBytes;
while (1) {
if ((nBytes = send(self->socketDescriptor, data, dataLength, 0)) < 0)
return NDN_ERROR_SocketTransport_error_in_send;
if (nBytes >= dataLength)
break;
// Send more.
dataLength -= nBytes;
}
return NDN_ERROR_success;
}
ndn_Error ndn_SocketTransport_receiveIsReady(struct ndn_SocketTransport *self, int *receiveIsReady)
{
// Default to not ready.
*receiveIsReady = 0;
if (self->socketDescriptor < 0)
// The socket is not open. Just silently return.
return NDN_ERROR_success;
struct pollfd pollInfo[1];
pollInfo[0].fd = self->socketDescriptor;
pollInfo[0].events = POLLIN;
int pollResult = poll(pollInfo, 1, 0);
if (pollResult < 0)
return NDN_ERROR_SocketTransport_error_in_poll;
else if (pollResult == 0)
// Timeout, so no data ready.
return NDN_ERROR_success;
else {
if (pollInfo[0].revents & POLLIN)
*receiveIsReady = 1;
}
return NDN_ERROR_success;
}
ndn_Error ndn_SocketTransport_receive
(struct ndn_SocketTransport *self, uint8_t *buffer, size_t bufferLength, size_t *nBytesOut)
{
if (self->socketDescriptor < 0)
return NDN_ERROR_SocketTransport_socket_is_not_open;
int nBytes;
if ((nBytes = recv(self->socketDescriptor, buffer, bufferLength, 0)) == -1)
return NDN_ERROR_SocketTransport_error_in_recv;
*nBytesOut = (size_t)nBytes;
return NDN_ERROR_success;
}
ndn_Error ndn_SocketTransport_close(struct ndn_SocketTransport *self)
{
if (self->socketDescriptor < 0)
// Already closed. Do nothing.
return NDN_ERROR_success;
if (close(self->socketDescriptor) != 0)
return NDN_ERROR_SocketTransport_error_in_close;
self->socketDescriptor = -1;
return NDN_ERROR_success;
}