Anope IRC Services  Version 1.8
sockutil.c
Go to the documentation of this file.
1 /* Socket utility routines.
2  *
3  * (C) 2003-2014 Anope Team
4  * Contact us at team@anope.org
5  *
6  * Please read COPYING and README for further details.
7  *
8  * Based on the original code of Epona by Lara.
9  * Based on the original code of Services by Andy Church.
10  *
11  *
12  */
13 
14 #include "services.h"
15 
16 /*************************************************************************/
17 
18 static char read_netbuf[NET_BUFSIZE];
19 static char *read_curpos = read_netbuf; /* Next byte to return */
20 static char *read_bufend = read_netbuf; /* Next position for data from socket */
21 static char *const read_buftop = read_netbuf + NET_BUFSIZE;
24 static char *write_curpos = write_netbuf; /* Next byte to write to socket */
25 static char *write_bufend = write_netbuf; /* Next position for data to socket */
26 static char *const write_buftop = write_netbuf + NET_BUFSIZE;
27 static int write_fd = -1;
29 static int lastchar = EOF;
30 
31 /*************************************************************************/
32 
38 {
39  if (read_bufend >= read_curpos) {
40  return read_bufend - read_curpos;
41  } else {
42  return (read_bufend + NET_BUFSIZE) - read_curpos;
43  }
44 }
45 
46 /*************************************************************************/
47 
55 static int buffered_read(ano_socket_t fd, char *buf, int len)
56 {
57  int nread, left = len;
58  fd_set fds;
59  struct timeval tv = { 0, 0 };
60  int errno_save = ano_sockgeterr();
61 
62  if (fd < 0) {
64  return -1;
65  }
66  while (left > 0) {
67  struct timeval *tvptr = (read_bufend == read_curpos ? NULL : &tv);
68  FD_ZERO(&fds);
69  FD_SET(fd, &fds);
70  while (read_bufend != read_curpos - 1
71  && !(read_curpos == read_netbuf
72  && read_bufend == read_buftop - 1)
73  && select(fd + 1, &fds, 0, 0, tvptr) == 1) {
74  int maxread;
75  tvptr = &tv; /* don't wait next time */
76  if (read_bufend < read_curpos) /* wrapped around? */
77  maxread = (read_curpos - 1) - read_bufend;
78  else if (read_curpos == read_netbuf)
79  maxread = read_buftop - read_bufend - 1;
80  else
81  maxread = read_buftop - read_bufend;
82  nread = ano_sockread(fd, read_bufend, maxread);
83  errno_save = ano_sockgeterr();
84  if (debug >= 3)
85  alog("debug: buffered_read wanted %d, got %d", maxread,
86  nread);
87  if (nread <= 0)
88  break;
89  read_bufend += nread;
90  if (read_bufend == read_buftop)
91  read_bufend = read_netbuf;
92  }
93  if (read_curpos == read_bufend) /* No more data on socket */
94  break;
95  /* See if we can gobble up the rest of the buffer. */
96  if (read_curpos + left >= read_buftop && read_bufend < read_curpos) {
97  nread = read_buftop - read_curpos;
98  memcpy(buf, read_curpos, nread);
99  buf += nread;
100  left -= nread;
101  read_curpos = read_netbuf;
102  }
103  /* Now everything we need is in a single chunk at read_curpos. */
105  nread = read_bufend - read_curpos;
106  else
107  nread = left;
108  if (nread) {
109  memcpy(buf, read_curpos, nread);
110  buf += nread;
111  left -= nread;
112  read_curpos += nread;
113  }
114  }
115  total_read += len - left;
116  if (debug >= 4) {
117  alog("debug: buffered_read(%d,%p,%d) returning %d",
118  fd, buf, len, len - left);
119  }
120  ano_sockseterr(errno_save);
121  return len - left;
122 }
123 
124 /*************************************************************************/
125 
133 {
134  int nread;
135  fd_set fds;
136  struct timeval tv = { 0, 0 };
137  char c;
138  struct timeval *tvptr = (read_bufend == read_curpos ? NULL : &tv);
139  int errno_save = ano_sockgeterr();
140 
141  if (fd < 0) {
143  return -1;
144  }
145  FD_ZERO(&fds);
146  FD_SET(fd, &fds);
147  while (read_bufend != read_curpos - 1
148  && !(read_curpos == read_netbuf
149  && read_bufend == read_buftop - 1)
150  && select(fd + 1, &fds, 0, 0, tvptr) == 1) {
151  int maxread;
152  tvptr = &tv; /* don't wait next time */
153  if (read_bufend < read_curpos) /* wrapped around? */
154  maxread = (read_curpos - 1) - read_bufend;
155  else if (read_curpos == read_netbuf)
156  maxread = read_buftop - read_bufend - 1;
157  else
158  maxread = read_buftop - read_bufend;
159  nread = ano_sockread(fd, read_bufend, maxread);
160  errno_save = ano_sockgeterr();
161  if (debug >= 3)
162  alog("debug: buffered_read_one wanted %d, got %d", maxread,
163  nread);
164  if (nread <= 0)
165  break;
166  read_bufend += nread;
167  if (read_bufend == read_buftop)
168  read_bufend = read_netbuf;
169  }
170  if (read_curpos == read_bufend) { /* No more data on socket */
171  if (debug >= 4)
172  alog("debug: buffered_read_one(%d) returning %d", fd, EOF);
173  ano_sockseterr(errno_save);
174  return EOF;
175  }
176  c = *read_curpos++;
177  if (read_curpos == read_buftop)
179  total_read++;
180  if (debug >= 4)
181  alog("debug: buffered_read_one(%d) returning %d", fd, c);
182  return (int) c & 0xFF;
183 }
184 
185 /*************************************************************************/
186 
192 {
193  if (write_bufend >= write_curpos) {
194  return write_bufend - write_curpos;
195  } else {
197  }
198 }
199 
200 /*************************************************************************/
201 
208 static int flush_write_buffer(int wait)
209 {
210  fd_set fds;
211  struct timeval tv = { 0, 0 };
212  int errno_save = ano_sockgeterr();
213 
214  if (write_bufend == write_curpos || write_fd == -1)
215  return 0;
216  FD_ZERO(&fds);
217  FD_SET(write_fd, &fds);
218  if (select(write_fd + 1, 0, &fds, 0, wait ? NULL : &tv) == 1) {
219  int maxwrite, nwritten;
220  if (write_curpos > write_bufend) /* wrapped around? */
221  maxwrite = write_buftop - write_curpos;
222  else if (write_bufend == write_netbuf)
223  maxwrite = write_buftop - write_curpos - 1;
224  else
225  maxwrite = write_bufend - write_curpos;
226  nwritten = ano_sockwrite(write_fd, write_curpos, maxwrite);
227  errno_save = ano_sockgeterr();
228  if (debug >= 3)
229  alog("debug: flush_write_buffer wanted %d, got %d", maxwrite,
230  nwritten);
231  if (nwritten > 0) {
232  write_curpos += nwritten;
233  if (write_curpos == write_buftop)
234  write_curpos = write_netbuf;
235  total_written += nwritten;
236  return nwritten;
237  }
238  }
239  ano_sockseterr(errno_save);
240  return 0;
241 }
242 
243 /*************************************************************************/
244 
252 static int buffered_write(ano_socket_t fd, char *buf, int len)
253 {
254  int nwritten, left = len;
255  int errno_save = ano_sockgeterr();
256 
257  if (fd < 0) {
258  errno = EBADF;
259  return -1;
260  }
261  write_fd = fd;
262 
263  while (left > 0) {
264 
265  /* Don't try putting anything in the buffer if it's full. */
266  if (write_curpos != write_bufend + 1 &&
268  || write_bufend != write_buftop - 1)) {
269  /* See if we need to write up to the end of the buffer. */
270  if (write_bufend + left >= write_buftop
271  && write_curpos <= write_bufend) {
272  nwritten = write_buftop - write_bufend;
273  memcpy(write_bufend, buf, nwritten);
274  buf += nwritten;
275  left -= nwritten;
276  write_bufend = write_netbuf;
277  }
278  /* Now we can copy a single chunk to write_bufend. */
280  && write_curpos - write_bufend - 1 < left)
281  nwritten = write_curpos - write_bufend - 1;
282  else
283  nwritten = left;
284  if (nwritten) {
285  memcpy(write_bufend, buf, nwritten);
286  buf += nwritten;
287  left -= nwritten;
288  write_bufend += nwritten;
289  }
290  }
291 
292  /* Now write to the socket as much as we can. */
293  if (write_curpos == write_bufend + 1 ||
295  && write_bufend == write_buftop - 1))
297  else
299  errno_save = errno;
300  if (write_curpos == write_bufend + 1 ||
302  && write_bufend == write_buftop - 1)) {
303  /* Write failed on full buffer */
304  break;
305  }
306  }
307 
308  if (debug >= 4) {
309  alog("debug: buffered_write(%d,%p,%d) returning %d",
310  fd, buf, len, len - left);
311  }
312  ano_sockseterr(errno_save);
313  return len - left;
314 }
315 
316 
317 /*************************************************************************/
318 
327 #if 0
328 static int buffered_write_one(int c, ano_socket_t fd)
329 {
330  struct timeval tv = { 0, 0 };
331 
332  if (fd < 0) {
334  return -1;
335  }
336  write_fd = fd;
337 
338  /* Try to flush the buffer if it's full. */
339  if (write_curpos == write_bufend + 1 ||
341  && write_bufend == write_buftop - 1)) {
343  if (write_curpos == write_bufend + 1 ||
345  && write_bufend == write_buftop - 1)) {
346  /* Write failed */
347  if (debug >= 4)
348  alog("debug: buffered_write_one(%d) returning %d", fd,
349  EOF);
350  return EOF;
351  }
352  }
353 
354  /* Write the character. */
355  *write_bufend++ = c;
356  if (write_bufend == write_buftop)
358 
359  /* Move it to the socket if we can. */
361 
362  if (debug >= 4)
363  alog("debug: buffered_write_one(%d) returning %d", fd, c);
364  return (int) c & 0xFF;
365 }
366 #endif /* 0 */
367 
368 /*************************************************************************/
369 
376 {
377  int c;
378 
379  if (lastchar != EOF) {
380  c = lastchar;
381  lastchar = EOF;
382  return c;
383  }
384  return buffered_read_one(s);
385 }
386 
387 /*************************************************************************/
388 
395 int sungetc(int c, int s)
396 {
397  return lastchar = c;
398 }
399 
400 /*************************************************************************/
401 
410 char *sgets(char *buf, int len, ano_socket_t s)
411 {
412  int c = 0;
413  struct timeval tv;
414  fd_set fds;
415  char *ptr = buf;
416 
418 
419  if (len == 0)
420  return NULL;
421  FD_ZERO(&fds);
422  FD_SET(s, &fds);
423  tv.tv_sec = ReadTimeout;
424  tv.tv_usec = 0;
425  while (read_buffer_len() == 0 &&
426  (c = select(s + 1, &fds, NULL, NULL, &tv)) < 0) {
427  if (ano_sockgeterr() != EINTR)
428  break;
430  }
431  if (read_buffer_len() == 0 && c == 0)
432  return (char *) -1;
433  c = sgetc(s);
434  while (--len && (*ptr++ = c) != '\n' && (c = sgetc(s)) >= 0);
435  if (c < 0)
436  return NULL;
437  *ptr = 0;
438  return buf;
439 }
440 
441 /*************************************************************************/
442 
451 char *sgets2(char *buf, int len, ano_socket_t s)
452 {
453  char *str = sgets(buf, len, s);
454 
455  if (!str || str == (char *) -1)
456  return str;
457  str = buf + strlen(buf) - 1;
458  if (*str == '\n')
459  *str-- = 0;
460  if (*str == '\r')
461  *str = 0;
462  return buf;
463 }
464 
465 /*************************************************************************/
466 
475 int sread(ano_socket_t s, char *buf, int len)
476 {
477  return buffered_read(s, buf, len);
478 }
479 
480 /*************************************************************************/
481 
488 int sputs(char *str, ano_socket_t s)
489 {
490  return buffered_write(s, str, strlen(str));
491 }
492 
493 /*************************************************************************/
494 
502 int sockprintf(ano_socket_t s, char *fmt, ...)
503 {
504  va_list args;
505  char buf[16384]; /* Really huge, to try and avoid truncation */
506  int value;
507 
508  va_start(args, fmt);
509  value = buffered_write(s, buf, vsnprintf(buf, sizeof(buf), fmt, args));
510  va_end(args);
511  return value;
512 }
513 
514 /*************************************************************************/
515 
516 #if !HAVE_GETHOSTBYNAME
517 
524 static char *pack_ip(const char *ipaddr)
525 {
526  static char ipbuf[4];
527  int tmp[4], i;
528 
529  if (sscanf(ipaddr, "%d.%d.%d.%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3])
530  != 4)
531  return NULL;
532  for (i = 0; i < 4; i++) {
533  if (tmp[i] < 0 || tmp[i] > 255)
534  return NULL;
535  ipbuf[i] = tmp[i];
536  }
537  return ipbuf;
538 }
539 
540 #endif
541 
542 /*************************************************************************/
543 
553 int conn(const char *host, int port, const char *lhost, int lport)
554 {
555 #if HAVE_GETHOSTBYNAME
556  struct hostent *hp;
557 #else
558  char *addr;
559 #endif
560  struct sockaddr_in sa, lsa;
561  ano_socket_t sock;
562  int sockopt = 1;
563 
564  memset(&lsa, 0, sizeof(lsa));
565  if (lhost) {
566 #if HAVE_GETHOSTBYNAME
567  if ((hp = gethostbyname(lhost)) != NULL) {
568  memcpy((char *) &lsa.sin_addr, hp->h_addr, hp->h_length);
569  lsa.sin_family = hp->h_addrtype;
570 #else
571  if (addr = pack_ip(lhost)) {
572  memcpy((char *) &lsa.sin_addr, addr, 4);
573  lsa.sin_family = AF_INET;
574 #endif
575  } else {
576  lhost = NULL;
577  }
578  }
579  if (lport)
580  lsa.sin_port = htons((unsigned short) lport);
581 
582  memset(&sa, 0, sizeof(sa));
583 #if HAVE_GETHOSTBYNAME
584  if (!(hp = gethostbyname(host)))
585  return -1;
586  memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
587  sa.sin_family = hp->h_addrtype;
588 #else
589  if (!(addr = pack_ip(host))) {
590  alog("conn(): `%s' is not a valid IP address", host);
592  return -1;
593  }
594  memcpy((char *) &sa.sin_addr, addr, 4);
595  sa.sin_family = AF_INET;
596 #endif
597  sa.sin_port = htons((unsigned short) port);
598 
599  if ((sock = socket(sa.sin_family, SOCK_STREAM, 0)) < 0)
600  return -1;
601 
602  if (setsockopt
603  (sock, SOL_SOCKET, SO_REUSEADDR, (char *) &sockopt,
604  sizeof(int)) < 0)
605  alog("debug: couldn't set SO_REUSEADDR on socket");
606 
607  if ((lhost || lport)
608  && bind(sock, (struct sockaddr *) &lsa, sizeof(lsa)) < 0) {
609  int errno_save = ano_sockgeterr();
610  ano_sockclose(sock);
611  ano_sockseterr(errno_save);
612  return -1;
613  }
614 
615  if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
616  int errno_save = ano_sockgeterr();
617  ano_sockclose(sock);
618  ano_sockseterr(errno_save);
619  return -1;
620  }
621 
622  return sock;
623 }
624 
625 /*************************************************************************/
626 
633 {
634  shutdown(s, 2);
635  ano_sockclose(s);
636 }
637 
638 /*************************************************************************/
639 /* Windows support functions */
640 
641 #ifdef _WIN32
642 /* Microsoft makes things nice and fun for us! */
643 struct u_WSA_errors {
644  int error_code;
645  char *error_string;
646 };
647 
648 /* Must be sorted ascending by error code */
649 struct u_WSA_errors WSAErrors[] = {
650  {WSAEINTR, "Interrupted system call"},
651  {WSAEBADF, "Bad file number"},
652  {WSAEACCES, "Permission denied"},
653  {WSAEFAULT, "Bad address"},
654  {WSAEINVAL, "Invalid argument"},
655  {WSAEMFILE, "Too many open sockets"},
656  {WSAEWOULDBLOCK, "Operation would block"},
657  {WSAEINPROGRESS, "Operation now in progress"},
658  {WSAEALREADY, "Operation already in progress"},
659  {WSAENOTSOCK, "Socket operation on non-socket"},
660  {WSAEDESTADDRREQ, "Destination address required"},
661  {WSAEMSGSIZE, "Message too long"},
662  {WSAEPROTOTYPE, "Protocol wrong type for socket"},
663  {WSAENOPROTOOPT, "Bad protocol option"},
664  {WSAEPROTONOSUPPORT, "Protocol not supported"},
665  {WSAESOCKTNOSUPPORT, "Socket type not supported"},
666  {WSAEOPNOTSUPP, "Operation not supported on socket"},
667  {WSAEPFNOSUPPORT, "Protocol family not supported"},
668  {WSAEAFNOSUPPORT, "Address family not supported"},
669  {WSAEADDRINUSE, "Address already in use"},
670  {WSAEADDRNOTAVAIL, "Can't assign requested address"},
671  {WSAENETDOWN, "Network is down"},
672  {WSAENETUNREACH, "Network is unreachable"},
673  {WSAENETRESET, "Net connection reset"},
674  {WSAECONNABORTED, "Software caused connection abort"},
675  {WSAECONNRESET, "Connection reset by peer"},
676  {WSAENOBUFS, "No buffer space available"},
677  {WSAEISCONN, "Socket is already connected"},
678  {WSAENOTCONN, "Socket is not connected"},
679  {WSAESHUTDOWN, "Can't send after socket shutdown"},
680  {WSAETOOMANYREFS, "Too many references, can't splice"},
681  {WSAETIMEDOUT, "Connection timed out"},
682  {WSAECONNREFUSED, "Connection refused"},
683  {WSAELOOP, "Too many levels of symbolic links"},
684  {WSAENAMETOOLONG, "File name too long"},
685  {WSAEHOSTDOWN, "Host is down"},
686  {WSAEHOSTUNREACH, "No route to host"},
687  {WSAENOTEMPTY, "Directory not empty"},
688  {WSAEPROCLIM, "Too many processes"},
689  {WSAEUSERS, "Too many users"},
690  {WSAEDQUOT, "Disc quota exceeded"},
691  {WSAESTALE, "Stale NFS file handle"},
692  {WSAEREMOTE, "Too many levels of remote in path"},
693  {WSASYSNOTREADY, "Network subsystem is unavailable"},
694  {WSAVERNOTSUPPORTED, "Winsock version not supported"},
695  {WSANOTINITIALISED, "Winsock not yet initialized"},
696  {WSAHOST_NOT_FOUND, "Host not found"},
697  {WSATRY_AGAIN, "Non-authoritative host not found"},
698  {WSANO_RECOVERY, "Non-recoverable errors"},
699  {WSANO_DATA, "Valid name, no data record of requested type"},
700  {WSAEDISCON, "Graceful disconnect in progress"},
701 #ifdef WSASYSCALLFAILURE
702  {WSASYSCALLFAILURE, "System call failure"},
703 #endif
704  {0, NULL}
705 };
706 
707 char *ano_sockstrerror(int error)
708 {
709  static char unkerr[64];
710  int start = 0;
711  int stop = sizeof(WSAErrors) / sizeof(WSAErrors[0]) - 1;
712  int mid;
713 
714  /* Microsoft decided not to use sequential numbers for the error codes,
715  * so we can't just use the array index for the code. But, at least
716  * use a binary search to make it as fast as possible.
717  */
718  while (start <= stop) {
719  mid = (start + stop) / 2;
720  if (WSAErrors[mid].error_code > error)
721  stop = mid - 1;
722 
723  else if (WSAErrors[mid].error_code < error)
724  start = mid + 1;
725  else
726  return WSAErrors[mid].error_string;
727  }
728  sprintf(unkerr, "Unknown Error: %d", error);
729  return unkerr;
730 }
731 
733 {
734  u_long i = 1;
735  return (!ioctlsocket(fd, FIONBIO, &i) ? -1 : 1);
736 }
737 #endif
int sgetc(ano_socket_t s)
Definition: sockutil.c:375
static char * read_curpos
Definition: sockutil.c:19
static int flush_write_buffer(int wait)
Definition: sockutil.c:208
#define ano_sockgeterr()
Definition: sockets.h:36
static char *const write_buftop
Definition: sockutil.c:26
static int buffered_read_one(ano_socket_t fd)
Definition: sockutil.c:132
int32 write_buffer_len()
Definition: sockutil.c:191
E int ReadTimeout
Definition: extern.h:346
void disconn(ano_socket_t s)
Definition: sockutil.c:632
int sockprintf(ano_socket_t s, char *fmt,...)
Definition: sockutil.c:502
#define SOCKERR_EINVAL
Definition: sockets.h:43
int32_t int32
Definition: db-merger.c:122
static char * pack_ip(const char *ipaddr)
Definition: sockutil.c:524
#define ano_sockclose(fd)
Definition: sockets.h:35
char * sgets2(char *buf, int len, ano_socket_t s)
Definition: sockutil.c:451
int sread(ano_socket_t s, char *buf, int len)
Definition: sockutil.c:475
static char write_netbuf[NET_BUFSIZE]
Definition: sockutil.c:23
Command * c
Definition: ns_recover.c:17
#define SOCKERR_EBADF
Definition: sockets.h:41
static char read_netbuf[NET_BUFSIZE]
Definition: sockutil.c:18
E void alog(const char *fmt,...) FORMAT(printf
char * sgets(char *buf, int len, ano_socket_t s)
Definition: sockutil.c:410
#define NET_BUFSIZE
Definition: config.h:31
static int lastchar
Definition: sockutil.c:29
#define ano_sockseterr(err)
Definition: sockets.h:37
E int debug
Definition: extern.h:775
static char * read_bufend
Definition: sockutil.c:20
static int buffered_write(ano_socket_t fd, char *buf, int len)
Definition: sockutil.c:252
int sputs(char *str, ano_socket_t s)
Definition: sockutil.c:488
int sungetc(int c, int s)
Definition: sockutil.c:395
int32 total_read
Definition: sockutil.c:22
#define ano_sockstrerror(err)
Definition: sockets.h:38
int32 total_written
Definition: sockutil.c:28
static char * write_bufend
Definition: sockutil.c:25
int32 read_buffer_len()
Definition: sockutil.c:37
#define ano_socksetnonb(fd)
Definition: sockets.h:39
E int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
static int buffered_read(ano_socket_t fd, char *buf, int len)
Definition: sockutil.c:55
static char *const read_buftop
Definition: sockutil.c:21
#define ano_sockread(fd, buf, len)
Definition: sockets.h:33
int conn(const char *host, int port, const char *lhost, int lport)
Definition: sockutil.c:553
static char * write_curpos
Definition: sockutil.c:24
void error(int linenum, const char *message,...)
Definition: config.c:648
int ano_socket_t
Definition: sockets.h:32
static int write_fd
Definition: sockutil.c:27
#define ano_sockwrite(fd, buf, len)
Definition: sockets.h:34