Last active
June 6, 2024 08:12
-
-
Save jweinst1/131656680f7d4d1aa32c865c407f306c to your computer and use it in GitHub Desktop.
unix sockets simplified programming
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <assert.h> | |
#include <signal.h> | |
#include <errno.h> | |
//--------system headers -------// | |
#include <unistd.h> | |
#include <sys/un.h> | |
#include <fcntl.h> | |
#include <sys/socket.h> | |
#include <sys/stat.h> | |
#include <optional> | |
enum class sock_result_type : int { | |
Ok, | |
SocketInUse, // to do socket exist | |
PathTooLong, | |
CannotCreateSocket, | |
CannotBindSocket, | |
CannotListenSocket, | |
CannotConnectSocket | |
}; | |
template<class T> | |
struct Result { | |
Result(sock_result_type type): type(type) {} | |
Result(const T& val): type(sock_result_type::Ok), value(val) {} | |
bool isOk() const { return value.has_value();} | |
const T& get() const { return value.value(); } | |
sock_result_type type; | |
std::optional<T> value; | |
}; | |
static int getAndResetErrNo() { | |
int eResult = errno; | |
errno = 0; | |
return eResult; | |
} | |
static constexpr size_t getMaxSizeOfUnixPath() { | |
constexpr struct sockaddr_un unix_addr = {}; | |
return sizeof(unix_addr.sun_path); | |
} | |
static const inline bool pathExists(const char* path) { | |
struct stat sbuf; | |
return stat(path, &sbuf) == 0; | |
} | |
static bool set_non_blocking(int sockfd, bool blocking) { | |
int flags = fcntl(sockfd, F_GETFL, 0); | |
flags = blocking ? (flags | O_NONBLOCK) : (flags & ~O_NONBLOCK); | |
if (fcntl(sockfd, F_SETFL, flags)) { | |
return false; | |
} | |
return true; | |
} | |
class UnixSockPath { | |
public: | |
UnixSockPath(const char* path) { | |
strncpy(_path, path, getMaxSizeOfUnixPath() - 1); | |
} | |
UnixSockPath(const char* path, size_t n) { | |
strncpy(_path, path, n); | |
} | |
const char* getPath() const { return _path; } | |
bool exists() const { return pathExists(_path); } | |
bool remove() const { return ::remove(_path) == 0; } | |
private: | |
char _path[getMaxSizeOfUnixPath()] = {'\0'}; | |
}; | |
class UnixStream { | |
public: | |
UnixStream(int fd, const UnixSockPath& path): _fd(fd), _path(path){} | |
~UnixStream(){ | |
close(_fd); | |
} | |
private: | |
int _fd = -1; | |
UnixSockPath _path; | |
}; | |
class UnixServer { | |
public: | |
UnixServer(int server_fd, const UnixSockPath& path): _server_fd(server_fd), | |
_path(path){} | |
~UnixServer() { | |
close(_server_fd); | |
_path.remove(); | |
} | |
private: | |
int _server_fd = -1; | |
UnixSockPath _path; | |
}; | |
static Result<int> create_server_socket(const char* path) { | |
int sfd = -1; | |
struct sockaddr_un unix_addr; | |
if (strlen(path) > getMaxSizeOfUnixPath() - 1) { | |
return Result<int>(sock_result_type::PathTooLong); | |
} | |
if (pathExists(path)) { | |
return Result<int>(sock_result_type::SocketInUse); | |
} | |
memset(&unix_addr, 0, sizeof(struct sockaddr_un)); | |
unix_addr.sun_family = AF_UNIX; | |
strncpy(unix_addr.sun_path, path, getMaxSizeOfUnixPath() - 1); | |
sfd = socket(AF_UNIX, SOCK_STREAM, 0); | |
if (sfd == -1) { | |
return Result<int>(sock_result_type::CannotCreateSocket); | |
} | |
if (bind(sfd, (struct sockaddr *) &unix_addr, sizeof(unix_addr)) == -1) { | |
return Result<int>(sock_result_type::CannotBindSocket); | |
} | |
if (listen(sfd, 5) == -1) { | |
return Result<int>(sock_result_type::CannotListenSocket); | |
} | |
return Result<int>(sfd); | |
} | |
static Result<int> create_client_socket(const char* path) { | |
int cfd = -1; | |
struct sockaddr_un unix_addr; | |
cfd = socket(AF_UNIX, SOCK_STREAM, 0); | |
if (cfd == -1) { | |
return Result<int>(sock_result_type::CannotCreateSocket); | |
} | |
if (strlen(path) > getMaxSizeOfUnixPath() - 1) { | |
// todo err | |
return Result<int>(sock_result_type::PathTooLong); | |
} | |
memset(&unix_addr, 0, sizeof(struct sockaddr_un)); | |
unix_addr.sun_family = AF_UNIX; | |
strncpy(unix_addr.sun_path, path, getMaxSizeOfUnixPath() - 1); | |
if (connect(cfd, (struct sockaddr *) &unix_addr, sizeof(unix_addr)) == -1) { | |
return Result<int>(sock_result_type::CannotConnectSocket); | |
} | |
return Result<int>(cfd); | |
} | |
int main(int argc, char const *argv[]) | |
{ | |
UnixSockPath p("foobar", 6); | |
auto result = create_server_socket("foobar"); | |
if (result.isOk()) { | |
UnixServer s(result.get(), p); | |
puts("destroy server"); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment