126 lines
3.7 KiB
C
Executable File
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);
|
|
}
|