📄 relay.c
字号:
/* camserv - An internet streaming picture application * * Copyright (C) 1999-2002 Jon Travis (jtravis@p00p.org) * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include "camserv_config.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <signal.h>#include "databuf.h"#include "socket.h"#include "sockset.h"#include "manager.h"#include "sock_field.h"#include "log.h"#define MODNAME "relay"#define BACKLOG 20extern int errno;#define CLIENT_T_UNK 0#define CLIENT_T_CAMSERV 1#define CLIENT_T_BROWSER 2#define CLIENT_T_PROXY 3#define CLIENT_T_SINGLE 4#define CAMSTATE_SEND_PROXY 1 /* Sending proxy notifier */#define CAMSTATE_RECV_SIZE 2 /* Receiving the size of the picture */#define CAMSTATE_RECV_PICTURE 3 /* Receiving the actual picture */#define BROWSERSTATE_SEND_PREAMBLE 0 /* Sending the preamble */#define BROWSERSTATE_SEND_PICTURE 1 /* Sending the picture */#define BROWSERSTATE_SEND_SEPERATOR 2 /* Sending the seperator */#define PROXYCLSTATE_SEND_PICSIZE 0 /* Sending the pic size */#define PROXYCLSTATE_SEND_PICTURE 1 /* Sending the actual picture */typedef struct client_data_st { int clienttype; /* one of CLIENT_T_* */ DataBuf *writebuf; DataBuf *readbuf; struct camdata_st { /* Valid only if clientttype == CAMSERV */ unsigned long int picsize; /* Picture size in network order */ char *picbuf; /* Actual picture data */ int camstate; /* State of camera */ } camdata; struct browser_st { int browserstate; void *management_data; int last_pic_id; } browserdata; struct proxycl_st { int proxystate; unsigned long int picsize; /* Picture size in network order */ void *management_data; int last_pic_id; char *pic_data; } proxycldata; char junkbuf[ 1024 ];} ClientData;typedef struct relay_data_st { char camera_ip[ 1024 ]; /* IP of the remote camserv or relay */ int camera_port; /* Port of the remote camserv or relay */ Socket *camera_sock; /* Connection of camera sock */} RelayData;#define RANDOMSTRING "ThisRandomString"#define CONTENTTYPE "image/jpeg"staticchar *get_preamble_text( size_t *len, int multi ){#define MPREAMBLE_STR "HTTP/1.0 200 OK\n" \ "Content-type: multipart/x-mixed-replace;boundary=" RANDOMSTRING "\n" \ "Cache-Control: no-cache\n" \ "Cache-Control: private\n" \ "Pragma: no-cache\n\n" \ "--" RANDOMSTRING "\n" \ "Content-type: " CONTENTTYPE "\n\n"#define SPREAMBLE_STR "HTTP/1.0 200 OK\n" \ "Content-type: " CONTENTTYPE "\n" \ "Cache-Control: no-cache\n" \ "Cache-Control: private\n" \ "Pragma: no-cache\n\n" if( multi ) { if( len != NULL ) *len = sizeof( MPREAMBLE_STR ) - 1; return MPREAMBLE_STR; } else { if( len != NULL ) *len = sizeof( SPREAMBLE_STR ) - 1; return SPREAMBLE_STR; }}staticchar *get_seperator_text( size_t *len ){#define SEPERATOR_TEXT "\n--" RANDOMSTRING "\n" \ "Content-type: " CONTENTTYPE "\n\n" /* XXX */ if( len != NULL ) *len = sizeof( SEPERATOR_TEXT ) - 1; return SEPERATOR_TEXT;}/* * client_data_new: Create and initialize a new clientinfo structure. * * Return values: Returns NULL on failure, else a valid new clientdata * on success. */staticClientData *client_data_new(){ ClientData *res; if( (res = malloc( sizeof( *res ))) == NULL ) return NULL; if( (res->readbuf = databuf_new()) == NULL ){ free( res ); return NULL; } if( (res->writebuf = databuf_new()) == NULL ){ databuf_dest( res->readbuf ); free( res ); return NULL; } res->clienttype = CLIENT_T_UNK; return res;}/* * client_data_dest: Destroy a client data structure. * * Arguments: cldata = Clientdata to destroy */staticvoid client_data_dest( ClientData *cldata ){ databuf_dest( cldata->readbuf ); databuf_dest( cldata->writebuf ); free( cldata );}/* * relay_connect_camserv: Connect to a camera server. * * Arguments: rdata = Relay data with info of where to connect. * * Return values: Returns -1 if the connection could not be made, else * 0. If successful, rdata->camera_sock will be * set to the new sock, else it will be set to NULL */staticint relay_connect_camserv( SockField_Data *sfdata, RelayData *rdata ){ ClientData *cldata; rdata->camera_sock = socket_connect( rdata->camera_ip, rdata->camera_port ); if( rdata->camera_sock == NULL ) return -1; if( (cldata = client_data_new()) == NULL ){ camserv_log( MODNAME, "Error mallocing clientdata"); socket_dest( rdata->camera_sock ); return -1; } cldata->clienttype = CLIENT_T_CAMSERV; if( sock_field_manage_socket( sfdata, rdata->camera_sock, cldata ) == -1 ) { camserv_log( MODNAME, "Error managing connect camera socket!"); client_data_dest( cldata ); socket_dest( rdata->camera_sock ); rdata->camera_sock = NULL; return -1; } /* Send the proxy keyword */ databuf_buf_set( cldata->writebuf, "PROXY", sizeof( "PROXY" )); cldata->camdata.picsize = 0; cldata->camdata.picbuf = NULL; cldata->camdata.camstate = CAMSTATE_SEND_PROXY; return 0;}/* * relay_init: Initialize the relay. This involves making the connection * to the camera server if possible. * * Arguments: sfdata = Sockfield data passed from the almighty. * * Return values: Returns SOCKFIELD_OK on success, else SOCKFIELD_CLOSE. */staticint relay_init( SockField_Data *sfdata, void *sys_cldata ){ RelayData *rdata = sys_cldata; if( relay_connect_camserv( sfdata, rdata ) == -1 ) camserv_log( MODNAME, "Couldn't connect to camserv: %s %d", rdata->camera_ip, rdata->camera_port ); return SOCKFIELD_OK;}/* * relay_preclose: Called by the field loop prior to closing a socket. * This routine should cleanup any of the clientdata passed * to the fieldloop management routines on socket init. * * Arguments: sock = Socket about to be closed. * cldata = Clientdata passed in for socket @ manage time. * sys_cldata = System clientdata, passed in as argument * to main field_loop */staticvoid relay_preclose( Socket *sock, void *cldata, void *sys_cldata ){ RelayData *rdata = sys_cldata; ClientData *clientdata = cldata; if( clientdata->clienttype == CLIENT_T_CAMSERV ) { camserv_log( MODNAME, "Closing connection to camsera server!" ); /* Camera sock is now invalid */ rdata->camera_sock = NULL; } else { camserv_log( MODNAME, "Closing client from: \"%s\"", socket_query_remote_name( sock )); } client_data_dest( cldata );}/* * read_camera: This routine is called everytime the camserv socket has * sent us some data to read. It is in 2 states the entire * time -- that of getting the size of the next picture, then * actually receiving the picture. After a successful * receipt of a picture, it is then put into the management bins. * * Arguments: sfdata = SockField data * sock = Socket of the camserv object * cldata = Clientdata of the camserv object. * * Return values: Returns one of SOCKFIELD_* */staticint read_camera( SockField_Data *sfdata, Socket *sock, ClientData *cldata ){ if( cldata->camdata.camstate == CAMSTATE_RECV_SIZE ) { /* We just got the size ... malloc the data and attempt to receive it too*/ cldata->camdata.camstate = CAMSTATE_RECV_PICTURE; cldata->camdata.picbuf = malloc( ntohl( cldata->camdata.picsize )); if( cldata->camdata.picbuf == NULL ) { camserv_log( MODNAME, "Couldn't malloc: %ld bytes for picture!", (long)ntohl( cldata->camdata.picsize )); return SOCKFIELD_CLOSE; } databuf_buf_set( cldata->readbuf, cldata->camdata.picbuf, ntohl( cldata->camdata.picsize ) ); } else { /* Else we just completed getting a whole picture */ cldata->camdata.camstate = CAMSTATE_RECV_SIZE; databuf_buf_set( cldata->readbuf, &cldata->camdata.picsize, sizeof( cldata->camdata.picsize ) ); if( manager_new_picture( cldata->camdata.picbuf, ntohl( cldata->camdata.picsize ), 100 ) == -1 ) { camserv_log( MODNAME, "Unable to manage picture!"); free( cldata->camdata.picbuf ); return SOCKFIELD_CLOSE; } sock_field_unhold_write( sfdata ); } return SOCKFIELD_OK;}/* * read_client: Called when a client has sent data to the relay. We just * ignore everything the client sends us after initialization. */staticint read_client( SockField_Data *sfdata, Socket *sock, ClientData *cldata ){ /* Just refill the buffer .. client's that write anything, we are really just disregarded */ databuf_buf_set( cldata->readbuf, &cldata->junkbuf[ 0 ], sizeof( cldata->junkbuf )); return SOCKFIELD_OK;}/* * set_client_writebuf: Set the writebuffer of the client for the first * time. This is usually the 'init' state for the * client. * * Arguments: cldata = client to set the writebuffer for. */staticvoid set_client_writebuf( ClientData *cldata ){ size_t len; char *cp; if( cldata->clienttype == CLIENT_T_BROWSER ){ cp = get_preamble_text( &len, 1 ); cldata->browserdata.browserstate = BROWSERSTATE_SEND_PREAMBLE; } else if( cldata->clienttype == CLIENT_T_SINGLE ) { cp = get_preamble_text( &len, 0 ); cldata->browserdata.browserstate = BROWSERSTATE_SEND_PREAMBLE; } else if( cldata->clienttype == CLIENT_T_PROXY ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -