Skip to content

Instantly share code, notes, and snippets.

@jweinst1
Last active June 6, 2024 08:12
Show Gist options
  • Save jweinst1/131656680f7d4d1aa32c865c407f306c to your computer and use it in GitHub Desktop.
Save jweinst1/131656680f7d4d1aa32c865c407f306c to your computer and use it in GitHub Desktop.
unix sockets simplified programming
#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