comm.c revision 90792
164562Sgshapiro/* 290792Sgshapiro * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 464562Sgshapiro * 564562Sgshapiro * By using this file, you agree to the terms and conditions set 664562Sgshapiro * forth in the LICENSE file which can be found at the top level of 764562Sgshapiro * the sendmail distribution. 864562Sgshapiro * 964562Sgshapiro */ 1064562Sgshapiro 1190792Sgshapiro#include <sm/gen.h> 1290792SgshapiroSM_RCSID("@(#)$Id: comm.c,v 8.48 2001/11/07 17:43:04 ca Exp $") 1364562Sgshapiro 1464562Sgshapiro#include "libmilter.h" 1590792Sgshapiro#include <sm/errstring.h> 1664562Sgshapiro 1790792Sgshapiro#define FD_Z FD_ZERO(&readset); \ 1890792Sgshapiro FD_SET((unsigned int) sd, &readset); \ 1990792Sgshapiro FD_ZERO(&excset); \ 2090792Sgshapiro FD_SET((unsigned int) sd, &excset) 2164562Sgshapiro 2264562Sgshapiro/* 2364562Sgshapiro** MI_RD_CMD -- read a command 2464562Sgshapiro** 2564562Sgshapiro** Parameters: 2664562Sgshapiro** sd -- socket descriptor 2764562Sgshapiro** timeout -- maximum time to wait 2864562Sgshapiro** cmd -- single character command read from sd 2964562Sgshapiro** rlen -- pointer to length of result 3064562Sgshapiro** name -- name of milter 3164562Sgshapiro** 3264562Sgshapiro** Returns: 3364562Sgshapiro** buffer with rest of command 3464562Sgshapiro** (malloc()ed here, should be free()d) 3564562Sgshapiro** hack: encode error in cmd 3664562Sgshapiro*/ 3764562Sgshapiro 3864562Sgshapirochar * 3964562Sgshapiromi_rd_cmd(sd, timeout, cmd, rlen, name) 4064562Sgshapiro socket_t sd; 4164562Sgshapiro struct timeval *timeout; 4264562Sgshapiro char *cmd; 4364562Sgshapiro size_t *rlen; 4464562Sgshapiro char *name; 4564562Sgshapiro{ 4664562Sgshapiro ssize_t len; 4764562Sgshapiro mi_int32 expl; 4864562Sgshapiro ssize_t i; 4964562Sgshapiro fd_set readset, excset; 5064562Sgshapiro int ret; 5164562Sgshapiro int save_errno; 5264562Sgshapiro char *buf; 5364562Sgshapiro char data[MILTER_LEN_BYTES + 1]; 5464562Sgshapiro 5564562Sgshapiro *cmd = '\0'; 5664562Sgshapiro *rlen = 0; 5771345Sgshapiro 5864562Sgshapiro if (sd >= FD_SETSIZE) 5964562Sgshapiro { 6064562Sgshapiro smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d", 6164562Sgshapiro name, sd, FD_SETSIZE); 6264562Sgshapiro *cmd = SMFIC_SELECT; 6364562Sgshapiro return NULL; 6464562Sgshapiro } 6571345Sgshapiro 6664562Sgshapiro FD_Z; 6764562Sgshapiro i = 0; 6864562Sgshapiro while ((ret = select(sd + 1, &readset, NULL, &excset, timeout)) >= 1) 6964562Sgshapiro { 7064562Sgshapiro if (FD_ISSET(sd, &excset)) 7164562Sgshapiro { 7264562Sgshapiro *cmd = SMFIC_SELECT; 7364562Sgshapiro return NULL; 7464562Sgshapiro } 7590792Sgshapiro 7690792Sgshapiro len = MI_SOCK_READ(sd, data + i, sizeof data - i); 7790792Sgshapiro if (MI_SOCK_READ_FAIL(len)) 7864562Sgshapiro { 7964562Sgshapiro smi_log(SMI_LOG_ERR, 8064562Sgshapiro "%s, mi_rd_cmd: read returned %d: %s", 8190792Sgshapiro name, len, sm_errstring(errno)); 8264562Sgshapiro *cmd = SMFIC_RECVERR; 8364562Sgshapiro return NULL; 8464562Sgshapiro } 8564562Sgshapiro if (len == 0) 8664562Sgshapiro { 8764562Sgshapiro *cmd = SMFIC_EOF; 8864562Sgshapiro return NULL; 8964562Sgshapiro } 9064562Sgshapiro if (len >= (ssize_t) sizeof data - i) 9164562Sgshapiro break; 9264562Sgshapiro i += len; 9364562Sgshapiro FD_Z; 9464562Sgshapiro } 9564562Sgshapiro if (ret == 0) 9664562Sgshapiro { 9764562Sgshapiro *cmd = SMFIC_TIMEOUT; 9864562Sgshapiro return NULL; 9964562Sgshapiro } 10064562Sgshapiro else if (ret < 0) 10164562Sgshapiro { 10264562Sgshapiro smi_log(SMI_LOG_ERR, 10364562Sgshapiro "%s: mi_rd_cmd: select returned %d: %s", 10490792Sgshapiro name, ret, sm_errstring(errno)); 10564562Sgshapiro *cmd = SMFIC_RECVERR; 10664562Sgshapiro return NULL; 10764562Sgshapiro } 10864562Sgshapiro 10964562Sgshapiro *cmd = data[MILTER_LEN_BYTES]; 11064562Sgshapiro data[MILTER_LEN_BYTES] = '\0'; 11164562Sgshapiro (void) memcpy((void *) &expl, (void *) &(data[0]), MILTER_LEN_BYTES); 11264562Sgshapiro expl = ntohl(expl) - 1; 11364562Sgshapiro if (expl <= 0) 11464562Sgshapiro return NULL; 11564562Sgshapiro if (expl > MILTER_CHUNK_SIZE) 11664562Sgshapiro { 11764562Sgshapiro *cmd = SMFIC_TOOBIG; 11864562Sgshapiro return NULL; 11964562Sgshapiro } 12090792Sgshapiro#if _FFR_ADD_NULL 12190792Sgshapiro buf = malloc(expl + 1); 12290792Sgshapiro#else /* _FFR_ADD_NULL */ 12364562Sgshapiro buf = malloc(expl); 12490792Sgshapiro#endif /* _FFR_ADD_NULL */ 12564562Sgshapiro if (buf == NULL) 12664562Sgshapiro { 12764562Sgshapiro *cmd = SMFIC_MALLOC; 12864562Sgshapiro return NULL; 12964562Sgshapiro } 13064562Sgshapiro 13164562Sgshapiro i = 0; 13264562Sgshapiro FD_Z; 13364562Sgshapiro while ((ret = select(sd + 1, &readset, NULL, &excset, timeout)) == 1) 13464562Sgshapiro { 13564562Sgshapiro if (FD_ISSET(sd, &excset)) 13664562Sgshapiro { 13764562Sgshapiro *cmd = SMFIC_SELECT; 13864562Sgshapiro free(buf); 13964562Sgshapiro return NULL; 14064562Sgshapiro } 14190792Sgshapiro len = MI_SOCK_READ(sd, buf + i, expl - i); 14290792Sgshapiro if (MI_SOCK_READ_FAIL(len)) 14364562Sgshapiro { 14464562Sgshapiro smi_log(SMI_LOG_ERR, 14564562Sgshapiro "%s: mi_rd_cmd: read returned %d: %s", 14690792Sgshapiro name, len, sm_errstring(errno)); 14764562Sgshapiro ret = -1; 14864562Sgshapiro break; 14964562Sgshapiro } 15064562Sgshapiro if (len == 0) 15164562Sgshapiro { 15264562Sgshapiro *cmd = SMFIC_EOF; 15364562Sgshapiro free(buf); 15464562Sgshapiro return NULL; 15564562Sgshapiro } 15664562Sgshapiro if (len > expl - i) 15764562Sgshapiro { 15864562Sgshapiro *cmd = SMFIC_RECVERR; 15964562Sgshapiro free(buf); 16064562Sgshapiro return NULL; 16164562Sgshapiro } 16264562Sgshapiro if (len >= expl - i) 16364562Sgshapiro { 16464562Sgshapiro *rlen = expl; 16590792Sgshapiro#if _FFR_ADD_NULL 16690792Sgshapiro /* makes life simpler for common string routines */ 16790792Sgshapiro buf[expl] = '\0'; 16890792Sgshapiro#endif /* _FFR_ADD_NULL */ 16964562Sgshapiro return buf; 17064562Sgshapiro } 17164562Sgshapiro i += len; 17264562Sgshapiro FD_Z; 17364562Sgshapiro } 17464562Sgshapiro 17564562Sgshapiro save_errno = errno; 17664562Sgshapiro free(buf); 17764562Sgshapiro 17864562Sgshapiro /* select returned 0 (timeout) or < 0 (error) */ 17964562Sgshapiro if (ret == 0) 18064562Sgshapiro { 18164562Sgshapiro *cmd = SMFIC_TIMEOUT; 18264562Sgshapiro return NULL; 18364562Sgshapiro } 18464562Sgshapiro if (ret < 0) 18564562Sgshapiro { 18664562Sgshapiro smi_log(SMI_LOG_ERR, 18764562Sgshapiro "%s: mi_rd_cmd: select returned %d: %s", 18890792Sgshapiro name, ret, sm_errstring(save_errno)); 18964562Sgshapiro *cmd = SMFIC_RECVERR; 19064562Sgshapiro return NULL; 19164562Sgshapiro } 19264562Sgshapiro *cmd = SMFIC_UNKNERR; 19364562Sgshapiro return NULL; 19464562Sgshapiro} 19590792Sgshapiro/* 19664562Sgshapiro** MI_WR_CMD -- write a cmd to sd 19764562Sgshapiro** 19864562Sgshapiro** Parameters: 19964562Sgshapiro** sd -- socket descriptor 20064562Sgshapiro** timeout -- maximum time to wait (currently unused) 20164562Sgshapiro** cmd -- single character command to write 20264562Sgshapiro** buf -- buffer with further data 20364562Sgshapiro** len -- length of buffer (without cmd!) 20464562Sgshapiro** 20564562Sgshapiro** Returns: 20664562Sgshapiro** MI_SUCCESS/MI_FAILURE 20764562Sgshapiro*/ 20864562Sgshapiro 20964562Sgshapiroint 21064562Sgshapiromi_wr_cmd(sd, timeout, cmd, buf, len) 21164562Sgshapiro socket_t sd; 21264562Sgshapiro struct timeval *timeout; 21364562Sgshapiro int cmd; 21464562Sgshapiro char *buf; 21564562Sgshapiro size_t len; 21664562Sgshapiro{ 21764562Sgshapiro size_t sl, i; 21864562Sgshapiro ssize_t l; 21964562Sgshapiro mi_int32 nl; 22064562Sgshapiro int ret; 22164562Sgshapiro fd_set wrtset; 22264562Sgshapiro char data[MILTER_LEN_BYTES + 1]; 22364562Sgshapiro 22464562Sgshapiro if (len > MILTER_CHUNK_SIZE) 22564562Sgshapiro return MI_FAILURE; 22664562Sgshapiro nl = htonl(len + 1); /* add 1 for the cmd char */ 22764562Sgshapiro (void) memcpy(data, (void *) &nl, MILTER_LEN_BYTES); 22864562Sgshapiro data[MILTER_LEN_BYTES] = (char) cmd; 22964562Sgshapiro i = 0; 23064562Sgshapiro sl = MILTER_LEN_BYTES + 1; 23164562Sgshapiro 23266494Sgshapiro do 23366494Sgshapiro { 23464562Sgshapiro FD_ZERO(&wrtset); 23590792Sgshapiro FD_SET((unsigned int) sd, &wrtset); 23664562Sgshapiro if ((ret = select(sd + 1, NULL, &wrtset, NULL, timeout)) == 0) 23764562Sgshapiro return MI_FAILURE; 23864562Sgshapiro } while (ret < 0 && errno == EINTR); 23964562Sgshapiro if (ret < 0) 24064562Sgshapiro return MI_FAILURE; 24164562Sgshapiro 24264562Sgshapiro /* use writev() instead to send the whole stuff at once? */ 24366494Sgshapiro while ((l = MI_SOCK_WRITE(sd, (void *) (data + i), 24466494Sgshapiro sl - i)) < (ssize_t) sl) 24564562Sgshapiro { 24664562Sgshapiro if (l < 0) 24764562Sgshapiro return MI_FAILURE; 24864562Sgshapiro i += l; 24964562Sgshapiro sl -= l; 25064562Sgshapiro } 25164562Sgshapiro 25264562Sgshapiro if (len > 0 && buf == NULL) 25364562Sgshapiro return MI_FAILURE; 25464562Sgshapiro if (len == 0 || buf == NULL) 25564562Sgshapiro return MI_SUCCESS; 25664562Sgshapiro i = 0; 25764562Sgshapiro sl = len; 25866494Sgshapiro do 25966494Sgshapiro { 26064562Sgshapiro FD_ZERO(&wrtset); 26190792Sgshapiro FD_SET((unsigned int) sd, &wrtset); 26264562Sgshapiro if ((ret = select(sd + 1, NULL, &wrtset, NULL, timeout)) == 0) 26364562Sgshapiro return MI_FAILURE; 26464562Sgshapiro } while (ret < 0 && errno == EINTR); 26564562Sgshapiro if (ret < 0) 26664562Sgshapiro return MI_FAILURE; 26766494Sgshapiro while ((l = MI_SOCK_WRITE(sd, (void *) (buf + i), 26866494Sgshapiro sl - i)) < (ssize_t) sl) 26964562Sgshapiro { 27064562Sgshapiro if (l < 0) 27164562Sgshapiro return MI_FAILURE; 27264562Sgshapiro i += l; 27364562Sgshapiro sl -= l; 27464562Sgshapiro } 27564562Sgshapiro return MI_SUCCESS; 27664562Sgshapiro} 277