tcp-chat/src/network/socket.c

126 lines
3.7 KiB
C
Executable File

#include "internal.h"
#include "socket.h"
#include <assert.h>
Result(Socket) socket_open_TCP(){
Socket s = socket(AF_INET, SOCK_STREAM, 0);
if(s == -1){
return RESULT_ERROR_SOCKET();
}
return RESULT_VALUE(i, s);
}
void socket_close(Socket s){
#if KN_USE_WINSOCK
closesocket(s);
#else
close(s);
#endif
}
Result(void) socket_shutdown(Socket s, SocketShutdownType direction){
if(shutdown(s, (int)direction) == -1)
return RESULT_ERROR_SOCKET();
return RESULT_VOID;
}
Result(void) socket_bind(Socket s, EndpointIPv4 local_end){
struct sockaddr_in sockaddr = EndpointIPv4_toSockaddr(local_end);
if(bind(s, (void*)&sockaddr, sizeof(sockaddr)) != 0)
return RESULT_ERROR_SOCKET();
return RESULT_VOID;
}
Result(void) socket_listen(Socket s, i32 backlog){
if(listen(s, backlog) != 0)
return RESULT_ERROR_SOCKET();
return RESULT_VOID;
}
Result(Socket) socket_accept(Socket main_socket, NULLABLE(EndpointIPv4*) remote_end) {
struct sockaddr_in remote_addr = {0};
i32 sockaddr_size = sizeof(remote_addr);
Socket user_connection = accept(main_socket, (void*)&remote_addr, (void*)&sockaddr_size);
if(user_connection == -1)
return RESULT_ERROR_SOCKET();
//TODO: add IPV6 support (struct sockaddr_in6)
assert(sockaddr_size == sizeof(remote_addr));
if(remote_end)
*remote_end = EndpointIPv4_fromSockaddr(remote_addr);
return RESULT_VALUE(i, user_connection);
}
Result(void) socket_connect(Socket s, EndpointIPv4 remote_end){
struct sockaddr_in sockaddr = EndpointIPv4_toSockaddr(remote_end);
if(connect(s, (void*)&sockaddr, sizeof(sockaddr)) != 0)
return RESULT_ERROR_SOCKET();
return RESULT_VOID;
}
Result(void) socket_send(Socket s, Array(u8) buffer){
i32 r = send(s, buffer.data, buffer.size, 0);
if(r < 0){
return RESULT_ERROR_SOCKET();
}
if((u32)r != buffer.size){
return RESULT_ERROR_FMT("Socket was unable to send data");
}
return RESULT_VOID;
}
Result(void) socket_sendto(Socket s, Array(u8) buffer, EndpointIPv4 dst){
struct sockaddr_in sockaddr = EndpointIPv4_toSockaddr(dst);
i32 r = sendto(s, buffer.data, buffer.size, 0, (void*)&sockaddr, sizeof(sockaddr));
if(r < 0){
return RESULT_ERROR_SOCKET();
}
if((u32)r != buffer.size){
return RESULT_ERROR_FMT("Socket was unable to send data");
}
return RESULT_VOID;
}
static inline int SocketRecvFlags_toStd(SocketRecvFlag flags){
int f = 0;
if (flags & SocketRecvFlag_Peek)
f |= MSG_PEEK;
if (flags & SocketRecvFlag_WaitAll)
f |= MSG_WAITALL;
return f;
}
Result(i32) socket_recv(Socket s, Array(u8) buffer, SocketRecvFlag flags){
i32 r = recv(s, buffer.data, buffer.size, SocketRecvFlags_toStd(flags));
if(r < 0){
return RESULT_ERROR_SOCKET();
}
if(r == 0 || (flags & SocketRecvFlag_WaitAll && (u32)r != buffer.size))
{
return RESULT_ERROR("Socket closed", false);
}
return RESULT_VALUE(i, r);
}
Result(i32) socket_recvfrom(Socket s, Array(u8) buffer, SocketRecvFlag flags, NULLABLE(EndpointIPv4*) remote_end){
struct sockaddr_in remote_addr = {0};
i32 sockaddr_size = sizeof(remote_addr);
i32 r = recvfrom(s, buffer.data, buffer.size, SocketRecvFlags_toStd(flags),
(struct sockaddr*)&remote_addr, (void*)&sockaddr_size);
if(r < 0){
return RESULT_ERROR_SOCKET();
}
if(r == 0 || (flags & SocketRecvFlag_WaitAll && (u32)r != buffer.size))
{
return RESULT_ERROR("Socket closed", false);
}
//TODO: add IPV6 support (struct sockaddr_in6)
assert(sockaddr_size == sizeof(remote_addr));
if(remote_end)
*remote_end = EndpointIPv4_fromSockaddr(remote_addr);
return RESULT_VALUE(i, r);
}