text: /*
   +----------------------------------------------------------------------+
   | Swoole                                                               |
   +----------------------------------------------------------------------+
   | This source file is subject to version 2.0 of the Apache license,    |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.apache.org/licenses/LICENSE-2.0.html                      |
   | If you did not receive a copy of the Apache2.0 license and are unable|
   | to obtain it through the world-wide-web, please send a note to       |
   | license@swoole.com so we can mail you a copy immediately.            |
   +----------------------------------------------------------------------+
   | Author: Tianfeng Han  <mikan.tenny@gmail.com>                        |
   +----------------------------------------------------------------------+
   */
  
  #include "server.h"
  
  static int swFactory_start(swFactory *factory);
  static int swFactory_shutdown(swFactory *factory);
  static int swFactory_dispatch(swFactory *factory, swSendData *req);
  static int swFactory_notify(swFactory *factory, swDataHead *event);
  static int swFactory_end(swFactory *factory, int fd);
  static void swFactory_free(swFactory *factory);
  
  int swFactory_create(swFactory *factory)
  {
      factory->dispatch = swFactory_dispatch;
      factory->finish = swFactory_finish;
      factory->start = swFactory_start;
      factory->shutdown = swFactory_shutdown;
      factory->end = swFactory_end;
      factory->notify = swFactory_notify;
      factory->free = swFactory_free;
  
      return SW_OK;
  }
  
  static int swFactory_start(swFactory *factory)
  {
      SwooleWG.run_always = 1;
      return SW_OK;
  }
  
  static int swFactory_shutdown(swFactory *factory)
  {
      return SW_OK;
  }
  
  static int swFactory_dispatch(swFactory *factory, swSendData *task)
  {
      swServer *serv = (swServer *) factory->ptr;
      swPacket_ptr pkg;
  
      if (swEventData_is_stream(task->info.type))
      {
          swConnection *conn = swServer_connection_get(serv, task->info.fd);
          if (conn == NULL || conn->active == 0)
          {
              swWarn("dispatch[type=%d] failed, connection#%d is not active", task->info.type, task->info.fd);
              return SW_ERR;
          }
          //server active close, discard data.
          if (conn->closed)
          {
              swWarn("dispatch[type=%d] failed, connection#%d is closed by server", task->info.type,
                      task->info.fd);
              return SW_OK;
          }
          //converted fd to session_id
          task->info.fd = conn->session_id;
          task->info.server_fd = conn->server_fd;
      }
      //with data
      if (task->info.len > 0)
      {
          memcpy(&pkg.info, &task->info, sizeof(pkg.info));
          pkg.info.flags = SW_EVENT_DATA_PTR;
          bzero(&pkg.data, sizeof(pkg.data));
          pkg.data.length = task->info.len;
          pkg.data.str = task->data;
  
          return swWorker_onTask(factory, (swEventData*) &pkg);
      }
      //no data
      else
      {
          return swWorker_onTask(factory, (swEventData*) &task->info);
      }
  }
  
  /**
   * only stream fd
   */
  static int swFactory_notify(swFactory *factory, swDataHead *info)
  {
      swServer *serv = (swServer *) factory->ptr;
      swConnection *conn = swServer_connection_get(serv, info->fd);
      if (conn == NULL || conn->active == 0)
      {
          swWarn("dispatch[type=%d] failed, connection#%d is not active", info->type, info->fd);
          return SW_ERR;
      }
      //server active close, discard data.
      if (conn->closed)
      {
          swWarn("dispatch[type=%d] failed, connection#%d is closed by server", info->type, info->fd);
          return SW_OK;
      }
      //converted fd to session_id
      info->fd = conn->session_id;
      info->server_fd = conn->server_fd;
      info->flags = SW_EVENT_DATA_NORMAL;
      return swWorker_onTask(factory, (swEventData *) info);
  }
  
  static int swFactory_end(swFactory *factory, int fd)
  {
      swServer *serv = (swServer *) factory->ptr;
      swSendData _send;
      swDataHead info;
  
      bzero(&_send, sizeof(_send));
      _send.info.fd = fd;
      _send.info.len = 0;
      _send.info.type = SW_SERVER_EVENT_CLOSE;
  
      swConnection *conn = swWorker_get_connection(serv, fd);
      if (conn == NULL || conn->active == 0)
      {
          //swWarn("can not close. Connection[%d] not found", _send.info.fd);
          return SW_ERR;
      }
      else if (conn->close_force)
      {
          goto _do_close;
      }
      else if (conn->closing)
      {
          swWarn("The connection[%d] is closing", fd);
          return SW_ERR;
      }
      else if (conn->closed)
      {
          return SW_ERR;
      }
      else
      {
          _do_close:
          conn->closing = 1;
          if (serv->onClose != NULL)
          {
              info.fd = fd;
              if (conn->close_actively)
              {
                  info.reactor_id = -1;
              }
              else
              {
                  info.reactor_id = conn->reactor_id;
              }
              info.server_fd = conn->server_fd;
              serv->onClose(serv, &info);
          }
          conn->closing = 0;
          conn->closed = 1;
          conn->close_errno = 0;
  
          if (swBuffer_empty(conn->socket->out_buffer) || conn->peer_closed)
          {
              swReactor *reactor = SwooleTG.reactor;
              return swReactorThread_close(reactor, conn->socket);
          }
          else
          {
              swBuffer_chunk *chunk = swBuffer_new_chunk(conn->socket->out_buffer, SW_CHUNK_CLOSE, 0);
              chunk->store.data.val1 = _send.info.type;
              conn->close_queued = 1;
              return SW_OK;
          }
      }
  }
  
  int swFactory_finish(swFactory *factory, swSendData *resp)
  {
      if (swServer_master_send((swServer *) factory->ptr, resp) < 0)
      {
          return SW_ERR;
      }
      else
      {
          return SW_OK;
      }
  }
  
  static void swFactory_free(swFactory *factory)
  {
  
  }
  