|
struct _repos_remote {
XML * parms;
#ifdef WINDOWS
SOCKET sock;
#else
int sock;
#endif
};
void _repos_remote_cleanup (void * _sock) {
struct _repos_remote * sock = (struct _repos_remote *) _sock;
xml_free (sock->parms);
#ifdef WINDOWS
if (sock->sock) closesocket (sock->sock);
#else
if (sock->sock) close (sock->sock);
#endif
free (sock);
}
const char * _repos_receive (struct _repos_remote * sock)
{
char *line;
int bufsize = 0;
int bufsizelen = sizeof (int);
int bytes;
/*#ifdef WINDOWS
ULONG flag = 1;
ioctlsocket (sock->sock, FIONBIO, &flag);
#else
int flags = fcntl (sock->sock, F_GETFL);
fcntl (sock->sock, F_SETFL, flags | O_NONBLOCKING);
#endif*/
getsockopt (sock->sock, SOL_SOCKET, SO_RCVBUF, (char *) &bufsize, &bufsizelen);
if (!bufsize) bufsize = 1024; /* Why doesn't the getsockopt work on Solaris? Dunno. */
line = (char *) malloc (bufsize);
xml_set (sock->parms, "buffer", "");
do {
bytes = recv (sock->sock, line, bufsize, 0);
if (bytes > 0) xml_attrncat (sock->parms, "buffer", line, bytes);
} while (!strstr (xml_attrval (sock->parms, "buffer"), "++done++"));
free (line);
return xml_attrval (sock->parms, "buffer");
}
void _repos_send (struct _repos_remote * sock)
{
send (sock->sock, xml_attrval (sock->parms, "outgoing"), strlen (xml_attrval (sock->parms, "outgoing")), 0);
}
static struct wftk_adaptor_info *
_repmgr_standard_adaptor_lookup_function (int adaptor_class,
int name_length,
const char * adaptor_descriptor);
WFTK_EXPORT XML * repos_open (XML * repository, WFTK_MODULE_LOOKUP_FN * lookup_function, const char * calling_app)
{
struct _repos_remote * sock;
const char * host = xml_attrval (repository, "host");
const char * mark;
struct hostent *server;
#ifdef WINDOWS
WSADATA wsa;
#endif
struct sockaddr_in name;
repos_log (repository, 2, 0, NULL, "repos", "opening repository (%s)", calling_app ? calling_app : "no app named");
if (*host) {
if (xml_getbin (repository)) return (repository);
#ifdef WINDOWS
WSAStartup (MAKEWORD (1, 0), &wsa);
#endif
sock = (struct _repos_remote *) malloc (sizeof (struct _repos_remote));
sock->parms = xml_create ("p");
sock->sock = 0;
xml_set (sock->parms, "mode", "sockets");
xml_set (sock->parms, "host", host);
mark = strchr (host, '!');
if (!mark) {
xml_set (sock->parms, "server", host);
xml_set (sock->parms, "port", "4239");
} else {
xml_set (sock->parms, "server", "");
xml_attrncat (sock->parms, "server", host, mark - host);
host = mark + 1;
mark = strchr (host, '!');
if (mark) {
xml_set (sock->parms, "port", "");
xml_attrncat (sock->parms, "port", host, mark - host);
xml_set (sock->parms, "repos", mark + 1);
} else {
xml_set (sock->parms, "port", "4239");
xml_set (sock->parms, "repos", host);
}
}
server = gethostbyname (xml_attrval (sock->parms, "server"));
if (!server) {
xml_setf (repository, "error-state", "Unable to resolve remote server name '%s'.", xml_attrval (sock->parms, "server"));
_repos_remote_cleanup (sock);
return repository;
}
sock->sock = socket (AF_INET, SOCK_STREAM, 0);
#ifdef WINDOWS
if (sock->sock == INVALID_SOCKET) {
#else
if (sock->sock < 0) {
#endif
xml_set (repository, "error-state", "Unable to allocate socket.");
sock->sock = 0;
_repos_remote_cleanup (sock);
return repository;
}
memset (&name, 0, sizeof (struct sockaddr_in));
name.sin_family = AF_INET;
name.sin_port = htons (xml_attrvalnum (sock->parms, "port"));
memcpy (&name.sin_addr, server->h_addr_list[0], server->h_length);
if (connect(sock->sock, (struct sockaddr *) &name, sizeof (struct sockaddr)) < 0) {
xml_setf (repository, "error-state", "Unable to connect to server '%s:%s'", xml_attrval (sock->parms, "server"), xml_attrval (sock->parms, "port"));
_repos_remote_cleanup (sock);
return repository;
}
xml_set (sock->parms, "outgoing", "\n");
_repos_send (sock);
_repos_receive (sock); /* Throw away greeting. */
if (*xml_attrval (sock->parms, "repos")) {
xml_setf (sock->parms, "outgoing", "repos %s\n", xml_attrval (sock->parms, "repos"));
_repos_send (sock);
if (*_repos_receive (sock) == '-') {
xml_setf (repository, "error-state", "Unable to open repository '%s'", xml_attrval (sock->parms, "repos"));
_repos_remote_cleanup (sock);
return repository;
}
}
xml_setbin (repository, sock, _repos_remote_cleanup);
} else {
/* Local repository, so we have to tell it about the adaptors we have statically linked. */
wftk_session_init(repository);
if (lookup_function) {
wftk_session_setlookup (repository, (WFTK_MODULE_LOOKUP_FN) lookup_function);
} else {
wftk_session_setlookup (repository, (WFTK_MODULE_LOOKUP_FN) _repmgr_standard_adaptor_lookup_function);
}
}
return repository;
}
WFTK_EXPORT XML * repos_open_file (const char * repfile, WFTK_MODULE_LOOKUP_FN * lookup_function, const char * calling_app)
{
char * buf;
char * chmark;
FILE * file;
XML * ret;
if (-1 == chdir(repfile)) {
buf = strdup (repfile);
chmark = strrchr (buf, '/');
if (!chmark) chmark = strrchr (buf, '\\');
if (chmark) {
*chmark = '\0';
if (-1 == chdir (buf)) {
free (buf);
return NULL;
}
repfile = chmark + 1;
if (!*repfile) repfile = "site.opm";
}
} else {
buf = strdup (repfile);
repfile = "site.opm"; /* TODO: um. configurable? But where? Compilation? */
}
file = fopen (repfile, "r");
if (!file) {
free (buf);
return NULL;
}
ret = xml_parse_general (file, (XMLAPI_DATARETRIEVE) fread);
fclose (file);
if (!xml_is (ret, "xml-error")) {
repos_open (ret, (WFTK_MODULE_LOOKUP_FN *)lookup_function, calling_app);
xml_set_nodup (ret, "basedir", buf);
return ret;
}
xml_free (ret);
free (buf);
return NULL;
}
WFTK_EXPORT void repos_close (XML * repository)
{
struct _repos_remote * sock = (struct _repos_remote *) xml_getbin (repository);
if (!sock) return;
_repos_remote_cleanup ((void *) sock);
xml_setbin (repository, NULL, NULL);
}
|