/* * Copyright (c) 2003, 2005 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. */ #include "sm/generic.h" SM_RCSID("@(#)$Id: stsocklisten.c,v 1.6 2005/04/19 22:19:50 ca Exp $") #include "sm/assert.h" #include "sm/error.h" #include "sm/memops.h" #include "sm/fcntl.h" #include "sm/unixsock.h" #include "sm/stsock.h" /* ** UN_ST_SERVER_LISTEN_ADDR -- Create a socket, bind, and listen. ** ** Parameters: ** my_addr -- sockaddr listen on ** addrlen -- Length of my_addr ** backlog -- Backlog of connections to accept ** pfd -- pointer to net fd (output) ** ** Returns: ** usual error type */ sm_ret_T un_st_server_listen_addr(sockaddr_un_T *my_addr, socklen_T addrlen, int backlog, st_netfd_t *pfd) { int listenfd; st_netfd_t netfd; sm_ret_T ret; SM_REQUIRE(my_addr != NULL); SM_REQUIRE(pfd != NULL); SM_REQUIRE(backlog > 0); *pfd = NULL; /* Open listen port */ listenfd = socket(AF_UNIX, SOCK_STREAM, 0); if (listenfd == -1) return sm_error_perm(SM_EM_STTHRIO, errno); if (bind(listenfd, (sockaddr_T *) my_addr, addrlen) == -1) { ret = sm_error_perm(SM_EM_STTHRIO, errno); goto error; } if (listen(listenfd, backlog) == -1) { ret = sm_error_perm(SM_EM_STTHRIO, errno); goto error; } netfd = st_netfd_open_socket(listenfd); if (netfd == NULL) { ret = sm_error_perm(SM_EM_STTHRIO, errno); goto error; } *pfd = netfd; return SM_SUCCESS; error: close(listenfd); return ret; } /* ** UN_ST_SERVER_ACCEPT -- Accept an incoming network connection. ** ** Parameters: ** listenfd -- fd that we are listening on. ** addr -- client address that is connecting. ** addrlen -- length of addr ** fd -- pointer to net fd (output) ** ** Returns: ** usual error type */ sm_ret_T un_st_server_accept(st_netfd_t listenfd, struct sockaddr *addr, sockaddr_len_T *addrlen, st_netfd_t *fd) { st_netfd_t connfd; int st_addrlen; SM_REQUIRE(listenfd != NULL); SM_REQUIRE(fd != NULL); SM_REQUIRE(addr != NULL); SM_REQUIRE(addrlen != NULL); *fd = NULL; connfd = st_accept(listenfd, addr, &st_addrlen, (st_utime_t) -1); if (connfd == NULL) { if (errno != EAGAIN) return sm_error_perm(SM_EM_STTHRIO, errno); /* XXX what to do if errno == EAGAIN? */ return sm_error_temp(SM_EM_STTHRIO, errno); } *addrlen = st_addrlen; *fd = connfd; return SM_SUCCESS; } /* ** UN_ST_SERVER_LISTEN -- Create a socket, bind, and listen. ** ** Parameters: ** name -- name to bind to. ** backlog -- Backlog of connections to accept. ** fd -- pointer to net fd (output) ** ** Returns: ** New socket fd or sm_error */ sm_ret_T un_st_server_listen(const char *name, int backlog, st_netfd_t *fd) { struct sockaddr_un servaddr; SM_REQUIRE(name != NULL); SM_REQUIRE(fd != NULL); *fd = NULL; sm_memset(&servaddr, 0, sizeof(servaddr)); servaddr.sun_family = AF_UNIX; if (strlcpy(servaddr.sun_path, name, sizeof servaddr.sun_path) >= sizeof servaddr.sun_path) return sm_error_perm(SM_EM_STTHRIO, SM_E_2BIG); #if HAVE_SOCK_UN_SUN_LEN servaddr.sun_len = strlen(name); #endif return un_st_server_listen_addr(&servaddr, sizeof(servaddr), backlog, fd); }