#include "internal.h" #include "socket.h" #include 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); }