⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nut-transfer.c

📁 Serveez是一个服务器框架
💻 C
📖 第 1 页 / 共 2 页
字号:
  svz_socket_t *sock;  nut_header_t hdr;  nut_push_t push;  nut_packet_t *pkt;  nut_transfer_t *trans;  char *pushkey;  struct sockaddr_in *addr = NULL;  svz_portcfg_t *port;  /* find original socket connection */  if ((sock = svz_sock_find (transfer->id, transfer->version)) != NULL)    {      /* create new gnutella header */      nut_calc_guid (hdr.id);      hdr.function = NUT_PUSH_REQ;      hdr.ttl = (svz_uint8_t) cfg->ttl;      hdr.hop = 0;      hdr.length = SIZEOF_NUT_PUSH;      /* create push request */      memcpy (push.id, transfer->guid, NUT_GUID_SIZE);      push.index = transfer->index;      if ((port = svz_sock_portcfg (sock)) != NULL)	addr = svz_portcfg_addr (port);      push.ip = cfg->ip ? cfg->ip : addr ? 	addr->sin_addr.s_addr : sock->local_addr;      push.port = (unsigned short) (cfg->port ? cfg->port : addr ?				    addr->sin_port : sock->local_port);            /* create push request key and check if it was already sent */      pushkey = svz_malloc (16 + NUT_GUID_SIZE * 2);      sprintf (pushkey, "%d:%s", push.index, nut_text_guid (push.id));      if ((trans = svz_hash_get (cfg->push, pushkey)) != NULL)	{#if ENABLE_DEBUG	  svz_log (LOG_DEBUG, "nut: push request already sent\n");#endif	  svz_free (pushkey);	  return -1;	}      /* try sending header and push request */      if (svz_sock_write (sock, (char *) nut_put_header (&hdr), 			  SIZEOF_NUT_HEADER) == -1 ||	  svz_sock_write (sock, (char *) nut_put_push (&push), 			  SIZEOF_NUT_PUSH) == -1)	{	  svz_sock_schedule_for_shutdown (sock);	  svz_free (pushkey);	  return -1;	}      /* put push request into hash for later reply detection */      trans = svz_malloc (sizeof (nut_transfer_t));      memcpy (trans, transfer, sizeof (nut_transfer_t));      trans->file = svz_strdup (transfer->file);      svz_hash_put (cfg->push, pushkey, trans);      svz_free (pushkey);#if ENABLE_DEBUG      svz_log (LOG_DEBUG, "nut: sent push request to %s:%u\n",		  svz_inet_ntoa (sock->remote_addr), 		  ntohs (sock->remote_port));#endif      /* put into sent packet hash */      pkt = svz_malloc (sizeof (nut_packet_t));      pkt->sock = sock;      pkt->sent = time (NULL);      svz_hash_put (cfg->packet, (char *) hdr.id, pkt);    }  return 0;}	  /* * Destroy database. */voidnut_destroy_database (nut_config_t *cfg){  nut_file_t *entry;    while ((entry = cfg->database) != NULL)    {      cfg->database = entry->next;      svz_free (entry->file);      svz_free (entry->path);      svz_free (entry);    }  cfg->db_files = 0;  cfg->db_size = 0;}/* * Add a further file to our database. */voidnut_add_database (nut_config_t *cfg, char *path, char *file, off_t size){  nut_file_t *entry;  entry = svz_malloc (sizeof (nut_file_t));  entry->file = svz_strdup (file);  entry->path = svz_strdup (path);  entry->size = size;  entry->index = cfg->db_files;  entry->next = cfg->database;  cfg->database = entry;  cfg->db_files++;  cfg->db_size += size;}/* * Find a given search pattern within the database. Start to find it * at the given ENTRY. If it is NULL we start at the very beginning. */nut_file_t *nut_find_database (nut_config_t *cfg, nut_file_t *entry, char *search){  if (entry == NULL)    entry = cfg->database;  else    entry = entry->next;  while (entry)    {      if (nut_string_regex (entry->file, search))	return entry;      entry = entry->next;    }  return NULL;}/* * This routine gets a gnutella database entry from a given FILE and * its appropriate INDEX. If no matching file has been found then return * NULL. If FILE is NULL we just search for the the given INDEX. */nut_file_t *nut_get_database (nut_config_t *cfg, char *file, unsigned index){  nut_file_t *entry = NULL;  for (entry = cfg->database; entry; entry = entry->next)    {      if (entry->index == index)	if (file == NULL || !strcmp (entry->file, file))	  return entry;    }  return entry;}/* * This routine will re-read the share directory. The routine itself is * recursive. Thus be careful ! It cannot check for recursion loops, yet. */voidnut_read_database_r (nut_config_t *cfg, char *dirname, int depth){  char *path;  static struct stat buf;  static char filename[NUT_PATH_SIZE];#ifndef __MINGW32__  DIR *dir;  static struct dirent *de = NULL;#else  HANDLE dir;  static WIN32_FIND_DATA de;#endif  /* first call */  if (!depth)     {      nut_destroy_database (cfg);    }  /* check recursion condition */  if (depth < NUT_PATH_DEPTH)    {      depth++;      /* open the directory */#ifdef __MINGW32__      if (svz_snprintf (filename, NUT_PATH_SIZE - 1, "%s/*", dirname) == -1)	return;            if ((dir = FindFirstFile (filename, &de)) != INVALID_HANDLE_VALUE)#else      if ((dir = opendir (dirname)) != NULL)#endif	{	  /* iterate directory */#ifndef __MINGW32__	  while (NULL != (de = readdir (dir)))#else	  do#endif	    {	      if (svz_snprintf (filename, NUT_PATH_SIZE - 1,				"%s/%s", dirname, FILENAME) == -1)		continue;	      /* stat the given file */	      if (stat (filename, &buf) != -1)		{		  /* add valid files to database */		  if (S_ISREG (buf.st_mode) && buf.st_size > 0)		    {		      nut_add_database (cfg, dirname, FILENAME, buf.st_size);		    }		  /* recurse into directories */		  else if (S_ISDIR (buf.st_mode) && FILENAME[0] != '.')		    {		      path = svz_strdup (filename);		      nut_read_database_r (cfg, path, depth);		      svz_free (path);		    }		}	    }#ifdef __MINGW32__	  while (FindNextFile (dir, &de));#endif	  closedir (dir);	}    }}/* * This routine checks for a valid http header for gnutella upload  * requests. */intnut_check_upload (svz_socket_t *sock){  char *p = sock->recv_buffer;  int len, fill = strlen (NUT_GET);  unsigned index = 0;  char *end, *file, *f, *hdr;  nut_file_t *entry;  /* enough receive buffer fill ? */  if (sock->recv_buffer_fill < fill)    return 0;  /* initial gnutella request detection */  if (memcmp (p, NUT_GET, fill))    return -1;  /* parse whole upload header and find the end of the HTTP header */  fill = sock->recv_buffer_fill;  while (p < sock->recv_buffer + (fill - 3) && memcmp (p, NUT_SEPERATOR, 4))    p++;  if (p < sock->recv_buffer + (fill - 3) && !memcmp (p, NUT_SEPERATOR, 4))    {#if ENABLE_DEBUG      svz_log (LOG_DEBUG, "nut: upload header received\n");#endif      /* parse first (GET) line */      len = p - sock->recv_buffer + 1;      p = sock->recv_buffer + strlen (NUT_GET);      end = sock->recv_buffer + len;      while (p < end && *p >= '0' && *p <= '9')	{	  index *= 10;	  index += *p - '0';	  p++;	}      /* parsed file index */      if (p >= end || *p != '/')	return -1;      f = ++p;      while (p < end && *p != '\r' && *p != '\n')	p++;      /* got actual header property field */      hdr = p + 2;      len -= hdr - sock->recv_buffer;      while (p > f && memcmp (p, " " NUT_HTTP, strlen (NUT_HTTP) + 1))	p--;      if (p <= f)	return -1;      /* parsed file itself */      fill = p - f;      file = svz_malloc (fill + 1);      memcpy (file, f, fill);      file[fill] = '\0';      /* here we parse all the header properties */      /* find file in database */      if ((entry = nut_get_database (sock->cfg, file, index)) == NULL)	{#if ENABLE_DEBUG	  svz_log (LOG_DEBUG, "nut: no such file: %s, %u\n", file, index);#endif	  svz_free (file);	  return -1;	}      len = end - sock->recv_buffer + 3;      svz_sock_reduce_recv (sock, len);      svz_free (file);      /* disable connection timeout */      sock->idle_func = NULL;      sock->userflags |= NUT_FLAG_HDR;      if (nut_init_upload (sock, entry) == -1)	return -1;    }  return 0;}/* * If the gnutella header has been successfully parsed this routine * initializes the file upload. */intnut_init_upload (svz_socket_t *sock, nut_file_t *entry){  char *file;  nut_config_t *cfg = sock->cfg;  struct stat buf;  int fd;  nut_transfer_t *transfer;  /* create filename */  file = svz_malloc (strlen (entry->path) + strlen (entry->file) + 2);  sprintf (file, "%s/%s", entry->path, entry->file);    /* check file */  if (stat (file, &buf) == -1 || !S_ISREG (buf.st_mode) || buf.st_size <= 0)    {      svz_log (LOG_ERROR, "nut: invalid file: %s %s\n", file);      svz_free (file);      return -1;    }    /* open the file for reading */  if ((fd = open (file, O_RDONLY | O_BINARY)) == -1)    {      svz_log (LOG_ERROR, "nut: open: %s\n", SYS_ERROR);      svz_free (file);      return -1;    }  svz_sock_printf (sock, NUT_GET_OK  NUT_AGENT);  svz_sock_printf (sock, NUT_CONTENT ": application/binary\r\n");  svz_sock_printf (sock, NUT_LENGTH ": %d\r\n", buf.st_size);  svz_sock_printf (sock, "\r\n");  sock->file_desc = fd;  sock->read_socket = nut_file_read;  sock->write_socket = nut_file_write;  sock->disconnected_socket = nut_disconnect_upload;  sock->flags |= SOCK_FLAG_FILE;  cfg->uploads++;  transfer = svz_malloc (sizeof (nut_transfer_t));  memset (transfer, 0, sizeof (nut_transfer_t));  transfer->size = buf.st_size;  transfer->original_size = buf.st_size;  transfer->file = svz_strdup (file);  transfer->start = time (NULL);  sock->data = transfer;  svz_free (file);  return 0;}/* * Disconnection callback for gnutella uploads. */intnut_disconnect_upload (svz_socket_t *sock){  nut_config_t *cfg = sock->cfg;  nut_transfer_t *transfer = sock->data;  /* decrement amount of concurrent uploads */  cfg->uploads--;  /* finally close the received file */  if (close (sock->file_desc) == -1)    svz_log (LOG_ERROR, "nut: close: %s\n", SYS_ERROR);  /* free the transfer data */  if (transfer)    {      svz_free (transfer->file);      svz_free (transfer);      sock->data = NULL;    }  return 0;}/* * Default gnutella file reader. It is the sock->read_socket callback for * file uploads. */intnut_file_read (svz_socket_t *sock){  int num_read;  int do_read;  nut_transfer_t *transfer = sock->data;  do_read = sock->send_buffer_size - sock->send_buffer_fill;  /*    * This means the send buffer is currently full, we have to    * wait until some data has been send via the socket.   */  if (do_read <= 0)    {      return 0;    }  /*   * Try to read as much data as possible from the file.   */  num_read = read (sock->file_desc,                   sock->send_buffer + sock->send_buffer_fill, do_read);  /* Read error occurred. */  if (num_read < 0)    {      svz_log (LOG_ERROR, "nut: read: %s\n", SYS_ERROR);      return -1;    }  /* Bogus file. File size from stat() was not true. */  if (num_read == 0 && transfer->size != 0)    {      return -1;    }  /* Data has been read or EOF reached, set the appropriate flags. */  sock->send_buffer_fill += num_read;  transfer->size -= num_read;  /* Read all file data ? */  if (transfer->size <= 0)    {#if ENABLE_DEBUG      svz_log (LOG_DEBUG, "nut: file successfully read\n");#endif      /*        * no further read()s from the file descriptor, signaling        * the writers there will not be additional data from now on       */      sock->read_socket = svz_tcp_read_socket;      sock->flags &= ~SOCK_FLAG_FILE;    }  return 0;}/* * This function is the upload callback for the gnutella server. It  * throttles its network output to a configured value. */intnut_file_write (svz_socket_t *sock){  int num_written, do_write;  nut_transfer_t *transfer = sock->data;  nut_config_t *cfg = sock->cfg;  time_t t = time (NULL);  /* throttle the network output */  num_written = transfer->original_size - transfer->size;  if (num_written / (t - transfer->start + 1) > cfg->speed * 1024 / 8)    {      sock->unavailable = t + RELAX_FD_TIME;      return 0;    }  /*    * Write as many bytes as possible, remember how many   * were actually sent.   */  do_write = (sock->send_buffer_fill > SOCK_MAX_WRITE)     ? SOCK_MAX_WRITE : sock->send_buffer_fill;      num_written = send (sock->sock_desc, sock->send_buffer, do_write, 0);  /* some data has been written */  if (num_written > 0)    {      sock->last_send = t;      if (sock->send_buffer_fill > num_written)        {          memmove (sock->send_buffer,                    sock->send_buffer + num_written,                   sock->send_buffer_fill - num_written);        }      sock->send_buffer_fill -= num_written;    }  /* write error occurred */  else if (num_written < 0)    {      svz_log (LOG_ERROR, "nut: send: %s\n", NET_ERROR);      if (svz_errno == SOCK_UNAVAILABLE)        {          sock->unavailable = t + RELAX_FD_TIME;          num_written = 0;        }    }  if (sock->send_buffer_fill == 0 && transfer->size <= 0)    {#if ENABLE_DEBUG      svz_log (LOG_DEBUG, "nut: file successfully sent\n");#endif      return -1;    }  /*   * Return a non-zero value if an error occurred.   */  return (num_written < 0) ? -1 : 0;}#else /* ENABLE_GNUTELLA */int nut_transfer_dummy;	/* Shut compiler warnings up. */#endif /* not ENABLE_GNUTELLA */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -