diff --git a/Makefile.am b/Makefile.am index 6b0f44c..29c9428 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = src data +SUBDIRS = src data contribs EXTRA_DIST = autogen.sh diff --git a/configure.ac b/configure.ac index fa5c848..bb7c106 100644 --- a/configure.ac +++ b/configure.ac @@ -111,6 +111,27 @@ if test x$HAVE_LIBUPNP = xyes; then fi AC_SUBST(HAVE_LIBUPNP) +PKG_CHECK_MODULES(ALSA, alsa, HAVE_ALSA=yes, HAVE_ALSA=no) +if test x$HAVE_ALSA = xyes; then + AC_DEFINE(HAVE_ALSA, , [Use Alsa]) +fi +AC_SUBST(HAVE_ALSA) +AM_CONDITIONAL(HAVE_ALSA, test x$HAVE_ALSA = xyes) + +AC_ARG_WITH( mpg123, + AC_HELP_STRING([--without-mpg123],[compile without MPG123 support]), + try_mpg123=$withval, try_mpg123=yes ) +HAVE_MPG123=no +if test x$try_gstreamer = xyes; then + dnl check for GStreamer + PKG_CHECK_MODULES(MPG123, libmpg123, HAVE_MPG123=yes, HAVE_MPG123=no) +fi +if test x$HAVE_MPG123 = xyes; then + AC_DEFINE(HAVE_MPG123, , [Use mpg123]) +fi +AC_SUBST(HAVE_MPG123) +AM_CONDITIONAL(HAVE_MPG123, test x$HAVE_MPG123 = xyes) + # Checks for header files. AC_HEADER_STDC @@ -123,6 +144,7 @@ fi AC_CONFIG_FILES([Makefile src/Makefile + contribs/Makefile data/Makefile]) AC_OUTPUT diff --git a/contribs/Makefile.am b/contribs/Makefile.am new file mode 100644 index 0000000..da89bb1 --- /dev/null +++ b/contribs/Makefile.am @@ -0,0 +1,22 @@ +if HAVE_MPG123 +pkglib_LTLIBRARIES = gmrender_mpg123.la +endif + +gmrender_mpg123_la_SOURCES = \ + sound_module.c sound_module.h \ + sound_alsa.c \ + webclient.c \ + output_mpg123.c + +GMRENDER_MPG123_VERSION=0.0.1 + +MOD_MAJOR_VERSION=$(word 1,$(subst ., ,$(GMRENDER_MPG123_VERSION))) +MOD_MINOR_VERSION=$(word 2,$(subst ., ,$(GMRENDER_MPG123_VERSION))) +MOD_MICRO_VERSION=$(word 3,$(subst ., ,$(GMRENDER_MPG123_VERSION))) + +gmrender_mpg123_la_CFLAGS = $(GLIB_CFLAGS) $(ALSA_CFLAGS) -I ../src +gmrender_mpg123_la_CFLAGS += -DMOD_MAJOR_VERSION=$(MOD_MAJOR_VERSION) +gmrender_mpg123_la_CFLAGS += -DMOD_MINOR_VERSION=$(MOD_MINOR_VERSION) +gmrender_mpg123_la_CFLAGS += -DMOD_MICRO_VERSION=$(MOD_MICRO_VERSION) +gmrender_mpg123_la_LIBADD = $(GLIB_LIBS) $(ALSA_LIBS) -lmpg123 +gmrender_mpg123_la_LDFLAGS = -module -release $(GMRENDER_MPG123_VERSION) diff --git a/contribs/output_mpg123.c b/contribs/output_mpg123.c new file mode 100644 index 0000000..8aa5f21 --- /dev/null +++ b/contribs/output_mpg123.c @@ -0,0 +1,393 @@ +/* output_mpg123.c - Output module for mpg123 + * + * Copyright (C) 2014-2019 Mar Chalain + * + * This file is part of GMediaRender. + * + * GMediaRender 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 of the License, or + * (at your option) any later version. + * + * GMediaRender 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 Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GMediaRender; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "output_module.h" +#include "sound_module.h" + +#include "logging.h" +#include "upnp_connmgr.h" + +#include "webclient.h" + +enum e_state +{ + STOPPED, + PLAYING, + PAUSING, + HALTED, +}; +enum e_state g_state = STOPPED; + +typedef struct st_output_mpg123_uri output_mpg123_uri_t; +struct st_output_mpg123_uri +{ + char *uri; + enum e_state state; + size_t position; + struct http_info info; + output_mpg123_uri_t *next; +}; + + +static output_mpg123_uri_t *g_first_uri; +static output_mpg123_uri_t *g_current_uri; +static output_transition_cb_t g_callback; + +static mpg123_pars *g_mpg123_pars; +static mpg123_handle *g_mpg123_handle = NULL; + +static pthread_mutex_t g_mutex_control; +static pthread_cond_t g_cond_control; + +static const char *g_cmd_mime = "audio/mpeg"; +static const struct sound_module *g_sound_api; + +static int +output_mpg123_init(void) +{ + int ret = -1; + + if (g_cmd_mime) + { + const char *mime = g_cmd_mime; + const char *nextmime = mime; + for (;*mime; mime++) + { + if (*mime == ',') + { + *(char *)mime = '\0'; + register_mime_type(nextmime); + nextmime = mime + 1; + } + } + register_mime_type(nextmime); + } + pthread_mutex_init(&g_mutex_control, NULL); + pthread_cond_init(&g_cond_control, NULL); + + ret = mpg123_init(); + g_mpg123_pars = mpg123_new_pars(&ret); + const char **decoderslist = mpg123_decoders(); + g_mpg123_handle = mpg123_new(decoderslist[0], &ret); + + if (!ret) + { + g_sound_api = sound_module_get(); + if (g_sound_api == NULL) + { + Log_error("mpg123", "sound module not found"); + ret = -1; + } + } + return ret; +} + +static void +output_mpg123_set_uri(const char *uri, + output_update_meta_cb_t meta_cb) +{ + struct st_output_mpg123_uri *entry = malloc(sizeof(*entry)); + memset(entry, 0 ,sizeof(*entry)); + entry->uri = strdup(uri); + if (g_state == PLAYING && g_current_uri != NULL) + { + g_current_uri->next = entry; + } + else + { + entry->next = g_first_uri; + g_first_uri = entry; + } +}; + +static void +output_mpg123_set_next_uri(const char *uri) +{ + struct st_output_mpg123_uri *entry = malloc(sizeof(*entry)); + memset(entry, 0 ,sizeof(*entry)); + entry->uri = strdup(uri); + if (g_first_uri == NULL) + { + g_first_uri = entry; + } + else + { + struct st_output_mpg123_uri *it = g_first_uri; + while (it->next != NULL) it = it->next; + it->next = entry; + } +} + +static int +output_mpg123_openstream(int fdin, int *channels, int *encoding, long *rate, long *buffsize) +{ + if(mpg123_open_fd(g_mpg123_handle, fdin) != MPG123_OK) + { + return -1; + } + + if (mpg123_getformat(g_mpg123_handle, rate, channels, encoding) != MPG123_OK) + { + return -1; + } + mpg123_format_none(g_mpg123_handle); + mpg123_format(g_mpg123_handle, *rate, *channels, *encoding); + + *buffsize = mpg123_outblock(g_mpg123_handle); + return 0; +} + +static void* +thread_play(void *arg) +{ + while (g_state != HALTED) + { + pthread_mutex_lock(&g_mutex_control); + while (g_state == STOPPED) + { + pthread_cond_wait(&g_cond_control, &g_mutex_control); + } + pthread_mutex_unlock(&g_mutex_control); + if (g_current_uri == NULL || g_current_uri->uri == NULL) + continue; + + int fdin = http_get(g_current_uri->uri, &g_current_uri->info); + if (fdin < 0) + break; + + int channels = 0, encoding = 0; + long rate = 0, buffsize = 0; + if (output_mpg123_openstream(fdin, &channels, &encoding, &rate, &buffsize)) + { + break; + } + unsigned char *buffer; + buffer = malloc(buffsize); + + g_sound_api->open(channels, encoding, rate); + + int err = MPG123_OK; + do + { + pthread_mutex_lock(&g_mutex_control); + while (g_state == PAUSING) + { + pthread_cond_wait(&g_cond_control, &g_mutex_control); + } + /** + * stop is requested from the controler + **/ + if (g_state == STOPPED) + { + g_current_uri->position = 0; + pthread_mutex_unlock(&g_mutex_control); + break; + } + pthread_mutex_unlock(&g_mutex_control); + size_t done = 0; + err = mpg123_read( g_mpg123_handle, buffer, buffsize, &done ); + g_current_uri->position += done; + if (err == MPG123_OK) + { + err = (g_sound_api->write(buffer, buffsize) >= 0)? MPG123_OK : MPG123_ERR; + } + } while (err == MPG123_OK); + mpg123_close(g_mpg123_handle); + g_sound_api->close(); + + struct st_output_mpg123_uri *it = g_first_uri; + if (it == g_current_uri) + { + g_first_uri = g_first_uri->next; + } + else + { + while (it->next != g_current_uri) it = it->next; + it->next = it->next->next; + } + + g_current_uri->position = g_current_uri->info.length; + /** + * prepare the next stream + **/ + struct st_output_mpg123_uri *entry = g_current_uri->next; + free(g_current_uri->uri); + free(g_current_uri); + if (!entry) + { + (*g_callback)(PLAY_STOPPED); + g_current_uri = NULL; + } + else + { + g_current_uri = entry; + g_current_uri->position = 0; + (*g_callback)(PLAY_STARTED_NEXT_STREAM); + } + } + return NULL; +} + +/** +static int +output_mpg123_loop() +{ + thread_play(NULL); + return 0; +} +**/ + +static int +output_mpg123_play(output_transition_cb_t callback) +{ + g_callback = callback; + g_state = PLAYING; + if (!g_current_uri) + { + struct st_output_mpg123_uri *entry = g_first_uri; + if (entry) + { + g_current_uri = entry; + g_current_uri->position = 0; + + pthread_t thread; + pthread_create(&thread, NULL, thread_play, NULL); + } + } + pthread_cond_signal(&g_cond_control); + return 0; +} + +static int +output_mpg123_stop(void) +{ + g_state = STOPPED; + pthread_cond_signal(&g_cond_control); + return 0; +} + +static int +output_mpg123_pause(void) +{ + g_state = PAUSING; + pthread_cond_signal(&g_cond_control); + return 0; +} + +static int +output_mpg123_seek(int64_t position_nanos) +{ + return 0; +} + +static int +output_mpg123_get_position(int64_t *track_duration, + int64_t *track_pos) +{ + if (g_current_uri == NULL) + { + *track_duration = 0; + *track_pos = 0; + } + else + { + *track_duration = g_current_uri->info.length; + *track_pos = g_current_uri->position; + } + return 0; +} + +static int +output_mpg123_getvolume(float *value) +{ + if (g_sound_api->get_volume) + return g_sound_api->get_volume(value); + return 0; +} +static int +output_mpg123_setvolume(float value) +{ + if (g_sound_api->set_volume) + return g_sound_api->set_volume(value); + return 0; +} +static int +output_mpg123_getmute(int *value) +{ + if (g_sound_api->get_mute) + return g_sound_api->get_mute(value); + return 0; +} +static int +output_mpg123_setmute(int value) +{ + if (g_sound_api->set_mute) + return g_sound_api->set_mute(value); + return 0; +} + + +struct output_module mpg123_output = { + .shortname = "mpg123", + .description = "daemon framework", + .init = output_mpg123_init, + .set_uri = output_mpg123_set_uri, + .set_next_uri= output_mpg123_set_next_uri, + .play = output_mpg123_play, + .stop = output_mpg123_stop, + .pause = output_mpg123_pause, + .seek = output_mpg123_seek, + .get_position = output_mpg123_get_position, + .get_volume = output_mpg123_getvolume, + .set_volume = output_mpg123_setvolume, + .get_mute = output_mpg123_getmute, + .set_mute = output_mpg123_setmute, +}; + +void output_mpg123_initlib(void) __attribute__((constructor)); + +void output_mpg123_initlib(void) +{ + output_append_module(&mpg123_output); +} diff --git a/contribs/sound_alsa.c b/contribs/sound_alsa.c new file mode 100644 index 0000000..88630e0 --- /dev/null +++ b/contribs/sound_alsa.c @@ -0,0 +1,123 @@ +/* output_alsa.c - Sound module for alsa + * + * Copyright (C) 2014-2019 Mar Chalain + * + * This file is part of GMediaRender. + * + * GMediaRender 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 of the License, or + * (at your option) any later version. + * + * GMediaRender 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 Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GMediaRender; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "logging.h" +#include "sound_module.h" + +struct sound_alsa_global_s +{ + const char *cmd_card; + snd_pcm_t *pcm; + int samplesize; + struct fifo_s *fifo; +}; +struct sound_alsa_global_s g = { + .cmd_card = "default", + .pcm = NULL, + .fifo = NULL +}; + +static int +sound_alsa_open(int channels, int encoding, unsigned int rate) +{ + int ret; + + ret = snd_pcm_open(&g.pcm, g.cmd_card, SND_PCM_STREAM_PLAYBACK, 0); + + if (ret == -1 || g.pcm == NULL) + return -1; + + snd_pcm_hw_params_t *hw_params; + ret = snd_pcm_hw_params_malloc(&hw_params); + ret = snd_pcm_hw_params_any(g.pcm, hw_params); + ret = snd_pcm_hw_params_set_access(g.pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); + snd_pcm_format_t pcm_format; + switch (encoding) + { + case MPG123_ENC_SIGNED_32: + pcm_format = SND_PCM_FORMAT_S32_LE; + g.samplesize = 4 * 2; + break; + case MPG123_ENC_SIGNED_16: + default: + pcm_format = SND_PCM_FORMAT_S16_LE; + g.samplesize = 2 * 2; + break; + } + ret = snd_pcm_hw_params_set_format(g.pcm, hw_params, pcm_format); + ret = snd_pcm_hw_params_set_rate_near(g.pcm, hw_params, &rate, NULL); + ret = snd_pcm_hw_params_set_channels(g.pcm, hw_params, channels); + + ret = snd_pcm_hw_params(g.pcm, hw_params); + ret = snd_pcm_prepare(g.pcm); + + return 0; +} + +static ssize_t +sound_alsa_write(unsigned char *buffer, ssize_t size) +{ + snd_pcm_sframes_t ret; + ret = snd_pcm_writei(g.pcm, buffer, size / g.samplesize); + if (ret == -EPIPE) + ret = snd_pcm_recover(g.pcm, ret, 0); + return ret * g.samplesize; +} + +static int +sound_alsa_close(void) +{ + return snd_pcm_close(g.pcm); +} + +struct sound_module const *g_sound_alsa = &(struct sound_module) +{ + .name = "alsa", + .open = sound_alsa_open, + .write = sound_alsa_write, + .close = sound_alsa_close, + .get_volume = NULL, + .set_volume = NULL, + .get_mute = NULL, + .set_mute = NULL, +}; diff --git a/contribs/sound_module.c b/contribs/sound_module.c new file mode 100644 index 0000000..fa3b5d3 --- /dev/null +++ b/contribs/sound_module.c @@ -0,0 +1,43 @@ +/* output_module.c - Sound module frontend + * + * Copyright (C) 2014 - 2019 Marc Chalain + * + * This file is part of GMediaRender. + * + * uplaymusic 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 of the License, or + * (at your option) any later version. + * + * uplaymusic 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 Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GMediaRender; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define _GNU_SOURCE +#include +#include +#include + +#include "sound_module.h" + +#ifdef HAVE_ALSA +extern const struct sound_module *g_sound_alsa; +#endif + +const struct sound_module *sound_module_get(void) +{ +#ifdef HAVE_ALSA + return g_sound_alsa; +#endif +} diff --git a/contribs/sound_module.h b/contribs/sound_module.h new file mode 100644 index 0000000..1708318 --- /dev/null +++ b/contribs/sound_module.h @@ -0,0 +1,40 @@ +/* sound_module.h - Audio sink module + * + * Copyright (C) 2014-2019 Marc Chalain + * + * This file is part of GMediaRender. + * + * GMediaRender 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 of the License, or + * (at your option) any later version. + * + * GMediaRender 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 Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GMediaRender; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifndef _SOUND_MODULE_H +#define _SOUND_MODULE_H +struct sound_module +{ + const char *name; + int (*open)(int channels, int encoding, unsigned int rate); + ssize_t (*write)(unsigned char *buffer, ssize_t size); + int (*close)(void); + int (*get_volume)(float *); + int (*set_volume)(float); + int (*get_mute)(int *); + int (*set_mute)(int); +}; + +const struct sound_module *sound_module_get(void); + +#endif diff --git a/contribs/webclient.c b/contribs/webclient.c new file mode 100644 index 0000000..7c6ccab --- /dev/null +++ b/contribs/webclient.c @@ -0,0 +1,229 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "webclient.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "logging.h" + +static int http_get_transaction(int fd, struct http_info *info) +{ + int ret = -1; + int len; + + /** + * generate the request + **/ + char *wbuff; + wbuff = malloc(1024 + 1); + len = 0; + const char *method = "GET"; + const char *page = "/index.html"; + if (info->method != NULL) + method = info->method; + if (info->uri != NULL) + page = info->uri; + sprintf(wbuff+len, "%s %s HTTP/1.0\r\n", method, page); + len += strlen(page) + 15; +/* + * sprintf(wbuff+len, "User-Agent: mpg123/1.12.1\r\n"); + len += 27; + sprintf(wbuff+len, "Host: 10.1.2.9:49152\r\n"); + len += 22; + sprintf(wbuff+len, "Accept: audio/mpeg, audio/x-mpeg, audio/mp3, audio/x-mp3, audio/mpeg3, audio/x-mpeg3, audio/mpg, audio/x-mpg, audio/x-mpegaudio, audio/mpegurl, audio/mpeg-url, audio/x-mpegurl, audio/x-scpls, audio/scpls, application/pls\r\n"); + len += 227; +*/ + sprintf(wbuff+len, "\r\n"); + len += 2; + + /** + * send the request + **/ + ret = write(fd, wbuff, len); + free(wbuff); + + /** + * look for bytes available on the connection + **/ + //int ret; + fd_set rfds; + int maxfd; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + maxfd = fd +1; + + do + { + ret = select(maxfd, &rfds, NULL, NULL, NULL); + } while (ret <= 0 || !FD_ISSET(fd, &rfds)); + + /** + * allocate buffer with enought space for the header + **/ + char rbuff[1024]; + char *it = rbuff; + memset(rbuff, 0, sizeof(rbuff)); + while (ret > 0) + { + char tbuff[1]; + len = 1; + + ret = recv(fd, tbuff, len, 0); + *it = tbuff[0]; + if (ret < 0) + { + //LOG_ERROR("read from socket error %d %s", ret, strerror(errno)); + return -1; + } + if (strstr(rbuff, "\r\n\r\n")) + { + Log_info("webclient", "header:\n%s", rbuff); + break; + } + it += ret; + if (it == rbuff + sizeof(rbuff)) + { + while (*it != '\n') it--; + int len = rbuff + sizeof(rbuff) - it; + memcpy(rbuff, it, len); + it = rbuff + len; + } + } + /** + * parse the header + **/ + char *value; + if ((value = strstr(rbuff, "Content-Length: "))) + { + sscanf(value,"Content-Length: %u[^\r]", &info->length); + } + if ((value = strstr(rbuff, "Content-Type: "))) + { + sscanf(value,"Content-Type: %99[^\r]", info->mime); + } + + return ret; +} + +int +http_get(char *uri, struct http_info *info) +{ + int fd = -1; + int port = 0; + char proto[10]; + char ip[100]; + char page[200]; + int err = -1; + + memset(proto, 0, 10); + memset(ip, 0, 100); + memset(page, 0, 100); + port = 80; + + page[0]='/'; + if (sscanf(uri, "%9[^:]://%99[^:]:%i/%198[^\n]", proto, ip, &port, page+1) == 4) { err = 0;} + else if (sscanf(uri, "%9[^:]://%99[^/]/%198[^\n]", proto, ip, page+1) == 3) { err = 0;} + else if (sscanf(uri, "%9[^:]://%99[^:]:%i[^\n]", proto, ip, &port) == 3) { err = 0;} + else if (sscanf(uri, "%9[^:]://%99[^\n]", proto, ip) == 2) { err = 0;} + + if (!err) + { +#ifndef IPV6 + struct sockaddr_in server; + + if((server.sin_addr.s_addr = inet_addr(ip)) == INADDR_NONE) + return -1; + + server.sin_port = htons(port); + server.sin_family = AF_INET; + + if((fd = socket(PF_INET, SOCK_STREAM, 6)) < 0) + { + return -1; + } + if(connect(fd, (struct sockaddr *)&server, sizeof(server))) + return -1; +#else + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ + hints.ai_flags = 0; + hints.ai_protocol = 0; /* Any protocol */ + if (strncmp(proto,"http",4)) + { + LOG_ERROR("bad protocol type %s", proto); + return -1; + } + struct addrinfo *result, *rp; + char aport[6]; + sprintf(aport,"%u",port); + + err = getaddrinfo(ip, aport, &hints, &result); + if (err) + return err; + + for (rp = result; rp != NULL; rp = rp->ai_next) + { + int yes = 0; + + fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (fd == -1) + continue; + else if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) + { + close(fd); + fd = -errno; + continue; + } + + if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) + break; /* Success */ + + close(fd); + } + freeaddrinfo(result); + if (rp == NULL) + return -1; +#endif + + info->uri = uri; + http_get_transaction(fd, info); + + } + return fd; +} + +#ifdef HTTP_GET_MAIN +int main(int argc, char **argv) +{ + if (argc > 1); + { + struct http_info info; + int fd; + fd = http_get(argv[1], &info); + printf("content length = %u\n",info.length); + printf("content type = %s\n",info.mime); + if (fd > 0) + close(fd); + } + return 0; +} +#endif diff --git a/contribs/webclient.h b/contribs/webclient.h new file mode 100644 index 0000000..3830c7c --- /dev/null +++ b/contribs/webclient.h @@ -0,0 +1,13 @@ +#ifndef __NETWORK_HTTP_GET_H__ +#define __NETWORK_HTTP_GET_H__ +struct http_info +{ + const char *method; + const char *uri; + unsigned int length; + char mime[100]; +}; + +extern int http_get(char *uri, struct http_info *info); + +#endif