From 9de0a2955fc33646214162c49329b23f175174c9 Mon Sep 17 00:00:00 2001 From: Marc Chalain Date: Fri, 26 Jun 2020 14:56:22 +0200 Subject: [PATCH] first contribs with mpg123 module This contribs is just an example how to create a new output module. It's not stable. output_mpg123.c is the real module sound_alsa and sound_module manages the sound playback with alsa (a version with tinyalsa may be contributed too in the future) webclient allows to send GET request to the server and to receive the audio file data. --- Makefile.am | 2 +- configure.ac | 22 +++ contribs/Makefile.am | 22 +++ contribs/output_mpg123.c | 393 +++++++++++++++++++++++++++++++++++++++ contribs/sound_alsa.c | 123 ++++++++++++ contribs/sound_module.c | 43 +++++ contribs/sound_module.h | 40 ++++ contribs/webclient.c | 229 +++++++++++++++++++++++ contribs/webclient.h | 13 ++ 9 files changed, 886 insertions(+), 1 deletion(-) create mode 100644 contribs/Makefile.am create mode 100644 contribs/output_mpg123.c create mode 100644 contribs/sound_alsa.c create mode 100644 contribs/sound_module.c create mode 100644 contribs/sound_module.h create mode 100644 contribs/webclient.c create mode 100644 contribs/webclient.h 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