Back to index

php5  5.3.10
Classes | Defines | Typedefs | Enumerations | Functions
fastcgi.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  _fcgi_header
struct  _fcgi_begin_request
struct  _fcgi_begin_request_rec
struct  _fcgi_end_request
struct  _fcgi_end_request_rec
struct  _fcgi_request

Defines

#define FCGI_VERSION_1   1
#define FCGI_MAX_LENGTH   0xffff
#define FCGI_KEEP_CONN   1

Typedefs

typedef enum _fcgi_role fcgi_role
typedef enum _fcgi_request_type fcgi_request_type
typedef enum _fcgi_protocol_status dcgi_protocol_status
typedef struct _fcgi_header fcgi_header
typedef struct _fcgi_begin_request fcgi_begin_request
typedef struct
_fcgi_begin_request_rec 
fcgi_begin_request_rec
typedef struct _fcgi_end_request fcgi_end_request
typedef struct
_fcgi_end_request_rec 
fcgi_end_request_rec
typedef struct _fcgi_request fcgi_request

Enumerations

enum  _fcgi_role {
  FCGI_RESPONDER = 1, FCGI_AUTHORIZER = 2, FCGI_FILTER = 3, FCGI_RESPONDER = 1,
  FCGI_AUTHORIZER = 2, FCGI_FILTER = 3
}
enum  _fcgi_request_type {
  FCGI_BEGIN_REQUEST = 1, FCGI_ABORT_REQUEST = 2, FCGI_END_REQUEST = 3, FCGI_PARAMS = 4,
  FCGI_STDIN = 5, FCGI_STDOUT = 6, FCGI_STDERR = 7, FCGI_DATA = 8,
  FCGI_GET_VALUES = 9, FCGI_GET_VALUES_RESULT = 10, FCGI_BEGIN_REQUEST = 1, FCGI_ABORT_REQUEST = 2,
  FCGI_END_REQUEST = 3, FCGI_PARAMS = 4, FCGI_STDIN = 5, FCGI_STDOUT = 6,
  FCGI_STDERR = 7, FCGI_DATA = 8, FCGI_GET_VALUES = 9, FCGI_GET_VALUES_RESULT = 10
}
enum  _fcgi_protocol_status {
  FCGI_REQUEST_COMPLETE = 0, FCGI_CANT_MPX_CONN = 1, FCGI_OVERLOADED = 2, FCGI_UNKNOWN_ROLE = 3,
  FCGI_REQUEST_COMPLETE = 0, FCGI_CANT_MPX_CONN = 1, FCGI_OVERLOADED = 2, FCGI_UNKNOWN_ROLE = 3
}

Functions

int fcgi_init (void)
void fcgi_shutdown (void)
void fcgi_init_request (fcgi_request *req, int listen_socket)
int fcgi_accept_request (fcgi_request *req)
int fcgi_finish_request (fcgi_request *req, int force_close)
void fcgi_set_in_shutdown (int)
void fcgi_set_allowed_clients (char *)
void fcgi_close (fcgi_request *req, int force, int destroy)
char * fcgi_getenv (fcgi_request *req, const char *var, int var_len)
char * fcgi_putenv (fcgi_request *req, char *var, int var_len, char *val)
int fcgi_read (fcgi_request *req, char *str, int len)
ssize_t fcgi_write (fcgi_request *req, fcgi_request_type type, const char *str, int len)
int fcgi_flush (fcgi_request *req, int close)
void fcgi_set_mgmt_var (const char *name, size_t name_len, const char *value, size_t value_len)
void fcgi_free_mgmt_var_cb (void *ptr)
char * fcgi_get_last_client_ip ()

Class Documentation

struct _fcgi_header

Definition at line 55 of file fastcgi.h.

Class Members
unsigned char contentLengthB0
unsigned char contentLengthB1
unsigned char paddingLength
unsigned char requestIdB0
unsigned char requestIdB1
unsigned char reserved
unsigned char type
unsigned char version
struct _fcgi_begin_request

Definition at line 66 of file fastcgi.h.

Class Members
unsigned char flags
unsigned char reserved
unsigned char roleB0
unsigned char roleB1
struct _fcgi_begin_request_rec

Definition at line 73 of file fastcgi.h.

Collaboration diagram for _fcgi_begin_request_rec:
Class Members
fcgi_begin_request body
fcgi_header hdr
struct _fcgi_end_request

Definition at line 78 of file fastcgi.h.

Class Members
unsigned char appStatusB0
unsigned char appStatusB1
unsigned char appStatusB2
unsigned char appStatusB3
unsigned char protocolStatus
unsigned char reserved
struct _fcgi_end_request_rec

Definition at line 87 of file fastcgi.h.

Collaboration diagram for _fcgi_end_request_rec:
Class Members
fcgi_end_request body
fcgi_header hdr
struct _fcgi_request

Definition at line 94 of file fastcgi.h.

Collaboration diagram for _fcgi_request:
Class Members
int closed
HashTable * env
int fd
int id
int in_len
int in_pad
int keep
int listen_socket
unsigned char out_buf
fcgi_header * out_hdr
unsigned char * out_pos
unsigned char reserved

Define Documentation

#define FCGI_KEEP_CONN   1

Definition at line 27 of file fastcgi.h.

#define FCGI_MAX_LENGTH   0xffff

Definition at line 25 of file fastcgi.h.

#define FCGI_VERSION_1   1

Definition at line 23 of file fastcgi.h.


Typedef Documentation

typedef struct _fcgi_header fcgi_header
typedef struct _fcgi_request fcgi_request
typedef enum _fcgi_role fcgi_role

Enumeration Type Documentation

Enumerator:
FCGI_REQUEST_COMPLETE 
FCGI_CANT_MPX_CONN 
FCGI_OVERLOADED 
FCGI_UNKNOWN_ROLE 
FCGI_REQUEST_COMPLETE 
FCGI_CANT_MPX_CONN 
FCGI_OVERLOADED 
FCGI_UNKNOWN_ROLE 

Definition at line 48 of file fastcgi.h.

Enumerator:
FCGI_BEGIN_REQUEST 
FCGI_ABORT_REQUEST 
FCGI_END_REQUEST 
FCGI_PARAMS 
FCGI_STDIN 
FCGI_STDOUT 
FCGI_STDERR 
FCGI_DATA 
FCGI_GET_VALUES 
FCGI_GET_VALUES_RESULT 
FCGI_BEGIN_REQUEST 
FCGI_ABORT_REQUEST 
FCGI_END_REQUEST 
FCGI_PARAMS 
FCGI_STDIN 
FCGI_STDOUT 
FCGI_STDERR 
FCGI_DATA 
FCGI_GET_VALUES 
FCGI_GET_VALUES_RESULT 

Definition at line 35 of file fastcgi.h.

                                {
       FCGI_BEGIN_REQUEST          =  1, /* [in]                              */
       FCGI_ABORT_REQUEST          =  2, /* [in]  (not supported)             */
       FCGI_END_REQUEST            =  3, /* [out]                             */
       FCGI_PARAMS                        =  4, /* [in]  environment variables       */
       FCGI_STDIN                         =  5, /* [in]  post data                   */
       FCGI_STDOUT                        =  6, /* [out] response                    */
       FCGI_STDERR                        =  7, /* [out] errors                      */
       FCGI_DATA                          =  8, /* [in]  filter data (not supported) */
       FCGI_GET_VALUES                    =  9, /* [in]                              */
       FCGI_GET_VALUES_RESULT      = 10  /* [out]                             */
} fcgi_request_type;
enum _fcgi_role
Enumerator:
FCGI_RESPONDER 
FCGI_AUTHORIZER 
FCGI_FILTER 
FCGI_RESPONDER 
FCGI_AUTHORIZER 
FCGI_FILTER 

Definition at line 29 of file fastcgi.h.


Function Documentation

Definition at line 927 of file fastcgi.c.

{
#ifdef _WIN32
       HANDLE pipe;
       OVERLAPPED ov;
#endif

       while (1) {
              if (req->fd < 0) {
                     while (1) {
                            if (in_shutdown) {
                                   return -1;
                            }
#ifdef _WIN32
                            if (!req->tcp) {
                                   pipe = (HANDLE)_get_osfhandle(req->listen_socket);
                                   FCGI_LOCK(req->listen_socket);
                                   ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
                                   if (!ConnectNamedPipe(pipe, &ov)) {
                                          errno = GetLastError();
                                          if (errno == ERROR_IO_PENDING) {
                                                 while (WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) {
                                                        if (in_shutdown) {
                                                               CloseHandle(ov.hEvent);
                                                               FCGI_UNLOCK(req->listen_socket);
                                                               return -1;
                                                        }
                                                 }
                                          } else if (errno != ERROR_PIPE_CONNECTED) {
                                          }
                                   }
                                   CloseHandle(ov.hEvent);
                                   req->fd = req->listen_socket;
                                   FCGI_UNLOCK(req->listen_socket);
                            } else {
                                   SOCKET listen_socket = (SOCKET)_get_osfhandle(req->listen_socket);
#else
                            {
                                   int listen_socket = req->listen_socket;
#endif
                                   sa_t sa;
                                   socklen_t len = sizeof(sa);

                                   FCGI_LOCK(req->listen_socket);
                                   req->fd = accept(listen_socket, (struct sockaddr *)&sa, &len);
                                   FCGI_UNLOCK(req->listen_socket);
                                   if (req->fd >= 0 && allowed_clients) {
                                          int n = 0;
                                          int allowed = 0;

                                                 while (allowed_clients[n] != INADDR_NONE) {
                                                        if (allowed_clients[n] == sa.sa_inet.sin_addr.s_addr) {
                                                               allowed = 1;
                                                               break;
                                                        }
                                                        n++;
                                                 }
                                          if (!allowed) {
                                                 fprintf(stderr, "Connection from disallowed IP address '%s' is dropped.\n", inet_ntoa(sa.sa_inet.sin_addr));
                                                 closesocket(req->fd);
                                                 req->fd = -1;
                                                 continue;
                                          }
                                   }
                            }

#ifdef _WIN32
                            if (req->fd < 0 && (in_shutdown || errno != EINTR)) {
#else
                            if (req->fd < 0 && (in_shutdown || (errno != EINTR && errno != ECONNABORTED))) {
#endif
                                   return -1;
                            }

#ifdef _WIN32
                            break;
#else
                            if (req->fd >= 0) {
#if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
                                   struct pollfd fds;
                                   int ret;

                                   fds.fd = req->fd;
                                   fds.events = POLLIN;
                                   fds.revents = 0;
                                   do {
                                          errno = 0;
                                          ret = poll(&fds, 1, 5000);
                                   } while (ret < 0 && errno == EINTR);
                                   if (ret > 0 && (fds.revents & POLLIN)) {
                                          break;
                                   }
                                   fcgi_close(req, 1, 0);
#else
                                   if (req->fd < FD_SETSIZE) {
                                          struct timeval tv = {5,0};
                                          fd_set set;
                                          int ret;

                                          FD_ZERO(&set);
                                          FD_SET(req->fd, &set);
                                          do {
                                                 errno = 0;
                                                 ret = select(req->fd + 1, &set, NULL, NULL, &tv) >= 0;
                                          } while (ret < 0 && errno == EINTR);
                                          if (ret > 0 && FD_ISSET(req->fd, &set)) {
                                                 break;
                                          }
                                          fcgi_close(req, 1, 0);
                                   } else {
                                          fprintf(stderr, "Too many open file descriptors. FD_SETSIZE limit exceeded.");
                                          fcgi_close(req, 1, 0);
                                   }
#endif
                            }
#endif
                     }
              } else if (in_shutdown) {
                     return -1;
              }
              if (fcgi_read_request(req)) {
#ifdef _WIN32
                     if (is_impersonate && !req->tcp) {
                            pipe = (HANDLE)_get_osfhandle(req->fd);
                            if (!ImpersonateNamedPipeClient(pipe)) {
                                   fcgi_close(req, 1, 1);
                                   continue;
                            }
                     }
#endif
                     return req->fd;
              } else {
                     fcgi_close(req, 1, 1);
              }
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void fcgi_close ( fcgi_request req,
int  force,
int  destroy 
)

Definition at line 711 of file fastcgi.c.

{
       if (destroy && req->env) {
              zend_hash_destroy(req->env);
              FREE_HASHTABLE(req->env);
              req->env = NULL;
       }

#ifdef _WIN32
       if (is_impersonate && !req->tcp) {
              RevertToSelf();
       }
#endif

       if ((force || !req->keep) && req->fd >= 0) {
#ifdef _WIN32
              if (!req->tcp) {
                     HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);

                     if (!force) {
                            FlushFileBuffers(pipe);
                     }
                     DisconnectNamedPipe(pipe);
              } else {
                     if (!force) {
                            char buf[8];

                            shutdown(req->fd, 1);
                            while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
                     }
                     closesocket(req->fd);
              }
#else
              if (!force) {
                     char buf[8];

                     shutdown(req->fd, 1);
                     while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
              }
              close(req->fd);
#endif
              req->fd = -1;
              fpm_request_finished();
       }
}

Here is the call graph for this function:

int fcgi_finish_request ( fcgi_request req,
int  force_close 
)

Definition at line 1223 of file fastcgi.c.

{
       int ret = 1;

       if (req->fd >= 0) {
              if (!req->closed) {
                     ret = fcgi_flush(req, 1);
                     req->closed = 1;
              }
              fcgi_close(req, force_close, 1);
       }
       return ret;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int fcgi_flush ( fcgi_request req,
int  close 
)

Definition at line 1082 of file fastcgi.c.

{
       int len;

       close_packet(req);

       len = req->out_pos - req->out_buf;

       if (close) {
              fcgi_end_request_rec *rec = (fcgi_end_request_rec*)(req->out_pos);

              fcgi_make_header(&rec->hdr, FCGI_END_REQUEST, req->id, sizeof(fcgi_end_request));
              rec->body.appStatusB3 = 0;
              rec->body.appStatusB2 = 0;
              rec->body.appStatusB1 = 0;
              rec->body.appStatusB0 = 0;
              rec->body.protocolStatus = FCGI_REQUEST_COMPLETE;
              len += sizeof(fcgi_end_request_rec);
       }

       if (safe_write(req, req->out_buf, len) != len) {
              req->keep = 0;
              return 0;
       }

       req->out_pos = req->out_buf;
       return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void fcgi_free_mgmt_var_cb ( void *  ptr)

Definition at line 1288 of file fastcgi.c.

{
       zval ** var = (zval **)ptr;
       pefree(Z_STRVAL_PP(var), 1);
       pefree(*var, 1);
}

Here is the caller graph for this function:

Definition at line 1092 of file fastcgi.c.

{
       if (client_sa.sa.sa_family == AF_UNIX) {
              return NULL;
       }
       return inet_ntoa(client_sa.sa_inet.sin_addr);
}

Here is the caller graph for this function:

char* fcgi_getenv ( fcgi_request req,
const char *  var,
int  var_len 
)

Definition at line 1237 of file fastcgi.c.

{
       char **val;

       if (!req) return NULL;

       if (zend_hash_find(req->env, (char*)var, var_len+1, (void**)&val) == SUCCESS) {
              return *val;
       }
       return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int fcgi_init ( void  )

Definition at line 183 of file fastcgi.c.

{
       if (!is_initialized) {
#ifndef _WIN32
              sa_t sa;
              socklen_t len = sizeof(sa);
#endif
              zend_hash_init(&fcgi_mgmt_vars, 0, NULL, fcgi_free_mgmt_var_cb, 1);
              fcgi_set_mgmt_var("FCGI_MPXS_CONNS", sizeof("FCGI_MPXS_CONNS")-1, "0", sizeof("0")-1);

              is_initialized = 1;
#ifdef _WIN32
# if 0
              /* TODO: Support for TCP sockets */
              WSADATA wsaData;

              if (WSAStartup(MAKEWORD(2,0), &wsaData)) {
                     fprintf(stderr, "Error starting Windows Sockets.  Error: %d", WSAGetLastError());
                     return 0;
              }
# endif
              if ((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) &&
                  (GetStdHandle(STD_ERROR_HANDLE)  == INVALID_HANDLE_VALUE) &&
                  (GetStdHandle(STD_INPUT_HANDLE)  != INVALID_HANDLE_VALUE)) {
                     char *str;
                     DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT;
                     HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE);

                     SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL);

                     str = getenv("_FCGI_SHUTDOWN_EVENT_");
                     if (str != NULL) {
                            HANDLE shutdown_event = (HANDLE) atoi(str);
                            if (!CreateThread(NULL, 0, fcgi_shutdown_thread,
                                              shutdown_event, 0, NULL)) {
                                   return -1;
                            }
                     }
                     str = getenv("_FCGI_MUTEX_");
                     if (str != NULL) {
                            fcgi_accept_mutex = (HANDLE) atoi(str);
                     }
                     return is_fastcgi = 1;
              } else {
                     return is_fastcgi = 0;
              }
#else
              errno = 0;
              if (getpeername(0, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) {
                     fcgi_setup_signals();
                     return is_fastcgi = 1;
              } else {
                     return is_fastcgi = 0;
              }
#endif
       }
       return is_fastcgi;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void fcgi_init_request ( fcgi_request req,
int  listen_socket 
)

Definition at line 510 of file fastcgi.c.

{
       memset(req, 0, sizeof(fcgi_request));
       req->listen_socket = listen_socket;
       req->fd = -1;
       req->id = -1;

       req->in_len = 0;
       req->in_pad = 0;

       req->out_hdr = NULL;
       req->out_pos = req->out_buf;

#ifdef _WIN32
       req->tcp = !GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL, NULL);
#endif
}

Here is the caller graph for this function:

char* fcgi_putenv ( fcgi_request req,
char *  var,
int  var_len,
char *  val 
)

Definition at line 1249 of file fastcgi.c.

{
       if (var && req) {
              if (val == NULL) {
                     zend_hash_del(req->env, var, var_len+1);
              } else {
                     char **ret;

                     val = estrdup(val);
                     if (zend_hash_update(req->env, var, var_len+1, &val, sizeof(char*), (void**)&ret) == SUCCESS) {
                            return *ret;
                     }
              }
       }
       return NULL;
}

Here is the caller graph for this function:

int fcgi_read ( fcgi_request req,
char *  str,
int  len 
)

Definition at line 829 of file fastcgi.c.

{
       int ret, n, rest;
       fcgi_header hdr;
       unsigned char buf[255];

       n = 0;
       rest = len;
       while (rest > 0) {
              if (req->in_len == 0) {
                     if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
                         hdr.version < FCGI_VERSION_1 ||
                         hdr.type != FCGI_STDIN) {
                            req->keep = 0;
                            return 0;
                     }
                     req->in_len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
                     req->in_pad = hdr.paddingLength;
                     if (req->in_len == 0) {
                            return n;
                     }
              }

              if (req->in_len >= rest) {
                     ret = safe_read(req, str, rest);
              } else {
                     ret = safe_read(req, str, req->in_len);
              }
              if (ret < 0) {
                     req->keep = 0;
                     return ret;
              } else if (ret > 0) {
                     req->in_len -= ret;
                     rest -= ret;
                     n += ret;
                     str += ret;
                     if (req->in_len == 0) {
                            if (req->in_pad) {
                                   if (safe_read(req, buf, req->in_pad) != req->in_pad) {
                                          req->keep = 0;
                                          return ret;
                                   }
                            }
                     } else {
                            return n;
                     }
              } else {
                     return n;
              }
       }
       return n;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void fcgi_set_allowed_clients ( char *  )

Definition at line 246 of file fastcgi.c.

{
       char *cur, *end;
       int n;

       if (ip) {
              ip = strdup(ip);
              cur = ip;
              n = 0;
              while (*cur) {
                     if (*cur == ',') n++;
                     cur++;
              }
              if (allowed_clients) free(allowed_clients);
              allowed_clients = malloc(sizeof(in_addr_t) * (n+2));
              n = 0;
              cur = ip;
              while (cur) {
                     end = strchr(cur, ',');
                     if (end) {
                            *end = 0;
                            end++;
                     }
                     allowed_clients[n] = inet_addr(cur);
                     if (allowed_clients[n] == INADDR_NONE) {
                            zlog(ZLOG_ERROR, "Wrong IP address '%s' in listen.allowed_clients", cur);
                     }
                     n++;
                     cur = end;
              }
              allowed_clients[n] = INADDR_NONE;
              free(ip);
       }
}

Here is the caller graph for this function:

Definition at line 231 of file fastcgi.c.

{
       in_shutdown = new_value;
}

Here is the caller graph for this function:

void fcgi_set_mgmt_var ( const char *  name,
size_t  name_len,
const char *  value,
size_t  value_len 
)

Definition at line 1278 of file fastcgi.c.

{
       zval * zvalue;
       zvalue = pemalloc(sizeof(*zvalue), 1);
       Z_TYPE_P(zvalue) = IS_STRING;
       Z_STRVAL_P(zvalue) = pestrndup(value, value_len, 1);
       Z_STRLEN_P(zvalue) = value_len;
       zend_hash_add(&fcgi_mgmt_vars, name, name_len + 1, &zvalue, sizeof(zvalue), NULL);
}

Here is the caller graph for this function:

void fcgi_shutdown ( void  )

Definition at line 252 of file fastcgi.c.

Here is the call graph for this function:

Here is the caller graph for this function:

ssize_t fcgi_write ( fcgi_request req,
fcgi_request_type  type,
const char *  str,
int  len 
)

Definition at line 1111 of file fastcgi.c.

{
       int limit, rest;

       if (len <= 0) {
              return 0;
       }

       if (req->out_hdr && req->out_hdr->type != type) {
              close_packet(req);
       }
#if 0
       /* Unoptimized, but clear version */
       rest = len;
       while (rest > 0) {
              limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);

              if (!req->out_hdr) {
                     if (limit < sizeof(fcgi_header)) {
                            if (!fcgi_flush(req, 0)) {
                                   return -1;
                            }
                     }
                     open_packet(req, type);
              }
              limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
              if (rest < limit) {
                     memcpy(req->out_pos, str, rest);
                     req->out_pos += rest;
                     return len;
              } else {
                     memcpy(req->out_pos, str, limit);
                     req->out_pos += limit;
                     rest -= limit;
                     str += limit;
                     if (!fcgi_flush(req, 0)) {
                            return -1;
                     }
              }
       }
#else
       /* Optimized version */
       limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
       if (!req->out_hdr) {
              limit -= sizeof(fcgi_header);
              if (limit < 0) limit = 0;
       }

       if (len < limit) {
              if (!req->out_hdr) {
                     open_packet(req, type);
              }
              memcpy(req->out_pos, str, len);
              req->out_pos += len;
       } else if (len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) {
              if (!req->out_hdr) {
                     open_packet(req, type);
              }
              if (limit > 0) {
                     memcpy(req->out_pos, str, limit);
                     req->out_pos += limit;
              }
              if (!fcgi_flush(req, 0)) {
                     return -1;
              }
              if (len > limit) {
                     open_packet(req, type);
                     memcpy(req->out_pos, str + limit, len - limit);
                     req->out_pos += len - limit;
              }
       } else {
              int pos = 0;
              int pad;

              close_packet(req);
              while ((len - pos) > 0xffff) {
                     open_packet(req, type);
                     fcgi_make_header(req->out_hdr, type, req->id, 0xfff8);
                     req->out_hdr = NULL;
                     if (!fcgi_flush(req, 0)) {
                            return -1;
                     }
                     if (safe_write(req, str + pos, 0xfff8) != 0xfff8) {
                            req->keep = 0;
                            return -1;
                     }
                     pos += 0xfff8;
              }             
              
              pad = (((len - pos) + 7) & ~7) - (len - pos);
              rest = pad ? 8 - pad : 0;

              open_packet(req, type);
              fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest);
              req->out_hdr = NULL;
              if (!fcgi_flush(req, 0)) {
                     return -1;
              }
              if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) {
                     req->keep = 0;
                     return -1;
              }
              if (pad) {
                     open_packet(req, type);
                     memcpy(req->out_pos, str + len - rest,  rest);
                     req->out_pos += rest;
              }
       }
#endif
       return len;
}

Here is the call graph for this function:

Here is the caller graph for this function: