diff --git a/.gitignore b/.gitignore index 0f3bd91..8639914 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ gmon.out test-driver /assets/html/_documentation.html tags +trio.h diff --git a/include/tr/interface/socket.h b/include/tr/interface/socket.h new file mode 100644 index 0000000..04f3a87 --- /dev/null +++ b/include/tr/interface/socket.h @@ -0,0 +1,52 @@ +/** + * \file + * Inteface for common socket operations. (bind, send, recv) + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TR_INTERFACE_SOCKET_H__ +#define __TR_INTERFACE_SOCKET_H__ + +#include + +#include "trbase.h" +#include "tr/remote_data.h" + +typedef int (* fptr_TR_socketBind)(void *); +typedef int (* fptr_TR_socketConnect)(void *); +typedef TR_RemoteData (* fptr_TR_socketRecv)(void *, size_t); +typedef ssize_t (* fptr_TR_socketSend)(void *, TR_RemoteData); + +TR_INTERFACE(TR_Socket) { + TR_IFID; + fptr_TR_socketBind bind; + fptr_TR_socketConnect connect; + fptr_TR_socketRecv recv; + fptr_TR_socketSend send; +}; + +extern int TR_socketBindAction(void *); +extern int TR_socketConnectAction(void *); +extern TR_RemoteData TR_socketRecv(void *, size_t); +extern ssize_t TR_socketSend(void *, TR_RemoteData); + +#endif // __TR_INTERFACE_SOCKET_H__ + +// vim: set ts=4 sw=4: diff --git a/include/tr/remote_data.h b/include/tr/remote_data.h new file mode 100644 index 0000000..2433b98 --- /dev/null +++ b/include/tr/remote_data.h @@ -0,0 +1,48 @@ +/** + * \file + * Abstraction layer above BSD sockets. Capsules and simplifies connect + * accept and listen. + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TR_REMOTE_DATA_H__ +#define __TR_REMOTE_DATA_H__ + +#include +#include +#include + +#include "trbase.h" + +TR_CLASS(TR_RemoteData) { + unsigned char * data; + size_t ndata; + struct sockaddr_in addr; // for now... should be more generic + socklen_t addrlen; +}; + +extern TR_RemoteData TR_emptyRemoteData; + +void TR_remoteDataSetData(TR_RemoteData, unsigned char *, size_t); + +#endif // __TR_REMOTE_DATA_H__ + +// vim: set ts=4 sw=4: + diff --git a/include/tr/socket.h b/include/tr/socket.h index 932c1e5..78c0042 100644 --- a/include/tr/socket.h +++ b/include/tr/socket.h @@ -1,7 +1,8 @@ /** * \file * Abstraction layer above BSD sockets. Capsules and simplifies connect - * accept and listen. + * accept and listen for TCP and UDP sockets. + * It also provides a mostly unified interface to both types of sockets. * * \author Georg Hopp * @@ -25,24 +26,82 @@ #ifndef __TR_SOCKET_H__ #define __TR_SOCKET_H__ -#include // for in_port_t +#include +#include +#include +#include + +//#include // for in_port_t #include "trbase.h" +#include "tr/interface/socket.h" #include "tr/logger.h" -TR_CLASS(TR_Sock) { - TR_Logger log; - in_port_t port; - struct sockaddr_in addr; - int handle; +typedef enum TR_e_socket_fin { + TR_FIN_NO = 0, + TR_FIN_RD = 1, + TR_FIN_WR = 2, + TR_FIN_RDWR = 3 +} TR_SocketFin; + +TR_CLASS(TR_Socket) { + TR_Logger log; + int flags; + int type; + char * host; + char * cname; + int port; + time_t ttl; + struct sockaddr_in addr; // for now... should be more generic. + socklen_t addrlen; + int handle; + TR_SocketFin fin_state; +}; + +#define TR_socketLog(socket) (((TR_Socket)(socket))->log) +#define TR_socketFlags(socket) (((TR_Socket)(socket))->flags) +#define TR_socketType(socket) (((TR_Socket)(socket))->type) +#define TR_socketHost(socket) (((TR_Socket)(socket))->host) +#define TR_socketPort(socket) (((TR_Socket)(socket))->port) +#define TR_socketCname(socket) (((TR_Socket)(socket))->cname) +#define TR_socketTtl(socket) (((TR_Socket)(socket))->ttl) +#define TR_socketAddr(socket) (((TR_Socket)(socket))->addr) +#define TR_socketAddrlen(socket) (((TR_Socket)(socket))->addrlen) +#define TR_socketHandle(socket) (((TR_Socket)(socket))->handle) +#define TR_socketFinState(socket) (((TR_Socket)(socket))->fin_state) +#define TR_socketFinRd(socket) ((TR_socketFinState((socket)) & 1) == 1) +#define TR_socketFinWr(socket) ((TR_socketFinState((socket)) & 2) == 2) +#define TR_socketFinRdWr(socket) ((TR_socketFinState((socket)) & 3) == 3) + +#define TR_socketGetIp(socket) (TR_socketAddr(socket).sin_addr.s_addr) +#define TR_socketGetIpStr(socket) (inet_ntoa(TR_socketGetIp(socket))) + +TR_CLASS(TR_TcpSocket) { + TR_EXTENDS(TR_Socket); + int listen; + int connected; }; -void TR_socketConnect(TR_Sock this, const char * addr, char (*)[16]); -void TR_socketListen(TR_Sock this, int backlog); -TR_Sock TR_socketAccept(TR_Sock this, char (*remoteAddr)[16]); -void TR_socketNonblock(TR_Sock this); -in_addr_t TR_socketGetIp(TR_Sock this); -const char * const TR_socketGetIpStr(TR_Sock this); +TR_CLASS(TR_UdpSocket) { + TR_EXTENDS(TR_Socket); +}; + +typedef int (* TR_socketAction_fptr)(void *); + +int TR_socketInit(TR_Socket, TR_socketAction_fptr); +TR_SocketFin TR_socketShutdownRead(TR_Socket); +TR_SocketFin TR_socketShutdownWrite(TR_Socket); +TR_SocketFin TR_socketShutdown(TR_Socket); +void TR_socketClose(TR_Socket); +void TR_socketNonblock(TR_Socket); + +#define TR_socketBind(socket) \ + (TR_socketInit((socket), TR_socketBindAction)) + +TR_TcpSocket TR_socketAccept(TR_TcpSocket); + +#define TR_socketConnect(socket) \ + (TR_socketInit((socket), TR_socketConnectAction)) #endif // __TR_SOCKET_H__ diff --git a/include/trio.h b/include/trio.h index ad1dd59..2c7c7b5 100644 --- a/include/trio.h +++ b/include/trio.h @@ -1,10 +1,10 @@ #ifndef __TR_IO_H__ #define __TR_IO_H__ -#include "tr/logger.h" #include "tr/socket.h" +#include "tr/remote_data.h" #include "tr/stream.h" -#include "tr/interface/logger.h" +#include "tr/interface/socket.h" #include "tr/interface/reader.h" #include "tr/interface/writer.h" diff --git a/src/Makefile.am b/src/Makefile.am index 8592cf4..13b930f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,12 +7,18 @@ TRIO = stream.c \ read.c \ write.c \ socket.c \ - accept.c \ - connect.c \ - listen.c \ - get_ip.c \ - get_ip_str.c \ - nonblock.c \ + socket_init.c \ + socket_accept.c \ + socket_nonblock.c \ + socket_close.c \ + socket_shutdown.c \ + socket_shutdown_read.c \ + socket_shutdown_write.c \ + tcp_socket.c \ + udp_socket.c \ + remote_data.c \ + remote_data_set_data.c \ + i_socket.c \ i_reader.c \ i_writer.c diff --git a/src/i_socket.c b/src/i_socket.c new file mode 100644 index 0000000..de543ef --- /dev/null +++ b/src/i_socket.c @@ -0,0 +1,115 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "tr/interface/socket.h" +#include "tr/remote_data.h" +#include "trbase.h" + +TR_CREATE_INTERFACE(TR_Socket, 4); + +int +TR_socketBindAction(void * _this) +{ + int callret; + + TR_RETCALL(_this, TR_Socket, bind, callret); + + return callret; +} + +int +TR_socketConnectAction(void * _this) +{ + int callret; + + TR_RETCALL(_this, TR_Socket, connect, callret); + + return callret; +} + +TR_RemoteData +TR_socketRecv(void * _this, size_t size) +{ + TR_RemoteData remote_data; + + TR_RETCALL(_this, TR_Socket, recv, remote_data, size); + + if (remote_data->ndata < 0) { + switch (errno) { + case (EAGAIN|EWOULDBLOCK): + TR_delete(remote_data); + return TR_emptyRemoteData; + + case EINTR: + case ENOMEM: + // these are fatal and should lead to a shutown + // of the whole application... + TR_delete(remote_data); + return NULL; + + default: + TR_delete(remote_data); + return NULL; + } + } else if (remote_data->ndata == 0) { + // this is a remote close... + TR_delete(remote_data); + return NULL; + } + + return remote_data; +} + +ssize_t +TR_socketSend(void * _this, TR_RemoteData data) +{ + ssize_t size; + + TR_RETCALL(_this, TR_Socket, send, size, data); + TR_delete(data); + + if (size < 0) { + switch (errno) { + case EINTR: + case ENOMEM: + // these are fatal and should lead to a shutown + // of the whole application... + return 0; + + case (EAGAIN|EWOULDBLOCK): + return -1; + + case ECONNRESET: + // this is a remote close... + return -2; + + default: + return -2; + } + } + + return size; +} + +// vim: set ts=4 sw=4: diff --git a/src/listen.c b/src/listen.c deleted file mode 100644 index bf4ed69..0000000 --- a/src/listen.c +++ /dev/null @@ -1,59 +0,0 @@ -/** - * \file - * - * \author Georg Hopp - * - * \copyright - * Copyright © 2012 Georg Hopp - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include // for atoi() and exit() -#include // for errno - -#include "tr/socket.h" -#include "tr/logger.h" - - -void -TR_socketListen(TR_Sock this, int backlog) -{ - (this->addr).sin_family = AF_INET; // Internet address family - (this->addr).sin_addr.s_addr = htonl(INADDR_ANY); // Any incoming interface - //(this->addr).sin_addr.s_addr = inet_addr("127.0.0.1"); // Any incoming interface - (this->addr).sin_port = htons(this->port); // Local port - - /** - * Bind to the local address - */ - if (-1 == bind(this->handle, (struct sockaddr *) &(this->addr), sizeof(this->addr))) { - TR_loggerLog(this->log, TR_LOGGER_CRIT, - "error binding socket: %s - service terminated", - strerror(errno)); - exit(EXIT_FAILURE); - } - - /** - * Mark the socket so it will listen for incoming connections - */ - if (-1 == listen(this->handle, backlog)) { - TR_loggerLog(this->log, TR_LOGGER_CRIT, - "error binding socket: %s - service terminated", - strerror(errno)); - exit(EXIT_FAILURE); - } -} - -// vim: set ts=4 sw=4: diff --git a/src/remote_data.c b/src/remote_data.c new file mode 100644 index 0000000..f7fa475 --- /dev/null +++ b/src/remote_data.c @@ -0,0 +1,66 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "tr/remote_data.h" +#include "trbase.h" + +static +int +remoteDataCtor(void * _this, va_list * params) +{ + TR_RemoteData this = _this; + struct sockaddr * addr_ptr = va_arg(*params, struct sockaddr *); + + this->addrlen = va_arg(*params, socklen_t); + memcpy(&(this->addr), addr_ptr, this->addrlen); + + this->data = NULL; + this->ndata = 0; + + return 0; +} + +static +void +remoteDataDtor(void * _this) +{ + TR_RemoteData this = _this; + + TR_MEM_FREE(this->data); +} + +TR_INIT_IFACE(TR_Class, remoteDataCtor, remoteDataDtor, NULL); +TR_CREATE_CLASS(TR_RemoteData, NULL, TR_IF(TR_Class)); + +TR_INSTANCE(TR_RemoteData, TR_emptyRemoteData, NULL, 0, NULL, NULL); + +// vim: set ts=4 sw=4: diff --git a/src/remote_data_set_data.c b/src/remote_data_set_data.c new file mode 100644 index 0000000..d2862e0 --- /dev/null +++ b/src/remote_data_set_data.c @@ -0,0 +1,43 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include // for atoi() and exit() +#include // for errno +#include +#include + +#include "tr/remote_data.h" +#include "tr/logger.h" + +void +TR_remoteDataSetData(TR_RemoteData this, unsigned char * data, size_t size) +{ + if (this->data && TR_getSize(this->data) < size) { + TR_MEM_FREE(this->data); + } + + this->data = TR_malloc(size); + this->ndata = size; + memcpy(this->data, data, size); +} + +// vim: set ts=4 sw=4: diff --git a/src/socket.c b/src/socket.c index a39f5fc..048be11 100644 --- a/src/socket.c +++ b/src/socket.c @@ -23,7 +23,14 @@ #include #include #include +#include +#include +#include +#include +#include + +#include "tr/remote_data.h" #include "tr/socket.h" #include "tr/logger.h" #include "trbase.h" @@ -32,30 +39,15 @@ static int socketCtor(void * _this, va_list * params) { - TR_Sock this = _this; - int reUse = 1; //! \todo make this configurable - int port; - - this->log = va_arg(* params, TR_Logger); - port = va_arg(* params, int); - - //! if port is -1 do not initialize the socket. (Used with accept) - if (-1 == port) { - return 0; - } else { - this->port = port; - } + TR_Socket this = _this; - //! Create socket for incoming connections - if (-1 == (this->handle = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))) { - TR_loggerLog(this->log, TR_LOGGER_CRIT, - "error opening socket: %s - service terminated", - strerror(errno)); - return -1; - } - - //! Make the socket REUSE a TIME_WAIT socket - setsockopt(this->handle, SOL_SOCKET, SO_REUSEADDR, &reUse, sizeof(reUse)); + this->type = 0; + this->handle = -1; + this->log = va_arg(*params, TR_Logger); + this->host = va_arg(*params, char*); + this->port = va_arg(*params, int); + this->flags = va_arg(*params, int); + this->fin_state = TR_FIN_RDWR; return 0; } @@ -64,15 +56,33 @@ static void socketDtor(void * _this) { - TR_Sock this = _this; + TR_Socket this = _this; + + TR_MEM_FREE(this->cname); if (STDERR_FILENO < this->handle) { - shutdown(this->handle, SHUT_RDWR); - close(this->handle); + TR_socketClose(this); + } +} + +static +int +socketBind(void * _this) +{ + TR_Socket this = _this; + int state; + + state = bind(this->handle, (struct sockaddr *)&(this->addr), this->addrlen); + + if (-1 == state) { + perror("bind"); } + + return state; } TR_INIT_IFACE(TR_Class, socketCtor, socketDtor, NULL); -TR_CREATE_CLASS(TR_Sock, NULL, TR_IF(TR_Class)); +TR_INIT_IFACE(TR_Socket, socketBind, NULL, NULL); +TR_CREATE_CLASS(TR_Socket, NULL, TR_IF(TR_Class), TR_IF(TR_Socket)); // vim: set ts=4 sw=4: diff --git a/src/accept.c b/src/socket_accept.c similarity index 51% rename from src/accept.c rename to src/socket_accept.c index e1872a5..cf76ef5 100644 --- a/src/accept.c +++ b/src/socket_accept.c @@ -20,38 +20,48 @@ * along with this program. If not, see . */ +#define _POSIX_SOURCE 1 + +#include // for atoi() and exit() #include // for errno +#include #include #include -#include "trbase.h" +#include +#include +#include +#include +#include + #include "tr/socket.h" #include "tr/logger.h" -TR_Sock -TR_socketAccept(TR_Sock this, char (*remoteAddr)[16]) +TR_TcpSocket +TR_socketAccept(TR_TcpSocket this) { - TR_Sock sock; // Socket for client - unsigned int len; // Length of client address data structure + TR_Socket remote = TR_new(TR_TcpSocket, TR_socketLog(this), NULL, 0, 0); + //int flags; - // Set the size of the in-out parameter - len = sizeof(this->addr); + remote->handle = accept( + TR_socketHandle(this), + (struct sockaddr *)&(remote->addr), + &(remote->addrlen)); - sock = TR_new(TR_Sock, this->log, -1); + //flags = fcntl(remote->handle, F_GETFL, 0); + //fcntl(remote->handle, F_SETFL, flags | O_NONBLOCK); - // Wait for a client to connect - sock->handle = accept(this->handle, (struct sockaddr *) &(sock->addr), &len); - if (-1 == sock->handle) { - TR_loggerLog(this->log, TR_LOGGER_WARNING, - "error accepting connection: %s", strerror(errno)); - } else { - strcpy(*remoteAddr, inet_ntoa((sock->addr).sin_addr)); + remote->host = TR_strdup(inet_ntoa(remote->addr.sin_addr)); + remote->port = ntohs(remote->addr.sin_port); + remote->type = TR_socketType(this); + remote->flags = TR_socketFlags(this); - //loggerLog(this->log, LOGGER_INFO, - // "handling client %s\n", inet_ntoa((sock->addr).sin_addr)); - } + if (-1 == remote->handle) { + perror("accept"); + TR_delete(remote); + } - return sock; + return (TR_TcpSocket)remote; } // vim: set ts=4 sw=4: diff --git a/src/get_ip.c b/src/socket_close.c similarity index 78% rename from src/get_ip.c rename to src/socket_close.c index 8566c6b..a632d6c 100644 --- a/src/get_ip.c +++ b/src/socket_close.c @@ -20,16 +20,20 @@ * along with this program. If not, see . */ -#include +#include // for atoi() and exit() +#include // for errno +#include +#include -#include "trbase.h" #include "tr/socket.h" #include "tr/logger.h" -in_addr_t -TR_socketGetIp(TR_Sock this) +void +TR_socketClose(TR_Socket this) { - return this->addr.sin_addr.s_addr; + TR_socketShutdown(this); + close(this->handle); + this->handle = -1; } // vim: set ts=4 sw=4: diff --git a/src/socket_init.c b/src/socket_init.c new file mode 100644 index 0000000..5400084 --- /dev/null +++ b/src/socket_init.c @@ -0,0 +1,103 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define _POSIX_SOURCE 1 + +#include // for atoi() and exit() +#include // for errno +#include +#include +#include + +#include +#include +#include + +#include "tr/socket.h" +#include "tr/logger.h" + +int +TR_socketInit(TR_Socket this, TR_socketAction_fptr action) +{ + struct addrinfo hint; + struct addrinfo * info, * current_info; + char port_str[6]; + + hint.ai_socktype = this->type; + hint.ai_flags = this->flags; + hint.ai_family = AF_UNSPEC; + hint.ai_protocol = 0; + hint.ai_addrlen = 0; + hint.ai_canonname = NULL; + hint.ai_addr = NULL; + hint.ai_next = NULL; + + sprintf(port_str, "%u", this->port); + if (0 != getaddrinfo(this->host, port_str, &hint, &info)) { + // TODO error handling... + return FALSE; + } + + current_info = info; + for ( + current_info = info; + current_info; + current_info = current_info->ai_next) + { + this->handle = socket( + current_info->ai_family, + current_info->ai_socktype, + current_info->ai_protocol); + + if (-1 == this->handle) { + continue; + } + + this->addrlen = current_info->ai_addrlen; + memcpy(&(this->addr), current_info->ai_addr, this->addrlen); + + if (0 == action(this)) { + break; // success / open and bind or open and connect... + } + + close(this->handle); + this->handle = -1; + } + + if (NULL != current_info) { + int reUse = 1; //! \todo make this configurable + //int flags = fcntl(this->handle, F_GETFL, 0); + + //fcntl(this->handle, F_SETFL, flags | O_NONBLOCK); + this->cname = TR_strdup(current_info->ai_canonname); + this->fin_state = TR_FIN_NO; + + //! Make the socket REUSE a TIME_WAIT socket + setsockopt(this->handle, SOL_SOCKET, SO_REUSEADDR, &reUse, sizeof(reUse)); + } + + freeaddrinfo(info); + + return TRUE; +} + +// vim: set ts=4 sw=4: diff --git a/src/nonblock.c b/src/socket_nonblock.c similarity index 96% rename from src/nonblock.c rename to src/socket_nonblock.c index f2a10f7..0d9873b 100644 --- a/src/nonblock.c +++ b/src/socket_nonblock.c @@ -28,7 +28,7 @@ #include "tr/logger.h" void -TR_socketNonblock(TR_Sock this) +TR_socketNonblock(TR_Socket this) { int flags = fcntl(this->handle, F_GETFL, 0); fcntl(this->handle, F_SETFL, flags | O_NONBLOCK); diff --git a/src/get_ip_str.c b/src/socket_shutdown.c similarity index 71% rename from src/get_ip_str.c rename to src/socket_shutdown.c index 3c2f911..0e6b6fb 100644 --- a/src/get_ip_str.c +++ b/src/socket_shutdown.c @@ -20,16 +20,25 @@ * along with this program. If not, see . */ -#include +#include // for atoi() and exit() +#include // for errno +#include +#include -#include "trbase.h" #include "tr/socket.h" #include "tr/logger.h" -const char * const -TR_socketGetIpStr(TR_Sock this) +TR_SocketFin +TR_socketShutdown(TR_Socket this) { - return inet_ntoa(this->addr.sin_addr); + if (TR_socketFinRdWr(this)) { + return this->fin_state; + } + + shutdown(this->handle, SHUT_RDWR); + this->fin_state |= TR_FIN_RDWR; + + return this->fin_state; } // vim: set ts=4 sw=4: diff --git a/src/connect.c b/src/socket_shutdown_read.c similarity index 54% rename from src/connect.c rename to src/socket_shutdown_read.c index e1b9037..a9c2ff3 100644 --- a/src/connect.c +++ b/src/socket_shutdown_read.c @@ -22,32 +22,26 @@ #include // for atoi() and exit() #include // for errno +#include +#include #include "tr/socket.h" #include "tr/logger.h" -void -TR_socketConnect(TR_Sock this, const char * addr, char (*remoteAddr)[16]) +TR_SocketFin +TR_socketShutdownRead(TR_Socket this) { - inet_pton(AF_INET, addr, &((this->addr).sin_addr)); - (this->addr).sin_family = AF_INET; // Internet address family - (this->addr).sin_port = htons(this->port); // Local port + if (TR_socketFinRd(this)) { + return this->fin_state; + } - if (-1 == connect( - this->handle, - (struct sockaddr*) &(this->addr), - sizeof(this->addr))) - { - TR_loggerLog(this->log, TR_LOGGER_CRIT, - "error connection socket: %s - service terminated", - strerror(errno)); - exit(EXIT_FAILURE); - } else { - strcpy(*remoteAddr, inet_ntoa((this->addr).sin_addr)); + if (0 == shutdown(this->handle, SHUT_RD)) { + this->fin_state |= TR_FIN_RD; + } else { + this->fin_state |= TR_FIN_RDWR; + } - TR_loggerLog(this->log, TR_LOGGER_INFO, - "handling connection %s\n", inet_ntoa((this->addr).sin_addr)); - } + return this->fin_state; } // vim: set ts=4 sw=4: diff --git a/src/socket_shutdown_write.c b/src/socket_shutdown_write.c new file mode 100644 index 0000000..6eba445 --- /dev/null +++ b/src/socket_shutdown_write.c @@ -0,0 +1,47 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include // for atoi() and exit() +#include // for errno +#include +#include + +#include "tr/socket.h" +#include "tr/logger.h" + +TR_SocketFin +TR_socketShutdownWrite(TR_Socket this) +{ + if (TR_socketFinWr(this)) { + return this->fin_state; + } + + if (0 == shutdown(this->handle, SHUT_WR)) { + this->fin_state |= TR_FIN_WR; + } else { + this->fin_state |= TR_FIN_RDWR; + } + + return this->fin_state; +} + +// vim: set ts=4 sw=4: diff --git a/src/tcp_socket.c b/src/tcp_socket.c new file mode 100644 index 0000000..293b41d --- /dev/null +++ b/src/tcp_socket.c @@ -0,0 +1,121 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "tr/socket.h" +#include "tr/logger.h" +#include "trbase.h" + +static +int +tcpSocketCtor(void * _this, va_list * params) +{ + TR_TcpSocket this = _this; + + TR_PARENTCALL(_this, TR_Class, ctor, params); + + TR_socketType(this) = SOCK_STREAM; + this->listen = FALSE; + this->connected = FALSE; + + return 0; +} + +static +int +tcpSocketBind(void * _this) +{ + TR_TcpSocket this = _this; + int bind_ret; + + TR_PARENTRETCALL(_this, TR_Socket, bind, bind_ret); + + if (bind_ret != 0) { + return -1; + } + + if (listen(TR_socketHandle(this), 128) != 0) { + // error + return -1; + } + this->listen = TRUE; + + return 0; +} + +static +int +tcpSocketConnect(void * _this) +{ + TR_Socket this = _this; + + return connect( + this->handle, + (struct sockaddr *)&(this->addr), + this->addrlen); +} + +static +TR_RemoteData +tcpSocketRecv(TR_Socket this, size_t size) +{ + TR_RemoteData rdata = TR_new(TR_RemoteData, &(this->addr), this->addrlen); + unsigned char buffer[size]; + ssize_t received; + + received = recv(this->handle, buffer, size, this->flags); + + if (-1 == received) { + perror("recv"); + TR_delete(rdata); + } else { + TR_remoteDataSetData(rdata, buffer, received); + } + + return rdata; +} + +static +ssize_t +tcpSocketSend(TR_Socket this, TR_RemoteData data) +{ + return send(this->handle, data->data, data->ndata, this->flags); +} + +TR_INIT_IFACE(TR_Class, tcpSocketCtor, NULL, NULL); +TR_INIT_IFACE( + TR_Socket, + tcpSocketBind, + tcpSocketConnect, + tcpSocketRecv, + tcpSocketSend); +TR_CREATE_CLASS(TR_TcpSocket, TR_Socket, TR_IF(TR_Class), TR_IF(TR_Socket)); + +// vim: set ts=4 sw=4: diff --git a/src/udp_socket.c b/src/udp_socket.c new file mode 100644 index 0000000..6f02fd5 --- /dev/null +++ b/src/udp_socket.c @@ -0,0 +1,102 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "tr/socket.h" +#include "tr/logger.h" +#include "trbase.h" + +static +int +udpSocketCtor(void * _this, va_list * params) +{ + TR_Socket this = _this; + + TR_PARENTCALL(_this, TR_Class, ctor, params); + + this->type = SOCK_DGRAM; + + return 0; +} + +static +TR_RemoteData +udpSocketRecv(TR_Socket this, size_t size) +{ + TR_RemoteData rdata; + struct sockaddr_in addr; + socklen_t addrlen = this->addrlen; + unsigned char buffer[size]; + ssize_t received; + + received = recvfrom( + this->handle, + buffer, + size, + this->flags, + (struct sockaddr *)&addr, + &addrlen); + + if (-1 == received) { + perror("recvfrom"); + } else { + rdata = TR_new(TR_RemoteData, &addr, addrlen); + TR_remoteDataSetData(rdata, buffer, received); + } + + return rdata; +} + +static +ssize_t +udpSocketSend(TR_Socket this, TR_RemoteData data) +{ + ssize_t send; + + send = sendto( + this->handle, + data->data, + data->ndata, + this->flags, + (struct sockaddr *)&(data->addr), + data->addrlen); + + if (-1 == send) { + perror("sendto"); + } + + return send; +} + +TR_INIT_IFACE(TR_Class, udpSocketCtor, NULL, NULL); +TR_INIT_IFACE(TR_Socket, NULL, NULL, udpSocketRecv, udpSocketSend); +TR_CREATE_CLASS(TR_UdpSocket, TR_Socket, TR_IF(TR_Class), TR_IF(TR_Socket)); + +// vim: set ts=4 sw=4: diff --git a/trio.h b/trio.h deleted file mode 100644 index 446b203..0000000 --- a/trio.h +++ /dev/null @@ -1,93 +0,0 @@ -/* trio.h. Generated from trio.h.in by configure. */ -/* trio.h.in. Generated from configure.ac by autoheader. */ - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the `memset' function. */ -/* #undef HAVE_MEMSET */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STDARG_H 1 - -/* Define to 1 if stdbool.h conforms to C99. */ -/* #undef HAVE_STDBOOL_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDIO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYSLOG_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if the system has the type `_Bool'. */ -#define HAVE__BOOL 1 - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#define LT_OBJDIR ".libs/" - -/* Name of package */ -#define PACKAGE "libtrio" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "Georg Hopp " - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "libtrio" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libtrio 0.0.0" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "libtrio" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "0.0.0" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Version number of package */ -#define VERSION "0.0.0" - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -/* #undef inline */ -#endif - -/* Define to `int' if does not define. */ -/* #undef pid_t */ - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */