changeset 19335:2a9d669e5ff6

isolated tcp socket code from network.c to a dedicated file
author ben
date Sat, 05 Aug 2006 10:30:06 +0000
parents c95db0988ded
children 714bb551a109
files stream/Makefile stream/asf_mmst_streaming.c stream/asf_streaming.c stream/network.c stream/network.h stream/pnm.c stream/stream_ftp.c stream/stream_netstream.c stream/stream_rtsp.c stream/stream_vstream.c stream/tcp.c stream/tcp.h
diffstat 12 files changed, 331 insertions(+), 209 deletions(-) [+]
line wrap: on
line diff
--- a/stream/Makefile	Sat Aug 05 10:02:09 2006 +0000
+++ b/stream/Makefile	Sat Aug 05 10:30:06 2006 +0000
@@ -87,6 +87,7 @@
         pnm.c \
         rtp.c \
         udp.c \
+        tcp.c \
         stream_rtsp.c \
         stream_rtp.c \
         stream_udp.c \
--- a/stream/asf_mmst_streaming.c	Sat Aug 05 10:02:09 2006 +0000
+++ b/stream/asf_mmst_streaming.c	Sat Aug 05 10:30:06 2006 +0000
@@ -42,6 +42,7 @@
 #include "stream.h"
 
 #include "network.h"
+#include "tcp.h"
 
 #define BUF_SIZE 102400
 #define HDR_BUF_SIZE 8192
--- a/stream/asf_streaming.c	Sat Aug 05 10:02:09 2006 +0000
+++ b/stream/asf_streaming.c	Sat Aug 05 10:30:06 2006 +0000
@@ -23,6 +23,7 @@
 #include "libmpdemux/demuxer.h"
 
 #include "network.h"
+#include "tcp.h"
 
 #ifdef ARCH_X86
 #define	ASF_LOAD_GUID_PREFIX(guid)	(*(uint32_t *)(guid))
--- a/stream/network.c	Sat Aug 05 10:02:09 2006 +0000
+++ b/stream/network.c	Sat Aug 05 10:30:06 2006 +0000
@@ -31,6 +31,7 @@
 #include "m_config.h"
 
 #include "network.h"
+#include "tcp.h"
 #include "http.h"
 #include "cookies.h"
 #include "url.h"
@@ -51,7 +52,6 @@
 char *network_useragent=NULL;
 
 /* IPv6 options */
-int   network_prefer_ipv4 = 0;
 int   network_ipv4_only_proxy = 0;
 
 
@@ -114,212 +114,6 @@
 	free( streaming_ctrl );
 }
 
-
-// Converts an address family constant to a string
-
-const char *af2String(int af) {
-	switch (af) {
-		case AF_INET:	return "AF_INET";
-		
-#ifdef HAVE_AF_INET6
-		case AF_INET6:	return "AF_INET6";
-#endif
-		default:	return "Unknown address family!";
-	}
-}
-
-
-
-// Connect to a server using a TCP connection, with specified address family
-// return -2 for fatal error, like unable to resolve name, connection timeout...
-// return -1 is unable to connect to a particular port
-
-int
-connect2Server_with_af(char *host, int port, int af,int verb) {
-	int socket_server_fd;
-	int err;
-        socklen_t err_len;
-	int ret,count = 0;
-	fd_set set;
-	struct timeval tv;
-	union {
-		struct sockaddr_in four;
-#ifdef HAVE_AF_INET6
-		struct sockaddr_in6 six;
-#endif
-	} server_address;
-	size_t server_address_size;
-	void *our_s_addr;	// Pointer to sin_addr or sin6_addr
-	struct hostent *hp=NULL;
-	char buf[255];
-	
-#ifdef HAVE_WINSOCK2
-	u_long val;
-#endif
-	
-	socket_server_fd = socket(af, SOCK_STREAM, 0);
-	
-	
-	if( socket_server_fd==-1 ) {
-//		mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to create %s socket:\n", af2String(af));
-		return -2;
-	}
-
-	switch (af) {
-		case AF_INET:  our_s_addr = (void *) &server_address.four.sin_addr; break;
-#ifdef HAVE_AF_INET6
-		case AF_INET6: our_s_addr = (void *) &server_address.six.sin6_addr; break;
-#endif
-		default:
-			mp_msg(MSGT_NETWORK,MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af);
-			return -2;
-	}
-	
-	
-	memset(&server_address, 0, sizeof(server_address));
-	
-#ifndef HAVE_WINSOCK2
-#ifdef USE_ATON
-	if (inet_aton(host, our_s_addr)!=1)
-#else
-	if (inet_pton(af, host, our_s_addr)!=1)
-#endif
-#else
-	if ( inet_addr(host)==INADDR_NONE )
-#endif
-	{
-		if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,MSGTR_MPDEMUX_NW_ResolvingHostForAF, host, af2String(af));
-		
-#ifdef HAVE_GETHOSTBYNAME2
-		hp=(struct hostent*)gethostbyname2( host, af );
-#else
-		hp=(struct hostent*)gethostbyname( host );
-#endif
-		if( hp==NULL ) {
-			if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_CantResolv, af2String(af), host);
-			return -2;
-		}
-		
-		memcpy( our_s_addr, (void*)hp->h_addr_list[0], hp->h_length );
-	}
-#ifdef HAVE_WINSOCK2
-	else {
-		unsigned long addr = inet_addr(host);
-		memcpy( our_s_addr, (void*)&addr, sizeof(addr) );
-	}
-#endif
-	
-	switch (af) {
-		case AF_INET:
-			server_address.four.sin_family=af;
-			server_address.four.sin_port=htons(port);			
-			server_address_size = sizeof(server_address.four);
-			break;
-#ifdef HAVE_AF_INET6		
-		case AF_INET6:
-			server_address.six.sin6_family=af;
-			server_address.six.sin6_port=htons(port);
-			server_address_size = sizeof(server_address.six);
-			break;
-#endif
-		default:
-			mp_msg(MSGT_NETWORK,MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af);
-			return -2;
-	}
-
-#if defined(USE_ATON) || defined(HAVE_WINSOCK2)
-	strncpy( buf, inet_ntoa( *((struct in_addr*)our_s_addr) ), 255);
-#else
-	inet_ntop(af, our_s_addr, buf, 255);
-#endif
-	if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,MSGTR_MPDEMUX_NW_ConnectingToServer, host, buf , port );
-
-	// Turn the socket as non blocking so we can timeout on the connection
-#ifndef HAVE_WINSOCK2
-	fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) | O_NONBLOCK );
-#else
-	val = 1;
-	ioctlsocket( socket_server_fd, FIONBIO, &val );
-#endif
-	if( connect( socket_server_fd, (struct sockaddr*)&server_address, server_address_size )==-1 ) {
-#ifndef HAVE_WINSOCK2
-		if( errno!=EINPROGRESS ) {
-#else
-		if( (WSAGetLastError() != WSAEINPROGRESS) && (WSAGetLastError() != WSAEWOULDBLOCK) ) {
-#endif
-			if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_CantConnect2Server, af2String(af));
-			closesocket(socket_server_fd);
-			return -1;
-		}
-	}
-	tv.tv_sec = 0;
-	tv.tv_usec = 500000;
-	FD_ZERO( &set );
-	FD_SET( socket_server_fd, &set );
-	// When the connection will be made, we will have a writable fd
-	while((ret = select(socket_server_fd+1, NULL, &set, NULL, &tv)) == 0) {
-	      if( ret<0 ) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_SelectFailed);
-	      else if(ret > 0) break;
-	      else if(count > 30 || mp_input_check_interrupt(500)) {
-		if(count > 30)
-		  mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ConnTimeout);
-		else
-		  mp_msg(MSGT_NETWORK,MSGL_V,"Connection interuppted by user\n");
-		return -3;
-	      }
-	      count++;
-	      FD_ZERO( &set );
-	      FD_SET( socket_server_fd, &set );
-	      tv.tv_sec = 0;
-	      tv.tv_usec = 500000;
-	}
-
-	// Turn back the socket as blocking
-#ifndef HAVE_WINSOCK2
-	fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) & ~O_NONBLOCK );
-#else
-	val = 0;
-	ioctlsocket( socket_server_fd, FIONBIO, &val );
-#endif
-	// Check if there were any error
-	err_len = sizeof(int);
-	ret =  getsockopt(socket_server_fd,SOL_SOCKET,SO_ERROR,&err,&err_len);
-	if(ret < 0) {
-		mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_GetSockOptFailed,strerror(errno));
-		return -2;
-	}
-	if(err > 0) {
-		mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ConnectError,strerror(err));
-		return -1;
-	}
-	
-	return socket_server_fd;
-}
-
-// Connect to a server using a TCP connection
-// return -2 for fatal error, like unable to resolve name, connection timeout...
-// return -1 is unable to connect to a particular port
-
-
-int
-connect2Server(char *host, int  port, int verb) {
-#ifdef HAVE_AF_INET6
-	int r;
-	int s = -2;
-
-	r = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET:AF_INET6,verb);	
-	if (r > -1) return r;
-
-	s = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET6:AF_INET,verb);
-	if (s == -2) return r;
-	return s;
-#else	
-	return connect2Server_with_af(host, port, AF_INET,verb);
-#endif
-
-	
-}
-
 URL_t*
 check4proxies( URL_t *url ) {
 	URL_t *url_out = NULL;
--- a/stream/network.h	Sat Aug 05 10:02:09 2006 +0000
+++ b/stream/network.h	Sat Aug 05 10:30:06 2006 +0000
@@ -57,8 +57,6 @@
 int nop_streaming_seek( int fd, off_t pos, streaming_ctrl_t *stream_ctrl );
 void streaming_ctrl_free( streaming_ctrl_t *streaming_ctrl );
 
-int connect2Server(char *host, int port,int verb);
-
 int http_send_request(URL_t *url, off_t pos);
 HTTP_header_t *http_read_response(int fd);
 
--- a/stream/pnm.c	Sat Aug 05 10:02:09 2006 +0000
+++ b/stream/pnm.c	Sat Aug 05 10:30:06 2006 +0000
@@ -50,6 +50,7 @@
 #include "osdep/timer.h"
 
 #include "pnm.h"
+#include "tcp.h"
 //#include "libreal/rmff.h"
 
 extern int network_bandwidth;
--- a/stream/stream_ftp.c	Sat Aug 05 10:02:09 2006 +0000
+++ b/stream/stream_ftp.c	Sat Aug 05 10:30:06 2006 +0000
@@ -21,6 +21,7 @@
 #include "help_mp.h"
 #include "m_option.h"
 #include "m_struct.h"
+#include "tcp.h"
 
 static struct stream_priv_s {
   char* user;
--- a/stream/stream_netstream.c	Sat Aug 05 10:02:09 2006 +0000
+++ b/stream/stream_netstream.c	Sat Aug 05 10:30:06 2006 +0000
@@ -63,6 +63,7 @@
 #include "bswap.h"
 
 #include "netstream.h"
+#include "tcp.h"
 
 static struct stream_priv_s {
   char* host;
--- a/stream/stream_rtsp.c	Sat Aug 05 10:02:09 2006 +0000
+++ b/stream/stream_rtsp.c	Sat Aug 05 10:30:06 2006 +0000
@@ -37,6 +37,7 @@
 #include <errno.h>
 
 #include "stream.h"
+#include "tcp.h"
 #include "librtsp/rtsp.h"
 #include "librtsp/rtsp_session.h"
 
--- a/stream/stream_vstream.c	Sat Aug 05 10:02:09 2006 +0000
+++ b/stream/stream_vstream.c	Sat Aug 05 10:30:06 2006 +0000
@@ -51,6 +51,7 @@
 #include "help_mp.h"
 #include "m_option.h"
 #include "m_struct.h"
+#include "tcp.h"
 
 #include <vstream-client.h>
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stream/tcp.c	Sat Aug 05 10:30:06 2006 +0000
@@ -0,0 +1,290 @@
+/*
+ *  Copyright (C) 2001 Bertrand BAUDET, 2006 Benjamin Zores
+ *   Network helpers for TCP connections
+ *   (originally borrowed from network.c,
+ *      by Bertrand BAUDET <bertrand_baudet@yahoo.com>).
+ *
+ *   This program 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.
+ *
+ *   This program 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 this program; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifndef HAVE_WINSOCK2
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#define closesocket close
+#else
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#include "mp_msg.h"
+#include "help_mp.h"
+#include "tcp.h"
+
+/* IPv6 options */
+int network_prefer_ipv4 = 0;
+
+/* Converts an address family constant to a string */
+static const char *
+af2String (int af)
+{
+  switch (af)
+  {
+  case AF_INET:
+    return "AF_INET";
+#ifdef HAVE_AF_INET6
+  case AF_INET6:
+    return "AF_INET6";
+#endif
+  default:
+    return "Unknown address family!";
+  }
+}
+
+static int
+connect2Server_with_af (char *host, int port, int af ,int verb)
+{
+  int socket_server_fd;
+  int err;
+  socklen_t err_len;
+  int ret, count = 0;
+  fd_set set;
+  struct timeval tv;
+
+  union {
+    struct sockaddr_in four;
+#ifdef HAVE_AF_INET6
+    struct sockaddr_in6 six;
+#endif
+  } server_address;
+
+  size_t server_address_size;
+  void *our_s_addr; /* Pointer to sin_addr or sin6_addr */
+  struct hostent *hp = NULL;
+  char buf[255];
+	
+#ifdef HAVE_WINSOCK2
+  u_long val;
+#endif
+	
+  socket_server_fd = socket (af, SOCK_STREAM, 0);
+  if (socket_server_fd == -1)
+    return TCP_ERROR_FATAL;
+
+  switch (af)
+  {
+  case AF_INET:
+    our_s_addr = (void *) &server_address.four.sin_addr;
+    break;
+#ifdef HAVE_AF_INET6
+  case AF_INET6:
+    our_s_addr = (void *) &server_address.six.sin6_addr;
+    break;
+#endif
+  default:
+    mp_msg (MSGT_NETWORK, MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af);
+    return TCP_ERROR_FATAL;
+  }
+	
+  memset (&server_address, 0, sizeof (server_address));
+	
+#ifndef HAVE_WINSOCK2
+#ifdef USE_ATON
+  if (inet_aton (host, our_s_addr) !=1)
+#else
+  if (inet_pton (af, host, our_s_addr) !=1)
+#endif /* USE_ATON */
+#else
+  if (inet_addr (host) == INADDR_NONE)
+#endif /* HAVE_WINSOCK2 */
+  {
+    if (verb)
+      mp_msg (MSGT_NETWORK, MSGL_STATUS,
+              MSGTR_MPDEMUX_NW_ResolvingHostForAF, host, af2String (af));
+		
+#ifdef HAVE_GETHOSTBYNAME2
+    hp = (struct hostent *) gethostbyname2 (host, af);
+#else
+    hp = (struct hostent *) gethostbyname (host);
+#endif /* HAVE_GETHOSTBYNAME2 */
+
+    if (!hp)
+    {
+      if (verb)
+        mp_msg (MSGT_NETWORK, MSGL_ERR,
+                MSGTR_MPDEMUX_NW_CantResolv, af2String (af), host);
+      return TCP_ERROR_FATAL;
+    }
+		
+    memcpy (our_s_addr, (void *) hp->h_addr_list[0], hp->h_length);
+  }
+#ifdef HAVE_WINSOCK2
+  else
+  {
+    unsigned long addr = inet_addr (host);
+    memcpy (our_s_addr, (void *) &addr, sizeof (addr));
+  }
+#endif /* HAVE_WINSOCK2 */
+	
+  switch (af)
+  {
+  case AF_INET:
+    server_address.four.sin_family = af;
+    server_address.four.sin_port = htons (port);			
+    server_address_size = sizeof (server_address.four);
+    break;
+#ifdef HAVE_AF_INET6		
+  case AF_INET6:
+    server_address.six.sin6_family = af;
+    server_address.six.sin6_port = htons (port);
+    server_address_size = sizeof (server_address.six);
+    break;
+#endif /* HAVE_AF_INET6 */
+  default:
+    mp_msg (MSGT_NETWORK, MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af);
+    return TCP_ERROR_FATAL;
+  }
+
+#if defined(USE_ATON) || defined(HAVE_WINSOCK2)
+  strncpy (buf, inet_ntoa (*((struct in_addr *) our_s_addr)), 255);
+#else
+  inet_ntop (af, our_s_addr, buf, 255);
+#endif /* USE_ATON || HAVE_WINSOCK2 */
+  
+  if (verb)
+    mp_msg (MSGT_NETWORK, MSGL_STATUS,
+            MSGTR_MPDEMUX_NW_ConnectingToServer, host, buf, port);
+
+  /* Turn the socket as non blocking so we can timeout on the connection */
+#ifndef HAVE_WINSOCK2
+  fcntl (socket_server_fd, F_SETFL,
+         fcntl (socket_server_fd, F_GETFL) | O_NONBLOCK);
+#else
+  val = 1;
+  ioctlsocket (socket_server_fd, FIONBIO, &val);
+#endif /* HAVE_WINSOCK2 */
+  
+  if (connect (socket_server_fd, (struct sockaddr *) &server_address,
+               server_address_size) == -1)
+  {
+#ifndef HAVE_WINSOCK2
+    if (errno != EINPROGRESS)
+#else
+    if ((WSAGetLastError () != WSAEINPROGRESS)
+        && (WSAGetLastError () != WSAEWOULDBLOCK))
+#endif /* HAVE_WINSOCK2 */
+    {
+      if (verb)
+        mp_msg (MSGT_NETWORK, MSGL_ERR,
+                MSGTR_MPDEMUX_NW_CantConnect2Server, af2String (af));
+
+      closesocket (socket_server_fd);
+      return TCP_ERROR_PORT;
+    }
+  }
+
+  tv.tv_sec = 0;
+  tv.tv_usec = 500000;
+
+  FD_ZERO (&set);
+  FD_SET (socket_server_fd, &set);
+
+  /* When the connection will be made, we will have a writable fd */
+  while ((ret = select (socket_server_fd + 1, NULL, &set, NULL, &tv)) == 0)
+  {
+    if (ret < 0)
+      mp_msg (MSGT_NETWORK, MSGL_ERR, MSGTR_MPDEMUX_NW_SelectFailed);
+    else if (ret > 0)
+      break;
+    else if (count > 30 || mp_input_check_interrupt (500))
+    {
+      if (count > 30)
+        mp_msg (MSGT_NETWORK, MSGL_ERR, MSGTR_MPDEMUX_NW_ConnTimeout);
+      else
+        mp_msg (MSGT_NETWORK, MSGL_V, "Connection interuppted by user\n");
+      return TCP_ERROR_TIMEOUT;
+    }
+
+    count++;
+    FD_ZERO (&set);
+    FD_SET (socket_server_fd, &set);
+    tv.tv_sec = 0;
+    tv.tv_usec = 500000;
+  }
+
+  /* Turn back the socket as blocking */
+#ifndef HAVE_WINSOCK2
+  fcntl (socket_server_fd, F_SETFL,
+         fcntl (socket_server_fd, F_GETFL) & ~O_NONBLOCK);
+#else
+  val = 0;
+  ioctlsocket (socket_server_fd, FIONBIO, &val);
+#endif /* HAVE_WINSOCK2 */
+  
+  /* Check if there were any error */
+  err_len = sizeof (int);
+  ret = getsockopt (socket_server_fd, SOL_SOCKET, SO_ERROR, &err, &err_len);
+  if (ret < 0)
+  {
+    mp_msg (MSGT_NETWORK, MSGL_ERR,
+            MSGTR_MPDEMUX_NW_GetSockOptFailed, strerror (errno));
+    return TCP_ERROR_FATAL;
+  }
+
+  if (err > 0)
+  {
+    mp_msg (MSGT_NETWORK, MSGL_ERR,
+            MSGTR_MPDEMUX_NW_ConnectError, strerror (err));
+    return TCP_ERROR_PORT;
+  }
+	
+  return socket_server_fd;
+}
+
+int
+connect2Server (char *host, int port, int verb)
+{
+#ifdef HAVE_AF_INET6
+  int r;
+  int s = TCP_ERROR_FATAL;
+
+  r = connect2Server_with_af (host, port,
+                              network_prefer_ipv4 ? AF_INET:AF_INET6, verb);
+  if (r > TCP_ERROR_PORT)
+    return r;
+
+  s = connect2Server_with_af (host, port,
+                              network_prefer_ipv4 ? AF_INET6:AF_INET, verb);
+  if (s == TCP_ERROR_FATAL)
+    return r;
+
+  return s;
+#else	
+  return connect2Server_with_af (host, port, AF_INET,verb);
+#endif /* HAVE_AF_INET6 */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stream/tcp.h	Sat Aug 05 10:30:06 2006 +0000
@@ -0,0 +1,32 @@
+/*
+ *  Copyright (C) 2001 Bertrand BAUDET, 2006 Benjamin Zores
+ *   Network helpers for TCP connections
+ *   (originally borrowed from network.c,
+ *      by Bertrand BAUDET <bertrand_baudet@yahoo.com>).
+ *
+ *   This program 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.
+ *
+ *   This program 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 this program; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _TCP_H_
+#define _TCP_H_
+
+/* Connect to a server using a TCP connection */
+int connect2Server (char *host, int port, int verb);
+
+#define TCP_ERROR_TIMEOUT -3     /* connection timeout */
+#define TCP_ERROR_FATAL   -2     /* unable to resolve name */
+#define TCP_ERROR_PORT    -1     /* unable to connect to a particular port */
+
+#endif /* _TCP_H_ */