utils.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /**
  2. * saop: smtp authentication over pop3
  3. * Copyright (C) 2007 Juan José Gutiérrez de Quevedo <juanjo@iteisa.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; version 2 of the License
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. *
  18. * @author Juan José Gutiérrez de Quevedo <juanjo@iteisa.com>
  19. */
  20. #include "utils.h"
  21. #ifdef DEBUG
  22. extern FILE *fsaopdebug;
  23. #endif /* DEBUG */
  24. /**
  25. * reads a string as safely as possible.
  26. *
  27. * it will read one byte at a time until a '\\n' is read.
  28. * we store one char at a time in a static buffer, and when
  29. * we find a '\\n', we do an strndup of the buffer.
  30. * it might be possible in this special case to just use
  31. * a static buffer, return a pointer to it and never assign
  32. * any memory with strndup or in any other way.
  33. *
  34. * @param fd fd to read from
  35. *
  36. * @return a pointer to the read string
  37. */
  38. char *read_string(int fd)
  39. {
  40. char chr;
  41. char *buffer=NULL,*tmpbuf=NULL;
  42. unsigned long strsize=0;
  43. unsigned long allocsize=0;
  44. debug("Reading from socket");
  45. assert(fd>=0);
  46. /* read one byte at a time */
  47. while(1)
  48. {
  49. if(1!=recv(fd,&chr,1,MSG_NOSIGNAL))
  50. break;
  51. if(0==allocsize||allocsize<strsize+2)
  52. {
  53. allocsize=MAX(allocsize+512,strsize+2);
  54. if(NULL==(tmpbuf=realloc(buffer,allocsize)))
  55. {
  56. printf(_("Error reserving memory\n"));
  57. condfree(buffer);
  58. break;
  59. }
  60. else
  61. buffer=tmpbuf;
  62. }
  63. if(10==chr) break;
  64. if(13!=chr)
  65. buffer[strsize++]=chr;
  66. }
  67. if(NULL==buffer) return NULL;
  68. /* finalize string */
  69. buffer[strsize]='\0';
  70. debug(buffer);
  71. /* return a new string with new mem */
  72. return buffer;
  73. }
  74. /**
  75. * create a new listening socket.
  76. *
  77. * with following options:
  78. * - SO_REUSEADDR
  79. * - INADDR_ANY
  80. *
  81. * @param port the port to listen on
  82. *
  83. * @return the new socket fd
  84. */
  85. int create_listening_socket(unsigned int port)
  86. {
  87. int fd_server;
  88. struct sockaddr_in address;
  89. int i;
  90. /* create socket */
  91. if(-1==(fd_server=socket(PF_INET,SOCK_STREAM,0))) { perror("Error creating socket"); return -1; }
  92. debug("Socket created successfully");
  93. /* set option for the socket: SO_REUSEADDR (will reuse address between invocations of the same program) */
  94. i=1;
  95. if(-1==setsockopt(fd_server,SOL_SOCKET,SO_REUSEADDR,(void *)&i,sizeof(i))) { perror("Error configuring socket reuse"); closeskt(fd_server); return -1; }
  96. /* bind to address :ANY */
  97. address.sin_family=AF_INET;
  98. address.sin_addr.s_addr=INADDR_ANY;
  99. address.sin_port=htons(port);
  100. if(-1==bind(fd_server,(struct sockaddr *)&address,sizeof(address))) { perror("Error binding to address"); closeskt(fd_server); return -1; }
  101. debug("bind() successful");
  102. /* listen on socket */
  103. if(-1==listen(fd_server,10)) { perror("Error listening on socket"); closeskt(fd_server); return -1; }
  104. debug("listen() successful");
  105. return fd_server;
  106. }
  107. /**
  108. * create a socket that is connected to an address.
  109. *
  110. * @param address address to connect to
  111. * @param port port to connect to
  112. *
  113. * @return fd of the opened connection
  114. */
  115. int create_connected_socket(char *address,unsigned int port)
  116. {
  117. int fd;
  118. struct sockaddr_in addr;
  119. /* create socket */
  120. if(-1==(fd=socket(PF_INET,SOCK_STREAM,0))) { perror("Error creating socket"); return -1; }
  121. debug("Connecting to..");
  122. debug(address);
  123. /* fill address structure */
  124. addr.sin_family=AF_INET;
  125. addr.sin_addr.s_addr=resolve(address);
  126. addr.sin_port=htons(port);
  127. /* connect to remote host */
  128. if(-1==connect(fd,(struct sockaddr *)&addr,sizeof(addr))) { perror("Error connecting to host"); return -1; }
  129. debug("Connection successful");
  130. return fd;
  131. }
  132. unsigned long resolve(char *address)
  133. {
  134. struct hostent *resolved;
  135. struct in_addr addr;
  136. if(NULL==(resolved=gethostbyname(address))) { perror("Error resolving"); return 0; }
  137. memcpy(&addr,resolved->h_addr,sizeof(addr));
  138. debug("Address resolved");
  139. debug(address);
  140. debug(inet_ntoa(addr));
  141. return addr.s_addr;
  142. }
  143. /**
  144. * whether a fd does have data waiting or not.
  145. *
  146. * @param fd fd to ask
  147. * @param time time to wait for data
  148. *
  149. * @return 1 on data waiting to be read, else return 0
  150. */
  151. unsigned char can_read(int fd,float time)
  152. {
  153. fd_set rfd;
  154. struct timeval timeout;
  155. assert(fd>=0);
  156. /* configure timeout */
  157. timeout.tv_sec=(int)time;
  158. timeout.tv_usec=(time-(int)time)*1000000;
  159. /* configure rfd */
  160. FD_ZERO(&rfd);
  161. FD_SET(fd,&rfd);
  162. return (select(fd+1,&rfd,NULL,NULL,&timeout)>0)?1:0;
  163. }