root/sapi/phpdbg/phpdbg_io.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_EXTERN_MODULE_GLOBALS
  2. phpdbg_consume_bytes
  3. phpdbg_send_bytes
  4. phpdbg_mixed_read
  5. phpdbg_output_pager
  6. phpdbg_mixed_write
  7. phpdbg_open_socket
  8. phpdbg_create_listenable_socket
  9. phpdbg_close_socket

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Authors: Anatol Belski <ab@php.net>                                  |
  16    +----------------------------------------------------------------------+
  17 */
  18 
  19 #ifdef HAVE_CONFIG_H
  20 #include "config.h"
  21 #endif
  22 
  23 #include "phpdbg_io.h"
  24 
  25 #ifdef PHP_WIN32
  26 #undef UNICODE
  27 #include "win32/inet.h"
  28 #include <winsock2.h>
  29 #include <windows.h>
  30 #include <Ws2tcpip.h>
  31 #include "win32/sockets.h"
  32 
  33 #else
  34 
  35 #if HAVE_SYS_TYPES_H
  36 #include <sys/types.h>
  37 #endif
  38 #include <sys/socket.h>
  39 #include <netinet/in.h>
  40 #if HAVE_ARPA_INET_H
  41 #include <arpa/inet.h>
  42 #endif
  43 #include <netdb.h>
  44 #include <fcntl.h>
  45 #include <poll.h>
  46 #endif
  47 
  48 ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
  49 
  50 /* is easy to generalize ... but not needed for now */
  51 PHPDBG_API int phpdbg_consume_stdin_line(char *buf) {
  52         int bytes = PHPDBG_G(input_buflen), len = 0;
  53 
  54         if (PHPDBG_G(input_buflen)) {
  55                 memcpy(buf, PHPDBG_G(input_buffer), bytes);
  56         }
  57 
  58         PHPDBG_G(last_was_newline) = 1;
  59 
  60         do {
  61                 int i;
  62                 if (bytes <= 0) {
  63                         continue;
  64                 }
  65 
  66                 for (i = len; i < len + bytes; i++) {
  67                         if (buf[i] == '\x03') {
  68                                 if (i != len + bytes - 1) {
  69                                         memmove(buf + i, buf + i + 1, len + bytes - i - 1);
  70                                 }
  71                                 len--;
  72                                 i--;
  73                                 continue;
  74                         }
  75                         if (buf[i] == '\n') {
  76                                 PHPDBG_G(input_buflen) = len + bytes - 1 - i;
  77                                 if (PHPDBG_G(input_buflen)) {
  78                                         memcpy(PHPDBG_G(input_buffer), buf + i + 1, PHPDBG_G(input_buflen));
  79                                 }
  80                                 if (i != PHPDBG_MAX_CMD - 1) {
  81                                         buf[i + 1] = 0;
  82                                 }
  83                                 return i;
  84                         }
  85                 }
  86 
  87                 len += bytes;
  88         } while ((bytes = phpdbg_mixed_read(PHPDBG_G(io)[PHPDBG_STDIN].fd, buf + len, PHPDBG_MAX_CMD - len, -1)) > 0);
  89 
  90         if (bytes <= 0) {
  91                 PHPDBG_G(flags) |= PHPDBG_IS_QUITTING | PHPDBG_IS_DISCONNECTED;
  92                 zend_bailout();
  93         }
  94 
  95         return bytes;
  96 }
  97 
  98 PHPDBG_API int phpdbg_consume_bytes(int sock, char *ptr, int len, int tmo) {
  99         int got_now, i = len, j;
 100         char *p = ptr;
 101 #ifndef PHP_WIN32
 102         struct pollfd pfd;
 103 
 104         if (tmo < 0) goto recv_once;
 105         pfd.fd = sock;
 106         pfd.events = POLLIN;
 107 
 108         j = poll(&pfd, 1, tmo);
 109 
 110         if (j == 0) {
 111 #else
 112         struct fd_set readfds;
 113         struct timeval ttmo;
 114 
 115         if (tmo < 0) goto recv_once;
 116         FD_ZERO(&readfds);
 117         FD_SET(sock, &readfds);
 118 
 119         ttmo.tv_sec = 0;
 120         ttmo.tv_usec = tmo*1000;
 121 
 122         j = select(0, &readfds, NULL, NULL, &ttmo);
 123 
 124         if (j <= 0) {
 125 #endif
 126                 return -1;
 127         }
 128 
 129 recv_once:
 130         while(i > 0) {
 131                 if (tmo < 0) {
 132                         /* There's something to read. Read what's available and proceed
 133                         disregarding whether len could be exhausted or not.*/
 134                         int can_read = recv(sock, p, i, MSG_PEEK);
 135 #ifndef _WIN32
 136                         if (can_read == -1 && errno == EINTR) {
 137                                 continue;
 138                         }
 139 #endif
 140                         i = can_read;
 141                 }
 142 
 143 #ifdef _WIN32
 144                 got_now = recv(sock, p, i, 0);
 145 #else
 146                 do {
 147                         got_now = recv(sock, p, i, 0);
 148                 } while (got_now == -1 && errno == EINTR);
 149 #endif
 150 
 151                 if (got_now == -1) {
 152                         quiet_write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Read operation timed out!\n"));
 153                         return -1;
 154                 }
 155                 i -= got_now;
 156                 p += got_now;
 157         }
 158 
 159         return p - ptr;
 160 }
 161 
 162 PHPDBG_API int phpdbg_send_bytes(int sock, const char *ptr, int len) {
 163         int sent, i = len;
 164         const char *p = ptr;
 165 /* XXX poll/select needed here? */
 166         while(i > 0) {
 167                 sent = send(sock, p, i, 0);
 168                 if (sent == -1) {
 169                         return -1;
 170                 }
 171                 i -= sent;
 172                 p += sent;
 173         }
 174 
 175         return len;
 176 }
 177 
 178 
 179 PHPDBG_API int phpdbg_mixed_read(int sock, char *ptr, int len, int tmo) {
 180         int ret;
 181 
 182         if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
 183                 return phpdbg_consume_bytes(sock, ptr, len, tmo);
 184         }
 185 
 186         do {
 187                 ret = read(sock, ptr, len);
 188         } while (ret == -1 && errno == EINTR);
 189 
 190         return ret;
 191 }
 192 
 193 static int phpdbg_output_pager(int sock, const char *ptr, int len) {
 194         int count = 0, bytes = 0;
 195         const char *p = ptr, *endp = ptr + len;
 196         
 197         while ((p = memchr(p, '\n', endp - p))) {
 198                 count++;
 199                 p++;
 200                 
 201                 if (count % PHPDBG_G(lines) == 0) {
 202                         bytes += write(sock, ptr + bytes, (p - ptr) - bytes);
 203                         
 204                         if (memchr(p, '\n', endp - p)) {
 205                                 char buf[PHPDBG_MAX_CMD];
 206                                 write(sock, ZEND_STRL("\r---Type <return> to continue or q <return> to quit---"));
 207                                 phpdbg_consume_stdin_line(buf);
 208                                 if (*buf == 'q') {
 209                                         break;
 210                                 }
 211                                 write(sock, "\r", 1);
 212                         } else break;
 213                 }
 214         }
 215         if (bytes && count % PHPDBG_G(lines) != 0) {
 216                 bytes += write(sock, ptr + bytes, len - bytes);
 217         } else if (!bytes) {
 218                 bytes += write(sock, ptr, len);
 219         }
 220         return bytes;
 221 }
 222 
 223 PHPDBG_API int phpdbg_mixed_write(int sock, const char *ptr, int len) {
 224         if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
 225                 return phpdbg_send_bytes(sock, ptr, len);
 226         }
 227         
 228         if ((PHPDBG_G(flags) & PHPDBG_HAS_PAGINATION)
 229          && !(PHPDBG_G(flags) & PHPDBG_WRITE_XML)
 230          && PHPDBG_G(io)[PHPDBG_STDOUT].fd == sock
 231          && PHPDBG_G(lines) > 0) {
 232                 return phpdbg_output_pager(sock, ptr, len);
 233         }
 234 
 235         return write(sock, ptr, len);
 236 }
 237 
 238 PHPDBG_API int phpdbg_open_socket(const char *interface, unsigned short port) {
 239         struct addrinfo res;
 240         int fd = phpdbg_create_listenable_socket(interface, port, &res);
 241 
 242         if (fd == -1) {
 243                 return -1;
 244         }
 245 
 246         if (bind(fd, res.ai_addr, res.ai_addrlen) == -1) {
 247                 phpdbg_close_socket(fd);
 248                 return -4;
 249         }
 250 
 251         listen(fd, 5);
 252 
 253         return fd;
 254 }
 255 
 256 
 257 PHPDBG_API int phpdbg_create_listenable_socket(const char *addr, unsigned short port, struct addrinfo *addr_res) {
 258         int sock = -1, rc;
 259         int reuse = 1;
 260         struct in6_addr serveraddr;
 261         struct addrinfo hints, *res = NULL;
 262         char port_buf[8];
 263         int8_t any_addr = *addr == '*';
 264 
 265         do {
 266                 memset(&hints, 0, sizeof hints);
 267                 if (any_addr) {
 268                         hints.ai_flags = AI_PASSIVE;
 269                 } else {
 270                         hints.ai_flags = AI_NUMERICSERV;
 271                 }
 272                 hints.ai_family = AF_UNSPEC;
 273                 hints.ai_socktype = SOCK_STREAM;
 274 
 275                 rc = inet_pton(AF_INET, addr, &serveraddr);
 276                 if (1 == rc) {
 277                         hints.ai_family = AF_INET;
 278                         if (!any_addr) {
 279                                 hints.ai_flags |= AI_NUMERICHOST;
 280                         }
 281                 } else {
 282                         rc = inet_pton(AF_INET6, addr, &serveraddr);
 283                         if (1 == rc) {
 284                                 hints.ai_family = AF_INET6;
 285                                 if (!any_addr) {
 286                                         hints.ai_flags |= AI_NUMERICHOST;
 287                                 }
 288                         } else {
 289                                 /* XXX get host by name ??? */
 290                         }
 291                 }
 292 
 293                 snprintf(port_buf, 7, "%u", port);
 294                 if (!any_addr) {
 295                         rc = getaddrinfo(addr, port_buf, &hints, &res);
 296                 } else {
 297                         rc = getaddrinfo(NULL, port_buf, &hints, &res);
 298                 }
 299 
 300                 if (0 != rc) {
 301 #ifndef PHP_WIN32
 302                         if (rc == EAI_SYSTEM) {
 303                                 char buf[128];
 304                                 int wrote;
 305 
 306                                 wrote = snprintf(buf, 128, "Could not translate address '%s'", addr);
 307                                 buf[wrote] = '\0';
 308                                 quiet_write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf));
 309 
 310                                 return sock;
 311                         } else {
 312 #endif
 313                                 char buf[256];
 314                                 int wrote;
 315 
 316                                 wrote = snprintf(buf, 256, "Host '%s' not found. %s", addr, estrdup(gai_strerror(rc)));
 317                                 buf[wrote] = '\0';
 318                                 quiet_write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf));
 319 
 320                                 return sock;
 321 #ifndef PHP_WIN32
 322                         }
 323 #endif
 324                         return sock;
 325                 }
 326 
 327                 if((sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) {
 328                         char buf[128];
 329                         int wrote;
 330 
 331                         wrote = sprintf(buf, "Unable to create socket");
 332                         buf[wrote] = '\0';
 333                         quiet_write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf));
 334 
 335                         return sock;
 336                 }
 337 
 338                 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse)) == -1) {
 339                         phpdbg_close_socket(sock);
 340                         return sock;
 341                 }
 342 
 343 
 344         } while (0);
 345 
 346         *addr_res = *res;
 347 
 348         return sock;
 349 }
 350 
 351 PHPDBG_API void phpdbg_close_socket(int sock) {
 352         if (socket >= 0) {
 353 #ifdef _WIN32
 354                 closesocket(sock);
 355 #else
 356                 shutdown(sock, SHUT_RDWR);
 357                 close(sock);
 358 #endif
 359         }
 360 }
 361 

/* [<][>][^][v][top][bottom][index][help] */