comm.c revision 64562
1/* 2 * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 * 9 */ 10 11#ifndef lint 12static char id[] = "@(#)$Id: comm.c,v 8.30.4.3 2000/06/12 14:53:01 ca Exp $"; 13#endif /* ! lint */ 14 15#if _FFR_MILTER 16#include "libmilter.h" 17 18#define FD_Z FD_ZERO(&readset); \ 19 FD_SET((u_int) sd, &readset); \ 20 FD_ZERO(&excset); \ 21 FD_SET((u_int) sd, &excset) 22 23/* 24** MI_RD_CMD -- read a command 25** 26** Parameters: 27** sd -- socket descriptor 28** timeout -- maximum time to wait 29** cmd -- single character command read from sd 30** rlen -- pointer to length of result 31** name -- name of milter 32** 33** Returns: 34** buffer with rest of command 35** (malloc()ed here, should be free()d) 36** hack: encode error in cmd 37*/ 38 39char * 40mi_rd_cmd(sd, timeout, cmd, rlen, name) 41 socket_t sd; 42 struct timeval *timeout; 43 char *cmd; 44 size_t *rlen; 45 char *name; 46{ 47 ssize_t len; 48 mi_int32 expl; 49 ssize_t i; 50 fd_set readset, excset; 51 int ret; 52 int save_errno; 53 char *buf; 54 char data[MILTER_LEN_BYTES + 1]; 55 56 *cmd = '\0'; 57 *rlen = 0; 58 if (sd >= FD_SETSIZE) 59 { 60 smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d", 61 name, sd, FD_SETSIZE); 62 *cmd = SMFIC_SELECT; 63 return NULL; 64 } 65 FD_Z; 66 i = 0; 67 while ((ret = select(sd + 1, &readset, NULL, &excset, timeout)) >= 1) 68 { 69 if (FD_ISSET(sd, &excset)) 70 { 71 *cmd = SMFIC_SELECT; 72 return NULL; 73 } 74 if ((len = read(sd, data + i, sizeof data - i)) < 0) 75 { 76 smi_log(SMI_LOG_ERR, 77 "%s, mi_rd_cmd: read returned %d: %s", 78 name, len, strerror(errno)); 79 *cmd = SMFIC_RECVERR; 80 return NULL; 81 } 82 if (len == 0) 83 { 84 *cmd = SMFIC_EOF; 85 return NULL; 86 } 87 if (len >= (ssize_t) sizeof data - i) 88 break; 89 i += len; 90 FD_Z; 91 } 92 if (ret == 0) 93 { 94 *cmd = SMFIC_TIMEOUT; 95 return NULL; 96 } 97 else if (ret < 0) 98 { 99 smi_log(SMI_LOG_ERR, 100 "%s: mi_rd_cmd: select returned %d: %s", 101 name, ret, strerror(errno)); 102 *cmd = SMFIC_RECVERR; 103 return NULL; 104 } 105 106 *cmd = data[MILTER_LEN_BYTES]; 107 data[MILTER_LEN_BYTES] = '\0'; 108 (void) memcpy((void *) &expl, (void *) &(data[0]), MILTER_LEN_BYTES); 109 expl = ntohl(expl) - 1; 110 if (expl <= 0) 111 return NULL; 112 if (expl > MILTER_CHUNK_SIZE) 113 { 114 *cmd = SMFIC_TOOBIG; 115 return NULL; 116 } 117 buf = malloc(expl); 118 if (buf == NULL) 119 { 120 *cmd = SMFIC_MALLOC; 121 return NULL; 122 } 123 124 i = 0; 125 FD_Z; 126 while ((ret = select(sd + 1, &readset, NULL, &excset, timeout)) == 1) 127 { 128 if (FD_ISSET(sd, &excset)) 129 { 130 *cmd = SMFIC_SELECT; 131 free(buf); 132 return NULL; 133 } 134 if ((len = read(sd, buf + i, expl - i)) < 0) 135 { 136 smi_log(SMI_LOG_ERR, 137 "%s: mi_rd_cmd: read returned %d: %s", 138 name, len, strerror(errno)); 139 ret = -1; 140 break; 141 } 142 if (len == 0) 143 { 144 *cmd = SMFIC_EOF; 145 free(buf); 146 return NULL; 147 } 148 if (len > expl - i) 149 { 150 *cmd = SMFIC_RECVERR; 151 free(buf); 152 return NULL; 153 } 154 if (len >= expl - i) 155 { 156 *rlen = expl; 157 return buf; 158 } 159 i += len; 160 FD_Z; 161 } 162 163 save_errno = errno; 164 free(buf); 165 166 /* select returned 0 (timeout) or < 0 (error) */ 167 if (ret == 0) 168 { 169 *cmd = SMFIC_TIMEOUT; 170 return NULL; 171 } 172 if (ret < 0) 173 { 174 smi_log(SMI_LOG_ERR, 175 "%s: mi_rd_cmd: select returned %d: %s", 176 name, ret, strerror(save_errno)); 177 *cmd = SMFIC_RECVERR; 178 return NULL; 179 } 180 *cmd = SMFIC_UNKNERR; 181 return NULL; 182} 183/* 184** MI_WR_CMD -- write a cmd to sd 185** 186** Parameters: 187** sd -- socket descriptor 188** timeout -- maximum time to wait (currently unused) 189** cmd -- single character command to write 190** buf -- buffer with further data 191** len -- length of buffer (without cmd!) 192** 193** Returns: 194** MI_SUCCESS/MI_FAILURE 195*/ 196 197int 198mi_wr_cmd(sd, timeout, cmd, buf, len) 199 socket_t sd; 200 struct timeval *timeout; 201 int cmd; 202 char *buf; 203 size_t len; 204{ 205 size_t sl, i; 206 ssize_t l; 207 mi_int32 nl; 208 int ret; 209 fd_set wrtset; 210 char data[MILTER_LEN_BYTES + 1]; 211 212 if (len > MILTER_CHUNK_SIZE) 213 return MI_FAILURE; 214 nl = htonl(len + 1); /* add 1 for the cmd char */ 215 (void) memcpy(data, (void *) &nl, MILTER_LEN_BYTES); 216 data[MILTER_LEN_BYTES] = (char) cmd; 217 i = 0; 218 sl = MILTER_LEN_BYTES + 1; 219 220 do { 221 FD_ZERO(&wrtset); 222 FD_SET((u_int) sd, &wrtset); 223 if ((ret = select(sd + 1, NULL, &wrtset, NULL, timeout)) == 0) 224 return MI_FAILURE; 225 } while (ret < 0 && errno == EINTR); 226 if (ret < 0) 227 return MI_FAILURE; 228 229 /* use writev() instead to send the whole stuff at once? */ 230 while ((l = write(sd, (void *) (data + i), sl - i)) < (ssize_t) sl) 231 { 232 if (l < 0) 233 return MI_FAILURE; 234 i += l; 235 sl -= l; 236 } 237 238 if (len > 0 && buf == NULL) 239 return MI_FAILURE; 240 if (len == 0 || buf == NULL) 241 return MI_SUCCESS; 242 i = 0; 243 sl = len; 244 do { 245 FD_ZERO(&wrtset); 246 FD_SET((u_int) sd, &wrtset); 247 if ((ret = select(sd + 1, NULL, &wrtset, NULL, timeout)) == 0) 248 return MI_FAILURE; 249 } while (ret < 0 && errno == EINTR); 250 if (ret < 0) 251 return MI_FAILURE; 252 while ((l = write(sd, (void *) (buf + i), sl - i)) < (ssize_t) sl) 253 { 254 if (l < 0) 255 return MI_FAILURE; 256 i += l; 257 sl -= l; 258 } 259 return MI_SUCCESS; 260} 261#endif /* _FFR_MILTER */ 262