%% options copyright owner = Dirk Krause copyright year = 2015-xxxx license = bsd %% module #include "dk4sock.h" #include #if DK4_HAVE_ERRNO_H #ifndef ERRNO_H_INCLUDED #include #define ERRNO_H_INCLUDED 1 #endif #endif #if DK4_HAVE_UNISTD_H #ifndef UNISTD_H_INCLUDED #include #define UNISTD_H_INCLUDED 1 #endif #endif #if DK4_HAVE_IO_H #ifndef IO_H_INCLUDED #include #define IO_H_INCLUDED 1 #endif #endif #if DK4_HAVE_STRINGS_H #ifndef STRINGS_H_INCLUDED #include #define STRINGS_H_INCLUDED 1 #endif #endif #include "dk4mem.h" #include "dk4stat.h" #include "dk4stat8.h" #include "dk4delfile08.h" $!trace-include int dk4socket_listen( dk4_socket_t sock, int bl, dk4_er_t *erp ) { int back = DK4_SOCKET_RESULT_FAILED; if ((INVALID_SOCKET != sock) && (0 < bl)) { dk4socket_error_reset(); if (0 == listen(sock, bl)) { back = DK4_SOCKET_RESULT_SUCCESS; } else { dk4socket_error_report(erp, DK4_E_SOCKET_LISTEN); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; } dk4_socket_t dk4socket_accept( dk4_socket_t sock, struct sockaddr *pAddr, size_t *pSzAddr, dk4_er_t *erp ) { dk4_socket_t back = INVALID_SOCKET; #if DK4_HAVE_SOCKLEN_T socklen_t sz; #else int sz; #endif $? "+ dk4socket_accept %d", (int)sock if (INVALID_SOCKET != sock) { if (NULL != pAddr) { $? ". address buffer" if (NULL != pSzAddr) { $? ". address size pointer" if (0 < *pSzAddr) { $? ". arguments ok" #if DK4_HAVE_SOCKLEN_T sz = (socklen_t)(*pSzAddr); #else sz = (int)(*pSzAddr); #endif dk4socket_error_reset(); back = accept(sock, pAddr, &sz); if (INVALID_SOCKET != back) { *pSzAddr = (size_t)sz; } else { dk4socket_error_report(erp, DK4_E_SOCKET_ACCEPT); *pSzAddr = 0; } } else { $? "! address size 0" dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } } else { $? "! no address size pointer" dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } } else { $? ". no address buffer" /* ACCEPT */ dk4socket_error_reset(); back = accept(sock, NULL, NULL); if (INVALID_SOCKET == back) { dk4socket_error_report(erp, DK4_E_SOCKET_ACCEPT); } } } else { $? "! invalid sock" dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } $? "- dk4socket_accept %d", back return back; } #if DK4_HAVE_STRUCT_SOCKADDR_UN /** Change mode and optionally owner and group for a socket. @param sock Socket file descriptor. @param filename Socket file name. @param owner New owner. @param group New group. @param mode New file mode. @param cog Flag: Also change owner and group. @param erp Error report, may be NULL */ static int dk4socket_i_change_owner_group_mode( dk4_socket_t sock, const char *filename, uid_t owner, gid_t group, mode_t mode, int cog, dk4_er_t *erp ) { int errval; int back = 1; $? "+ dk4socket_i_change_owner_group_mode" if (0 != cog) { errno = 0; if (0 != chown(filename, owner, group)) { errval = errno; if (0 != fchown(sock, owner, group)) { back = 0; dk4error_set_idetails(erp, DK4_E_CHOWN_FAILED, errval); } } } errno = 0; if (0 != chmod(filename, mode)) { errval = errno; if (0 != fchmod(sock, mode)) { back = 0; dk4error_set_idetails(erp, DK4_E_CHMOD_FAILED, errval); } } $? "- dk4socket_i_change_owner_group_mode" return back; } static dk4_socket_t dk4socket_i_c8_unix_listener_ogm( const char *filename, int backlog, uid_t owner, gid_t group, mode_t mode, int change, dk4_er_t *erp ) { struct sockaddr_un soun; dk4_stat_t stb; size_t slen; dk4_socket_t back = INVALID_SOCKET; int md = 0; int res; int ogm1; int ogm2; if ((NULL != filename) && (0 < backlog)) { if (108 > strlen(filename)) { /* Attempt to remove existing socket. */ res = 1; if (0 != dk4stat_c8(&stb, filename, NULL)) { res = 0; if (0 != dk4stat_is_unix_domain_socket(&stb, NULL)) { if (0 != dk4delete_file_c8(filename, NULL)) { res = 1; } else { /* ERROR: Failed to remove old socket */ dk4error_set_simple_error_code(erp, DK4_E_UNLINK_FAILED); } } else { /* ERROR: Not a socket */ dk4error_set_simple_error_code(erp, DK4_E_NON_SOCKET); } } /* Open and bind new socket. */ if (0 != res) { DK4_MEMRES(&soun, sizeof(soun)); soun.sun_family = AF_UNIX; strcpy(soun.sun_path, filename); slen = dk4socket_unix_length(&soun); back = dk4socket_open(AF_UNIX, SOCK_STREAM, 0, erp); if (INVALID_SOCKET != back) { (void)dk4socket_option_set_reuse(back, 1, NULL); res = dk4socket_bind( back, (const struct sockaddr *)(&soun), slen, erp ); if (DK4_SOCKET_RESULT_SUCCESS == res) { ogm1 = dk4socket_i_change_owner_group_mode( back, filename, owner, group, mode, change, erp ); res = dk4socket_listen(back, backlog, erp); if (DK4_SOCKET_RESULT_SUCCESS == res) { ogm2 = dk4socket_i_change_owner_group_mode( back, filename, owner, group, mode, change, erp ); if ((0 == ogm1) && (0 == ogm2)) { (void)dk4socket_close(back, NULL); back = INVALID_SOCKET; md = 1; } } else { (void)dk4socket_close(back, NULL); back = INVALID_SOCKET; md = 1; } } else { (void)dk4socket_close(back, NULL); back = INVALID_SOCKET; } if ((INVALID_SOCKET == back) && (0 != md)) { (void)dk4delete_file_c8(filename, NULL); } } } else { } } else { dk4error_set_simple_error_code(erp, DK4_E_SYNTAX); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; } dk4_socket_t dk4socket_c8_unix_listener( const char *filename, int backlog, dk4_er_t *erp ) { return ( dk4socket_i_c8_unix_listener_ogm(filename, backlog, 0, 0, 0660, 0, erp) ); } dk4_socket_t dk4socket_c8_unix_listener_owner_group_mode( const char *filename, int backlog, uid_t owner, gid_t group, mode_t mode, dk4_er_t *erp ) { return ( dk4socket_i_c8_unix_listener_ogm( filename, backlog, owner, group, mode, 1, erp ) ); } #endif