+ persistence mechanism (design done)
+ sharing API
~ file-information (needs testing)
- ~ directory: implement new directory builder!
- ~ insert: close, need directory builder first!
- ~ unindex & list indexed!!!
- ~ search
- ~ download
+ ~ directory (needs testing)
+ ~ publish (work in progress...)
+ ~ unindex & list indexed!!! (need publish to be done)
+ ~ search (need publish to be done)
+ ~ download (need publish/search to be done)
~ namespaces
~ collection
- design network structs (P2P)
- datastore request queueing mechanism
- implement FS service (needs DHT)
- + insert
+ download
+ search
- + unindex
- implement testcases
+ URI API
+ getopt API
man_MANS = \
gnunet-arm.1 \
gnunet-peerinfo.1 \
+ gnunet-publish.1 \
gnunet-statistics.1 \
gnunet-transport.c
--- /dev/null
+.TH GNUNET-PUBLISH "1" "27 Aug 2009" "GNUnet"
+.SH NAME
+gnunet\-publish \- a command line interface for publishing new content into GNUnet
+.SH SYNOPSIS
+.B gnunet\-publish
+[\fIOPTIONS\fR] FILENAME
+.SH DESCRIPTION
+.PP
+In order to share files with other GNUnet users, the files must first be made available to GNUnet. GNUnet does not automatically share all files from a certain directory. In fact, even files that are downloaded are not automatically shared.
+.PP
+In order to start sharing files, the files must be added either using gnunet\-publish or a graphical interface such as gnunet\-gtk. The command line tool gnunet\-publish is more useful if many files are supposed to be added. gnunet\-publish can automatically publish batches of files, recursively publish directories, create directories that can be browsed within GNUnet and publish file lists in a namespace. When run on a directory, gnunet\-publish will always recursively publish all of the files in the directory.
+.PP
+gnunet\-publish can automatically extract keywords from the files that are shared. Users that want to download files from GNUnet use keywords to search for the appropriate content. You can disable keyword extraction with the \-D option. You can manually add keywords using the \-k option. The keywords are case\-sensitive. (However, keyword normalization can also be used.)
+.PP
+You can use automatic meta\-data extraction (based on libextractor) or the command\-line option \-m to specify meta-data. For the \-m option you need to use the form keyword\-type:value. For example, use "\-m os:Linux" to specify that the operating system is Linux. Common meta\-data types are "author", "title" , "mimetype", "filename", "language", "subject" and "keywords". A full list can be obtained from the extract tool using the option \-\-list. The meta\-data is used to help users in searching for files on the network.
+.PP
+In addition to searching for files by keyword, GNUnet allows organizing files into directories. With directories, the user only needs to find the directory in order to be able to download any of the files listed in the directory. Directories can contain pointers to other directories.
+.PP
+With gnunet\-publish, it is easy to create new directories simultaneously when adding the files. Simply pass the name of a directory instead of a file.
+.PP
+Since keywords can be spammed (any user can add any content under any keyword), GNUnet supports namespaces. A namespace is a subset of the searchspace into which only the holder of a certain pseudonym can add content. Any GNUnet user can create any number of pseudonyms using \fBgnunet\-pseudonym\fR. Pseudonyms are stored in the user's GNUnet directory. While pseudonyms are locally identified with an arbitrary string that the user selects when the pseudonym is created, the namespace is globally known only under the hash of the public key of the pseudonym. Since only the owner of the pseudonym can add content to the namespace, it is impossible for other users to pollute the namespace. gnunet\-publish automatically publishs the top\-directory (or the only file if only one file is specified) into the namespace if a pseudonym is specified.
+.PP
+It is possible to update content in GNUnet if that content was placed and obtained from a particular namespace. Updates are only possible for content in namespaces since this is the only way to assure that a malicious party can not supply counterfeited updates. Note that an update with GNUnet does not make the old content unavailable, GNUnet merely allows the publisher to point users to more recent versions. You can use the \-N option to specify the future identifier of an update. When using this option, a GNUnet client that finds the current (\-t) identifier will automatically begin a search for the update (\-N) identifier. If you later publish an update under the (\-N) identifier, both results will be given to the user.
+.PP
+You can use automatic meta\-data extraction (based on libextractor) or the command\-line option \-m to specify meta-data. For the \-m option you need to use the form keyword\-type:value. For example, use "\-m os:Linux" to specify that the operating system is Linux. Common meta\-data types are "author", "title" , "mimetype", "filename", "language", "subject" and "keywords". A full list can be obtained from the extract tool using the option \-\-list. The meta\-data is used to help users in searching for files on the network. The keywords are case\-sensitive.
+.PP
+GNUnet supports two styles of publishing files on the network. Publishing a file means that a copy of the file is made in the local (!) database of the node. Indexing a file means that an index is added to the local (!) database with symbolic links to the file itself. The links will use the SHA-512 hash of the entire file as the filename. Indexing is generally significantly more efficient and the default choice. However, indexing only works if the indexed file can be read (using the same absolute path) by gnunetd. If this is not the case, indexing will fail (and gnunet\-publish will automatically revert to publishing instead). Regardless of which method is used to publish the file, the file will be slowly (depending on how often it is requested and on how much bandwidth is available) dispersed into the network. If you publish or index a file and then leave the network, it will almost always NOT be available anymore.
+
+\fB\-c \fIFILENAME\fR, \fB\-\-config=FILENAME\fR
+Use alternate config file (if this option is not specified, the default is ~/.gnunet/gnunet.conf).
+
+.TP
+\fB\-D\fR, \fB\-\-disable\-extractor\fR
+Disable use of GNU libextractor for finding additional keywords and metadata.
+
+.TP
+\fB\-e\fR, \fB\-\-extract\fR
+Print the list of keywords that will be used for each file given the current options. Do not perform any indexing or publishing.
+
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+Print a brief help page with all the options.
+
+.TP
+\fB\-H \fIHOSTNAME\fR, \fB\-\-host=\fIHOSTNAME\fR
+on which host is gnunetd running (default: localhost). You can also specify a port using the syntax HOSTNAME:PORT. The default port is 2087.
+.TP
+\fB\-k \fIKEYWORD\fR, \fB\-\-key=KEYWORD\fR
+additional key to index the content with (to add multiple keys, specify multiple times). Each additional key is case\-sensitive. Can be specified multiple times. The keyword is only applied to the top\-level file or directory.
+
+.TP
+\fB\-L \fILOGLEVEL\fR, \fB\-\-loglevel=\fILOGLEVEL\fR
+Change the loglevel. Possible values for LOGLEVEL are NOTHING, FATAL,
+ERROR, WARNING, INFO, STATUS and DEBUG. Note that options in the
+configuration file take precedence over this option (the argument
+will be ignored in that case).
+
+.TP
+\fB\-m \fITYPE:VALUE\fR, \fB\-\-meta=\fITYPE:VALUE\fR
+For the main file (or directory), set the metadata of the given TYPE to the given VALUE. Note that this will not add the respective VALUE to the set of keywords under which the file can be found.
+
+.TP
+\fB\-n\fR, \fB\-\-noindex\fR
+Executive summary: You probably don't need it.
+
+Do not index, full publishion. Note that directories, RBlocks, SBlocks and IBlocks are always published (even without this option). With this option, every block of the actual files is stored in encrypted form in the block database of the local peer. While this adds security if the local node is compromised (the adversary snags your machine), it is significantly less efficient compared to on\-demand encryption and is definitely not recommended for large files.
+
+.TP
+\fB\-N \fIID\fR, \fB\-\-next=\fIID\fR
+Specifies the next ID of a future version of the SBlock. This option is only valid together with the \-P option. This option can be used to specify what the identifier of an updated version will look like. Note that specifying \-i and \-N without \-t is not allowed.
+
+.TP
+\fB\-p \fIPRIORITY\fR, \fB\-\-prio=\fIPRIORITY\fR
+Executive summary: You probably don't need it.
+
+Set the priority of the published content (default: 365). If the local database is full, GNUnet will discard the content with the lowest ranking. Note that ranks change over time depending on popularity. The default should be high enough to preserve the locally published content in favor of content that migrates from other peers.
+
+.TP
+\fB\-P \fINAME\fR, \fB\-\-pseudonym=\fINAME\fR
+For the top\-level directory or file, create an SBlock that places the file into the namespace specified by the pseudonym NAME.
+
+.TP
+\fB\-s\fR, \fB\-\-simulate-only\fR
+When this option is used, gnunet\-publish will not actually publish the file but just simulate what would be done. This can be used to compute the GNUnet URI for a file without actually sharing it.
+
+.TP
+\fB\-t \fIID\fR, \fB\-\-this=\fIID\fR
+Specifies the ID of the SBlock. This option is only valid together with the\ \-s option.
+
+.TP
+\fB\-u \fIURI\fR, \fB\-\-uri=\fIURI\fR
+This option can be used to specify the URI of a file instead of a filename (this is the only case where the otherwise mandatory filename argument must be omitted). Instead of publishing a file or directory and using the corresponding URI, gnunet\-publish will use this URI and perform the selected namespace or keyword operations. This can be used to add additional keywords to a file that has already been shared or to add files to a namespace for which the URI is known but the content is not locally available.
+
+.TP
+\fB\-v\fR, \fB\-\-version\fR
+Print the version number.
+
+.TP
+\fB\-V\fR, \fB\-\-verbose\fR
+Be verbose. Using this option causes gnunet\-publish to print progress information and at the end the file identification that can be used to download the file from GNUnet.
+
+
+.SH EXAMPLES
+.PP
+
+\fBBasic examples\fR
+
+Index a file COPYING:
+
+ # gnunet\-publish COPYING
+
+Publish a file COPYING:
+
+ # gnunet\-publish \-n COPYING
+
+Index a file COPYING with the keywords \fBgpl\fR and \fBtest\fR:
+
+ # gnunet\-publish \-k gpl \-k test COPYING
+
+Index a file COPYING with description "GNU License", mime-type "text/plain" and keywords \fBgpl\fR and \fBtest\fR:
+
+ # gnunet\-publish \-m "description:GNU License" \-k gpl \-k test -m "mimetype:text/plain" COPYING
+
+\fBUsing directories\fR
+
+Index the files COPYING and AUTHORS with keyword \fBtest\fR and build a directory containing the two files. Make the directory itself available under keyword \fBgnu\fR and disable keyword extraction using libextractor:
+
+ # mkdir gnu
+ # mv COPYING AUTHORS gnu/
+ # gnunet\-publish \-K test \-k gnu \-D gnu/
+
+Neatly publish an image gallery in \fBkittendir/\fR and its subdirs with keyword \fBkittens\fR for the directory but no keywords for the individual files or subdirs (\-n). Force description for all files:
+
+ # gnunet\-publish \-n \-m "description:Kitten collection" \-k kittens kittendir/
+
+\fBSecure publishing with namespaces\fR
+
+Publish file COPYING with pseudonym RIAA-2 (\-P) and with identifier \fBgpl\fR (\-t) and no updates:
+
+ # gnunet\-publish \-P RIAA-2 \-t gpl COPYING
+
+Recursively index /home/ogg and build a matching directory structure. Publish the top\-level directory into the namespace under the pseudonym RIAA-2 (\-P) under identifier 'MUSIC' (\-t) and promise to provide an update with identifier 'VIDEOS' (\-N):
+
+ # gnunet\-publish \-P RIAA-2 \-t MUSIC \-N VIDEOS /home/ogg
+
+Recursively publish (\-n) /var/lib/mysql and build a matching directory structure, but disable the use of libextractor to extract keywords (\-n). Print the file identifiers (\-V) that can be used to retrieve the files. This will store a copy of the MySQL database in GNUnet but without adding any keywords to search for it. Thus only people that have been told the secret file identifiers printed with the \-V option can retrieve the (secret?) files:
+
+ # gnunet\-publish \-nV /var/lib/mysql
+
+Create a namespace entry 'root' in namespace MPAA-1 and announce that the next update will be called 'next':
+
+ # gnunet\-publish \-P MPAA-1 -t root \-N next noise.mp3
+
+Update the previous entry, do not allow any future updates:
+
+ # gnunet\-publish \-P MPAA-1 \-t next noise_updated.mp3
+
+
+.SH FILES
+.TP
+~/.gnunet/gnunet.conf
+GNUnet configuration file
+.SH "REPORTING BUGS"
+Report bugs by using mantis <https://gnunet.org/mantis/> or by sending electronic mail to <gnunet\-developers@gnu.org>
+.SH "SEE ALSO"
+\fBgnunet\-auto\-share\fP(1), \fBgnunet\-gtk\fP(1), \fBgnunet\-pseudonym\fP(1), \fBgnunet\-search\fP(1), \fBgnunet\-download\fP(1), \fBgnunet.conf\fP(5), \fBgnunetd\fP(1), \fBextract\fP(1)
fs_uri.c
libgnunetfs_la_LIBADD = \
+ $(top_builddir)/src/datastore/libgnunetdatastore.la \
$(top_builddir)/src/util/libgnunetutil.la \
-lextractor \
$(GN_LIBINTL) $(XLIB)
-version-info 0:0:0
-#bin_PROGRAMS =
+bin_PROGRAMS = \
+ gnunet-publish
# gnunet-directory
# gnunet-download
# gnunet-pseudonym
-# gnunet-publish
# gnunet-search
# gnunet-unindex
# $(GN_LIBINTL)
+gnunet_publish_SOURCES = \
+ gnunet-publish.c
+gnunet_publish_LDADD = \
+ $(top_builddir)/src/fs/libgnunetfs.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL)
+
+
check_PROGRAMS = \
test_fs_collection \
test_fs_directory \
* Size of the directory itself (in bytes); 0 if the
* size has not yet been calculated.
*/
- uint64_t dir_size;
+ size_t dir_size;
/**
* Pointer to the data for the directory (or NULL if not
* available).
*/
- char *dir_data;
+ void *dir_data;
} dir;
* @author Christian Grothoff
*
* TODO:
- * - add support for embedded file data (use padding room!)
* - modify directory builder API to support incremental
* generation of directories (to allow directories that
* would not fit into memory to be created)
#define EXTRACTOR_GNUNET_FULL_DATA 137
#endif
+/**
+ * String that is used to indicate that a file
+ * is a GNUnet directory.
+ */
+#define GNUNET_DIRECTORY_MAGIC "\211GND\r\n\032\n"
+
+
/**
* Does the meta-data claim that this is a directory?
* Checks if the mime-type is that of a GNUnet directory.
void *dep_cls)
{
const char *cdata = data;
+ char *file_data;
char *emsg;
uint64_t pos;
uint64_t align;
return; /* malformed ! */
}
pos += mdSize;
- // EXTRACTOR_GNUNET_FULL_DATA
- /* FIXME: add support for embedded data */
filename = GNUNET_CONTAINER_meta_data_get_by_type (md,
EXTRACTOR_FILENAME);
+ file_data = GNUNET_CONTAINER_meta_data_get_by_type (md,
+ EXTRACTOR_GNUNET_FULL_DATA);
if (dep != NULL)
dep (dep_cls,
filename,
uri,
md,
- 0,
- NULL);
+ (file_data != NULL) ? strlen(file_data) : 0,
+ file_data);
+ GNUNET_free_non_null (file_data);
GNUNET_free_non_null (filename);
GNUNET_CONTAINER_meta_data_destroy (md);
GNUNET_FS_uri_destroy (uri);
struct BuilderEntry *e;
uint64_t fsize;
uint32_t big;
+ ssize_t ret;
size_t mds;
size_t mdxs;
char *uris;
struct GNUNET_CONTAINER_MetaData *meta;
const struct GNUNET_CONTAINER_MetaData *meta_use;
- GNUNET_assert (! GNUNET_FS_uri_ksk_test (uri));
+ GNUNET_assert (! GNUNET_FS_uri_test_ksk (uri));
if (NULL != data)
- if (GNUNET_FS_uri_chk_test (uri))
- fsize = GNUNET_FS_uri_chk_get_size (uri);
+ if (GNUNET_FS_uri_test_chk (uri))
+ fsize = GNUNET_FS_uri_chk_get_file_size (uri);
else
- fsize = GNUNET_FS_uri_chk_get_size (GNUNET_FS_uri_loc_get_uri (uri));
+ fsize = GNUNET_FS_uri_chk_get_file_size (GNUNET_FS_uri_loc_get_uri (uri));
else
fsize = 0; /* not given */
if (fsize > GNUNET_FS_MAX_INLINE_SIZE)
uint32_t big;
size = 8 + sizeof (uint32_t);
- size += GNUNET_meta_data_get_serialized_size (bld->meta,
- GNUNET_SERIALIZE_FULL);
+ size += GNUNET_CONTAINER_meta_data_get_serialized_size (bld->meta,
+ GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL);
if (bld->count > 0)
{
sizes = GNUNET_malloc (bld->count * sizeof (size_t));
{
perm[i] = i;
bes[i] = pos;
- sizes[i] = pos->size;
+ sizes[i] = pos->len;
pos = pos->next;
}
}
memcpy (data, GNUNET_DIRECTORY_MAGIC, 8);
off = 8;
- ret = GNUNET_CONTAINER_meta_data_serialize (meta,
- &(*data)[off +
- sizeof (uint32_t)],
- size - pos - sizeof (uint32_t),
- GNUNET_SERIALIZE_FULL);
+ ret = GNUNET_CONTAINER_meta_data_serialize (bld->meta,
+ &data[off +
+ sizeof (uint32_t)],
+ size - off - sizeof (uint32_t),
+ GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL);
GNUNET_assert (ret != -1);
big = htonl (ret);
- memcpy (&(*data)[8], &big, sizeof (uint32_t));
- pos += sizeof (uint32_t) + ret;
- for (j = 0; j < count; j++)
+ memcpy (&data[8], &big, sizeof (uint32_t));
+ off += sizeof (uint32_t) + ret;
+ for (j = 0; j < bld->count; j++)
{
i = perm[j];
- psize = pos;
- pos += sizes[i];
- pos = do_align (psize, pos);
- memcpy (&data[pos - sizes[i]],
+ psize = off;
+ off += sizes[i];
+ off = do_align (psize, off);
+ memcpy (&data[off - sizes[i]],
&(bes[i])[1],
sizes[i]);
GNUNET_free (bes[i]);
GNUNET_free (sizes);
GNUNET_free (perm);
GNUNET_free (bes);
- GNUNET_assert (pos == size);
+ GNUNET_assert (off == size);
GNUNET_CONTAINER_meta_data_destroy (bld->meta);
GNUNET_free (bld);
}
* @return GNUNET_OK on success
*/
int
-GNUNET_FS_getopt_configure_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext* ctx,
+GNUNET_FS_getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext* ctx,
void *scls,
const char *option,
const char *value)
* @return GNUNET_OK on success
*/
int
-GNUNET_FS_getopt_configure_set_metadata (struct GNUNET_GETOPT_CommandLineProcessorContext* ctx,
+GNUNET_FS_getopt_set_metadata (struct GNUNET_GETOPT_CommandLineProcessorContext* ctx,
void *scls,
const char *option,
const char *value)
* @author Christian Grothoff
*
* TODO:
- * - directory creation
* - KBlocks
* - SBlocks
* - indexing support
*
* @param sc overall upload data
* @param p file that the block belongs to (needed for options!)
+ * @param query what the block should be indexed under
* @param blk encoded block to publish
* @param blk_size size of the block
* @param blk_type type of the block
static void
publish_block (struct GNUNET_FS_PublishContext *sc,
struct GNUNET_FS_FileInformation *p,
+ const GNUNET_HashCode *query,
const void* blk,
uint16_t blk_size,
uint32_t blk_type,
GNUNET_SCHEDULER_Task cont)
{
- struct GNUNET_HashCode key;
+ struct PutContCtx * dpc_cls;
- // FIXME: GNUNET_FS_get_key (blk_type, blk, blk_size, &key);
- // (or add "key" as argument to reduce hashing?)
dpc_cls = GNUNET_malloc(sizeof(struct PutContCtx));
dpc_cls->cont = cont;
dpc_cls->sc = sc;
// a task ID!
GNUNET_DATASTORE_put (sc->dsh,
sc->rid,
- &key,
+ query,
blk_size,
+ blk,
blk_type,
p->priority,
p->anonymity,
uint64_t offset)
{
uint64_t bds;
- unsigned int ret;
+ unsigned int ret;
+ unsigned int i;
bds = GNUNET_FS_DBLOCK_SIZE; /* number of bytes each CHK at level "i"
corresponds to */
publish_content (struct GNUNET_FS_PublishContext *sc,
struct GNUNET_FS_FileInformation *p)
{
- struct ContentHashKey *chk;
+ struct ContentHashKey *mychk;
const void *pt_block;
uint16_t pt_size;
char *emsg;
struct GNUNET_CRYPTO_AesInitializationVector iv;
uint64_t size;
unsigned int off;
+ struct GNUNET_FS_DirectoryBuilder *db;
+ struct GNUNET_FS_FileInformation *dirpos;
+ void *raw_data;
+ char *dd;
// FIXME: figure out how to share this code
// with unindex!
{
if (p->is_directory)
{
- /* FIXME: create function to create directory
- and use that API here! */
- GNUNET_FS_directory_create (&p->data.dir.dir_size,
- &p->data.dir.dir_data,
- p->meta,
- &directory_entry_lister,
- p->data.dir.entries);
- size = p->data.dir.data_size;
+ db = GNUNET_FS_directory_builder_create (p->meta);
+ dirpos = p->data.dir.entries;
+ while (NULL != dirpos)
+ {
+ if (dirpos->is_directory)
+ {
+ raw_data = dirpos->data.dir.dir_data;
+ dirpos->data.dir.dir_data = NULL;
+ }
+ else
+ {
+ raw_data = NULL;
+ if ( (dirpos->data.file.file_size < GNUNET_FS_MAX_INLINE_SIZE) &&
+ (dirpos->data.file.file_size > 0) )
+ {
+ raw_data = GNUNET_malloc (dirpos->data.file.file_size);
+ emsg = NULL;
+ if (dirpos->data.file.file_size !=
+ dirpos->data.file.reader (dirpos->data.file.reader_cls,
+ 0,
+ dirpos->data.file.file_size,
+ raw_data,
+ &emsg))
+ {
+ GNUNET_free_non_null (emsg);
+ GNUNET_free (raw_data);
+ raw_data = NULL;
+ }
+ }
+ }
+ GNUNET_FS_directory_builder_add (db,
+ dirpos->chk_uri,
+ dirpos->meta,
+ raw_data);
+ GNUNET_free_non_null (raw_data);
+ dirpos = dirpos->next;
+ }
+ GNUNET_FS_directory_builder_finish (db,
+ &p->data.dir.dir_size,
+ &p->data.dir.dir_data);
+ size = p->data.dir.dir_size;
}
p->chk_tree_depth = compute_depth (size);
p->chk_tree = GNUNET_malloc (p->chk_tree_depth *
{
pt_size = GNUNET_MIN(GNUNET_FS_DBLOCK_SIZE,
p->data.dir.dir_size - p->publish_offset);
- pt_block = &p->data.dir.dir_data[p->publish_offset];
+ dd = p->data.dir.dir_data;
+ pt_block = &dd[p->publish_offset];
}
else
{
pt_size = GNUNET_MIN(GNUNET_FS_DBLOCK_SIZE,
p->data.file.file_size - p->publish_offset);
- p->data.file.reader (p->data.file.reader_cls,
- p->publish_offset,
- pt_size,
- iob,
- &emsg);
+ emsg = NULL;
+ if (pt_size !=
+ p->data.file.reader (p->data.file.reader_cls,
+ p->publish_offset,
+ pt_size,
+ iob,
+ &emsg))
+ {
+ // FIXME: abort with error "emsg"
+ GNUNET_free (emsg);
+ }
pt_block = iob;
}
}
}
off = compute_chk_offset (p->chk_tree_depth - p->current_depth,
p->publish_offset);
- chk = &p->chk_tree[(p->current_depth-1)*GNUNET_FS_CHK_PER_INODE+off];
- GNUNET_CRYPTO_hash (pt_block, pt_size, &chk->key);
- GNUNET_CRYPTO_hash_to_aes_key (&chk->key, &sk, &iv);
+ mychk = &p->chk_tree[(p->current_depth-1)*GNUNET_FS_CHK_PER_INODE+off];
+ GNUNET_CRYPTO_hash (pt_block, pt_size, &mychk->key);
+ GNUNET_CRYPTO_hash_to_aes_key (&mychk->key, &sk, &iv);
GNUNET_CRYPTO_aes_encrypt (pt_block,
pt_size,
&sk,
// between publish/unindex! Parameterize & move this code!
// FIXME: something around here would need to change
// for indexing!
- publish_block (sc, p, enc, pt_size,
+ publish_block (sc, p,
+ &mychk->query,
+ enc,
+ pt_size,
(p->current_depth == p->chk_tree_depth)
? GNUNET_DATASTORE_BLOCKTYPE_DBLOCK
: GNUNET_DATASTORE_BLOCKTYPE_IBLOCK,
&do_upload);
// FIXME: should call progress function somewhere here!
- GNUNET_CRYPTO_hash (enc, pt_size, &chk->query);
+ GNUNET_CRYPTO_hash (enc, pt_size, &mychk->query);
if (p->current_depth == p->chk_tree_depth)
{
p->publish_offset += pt_size;
if (0 == p->current_depth)
{
p->chk_uri = GNUNET_malloc (sizeof(struct GNUNET_FS_Uri));
- p->chk_uri.type = chk;
- p->chk_uri.data.chk.chk = p->chk_tree[0];
- p->chk_uri.data.chk.file_length = size;
+ p->chk_uri->type = chk;
+ p->chk_uri->data.chk.chk = p->chk_tree[0];
+ p->chk_uri->data.chk.file_length = size;
GNUNET_free (p->chk_tree);
p->chk_tree = NULL;
}
publish_kblocks (sc, p);
return;
}
- if (p->do_index)
+ if ( (!p->is_directory) &&
+ (p->data.file.do_index) )
{
// FIXME: need to pre-compute hash over
// the entire file and ask FS to prepare
GNUNET_FS_namespace_delete (sc->namespace, GNUNET_NO);
GNUNET_free_non_null (sc->nid);
GNUNET_free_non_null (sc->nuid);
- GNUNET_DATASTORE_disconnect (sc->dsh);
+ GNUNET_DATASTORE_disconnect (sc->dsh, GNUNET_NO);
GNUNET_free (sc);
}
--- /dev/null
+/*
+ This file is part of GNUnet.
+ (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file fs/gnunet-publish.c
+ * @brief publishing files on GNUnet
+ * @author Christian Grothoff
+ * @author Krista Bennett
+ * @author James Blackwell
+ * @author Igor Wronsky
+ *
+ * TODO:
+ * - support for some options is still missing (uri argument, simulate)
+ * - progress callbacks not implemented (and need verbosity option)
+ * - clean shutdown is not implemented (stop ctx, etc.)
+ */
+#include "platform.h"
+#include "gnunet_fs_service.h"
+
+#define DEFAULT_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_YEARS, 2)
+
+static int ret;
+
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+static struct GNUNET_FS_Handle *ctx;
+
+static struct GNUNET_FS_PublishContext *pc;
+
+static struct GNUNET_TIME_Absolute start_time;
+
+static struct GNUNET_CONTAINER_MetaData *meta;
+
+static struct GNUNET_FS_Uri *topKeywords;
+
+static unsigned int anonymity = 1;
+
+static unsigned int priority = 365;
+
+static char *uri_string;
+
+static char *next_id;
+
+static char *this_id;
+
+static char *pseudonym;
+
+static int do_insert;
+
+static int disable_extractor;
+
+static int do_simulate;
+
+static int extract_only;
+
+static int do_disable_creation_time;
+
+
+/**
+ * Called by FS client to give information about the progress of an
+ * operation.
+ *
+ * @param cls closure
+ * @param info details about the event, specifying the event type
+ * and various bits about the event
+ * @return client-context (for the next progress call
+ * for this operation; should be set to NULL for
+ * SUSPEND and STOPPED events). The value returned
+ * will be passed to future callbacks in the respective
+ * field in the GNUNET_FS_ProgressInfo struct.
+ */
+static void *
+progress_cb (void *cls,
+ const struct GNUNET_FS_ProgressInfo *info)
+{
+ return NULL;
+}
+
+
+/**
+ * Print metadata entries (except binary
+ * metadata and the filename).
+ *
+ * @param cls closure
+ * @param type type of the meta data
+ * @param data value of the meta data
+ * @return GNUNET_OK to continue to iterate, GNUNET_SYSERR to abort
+ */
+static int
+meta_printer (void *cls,
+ EXTRACTOR_KeywordType type,
+ const char *data)
+{
+ if ( (type == EXTRACTOR_FILENAME) ||
+ (EXTRACTOR_isBinaryType (type)) )
+ return GNUNET_OK;
+ fprintf (stdout,
+ "%s - %s",
+ EXTRACTOR_getKeywordTypeAsString (type),
+ data);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Merge metadata entries (except binary
+ * metadata).
+ *
+ * @param cls closure, target metadata structure
+ * @param type type of the meta data
+ * @param data value of the meta data
+ * @return GNUNET_OK to continue to iterate, GNUNET_SYSERR to abort
+ */
+static int
+meta_merger (void *cls,
+ EXTRACTOR_KeywordType type,
+ const char *data)
+{
+ struct GNUNET_CONTAINER_MetaData *m = cls;
+ GNUNET_CONTAINER_meta_data_insert (m,
+ type,
+ data);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called on all entries before the
+ * publication. This is where we perform
+ * modifications to the default based on
+ * command-line options.
+ *
+ * @param cls closure
+ * @param fi the entry in the publish-structure
+ * @param length length of the file or directory
+ * @param m metadata for the file or directory (can be modified)
+ * @param uri pointer to the keywords that will be used for this entry (can be modified)
+ * @param anonymity pointer to selected anonymity level (can be modified)
+ * @param priority pointer to selected priority (can be modified)
+ * @param expirationTime pointer to selected expiration time (can be modified)
+ * @param client_info pointer to client context set upon creation (can be modified)
+ * @return GNUNET_OK to continue, GNUNET_NO to remove
+ * this entry from the directory, GNUNET_SYSERR
+ * to abort the iteration
+ */
+static int
+publish_inspector (void *cls,
+ struct GNUNET_FS_FileInformation *fi,
+ uint64_t length,
+ struct GNUNET_CONTAINER_MetaData *m,
+ struct GNUNET_FS_Uri **uri,
+ unsigned int *anonymity,
+ unsigned int *priority,
+ struct GNUNET_TIME_Absolute *expirationTime,
+ void **client_info)
+{
+ char *fn;
+ char *fs;
+ struct GNUNET_FS_Uri *new_uri;
+
+ if (! do_disable_creation_time)
+ GNUNET_CONTAINER_meta_data_add_publication_date (meta);
+ if (NULL != topKeywords)
+ {
+ new_uri = GNUNET_FS_uri_ksk_merge (topKeywords,
+ *uri);
+ GNUNET_FS_uri_destroy (*uri);
+ *uri = new_uri;
+ GNUNET_FS_uri_destroy (topKeywords);
+ topKeywords = NULL;
+ }
+ if (NULL != meta)
+ {
+ GNUNET_CONTAINER_meta_data_get_contents (meta,
+ &meta_merger,
+ m);
+ GNUNET_CONTAINER_meta_data_destroy (meta);
+ meta = NULL;
+ }
+ if (extract_only)
+ {
+ fn = GNUNET_CONTAINER_meta_data_get_by_type (meta,
+ EXTRACTOR_FILENAME);
+ fs = GNUNET_STRINGS_byte_size_fancy (length);
+ fprintf (stdout,
+ _("Keywords for file `%s' (%s)\n"),
+ fn,
+ fs);
+ GNUNET_free (fn);
+ GNUNET_free (fs);
+ GNUNET_CONTAINER_meta_data_get_contents (meta,
+ &meta_printer,
+ NULL);
+ fprintf (stdout, "\n");
+ }
+ if (GNUNET_FS_meta_data_test_for_directory (meta))
+ GNUNET_FS_file_information_inspect (fi,
+ &publish_inspector,
+ NULL);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure
+ * @param sched the scheduler to use
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param cfg configuration
+ */
+static void
+run (void *cls,
+ struct GNUNET_SCHEDULER_Handle *sched,
+ char *const *args,
+ const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ struct GNUNET_FS_FileInformation *fi;
+ struct GNUNET_FS_Namespace *namespace;
+ EXTRACTOR_ExtractorList *l;
+ char *ex;
+ char *emsg;
+
+ /* check arguments */
+ if ( ( (uri_string == NULL) || (extract_only) )
+ && ( (args[0] == NULL) || (args[1] != NULL) ) )
+ {
+ printf (_
+ ("You must specify one and only one filename for insertion.\n"));
+ ret = -1;
+ return;
+ }
+ if ((uri_string != NULL) && (args[0] != NULL))
+ {
+ printf (_("You must NOT specify an URI and a filename.\n"));
+ ret = -1;
+ return;
+ }
+ if ((uri_string != NULL) && (extract_only))
+ {
+ printf (_("Cannot extract metadata from a URI!\n"));
+ ret = -1;
+ return;
+ }
+ if (pseudonym != NULL)
+ {
+ if (NULL == this_id)
+ {
+ fprintf (stderr,
+ _("Option `%s' is required when using option `%s'.\n"),
+ "-t", "-P");
+ ret = -1;
+ return;
+ }
+ }
+ else
+ { /* ordinary insertion checks */
+ if (NULL != next_id)
+ {
+ fprintf (stderr,
+ _("Option `%s' makes no sense without option `%s'.\n"),
+ "-N", "-P");
+ ret = -1;
+ return;
+ }
+ if (NULL != this_id)
+ {
+ fprintf (stderr,
+ _("Option `%s' makes no sense without option `%s'.\n"),
+ "-t", "-P");
+ ret = -1;
+ return;
+ }
+ }
+ if (args[0] == NULL)
+ {
+ fprintf (stderr,
+ _("Need the name of a file to publish!\n"));
+ ret = 1;
+ return;
+ }
+ cfg = c;
+ ctx = GNUNET_FS_start (sched,
+ cfg,
+ "gnunet-publish",
+ &progress_cb,
+ NULL);
+ if (NULL == ctx)
+ {
+ fprintf (stderr,
+ _("Could not initialize `%s' subsystem.\n"),
+ "FS");
+ ret = 1;
+ return;
+ }
+ namespace = NULL;
+ if (NULL != pseudonym)
+ {
+ namespace = GNUNET_FS_namespace_create (ctx,
+ pseudonym);
+ if (NULL == namespace)
+ {
+ fprintf (stderr,
+ _("Could not create namespace `%s'\n"),
+ pseudonym);
+ GNUNET_FS_stop (ctx);
+ ret = 1;
+ return;
+ }
+ }
+ if (NULL != uri_string)
+ {
+ // FIXME -- implement!
+ return;
+ }
+ start_time = GNUNET_TIME_absolute_get ();
+
+ l = NULL;
+ if (! disable_extractor)
+ {
+ l = EXTRACTOR_loadDefaultLibraries ();
+ if (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (cfg, "FS", "EXTRACTORS",
+ &ex))
+ {
+ if (strlen (ex) > 0)
+ l = EXTRACTOR_loadConfigLibraries (l, ex);
+ GNUNET_free (ex);
+ }
+ }
+ fi = GNUNET_FS_file_information_create_from_directory (NULL,
+ args[0],
+ &GNUNET_FS_directory_scanner_default,
+ l,
+ !do_insert,
+ anonymity,
+ priority,
+ GNUNET_TIME_relative_to_absolute (DEFAULT_EXPIRATION),
+ &emsg);
+ EXTRACTOR_removeAll (l);
+ if (fi == NULL)
+ {
+ fprintf (stderr,
+ _("Could not publish `%s': %s\n"),
+ args[0],
+ emsg);
+ GNUNET_free (emsg);
+ if (namespace != NULL)
+ GNUNET_FS_namespace_delete (namespace, GNUNET_NO);
+ GNUNET_FS_stop (ctx);
+ ret = 1;
+ return;
+ }
+ GNUNET_FS_file_information_inspect (fi,
+ &publish_inspector,
+ NULL);
+ if (extract_only)
+ {
+ if (namespace != NULL)
+ GNUNET_FS_namespace_delete (namespace, GNUNET_NO);
+ GNUNET_FS_file_information_destroy (fi, NULL, NULL);
+ GNUNET_FS_stop (ctx);
+ return;
+ }
+ pc = GNUNET_FS_publish_start (ctx,
+ NULL,
+ fi,
+ namespace,
+ this_id,
+ next_id);
+}
+
+
+/**
+ * gnunet-publish command line options
+ */
+static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'a', "anonymity", "LEVEL",
+ gettext_noop ("set the desired LEVEL of sender-anonymity"),
+ 1, &GNUNET_GETOPT_set_uint, &anonymity},
+ {'d', "disable-creation-time", NULL,
+ gettext_noop
+ ("disable adding the creation time to the metadata of the uploaded file"),
+ 0, &GNUNET_GETOPT_set_one, &do_disable_creation_time},
+ {'D', "disable-extractor", NULL,
+ gettext_noop
+ ("do not use libextractor to add keywords or metadata"),
+ 0, &GNUNET_GETOPT_set_one, &disable_extractor},
+ {'e', "extract", NULL,
+ gettext_noop
+ ("print list of extracted keywords that would be used, but do not perform upload"),
+ 0, &GNUNET_GETOPT_set_one, &extract_only},
+ {'k', "key", "KEYWORD",
+ gettext_noop
+ ("add an additional keyword for the top-level file or directory"
+ " (this option can be specified multiple times)"),
+ 1, &GNUNET_FS_getopt_set_keywords, &topKeywords},
+ // *: option not yet used... (can handle in a pass over FI)
+ {'m', "meta", "TYPE:VALUE",
+ gettext_noop ("set the meta-data for the given TYPE to the given VALUE"),
+ 1, &GNUNET_FS_getopt_set_metadata, &meta},
+ {'n', "noindex", NULL,
+ gettext_noop ("do not index, perform full insertion (stores entire "
+ "file in encrypted form in GNUnet database)"),
+ 0, &GNUNET_GETOPT_set_one, &do_insert},
+ {'N', "next", "ID",
+ gettext_noop
+ ("specify ID of an updated version to be published in the future"
+ " (for namespace insertions only)"),
+ 1, &GNUNET_GETOPT_set_string, &next_id},
+ {'p', "priority", "PRIORITY",
+ gettext_noop ("specify the priority of the content"),
+ 1, &GNUNET_GETOPT_set_uint, &priority},
+ {'P', "pseudonym", "NAME",
+ gettext_noop
+ ("publish the files under the pseudonym NAME (place file into namespace)"),
+ 1, &GNUNET_GETOPT_set_string, &pseudonym},
+ // *: option not yet used... (need FS API support!)
+ {'s', "simulate-only", NULL,
+ gettext_noop ("only simulate the process but do not do any "
+ "actual publishing (useful to compute URIs)"),
+ 0, &GNUNET_GETOPT_set_one, &do_simulate},
+ {'t', "this", "ID",
+ gettext_noop ("set the ID of this version of the publication"
+ " (for namespace insertions only)"),
+ 1, &GNUNET_GETOPT_set_string, &this_id},
+ // *: option not yet used... (need FS API support!)
+ {'u', "uri", "URI",
+ gettext_noop ("URI to be published (can be used instead of passing a "
+ "file to add keywords to the file with the respective URI)"),
+ 1, &GNUNET_GETOPT_set_string, &uri_string},
+ GNUNET_GETOPT_OPTION_END
+};
+
+
+/**
+ * The main function to publish content to GNUnet.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+ return (GNUNET_OK ==
+ GNUNET_PROGRAM_run (argc,
+ argv,
+ "gnunet-publish",
+ gettext_noop
+ ("Publish files on GNUnet."),
+ options, &run, NULL)) ? ret : 1;
+}
+
+/* end of gnunet-publish.c */
+
+////////////////////////////////////////////////////////////////
+
+
+/**
+ * Print progess message.
+ */
+static void *
+printstatus (void *ctx, const GNUNET_FSUI_Event * event)
+{
+ unsigned long long delta;
+ char *fstring;
+
+ switch (event->type)
+ {
+ case GNUNET_FSUI_upload_progress:
+ if (*verboselevel)
+ {
+ char *ret;
+ GNUNET_CronTime now;
+
+ now = GNUNET_get_time ();
+ delta = event->data.UploadProgress.eta - now;
+ if (event->data.UploadProgress.eta < now)
+ delta = 0;
+ ret = GNUNET_get_time_interval_as_fancy_string (delta);
+ PRINTF (_("%16llu of %16llu bytes inserted "
+ "(estimating %6s to completion) - %s\n"),
+ event->data.UploadProgress.completed,
+ event->data.UploadProgress.total,
+ ret, event->data.UploadProgress.filename);
+ GNUNET_free (ret);
+ }
+ break;
+ case GNUNET_FSUI_upload_completed:
+ if (*verboselevel)
+ {
+ delta = GNUNET_get_time () - start_time;
+ PRINTF (_("Upload of `%s' complete, "
+ "%llu bytes took %llu seconds (%8.3f KiB/s).\n"),
+ event->data.UploadCompleted.filename,
+ event->data.UploadCompleted.total,
+ delta / GNUNET_CRON_SECONDS,
+ (delta == 0)
+ ? (double) (-1.0)
+ : (double) (event->data.UploadCompleted.total
+ / 1024.0 * GNUNET_CRON_SECONDS / delta));
+ }
+ fstring = GNUNET_ECRS_uri_to_string (event->data.UploadCompleted.uri);
+ printf (_("File `%s' has URI: %s\n"),
+ event->data.UploadCompleted.filename, fstring);
+ GNUNET_free (fstring);
+ if (ul == event->data.UploadCompleted.uc.pos)
+ {
+ postProcess (event->data.UploadCompleted.uri);
+ errorCode = 0;
+ GNUNET_shutdown_initiate ();
+ }
+ break;
+ case GNUNET_FSUI_upload_aborted:
+ printf (_("\nUpload aborted.\n"));
+ errorCode = 2;
+ GNUNET_shutdown_initiate ();
+ break;
+ case GNUNET_FSUI_upload_error:
+ printf (_("\nError uploading file: %s"),
+ event->data.UploadError.message);
+ errorCode = 3;
+ GNUNET_shutdown_initiate ();
+ break;
+ case GNUNET_FSUI_upload_started:
+ case GNUNET_FSUI_upload_stopped:
+ break;
+ default:
+ printf (_("\nUnexpected event: %d\n"), event->type);
+ GNUNET_GE_BREAK (ectx, 0);
+ break;
+ }
+ return NULL;
+}
+#endif
+
+/* end of gnunet-publish.c */
* @brief basic, low-level TCP networking interface\r
* @author Christian Grothoff\r
*/\r
-#ifndef GNUNET_NETWORK_LIB_H\r
-#define GNUNET_NETWORK_LIB_H\r
+#ifndef GNUNET_CONNECTION_LIB_H\r
+#define GNUNET_CONNECTION_LIB_H\r
\r
#ifdef __cplusplus\r
extern "C"\r
#endif\r
\r
\r
-/* ifndef GNUNET_NETWORK_LIB_H */\r
+/* ifndef GNUNET_CONNECTION_LIB_H */\r
#endif\r
/* end of gnunet_connection_lib.h */\r
/*
This file is part of GNUnet.
- (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008 Christian Grothoff (and other contributing authors)
+ (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors)
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
/**
* Create a fresh MetaData token.
+ *
+ * @return empty meta-data container
*/
struct GNUNET_CONTAINER_MetaData *GNUNET_CONTAINER_meta_data_create (void);
/**
* Duplicate a MetaData token.
+ *
+ * @param meta what to duplicate
+ * @return duplicate meta-data container
*/
struct GNUNET_CONTAINER_MetaData *GNUNET_CONTAINER_meta_data_duplicate (const
struct
/**
* Free meta data.
+ *
+ * @param md what to free
*/
void GNUNET_CONTAINER_meta_data_destroy (struct GNUNET_CONTAINER_MetaData
*md);
/**
* Test if two MDs are equal.
+ *
+ * @param md1 first value to check
+ * @param md2 other value to check
+ * @return GNUNET_YES if they are equal
*/
int GNUNET_CONTAINER_meta_data_test_equal (const struct
GNUNET_CONTAINER_MetaData *md1,
/**
* Extend metadata.
+ *
+ * @param md metadata to extend
+ * @param type type of the new entry
+ * @param data value for the entry
* @return GNUNET_OK on success, GNUNET_SYSERR if this entry already exists
*/
int GNUNET_CONTAINER_meta_data_insert (struct GNUNET_CONTAINER_MetaData *md,
/**
* Remove an item.
+ *
+ * @param type type of the item to remove
+ * @param data specific value to remove, NULL to remove all
+ * entries of the given type
* @return GNUNET_OK on success, GNUNET_SYSERR if the item does not exist in md
*/
int GNUNET_CONTAINER_meta_data_delete (struct GNUNET_CONTAINER_MetaData *md,
/**
* Add the current time as the publication date
* to the meta-data.
+ *
+ * @param md metadata to modify
*/
void GNUNET_CONTAINER_meta_data_add_publication_date (struct
GNUNET_CONTAINER_MetaData
/**
* Iterate over MD entries, excluding thumbnails.
*
+ * @param md metadata to inspect
+ * @param iterator function to call on each entry
+ * @param closure closure for iterator
* @return number of entries
*/
int GNUNET_CONTAINER_meta_data_get_contents (const struct
/**
* Get the first MD entry of the given type.
+ *
+ * @param md metadata to inspect
+ * @param type type to look for
* @return NULL if we do not have any such entry,
* otherwise client is responsible for freeing the value!
*/
/**
* Get the first matching MD entry of the given types.
- * @paarm ... -1-terminated list of types
+ *
+ * @param md metadata to inspect
+ * @param ... -1-terminated list of types
* @return NULL if we do not have any such entry,
* otherwise client is responsible for freeing the value!
*/
/**
* Get a thumbnail from the meta-data (if present).
*
+ * @param md metadata to inspect
* @param thumb will be set to the thumbnail data. Must be
* freed by the caller!
* @return number of bytes in thumbnail, 0 if not available
/**
* Extract meta-data from a file.
*
+ * @param md metadata to set
+ * @param filename name of file to inspect
+ * @param extractors plugins to use
* @return GNUNET_SYSERR on error, otherwise the number
* of meta-data items obtained
*/
/**
* Serialize meta-data to target.
*
+ * @param md metadata to serialize
* @param size maximum number of bytes available
* @param opt is it ok to just write SOME of the
* meta-data to match the size constraint,
* possibly discarding some data?
* @return number of bytes written on success,
- * GNUNET_SYSERR on error (typically: not enough
+ * -1 on error (typically: not enough
* space)
*/
ssize_t GNUNET_CONTAINER_meta_data_serialize (const struct
/**
* Compute size of the meta-data in
* serialized form.
+ *
+ * @param md metadata to inspect
* @param opt is it ok to just write SOME of the
* meta-data to match the size constraint,
* possibly discarding some data?
+ * @return number of bytes needed for serialization, -1 on error
*/
ssize_t GNUNET_CONTAINER_meta_data_get_serialized_size (const struct
GNUNET_CONTAINER_MetaData
/**
* Deserialize meta-data. Initializes md.
+ *
+ * @param input serialized meta-data.
* @param size number of bytes available
* @return MD on success, NULL on error (i.e.
* bad format)
* Does the meta-data claim that this is a directory?
* Checks if the mime-type is that of a GNUnet directory.
*
+ * @param md metadata to inspect
* @return GNUNET_YES if it is, GNUNET_NO if it is not, GNUNET_SYSERR if
* we have no mime-type information (treat as 'GNUNET_NO')
*/
* @file include/gnunet_fs_service.h
* @brief API for file-sharing via GNUnet
* @author Christian Grothoff
+ *
+ * TODO:
+ * - extend API with support for publish simulation (-s)
+ * and URI-argument binding to keyword/namespace (-u)
*/
#ifndef GNUNET_FS_LIB_H
#define GNUNET_FS_LIB_H
* @return GNUNET_OK on success
*/
int
-GNUNET_FS_getopt_configure_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext* ctx,
+GNUNET_FS_getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext* ctx,
void *scls,
const char *option,
const char *value);
* @return GNUNET_OK on success
*/
int
-GNUNET_FS_getopt_configure_set_metadata (struct GNUNET_GETOPT_CommandLineProcessorContext* ctx,
+GNUNET_FS_getopt_set_metadata (struct GNUNET_GETOPT_CommandLineProcessorContext* ctx,
void *scls,
const char *option,
const char *value);
* @author Nils Durner
*/
-#ifndef GNUNET_NETWORK_LIB_H_
-#define GNUNET_NETWORK_LIB_H_
+#ifndef GNUNET_NETWORK_LIB_H
+#define GNUNET_NETWORK_LIB_H
#ifdef __cplusplus
extern "C"
struct sockaddr *address,
socklen_t *address_len);
+int
+GNUNET_NETWORK_socket_set_inheritable (const struct GNUNET_NETWORK_Descriptor
+ *desc);
+
+
int GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Descriptor *desc,
const struct sockaddr *address, socklen_t address_len);
int GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1, const struct GNUNET_NETWORK_FDSet *fds2);
-struct GNUNET_NETWORK_FDSet *GNUNET_NETWORK_fdset_create ();
+struct GNUNET_NETWORK_FDSet *GNUNET_NETWORK_fdset_create (void);
void GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds);
}
#endif
-#endif /* GNUNET_NETWORK_LIB_H_ */
+#endif /* GNUNET_NETWORK_LIB_H */
getopt.c \
getopt_helpers.c \
network.c \
+ network_socket.c \
os_installation.c \
os_load.c \
os_network.c \
server_tc.c \
service.c \
signal.c \
- sock.c \
strings.c \
time.c \
$(WINSRC)
/**
* Test if two MDs are equal.
+ *
+ * @param md1 first value to check
+ * @param md2 other value to check
+ * @return GNUNET_YES if they are equal
*/
int
GNUNET_CONTAINER_meta_data_test_equal (const struct GNUNET_CONTAINER_MetaData
--- /dev/null
+/*\r
+ This file is part of GNUnet.\r
+ (C) 2009 Christian Grothoff (and other contributing authors)\r
+\r
+ GNUnet is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published\r
+ by the Free Software Foundation; either version 2, or (at your\r
+ option) any later version.\r
+\r
+ GNUnet is distributed in the hope that it will be useful, but\r
+ WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+ General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with GNUnet; see the file COPYING. If not, write to the\r
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,\r
+ Boston, MA 02111-1307, USA.\r
+*/\r
+\r
+/**\r
+ * @file util/sock.c\r
+ * @brief basic, low-level networking interface\r
+ * @author Nils Durner\r
+ */\r
+\r
+#include "platform.h"\r
+#include "gnunet_disk_lib.h"\r
+#include "disk.h"\r
+#include "gnunet_container_lib.h"\r
+\r
+#define DEBUG_SOCK GNUNET_NO\r
+\r
+struct GNUNET_NETWORK_Descriptor\r
+{\r
+ int fd;\r
+};\r
+\r
+struct GNUNET_NETWORK_FDSet\r
+{\r
+ /* socket descriptors */\r
+ int nsds;\r
+ fd_set sds;\r
+#ifdef WINDOWS\r
+ /* handles */\r
+ struct GNUNET_CONTAINER_Vector *handles;\r
+#endif\r
+};\r
+\r
+#ifndef FD_COPY\r
+#define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set)))\r
+#endif\r
+\r
+struct GNUNET_NETWORK_Descriptor *\r
+GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Descriptor *desc,\r
+ struct sockaddr *address,\r
+ socklen_t * address_len)\r
+{\r
+ struct GNUNET_NETWORK_Descriptor *ret;\r
+\r
+ ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Descriptor));\r
+ ret->fd = accept (desc->fd, address, address_len);\r
+#ifdef MINGW\r
+ if (INVALID_SOCKET == ret->fd)\r
+ SetErrnoFromWinsockError (WSAGetLastError ());\r
+#endif\r
+ return ret;\r
+}\r
+\r
+int\r
+GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Descriptor *desc,\r
+ const struct sockaddr *address,\r
+ socklen_t address_len)\r
+{\r
+ int ret;\r
+\r
+ ret = bind (desc->fd, address, address_len);\r
+#ifdef MINGW\r
+ if (SOCKET_ERROR == ret)\r
+ SetErrnoFromWinsockError (WSAGetLastError ());\r
+#endif\r
+ return ret;\r
+}\r
+\r
+/**\r
+ * Set if a socket should use blocking or non-blocking IO.\r
+ *\r
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error\r
+ */\r
+int\r
+GNUNET_NETWORK_socket_set_blocking (struct GNUNET_NETWORK_Descriptor *fd,\r
+ int doBlock)\r
+{\r
+#if MINGW\r
+ u_long mode;\r
+ mode = !doBlock;\r
+ if (ioctlsocket (fd->fd, FIONBIO, &mode) == SOCKET_ERROR)\r
+ {\r
+ SetErrnoFromWinsockError (WSAGetLastError ());\r
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctlsocket");\r
+ return GNUNET_SYSERR;\r
+ }\r
+ return GNUNET_OK;\r
+\r
+#else\r
+ /* not MINGW */\r
+ int flags = fcntl (fd->fd, F_GETFL);\r
+ if (flags == -1)\r
+ {\r
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");\r
+ return GNUNET_SYSERR;\r
+ }\r
+ if (doBlock)\r
+ flags &= ~O_NONBLOCK;\r
+ else\r
+ flags |= O_NONBLOCK;\r
+ if (0 != fcntl (fd->fd, F_SETFL, flags))\r
+ {\r
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");\r
+ return GNUNET_SYSERR;\r
+ }\r
+ return GNUNET_OK;\r
+#endif\r
+}\r
+\r
+int\r
+GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Descriptor *desc)\r
+{\r
+ int ret;\r
+#ifdef MINGW\r
+ ret = closesocket (desc->fd);\r
+ if (SOCKET_ERROR != ret)\r
+ GNUNET_free (desc);\r
+ else\r
+ SetErrnoFromWinsockError (WSAGetLastError ());\r
+#else\r
+ ret = close (desc->fd);\r
+ if (-1 == ret)\r
+ {\r
+ GNUNET_free (desc);\r
+ }\r
+#endif\r
+\r
+ return ret;\r
+}\r
+\r
+int\r
+GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Descriptor *desc,\r
+ const struct sockaddr *address,\r
+ socklen_t address_len)\r
+{\r
+ int ret;\r
+\r
+ ret = connect (desc->fd, address, address_len);\r
+#ifdef MINGW\r
+ if (SOCKET_ERROR == ret)\r
+ SetErrnoFromWinsockError (WSAGetLastError ());\r
+#endif\r
+ return ret;\r
+}\r
+\r
+int\r
+GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Descriptor *desc,\r
+ int level, int optname, void *optval,\r
+ socklen_t * optlen)\r
+{\r
+ int ret;\r
+\r
+ ret = getsockopt (desc->fd, level, optname, optval, optlen);\r
+#ifdef MINGW\r
+ if (ret == 0 && level == SOL_SOCKET && optname == SO_ERROR)\r
+ *((int *) optval) = GetErrnoFromWinsockError (*((int *) optval));\r
+ else if (SOCKET_ERROR == ret)\r
+ SetErrnoFromWinsockError (WSAGetLastError ());\r
+#endif\r
+ return ret;\r
+}\r
+\r
+int\r
+GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Descriptor *desc,\r
+ int backlog)\r
+{\r
+ int ret;\r
+\r
+ ret = listen (desc->fd, backlog);\r
+#ifdef MINGW\r
+ if (SOCKET_ERROR == ret)\r
+ SetErrnoFromWinsockError (WSAGetLastError ());\r
+#endif\r
+\r
+ return ret;\r
+}\r
+\r
+ssize_t\r
+GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Descriptor * desc,\r
+ void *buffer, size_t length, int flags)\r
+{\r
+ int ret;\r
+\r
+ ret = recv (desc->fd, buffer, length, flags);\r
+#ifdef MINGW\r
+ if (SOCKET_ERROR == ret)\r
+ SetErrnoFromWinsockError (WSAGetLastError ());\r
+#endif\r
+\r
+ return ret;\r
+}\r
+\r
+ssize_t\r
+GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Descriptor * desc,\r
+ const void *buffer, size_t length, int flags)\r
+{\r
+ int ret;\r
+\r
+ ret = send (desc->fd, buffer, length, flags);\r
+#ifdef MINGW\r
+ if (SOCKET_ERROR == ret)\r
+ SetErrnoFromWinsockError (WSAGetLastError ());\r
+#endif\r
+\r
+ return ret;\r
+}\r
+\r
+ssize_t\r
+GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Descriptor * desc,\r
+ const void *message, size_t length, int flags,\r
+ const struct sockaddr * dest_addr,\r
+ socklen_t dest_len)\r
+{\r
+ int ret;\r
+\r
+ ret = sendto (desc->fd, message, length, flags, dest_addr, dest_len);\r
+#ifdef MINGW\r
+ if (SOCKET_ERROR == ret)\r
+ SetErrnoFromWinsockError (WSAGetLastError ());\r
+#endif\r
+\r
+ return ret;\r
+}\r
+\r
+int\r
+GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Descriptor *fd,\r
+ int level, int option_name,\r
+ const void *option_value,\r
+ socklen_t option_len)\r
+{\r
+ int ret;\r
+\r
+ ret = setsockopt (fd->fd, level, option_name, option_value, option_len);\r
+#ifdef MINGW\r
+ if (SOCKET_ERROR == ret)\r
+ SetErrnoFromWinsockError (WSAGetLastError ());\r
+#endif\r
+\r
+ return ret;\r
+}\r
+\r
+struct GNUNET_NETWORK_Descriptor *\r
+GNUNET_NETWORK_socket_socket (int domain, int type, int protocol)\r
+{\r
+ struct GNUNET_NETWORK_Descriptor *ret;\r
+\r
+ ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Descriptor));\r
+ ret->fd = socket (domain, type, protocol);\r
+#ifdef MINGW\r
+ if (INVALID_SOCKET == ret->fd)\r
+ SetErrnoFromWinsockError (WSAGetLastError ());\r
+#endif\r
+\r
+ if (ret->fd < 0)\r
+ {\r
+ GNUNET_free (ret);\r
+ ret = NULL;\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+int\r
+GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Descriptor *desc,\r
+ int how)\r
+{\r
+ int ret;\r
+\r
+ ret = shutdown (desc->fd, how);\r
+#ifdef MINGW\r
+ if (ret != 0)\r
+ SetErrnoFromWinsockError (WSAGetLastError ());\r
+#endif\r
+\r
+ return ret;\r
+}\r
+\r
+int\r
+GNUNET_NETWORK_socket_set_inheritable (const struct GNUNET_NETWORK_Descriptor\r
+ *desc)\r
+{\r
+#ifdef MINGW\r
+ errno = ENOSYS;\r
+ return GNUNET_SYSERR;\r
+#else\r
+ return fcntl (desc->fd, F_SETFD,\r
+ fcntl (desc->fd,\r
+ F_GETFD) | FD_CLOEXEC) ==\r
+ 0 ? GNUNET_OK : GNUNET_SYSERR;\r
+#endif\r
+}\r
+\r
+void\r
+GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds)\r
+{\r
+ FD_ZERO (&fds->sds);\r
+ fds->nsds = 0;\r
+#ifdef MINGW\r
+ if (fds->handles)\r
+ GNUNET_CONTAINER_vector_destroy (fds->handles);\r
+ fds->handles = GNUNET_CONTAINER_vector_create (2);\r
+#endif\r
+}\r
+\r
+void\r
+GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds,\r
+ const struct GNUNET_NETWORK_Descriptor *desc)\r
+{\r
+ FD_SET (desc->fd, &fds->sds);\r
+\r
+ if (desc->fd + 1 > fds->nsds)\r
+ fds->nsds = desc->fd + 1;\r
+}\r
+\r
+int\r
+GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds,\r
+ const struct GNUNET_NETWORK_Descriptor *desc)\r
+{\r
+ return FD_ISSET (desc->fd, &fds->sds);\r
+}\r
+\r
+void\r
+GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst,\r
+ const struct GNUNET_NETWORK_FDSet *src)\r
+{\r
+ int nfds;\r
+\r
+ for (nfds = src->nsds; nfds > 0; nfds--)\r
+ if (FD_ISSET (nfds, &src->sds))\r
+ {\r
+ FD_SET (nfds, &dst->sds);\r
+ if (nfds + 1 > dst->nsds)\r
+ dst->nsds = nfds + 1;\r
+ }\r
+}\r
+\r
+void\r
+GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,\r
+ const struct GNUNET_NETWORK_FDSet *from)\r
+{\r
+ FD_COPY (&from->sds, &to->sds);\r
+ to->nsds = from->nsds;\r
+#ifdef MINGW\r
+ void *obj;\r
+\r
+ if (to->handles)\r
+ GNUNET_CONTAINER_vector_destroy (to->handles);\r
+ to->handles = GNUNET_CONTAINER_vector_create (2);\r
+ for (obj = GNUNET_CONTAINER_vector_get_first (from->handles); obj != NULL;\r
+ obj = GNUNET_CONTAINER_vector_get_next (from->handles))\r
+ {\r
+ GNUNET_CONTAINER_vector_insert_last (to->handles, obj);\r
+ }\r
+#endif\r
+}\r
+\r
+void\r
+GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to,\r
+ const fd_set * from, int nfds)\r
+{\r
+ FD_COPY (from, &to->sds);\r
+ to->nsds = nfds;\r
+}\r
+\r
+void\r
+GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds,\r
+ const struct GNUNET_DISK_FileHandle *h)\r
+{\r
+#ifdef MINGW\r
+ HANDLE hw;\r
+\r
+ GNUNET_internal_disk_file_handle (h, &hw, sizeof (HANDLE));\r
+ GNUNET_CONTAINER_vector_insert_last (fds->handles, h);\r
+#else\r
+ int fd;\r
+\r
+ GNUNET_internal_disk_file_handle (h, &fd, sizeof (int));\r
+ FD_SET (fd, &fds->sds);\r
+ if (fd + 1 > fds->nsds)\r
+ fds->nsds = fd + 1;\r
+#endif\r
+}\r
+\r
+int\r
+GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,\r
+ const struct GNUNET_DISK_FileHandle *h)\r
+{\r
+#ifdef MINGW\r
+ return GNUNET_CONTAINER_vector_index_of (fds->handles, h->h) !=\r
+ (unsigned int) -1;\r
+#else\r
+ return FD_ISSET (h->fd, &fds->sds);\r
+#endif\r
+}\r
+\r
+int\r
+GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,\r
+ const struct GNUNET_NETWORK_FDSet *fds2)\r
+{\r
+ int nfds;\r
+\r
+ nfds = fds1->nsds;\r
+ if (nfds < fds2->nsds)\r
+ nfds = fds2->nsds;\r
+\r
+ for (; nfds >= 0; nfds--)\r
+ if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds))\r
+ return GNUNET_YES;\r
+\r
+ return GNUNET_NO;\r
+}\r
+\r
+struct GNUNET_NETWORK_FDSet *\r
+GNUNET_NETWORK_fdset_create ()\r
+{\r
+ struct GNUNET_NETWORK_FDSet *fds;\r
+\r
+ fds = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_FDSet));\r
+#ifdef MINGW\r
+ fds->handles = NULL;\r
+#endif\r
+ GNUNET_NETWORK_fdset_zero (fds);\r
+\r
+ return fds;\r
+}\r
+\r
+void\r
+GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)\r
+{\r
+#ifdef MINGW\r
+ GNUNET_CONTAINER_vector_destroy (fds->handles);\r
+#endif\r
+ GNUNET_free (fds);\r
+}\r
+\r
+int\r
+GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,\r
+ struct GNUNET_NETWORK_FDSet *wfds,\r
+ struct GNUNET_NETWORK_FDSet *efds,\r
+ const struct GNUNET_TIME_Relative timeout)\r
+{\r
+ int nfds;\r
+\r
+ nfds = 0;\r
+\r
+ if (rfds)\r
+ nfds = rfds->nsds;\r
+ if (wfds && wfds->nsds > nfds)\r
+ nfds = wfds->nsds;\r
+ if (efds && efds->nsds > nfds)\r
+ nfds = efds->nsds;\r
+\r
+#ifndef MINGW\r
+ struct timeval tv;\r
+\r
+ tv.tv_sec = timeout.value / GNUNET_TIME_UNIT_SECONDS.value;\r
+ tv.tv_usec = (timeout.value - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.value))\r
+ / GNUNET_TIME_UNIT_MILLISECONDS.value;\r
+\r
+ return select (nfds + 1, rfds ? &rfds->sds : NULL, wfds ? &wfds->sds : NULL,\r
+ efds ? &efds->sds : NULL, timeout.value\r
+ == GNUNET_TIME_UNIT_FOREVER_REL.value ? NULL : &tv);\r
+#else\r
+ DWORD limit;\r
+ fd_set sock_read, sock_write, sock_except;\r
+ fd_set aread, awrite, aexcept;\r
+ int i;\r
+ struct timeval tvslice;\r
+ int retcode;\r
+ DWORD ms_total;\r
+\r
+#define SAFE_FD_ISSET(fd, set) (set != NULL && FD_ISSET(fd, set))\r
+\r
+ /* calculate how long we need to wait in milliseconds */\r
+ if (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)\r
+ ms_total = INFINITE;\r
+ else\r
+ ms_total = timeout.value / GNUNET_TIME_UNIT_MILLISECONDS.value;\r
+\r
+ /* select() may be used as a portable way to sleep */\r
+ if (!(rfds || wfds || efds))\r
+ {\r
+ Sleep (ms_total);\r
+\r
+ return 0;\r
+ }\r
+\r
+ if (rfds)\r
+ sock_read = rfds->sds;\r
+ else\r
+ FD_ZERO(&sock_read);\r
+\r
+ if (wfds)\r
+ sock_write = wfds->sds;\r
+ else\r
+ FD_ZERO(&sock_write);\r
+\r
+ if (efds)\r
+ sock_except = efds->sds;\r
+ else\r
+ FD_ZERO(&sock_except);\r
+\r
+ /*\r
+ if (rfds)\r
+ FD_COPY (&rfds->sds, &sock_read);\r
+ else\r
+ FD_ZERO(&sock_read);\r
+\r
+ if (wfds)\r
+ FD_COPY (&wfds->sds, &sock_write);\r
+ else\r
+ FD_ZERO(&sock_write);\r
+\r
+ if (efds)\r
+ FD_COPY (&efds->sds, &sock_except);\r
+ else\r
+ FD_ZERO(&sock_except);\r
+*/\r
+\r
+ /* multiplex between winsock select() and waiting on the handles */\r
+\r
+ FD_ZERO (&aread);\r
+ FD_ZERO (&awrite);\r
+ FD_ZERO (&aexcept);\r
+\r
+ limit = GetTickCount () + ms_total;\r
+ do\r
+ {\r
+ retcode = 0;\r
+\r
+ if (nfds > 0)\r
+ {\r
+ /* overwrite the zero'd sets here; the select call\r
+ * will clear those that are not active */\r
+\r
+ FD_COPY (&sock_read, &aread);\r
+ FD_COPY (&sock_write, &awrite);\r
+ FD_COPY (&sock_except, &aexcept);\r
+\r
+ tvslice.tv_sec = 0;\r
+ tvslice.tv_usec = 100000;\r
+\r
+ if ((retcode =\r
+ select (nfds + 1, &aread, &awrite, &aexcept,\r
+ &tvslice)) == SOCKET_ERROR)\r
+ {\r
+ SetErrnoFromWinsockError (WSAGetLastError ());\r
+ if (errno == ENOTSOCK)\r
+ errno = EBADF;\r
+\r
+#if DEBUG_SOCK\r
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");\r
+#endif\r
+\r
+ goto select_loop_end;\r
+ }\r
+ }\r
+\r
+ /* Poll read pipes */\r
+ if (rfds)\r
+ for (i = GNUNET_CONTAINER_vector_size (rfds->handles) - 1; i >= 0; i--)\r
+ {\r
+ DWORD dwBytes;\r
+\r
+ if (!PeekNamedPipe\r
+ (GNUNET_CONTAINER_vector_get_at (rfds->handles, i), NULL, 0,\r
+ NULL, &dwBytes, NULL))\r
+ {\r
+ GNUNET_CONTAINER_vector_remove_at (rfds->handles, i);\r
+\r
+ retcode = -1;\r
+ SetErrnoFromWinError (GetLastError ());\r
+#if DEBUG_SOCK\r
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "PeekNamedPipe");\r
+#endif\r
+ goto select_loop_end;\r
+ }\r
+ else if (dwBytes)\r
+ {\r
+ retcode++;\r
+ }\r
+ else\r
+ GNUNET_CONTAINER_vector_remove_at (rfds->handles, i);\r
+ }\r
+\r
+ /* Poll for faulty pipes */\r
+ if (efds)\r
+ for (i = GNUNET_CONTAINER_vector_size (efds->handles); i >= 0; i--)\r
+ {\r
+ DWORD dwBytes;\r
+\r
+ if (PeekNamedPipe\r
+ (GNUNET_CONTAINER_vector_get_at (rfds->handles, i), NULL, 0,\r
+ NULL, &dwBytes, NULL))\r
+ {\r
+ GNUNET_CONTAINER_vector_remove_at (efds->handles, i);\r
+\r
+ retcode++;\r
+ }\r
+ }\r
+\r
+ /* FIXME */\r
+ if (wfds)\r
+ GNUNET_assert (GNUNET_CONTAINER_vector_size (wfds->handles) == 0);\r
+\r
+ /* Check for closed sockets */\r
+ for (i = 0; i < nfds; i++)\r
+ {\r
+ if (SAFE_FD_ISSET (i, &sock_read))\r
+ {\r
+ struct sockaddr addr;\r
+ int len;\r
+\r
+ if (getpeername (i, &addr, &len) == SOCKET_ERROR)\r
+ {\r
+ int err, len;\r
+\r
+ len = sizeof (err);\r
+ if (getsockopt\r
+ (i, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == 0\r
+ && err == WSAENOTCONN)\r
+ {\r
+ if (!SAFE_FD_ISSET (i, &aread))\r
+ {\r
+ FD_SET (i, &aread);\r
+ retcode++;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ select_loop_end:;\r
+ }\r
+ while (retcode == 0 && (ms_total == INFINITE || GetTickCount () < limit));\r
+\r
+ if (retcode != -1)\r
+ {\r
+ if (rfds)\r
+ {\r
+ GNUNET_NETWORK_fdset_zero (rfds);\r
+ GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode);\r
+ }\r
+\r
+ if (wfds)\r
+ {\r
+ GNUNET_NETWORK_fdset_zero (wfds);\r
+ GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode);\r
+ }\r
+\r
+ if (efds)\r
+ {\r
+ GNUNET_NETWORK_fdset_zero (efds);\r
+ GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode);\r
+ }\r
+ }\r
+\r
+ return retcode;\r
+#endif\r
+}\r
+\r
+/* end of sock.c */\r
+++ /dev/null
-/*\r
- This file is part of GNUnet.\r
- (C) 2009 Christian Grothoff (and other contributing authors)\r
-\r
- GNUnet is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU General Public License as published\r
- by the Free Software Foundation; either version 2, or (at your\r
- option) any later version.\r
-\r
- GNUnet is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of\r
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- General Public License for more details.\r
-\r
- You should have received a copy of the GNU General Public License\r
- along with GNUnet; see the file COPYING. If not, write to the\r
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,\r
- Boston, MA 02111-1307, USA.\r
-*/\r
-\r
-/**\r
- * @file util/sock.c\r
- * @brief basic, low-level networking interface\r
- * @author Nils Durner\r
- */\r
-\r
-#include "platform.h"\r
-#include "gnunet_disk_lib.h"\r
-#include "disk.h"\r
-#include "gnunet_container_lib.h"\r
-\r
-#define DEBUG_SOCK GNUNET_NO\r
-\r
-struct GNUNET_NETWORK_Descriptor\r
-{\r
- int fd;\r
-};\r
-\r
-struct GNUNET_NETWORK_FDSet\r
-{\r
- /* socket descriptors */\r
- int nsds;\r
- fd_set sds;\r
-#ifdef WINDOWS\r
- /* handles */\r
- struct GNUNET_CONTAINER_Vector *handles;\r
-#endif\r
-};\r
-\r
-#ifndef FD_COPY\r
-#define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set)))\r
-#endif\r
-\r
-struct GNUNET_NETWORK_Descriptor *\r
-GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Descriptor *desc,\r
- struct sockaddr *address,\r
- socklen_t * address_len)\r
-{\r
- struct GNUNET_NETWORK_Descriptor *ret;\r
-\r
- ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Descriptor));\r
- ret->fd = accept (desc->fd, address, address_len);\r
-#ifdef MINGW\r
- if (INVALID_SOCKET == ret->fd)\r
- SetErrnoFromWinsockError (WSAGetLastError ());\r
-#endif\r
- return ret;\r
-}\r
-\r
-int\r
-GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Descriptor *desc,\r
- const struct sockaddr *address,\r
- socklen_t address_len)\r
-{\r
- int ret;\r
-\r
- ret = bind (desc->fd, address, address_len);\r
-#ifdef MINGW\r
- if (SOCKET_ERROR == ret)\r
- SetErrnoFromWinsockError (WSAGetLastError ());\r
-#endif\r
- return ret;\r
-}\r
-\r
-/**\r
- * Set if a socket should use blocking or non-blocking IO.\r
- *\r
- * @return GNUNET_OK on success, GNUNET_SYSERR on error\r
- */\r
-int\r
-GNUNET_NETWORK_socket_set_blocking (struct GNUNET_NETWORK_Descriptor *fd,\r
- int doBlock)\r
-{\r
-#if MINGW\r
- u_long mode;\r
- mode = !doBlock;\r
- if (ioctlsocket (fd->fd, FIONBIO, &mode) == SOCKET_ERROR)\r
- {\r
- SetErrnoFromWinsockError (WSAGetLastError ());\r
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctlsocket");\r
- return GNUNET_SYSERR;\r
- }\r
- return GNUNET_OK;\r
-\r
-#else\r
- /* not MINGW */\r
- int flags = fcntl (fd->fd, F_GETFL);\r
- if (flags == -1)\r
- {\r
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");\r
- return GNUNET_SYSERR;\r
- }\r
- if (doBlock)\r
- flags &= ~O_NONBLOCK;\r
- else\r
- flags |= O_NONBLOCK;\r
- if (0 != fcntl (fd->fd, F_SETFL, flags))\r
- {\r
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");\r
- return GNUNET_SYSERR;\r
- }\r
- return GNUNET_OK;\r
-#endif\r
-}\r
-\r
-int\r
-GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Descriptor *desc)\r
-{\r
- int ret;\r
-#ifdef MINGW\r
- ret = closesocket (desc->fd);\r
- if (SOCKET_ERROR != ret)\r
- GNUNET_free (desc);\r
- else\r
- SetErrnoFromWinsockError (WSAGetLastError ());\r
-#else\r
- ret = close (desc->fd);\r
- if (-1 == ret)\r
- {\r
- GNUNET_free (desc);\r
- }\r
-#endif\r
-\r
- return ret;\r
-}\r
-\r
-int\r
-GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Descriptor *desc,\r
- const struct sockaddr *address,\r
- socklen_t address_len)\r
-{\r
- int ret;\r
-\r
- ret = connect (desc->fd, address, address_len);\r
-#ifdef MINGW\r
- if (SOCKET_ERROR == ret)\r
- SetErrnoFromWinsockError (WSAGetLastError ());\r
-#endif\r
- return ret;\r
-}\r
-\r
-int\r
-GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Descriptor *desc,\r
- int level, int optname, void *optval,\r
- socklen_t * optlen)\r
-{\r
- int ret;\r
-\r
- ret = getsockopt (desc->fd, level, optname, optval, optlen);\r
-#ifdef MINGW\r
- if (ret == 0 && level == SOL_SOCKET && optname == SO_ERROR)\r
- *((int *) optval) = GetErrnoFromWinsockError (*((int *) optval));\r
- else if (SOCKET_ERROR == ret)\r
- SetErrnoFromWinsockError (WSAGetLastError ());\r
-#endif\r
- return ret;\r
-}\r
-\r
-int\r
-GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Descriptor *desc,\r
- int backlog)\r
-{\r
- int ret;\r
-\r
- ret = listen (desc->fd, backlog);\r
-#ifdef MINGW\r
- if (SOCKET_ERROR == ret)\r
- SetErrnoFromWinsockError (WSAGetLastError ());\r
-#endif\r
-\r
- return ret;\r
-}\r
-\r
-ssize_t\r
-GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Descriptor * desc,\r
- void *buffer, size_t length, int flags)\r
-{\r
- int ret;\r
-\r
- ret = recv (desc->fd, buffer, length, flags);\r
-#ifdef MINGW\r
- if (SOCKET_ERROR == ret)\r
- SetErrnoFromWinsockError (WSAGetLastError ());\r
-#endif\r
-\r
- return ret;\r
-}\r
-\r
-ssize_t\r
-GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Descriptor * desc,\r
- const void *buffer, size_t length, int flags)\r
-{\r
- int ret;\r
-\r
- ret = send (desc->fd, buffer, length, flags);\r
-#ifdef MINGW\r
- if (SOCKET_ERROR == ret)\r
- SetErrnoFromWinsockError (WSAGetLastError ());\r
-#endif\r
-\r
- return ret;\r
-}\r
-\r
-ssize_t\r
-GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Descriptor * desc,\r
- const void *message, size_t length, int flags,\r
- const struct sockaddr * dest_addr,\r
- socklen_t dest_len)\r
-{\r
- int ret;\r
-\r
- ret = sendto (desc->fd, message, length, flags, dest_addr, dest_len);\r
-#ifdef MINGW\r
- if (SOCKET_ERROR == ret)\r
- SetErrnoFromWinsockError (WSAGetLastError ());\r
-#endif\r
-\r
- return ret;\r
-}\r
-\r
-int\r
-GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Descriptor *fd,\r
- int level, int option_name,\r
- const void *option_value,\r
- socklen_t option_len)\r
-{\r
- int ret;\r
-\r
- ret = setsockopt (fd->fd, level, option_name, option_value, option_len);\r
-#ifdef MINGW\r
- if (SOCKET_ERROR == ret)\r
- SetErrnoFromWinsockError (WSAGetLastError ());\r
-#endif\r
-\r
- return ret;\r
-}\r
-\r
-struct GNUNET_NETWORK_Descriptor *\r
-GNUNET_NETWORK_socket_socket (int domain, int type, int protocol)\r
-{\r
- struct GNUNET_NETWORK_Descriptor *ret;\r
-\r
- ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Descriptor));\r
- ret->fd = socket (domain, type, protocol);\r
-#ifdef MINGW\r
- if (INVALID_SOCKET == ret->fd)\r
- SetErrnoFromWinsockError (WSAGetLastError ());\r
-#endif\r
-\r
- if (ret->fd < 0)\r
- {\r
- GNUNET_free (ret);\r
- ret = NULL;\r
- }\r
-\r
- return ret;\r
-}\r
-\r
-int\r
-GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Descriptor *desc,\r
- int how)\r
-{\r
- int ret;\r
-\r
- ret = shutdown (desc->fd, how);\r
-#ifdef MINGW\r
- if (ret != 0)\r
- SetErrnoFromWinsockError (WSAGetLastError ());\r
-#endif\r
-\r
- return ret;\r
-}\r
-\r
-int\r
-GNUNET_NETWORK_socket_set_inheritable (const struct GNUNET_NETWORK_Descriptor\r
- *desc)\r
-{\r
-#ifdef MINGW\r
- errno = ENOSYS;\r
- return GNUNET_SYSERR;\r
-#else\r
- return fcntl (desc->fd, F_SETFD,\r
- fcntl (desc->fd,\r
- F_GETFD) | FD_CLOEXEC) ==\r
- 0 ? GNUNET_OK : GNUNET_SYSERR;\r
-#endif\r
-}\r
-\r
-void\r
-GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds)\r
-{\r
- FD_ZERO (&fds->sds);\r
- fds->nsds = 0;\r
-#ifdef MINGW\r
- if (fds->handles)\r
- GNUNET_CONTAINER_vector_destroy (fds->handles);\r
- fds->handles = GNUNET_CONTAINER_vector_create (2);\r
-#endif\r
-}\r
-\r
-void\r
-GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds,\r
- const struct GNUNET_NETWORK_Descriptor *desc)\r
-{\r
- FD_SET (desc->fd, &fds->sds);\r
-\r
- if (desc->fd + 1 > fds->nsds)\r
- fds->nsds = desc->fd + 1;\r
-}\r
-\r
-int\r
-GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds,\r
- const struct GNUNET_NETWORK_Descriptor *desc)\r
-{\r
- return FD_ISSET (desc->fd, &fds->sds);\r
-}\r
-\r
-void\r
-GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst,\r
- const struct GNUNET_NETWORK_FDSet *src)\r
-{\r
- int nfds;\r
-\r
- for (nfds = src->nsds; nfds > 0; nfds--)\r
- if (FD_ISSET (nfds, &src->sds))\r
- {\r
- FD_SET (nfds, &dst->sds);\r
- if (nfds + 1 > dst->nsds)\r
- dst->nsds = nfds + 1;\r
- }\r
-}\r
-\r
-void\r
-GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,\r
- const struct GNUNET_NETWORK_FDSet *from)\r
-{\r
- FD_COPY (&from->sds, &to->sds);\r
- to->nsds = from->nsds;\r
-#ifdef MINGW\r
- void *obj;\r
-\r
- if (to->handles)\r
- GNUNET_CONTAINER_vector_destroy (to->handles);\r
- to->handles = GNUNET_CONTAINER_vector_create (2);\r
- for (obj = GNUNET_CONTAINER_vector_get_first (from->handles); obj != NULL;\r
- obj = GNUNET_CONTAINER_vector_get_next (from->handles))\r
- {\r
- GNUNET_CONTAINER_vector_insert_last (to->handles, obj);\r
- }\r
-#endif\r
-}\r
-\r
-void\r
-GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to,\r
- const fd_set * from, int nfds)\r
-{\r
- FD_COPY (from, &to->sds);\r
- to->nsds = nfds;\r
-}\r
-\r
-void\r
-GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds,\r
- const struct GNUNET_DISK_FileHandle *h)\r
-{\r
-#ifdef MINGW\r
- HANDLE hw;\r
-\r
- GNUNET_internal_disk_file_handle (h, &hw, sizeof (HANDLE));\r
- GNUNET_CONTAINER_vector_insert_last (fds->handles, h);\r
-#else\r
- int fd;\r
-\r
- GNUNET_internal_disk_file_handle (h, &fd, sizeof (int));\r
- FD_SET (fd, &fds->sds);\r
- if (fd + 1 > fds->nsds)\r
- fds->nsds = fd + 1;\r
-#endif\r
-}\r
-\r
-int\r
-GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,\r
- const struct GNUNET_DISK_FileHandle *h)\r
-{\r
-#ifdef MINGW\r
- return GNUNET_CONTAINER_vector_index_of (fds->handles, h->h) !=\r
- (unsigned int) -1;\r
-#else\r
- return FD_ISSET (h->fd, &fds->sds);\r
-#endif\r
-}\r
-\r
-int\r
-GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,\r
- const struct GNUNET_NETWORK_FDSet *fds2)\r
-{\r
- int nfds;\r
-\r
- nfds = fds1->nsds;\r
- if (nfds < fds2->nsds)\r
- nfds = fds2->nsds;\r
-\r
- for (; nfds >= 0; nfds--)\r
- if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds))\r
- return GNUNET_YES;\r
-\r
- return GNUNET_NO;\r
-}\r
-\r
-struct GNUNET_NETWORK_FDSet *\r
-GNUNET_NETWORK_fdset_create ()\r
-{\r
- struct GNUNET_NETWORK_FDSet *fds;\r
-\r
- fds = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_FDSet));\r
-#ifdef MINGW\r
- fds->handles = NULL;\r
-#endif\r
- GNUNET_NETWORK_fdset_zero (fds);\r
-\r
- return fds;\r
-}\r
-\r
-void\r
-GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)\r
-{\r
-#ifdef MINGW\r
- GNUNET_CONTAINER_vector_destroy (fds->handles);\r
-#endif\r
- GNUNET_free (fds);\r
-}\r
-\r
-int\r
-GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,\r
- struct GNUNET_NETWORK_FDSet *wfds,\r
- struct GNUNET_NETWORK_FDSet *efds,\r
- const struct GNUNET_TIME_Relative timeout)\r
-{\r
- int nfds;\r
-\r
- nfds = 0;\r
-\r
- if (rfds)\r
- nfds = rfds->nsds;\r
- if (wfds && wfds->nsds > nfds)\r
- nfds = wfds->nsds;\r
- if (efds && efds->nsds > nfds)\r
- nfds = efds->nsds;\r
-\r
-#ifndef MINGW\r
- struct timeval tv;\r
-\r
- tv.tv_sec = timeout.value / GNUNET_TIME_UNIT_SECONDS.value;\r
- tv.tv_usec = (timeout.value - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.value))\r
- / GNUNET_TIME_UNIT_MILLISECONDS.value;\r
-\r
- return select (nfds + 1, rfds ? &rfds->sds : NULL, wfds ? &wfds->sds : NULL,\r
- efds ? &efds->sds : NULL, timeout.value\r
- == GNUNET_TIME_UNIT_FOREVER_REL.value ? NULL : &tv);\r
-#else\r
- DWORD limit;\r
- fd_set sock_read, sock_write, sock_except;\r
- fd_set aread, awrite, aexcept;\r
- int i;\r
- struct timeval tvslice;\r
- int retcode;\r
- DWORD ms_total;\r
-\r
-#define SAFE_FD_ISSET(fd, set) (set != NULL && FD_ISSET(fd, set))\r
-\r
- /* calculate how long we need to wait in milliseconds */\r
- if (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)\r
- ms_total = INFINITE;\r
- else\r
- ms_total = timeout.value / GNUNET_TIME_UNIT_MILLISECONDS.value;\r
-\r
- /* select() may be used as a portable way to sleep */\r
- if (!(rfds || wfds || efds))\r
- {\r
- Sleep (ms_total);\r
-\r
- return 0;\r
- }\r
-\r
- if (rfds)\r
- sock_read = rfds->sds;\r
- else\r
- FD_ZERO(&sock_read);\r
-\r
- if (wfds)\r
- sock_write = wfds->sds;\r
- else\r
- FD_ZERO(&sock_write);\r
-\r
- if (efds)\r
- sock_except = efds->sds;\r
- else\r
- FD_ZERO(&sock_except);\r
-\r
- /*\r
- if (rfds)\r
- FD_COPY (&rfds->sds, &sock_read);\r
- else\r
- FD_ZERO(&sock_read);\r
-\r
- if (wfds)\r
- FD_COPY (&wfds->sds, &sock_write);\r
- else\r
- FD_ZERO(&sock_write);\r
-\r
- if (efds)\r
- FD_COPY (&efds->sds, &sock_except);\r
- else\r
- FD_ZERO(&sock_except);\r
-*/\r
-\r
- /* multiplex between winsock select() and waiting on the handles */\r
-\r
- FD_ZERO (&aread);\r
- FD_ZERO (&awrite);\r
- FD_ZERO (&aexcept);\r
-\r
- limit = GetTickCount () + ms_total;\r
- do\r
- {\r
- retcode = 0;\r
-\r
- if (nfds > 0)\r
- {\r
- /* overwrite the zero'd sets here; the select call\r
- * will clear those that are not active */\r
-\r
- FD_COPY (&sock_read, &aread);\r
- FD_COPY (&sock_write, &awrite);\r
- FD_COPY (&sock_except, &aexcept);\r
-\r
- tvslice.tv_sec = 0;\r
- tvslice.tv_usec = 100000;\r
-\r
- if ((retcode =\r
- select (nfds + 1, &aread, &awrite, &aexcept,\r
- &tvslice)) == SOCKET_ERROR)\r
- {\r
- SetErrnoFromWinsockError (WSAGetLastError ());\r
- if (errno == ENOTSOCK)\r
- errno = EBADF;\r
-\r
-#if DEBUG_SOCK\r
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");\r
-#endif\r
-\r
- goto select_loop_end;\r
- }\r
- }\r
-\r
- /* Poll read pipes */\r
- if (rfds)\r
- for (i = GNUNET_CONTAINER_vector_size (rfds->handles) - 1; i >= 0; i--)\r
- {\r
- DWORD dwBytes;\r
-\r
- if (!PeekNamedPipe\r
- (GNUNET_CONTAINER_vector_get_at (rfds->handles, i), NULL, 0,\r
- NULL, &dwBytes, NULL))\r
- {\r
- GNUNET_CONTAINER_vector_remove_at (rfds->handles, i);\r
-\r
- retcode = -1;\r
- SetErrnoFromWinError (GetLastError ());\r
-#if DEBUG_SOCK\r
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "PeekNamedPipe");\r
-#endif\r
- goto select_loop_end;\r
- }\r
- else if (dwBytes)\r
- {\r
- retcode++;\r
- }\r
- else\r
- GNUNET_CONTAINER_vector_remove_at (rfds->handles, i);\r
- }\r
-\r
- /* Poll for faulty pipes */\r
- if (efds)\r
- for (i = GNUNET_CONTAINER_vector_size (efds->handles); i >= 0; i--)\r
- {\r
- DWORD dwBytes;\r
-\r
- if (PeekNamedPipe\r
- (GNUNET_CONTAINER_vector_get_at (rfds->handles, i), NULL, 0,\r
- NULL, &dwBytes, NULL))\r
- {\r
- GNUNET_CONTAINER_vector_remove_at (efds->handles, i);\r
-\r
- retcode++;\r
- }\r
- }\r
-\r
- /* FIXME */\r
- if (wfds)\r
- GNUNET_assert (GNUNET_CONTAINER_vector_size (wfds->handles) == 0);\r
-\r
- /* Check for closed sockets */\r
- for (i = 0; i < nfds; i++)\r
- {\r
- if (SAFE_FD_ISSET (i, &sock_read))\r
- {\r
- struct sockaddr addr;\r
- int len;\r
-\r
- if (getpeername (i, &addr, &len) == SOCKET_ERROR)\r
- {\r
- int err, len;\r
-\r
- len = sizeof (err);\r
- if (getsockopt\r
- (i, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == 0\r
- && err == WSAENOTCONN)\r
- {\r
- if (!SAFE_FD_ISSET (i, &aread))\r
- {\r
- FD_SET (i, &aread);\r
- retcode++;\r
- }\r
- }\r
- }\r
- }\r
- }\r
-\r
- select_loop_end:;\r
- }\r
- while (retcode == 0 && (ms_total == INFINITE || GetTickCount () < limit));\r
-\r
- if (retcode != -1)\r
- {\r
- if (rfds)\r
- {\r
- GNUNET_NETWORK_fdset_zero (rfds);\r
- GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode);\r
- }\r
-\r
- if (wfds)\r
- {\r
- GNUNET_NETWORK_fdset_zero (wfds);\r
- GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode);\r
- }\r
-\r
- if (efds)\r
- {\r
- GNUNET_NETWORK_fdset_zero (efds);\r
- GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode);\r
- }\r
- }\r
-\r
- return retcode;\r
-#endif\r
-}\r
-\r
-/* end of io.c */\r